loadSkillFromZipBytes function
Loads a Skill from ZIP bytes containing a root-level SKILL.md.
Implementation
Skill loadSkillFromZipBytes(List<int> zipBytes) {
final archive.Archive skillArchive = archive.ZipDecoder().decodeBytes(
zipBytes,
);
final Map<String, archive.ArchiveFile> files =
<String, archive.ArchiveFile>{};
for (final archive.ArchiveFile entry in skillArchive) {
final String name = _normalizeArchiveEntryName(entry.name);
_assertSafeArchiveEntry(entry.name, name);
if (!entry.isFile) {
continue;
}
if (entry.isSymbolicLink) {
throw ArgumentError('Dangerous zip entry ignored: ${entry.name}');
}
files[name] = entry;
}
final archive.ArchiveFile? skillMd = files['SKILL.md'] ?? files['skill.md'];
if (skillMd == null) {
throw StateError('SKILL.md not found in zipped filesystem.');
}
final List<int>? skillMdBytes = skillMd.readBytes();
if (skillMdBytes == null) {
throw const FormatException(
'SKILL.md could not be read from zipped filesystem.',
);
}
final _ParsedSkillMd parsed = _parseSkillMdContent(
_decodeSkillText(skillMdBytes),
);
final Object? skillName = parsed.frontmatter['name'];
if (skillName == null) {
throw ArgumentError("SKILL.md frontmatter must contain 'name'");
}
if (skillName is! String || _isInvalidArchiveSkillName(skillName)) {
throw ArgumentError('Invalid skill name in SKILL.md: $skillName');
}
final Frontmatter frontmatter = Frontmatter.fromMap(parsed.frontmatter);
final Map<String, SkillResourceData> references =
<String, SkillResourceData>{};
final Map<String, SkillResourceData> assets = <String, SkillResourceData>{};
final Map<String, Script> scripts = <String, Script>{};
for (final MapEntry<String, archive.ArchiveFile> entry in files.entries) {
if (entry.key == 'SKILL.md' || entry.key == 'skill.md') {
continue;
}
if (_containsIgnoredArchiveSegment(entry.key)) {
continue;
}
final List<int>? bytes = entry.value.readBytes();
if (bytes == null) {
continue;
}
if (entry.key.startsWith('references/')) {
final String resourceId = entry.key.substring('references/'.length);
if (resourceId.isNotEmpty) {
references[resourceId] = _decodeSkillResource(resourceId, bytes);
}
continue;
}
if (entry.key.startsWith('assets/')) {
final String resourceId = entry.key.substring('assets/'.length);
if (resourceId.isNotEmpty) {
assets[resourceId] = _decodeSkillResource(resourceId, bytes);
}
continue;
}
if (entry.key.startsWith('scripts/')) {
final String scriptId = entry.key.substring('scripts/'.length);
if (scriptId.isEmpty) {
continue;
}
try {
scripts[scriptId] = Script(src: _decodeSkillText(bytes));
} on FormatException {
continue;
}
}
}
return Skill(
frontmatter: frontmatter,
instructions: parsed.body,
resources: Resources(
references: references,
assets: assets,
scripts: scripts,
),
);
}