@polpo-ai/core 0.18.22 → 0.18.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/__tests__/skill-archive.test.d.ts +2 -0
  2. package/dist/__tests__/skill-archive.test.d.ts.map +1 -0
  3. package/dist/__tests__/skill-archive.test.js +72 -0
  4. package/dist/__tests__/skill-archive.test.js.map +1 -0
  5. package/dist/__tests__/skill-bundle.test.js +22 -1
  6. package/dist/__tests__/skill-bundle.test.js.map +1 -1
  7. package/dist/__tests__/skill-manifest.test.d.ts +2 -0
  8. package/dist/__tests__/skill-manifest.test.d.ts.map +1 -0
  9. package/dist/__tests__/skill-manifest.test.js +70 -0
  10. package/dist/__tests__/skill-manifest.test.js.map +1 -0
  11. package/dist/__tests__/task-runner-model-profiles.test.js +49 -0
  12. package/dist/__tests__/task-runner-model-profiles.test.js.map +1 -1
  13. package/dist/adapter.d.ts +2 -0
  14. package/dist/adapter.d.ts.map +1 -1
  15. package/dist/hooks.d.ts +1 -0
  16. package/dist/hooks.d.ts.map +1 -1
  17. package/dist/hooks.js.map +1 -1
  18. package/dist/index.d.ts +10 -2
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +5 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/orchestrator-engine.d.ts +4 -0
  23. package/dist/orchestrator-engine.d.ts.map +1 -1
  24. package/dist/orchestrator-engine.js.map +1 -1
  25. package/dist/scheduling/types.d.ts +2 -0
  26. package/dist/scheduling/types.d.ts.map +1 -1
  27. package/dist/scheduling/validation.d.ts.map +1 -1
  28. package/dist/scheduling/validation.js +5 -1
  29. package/dist/scheduling/validation.js.map +1 -1
  30. package/dist/scheduling/validation.test.js +16 -0
  31. package/dist/scheduling/validation.test.js.map +1 -1
  32. package/dist/skill-activation.d.ts +24 -0
  33. package/dist/skill-activation.d.ts.map +1 -0
  34. package/dist/skill-activation.js +78 -0
  35. package/dist/skill-activation.js.map +1 -0
  36. package/dist/skill-activation.test.d.ts +2 -0
  37. package/dist/skill-activation.test.d.ts.map +1 -0
  38. package/dist/skill-activation.test.js +43 -0
  39. package/dist/skill-activation.test.js.map +1 -0
  40. package/dist/skill-archive.d.ts +19 -0
  41. package/dist/skill-archive.d.ts.map +1 -0
  42. package/dist/skill-archive.js +230 -0
  43. package/dist/skill-archive.js.map +1 -0
  44. package/dist/skill-bundle-store.d.ts +57 -0
  45. package/dist/skill-bundle-store.d.ts.map +1 -0
  46. package/dist/skill-bundle-store.js +11 -0
  47. package/dist/skill-bundle-store.js.map +1 -0
  48. package/dist/skill-bundle.d.ts +19 -0
  49. package/dist/skill-bundle.d.ts.map +1 -1
  50. package/dist/skill-bundle.js +58 -8
  51. package/dist/skill-bundle.js.map +1 -1
  52. package/dist/skill-manifest.d.ts +32 -0
  53. package/dist/skill-manifest.d.ts.map +1 -0
  54. package/dist/skill-manifest.js +165 -0
  55. package/dist/skill-manifest.js.map +1 -0
  56. package/dist/skills-reader.d.ts +11 -0
  57. package/dist/skills-reader.d.ts.map +1 -1
  58. package/dist/skills-reader.js +72 -37
  59. package/dist/skills-reader.js.map +1 -1
  60. package/dist/skills-reader.test.js +18 -2
  61. package/dist/skills-reader.test.js.map +1 -1
  62. package/dist/task-manager.d.ts +1 -0
  63. package/dist/task-manager.d.ts.map +1 -1
  64. package/dist/task-manager.js +3 -0
  65. package/dist/task-manager.js.map +1 -1
  66. package/dist/task-runner.d.ts.map +1 -1
  67. package/dist/task-runner.js +3 -0
  68. package/dist/task-runner.js.map +1 -1
  69. package/dist/types/task.d.ts +2 -0
  70. package/dist/types/task.d.ts.map +1 -1
  71. package/package.json +11 -1
@@ -0,0 +1,78 @@
1
+ /** Maximum number of skills that a caller may explicitly activate per run. */
2
+ export const MAX_ACTIVATED_SKILLS = 16;
3
+ /** Maximum length of a skill identifier accepted by runtime surfaces. */
4
+ export const MAX_ACTIVATED_SKILL_NAME_LENGTH = 256;
5
+ /** Reject malformed persisted or host-resolved activation snapshots. */
6
+ export function normalizeActivatedSkillReferences(value) {
7
+ if (value === undefined)
8
+ return [];
9
+ if (!Array.isArray(value) || value.length > MAX_ACTIVATED_SKILLS) {
10
+ throw new SkillActivationError("Activated skill references are invalid");
11
+ }
12
+ const seen = new Set();
13
+ return value.map((item, index) => {
14
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
15
+ throw new SkillActivationError(`Activated skill reference at index ${index} must be an object`);
16
+ }
17
+ const name = item.name;
18
+ const digest = item.digest;
19
+ if (typeof name !== "string" || name.length === 0 || name.length > MAX_ACTIVATED_SKILL_NAME_LENGTH) {
20
+ throw new SkillActivationError(`Activated skill reference at index ${index} has an invalid name`);
21
+ }
22
+ if (digest !== undefined && (typeof digest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(digest))) {
23
+ throw new SkillActivationError(`Activated skill reference "${name}" has an invalid digest`);
24
+ }
25
+ if (seen.has(name))
26
+ throw new SkillActivationError(`Duplicate activated skill reference: ${name}`);
27
+ seen.add(name);
28
+ return digest === undefined ? { name } : { name, digest };
29
+ });
30
+ }
31
+ export class SkillActivationError extends Error {
32
+ code = "skill_activation_invalid";
33
+ constructor(message) {
34
+ super(message);
35
+ this.name = "SkillActivationError";
36
+ }
37
+ }
38
+ /**
39
+ * Normalize the additive skill selection shared by chat, Tasks and Schedules.
40
+ * Undefined means "no explicit activation"; an explicit empty array is invalid.
41
+ */
42
+ export function normalizeActivatedSkills(value) {
43
+ if (value === undefined)
44
+ return undefined;
45
+ if (!Array.isArray(value) || value.length === 0 || value.length > MAX_ACTIVATED_SKILLS) {
46
+ throw new SkillActivationError(`Activated skills must contain between 1 and ${MAX_ACTIVATED_SKILLS} names`);
47
+ }
48
+ const normalized = [];
49
+ const seen = new Set();
50
+ for (const [index, item] of value.entries()) {
51
+ if (typeof item !== "string") {
52
+ throw new SkillActivationError(`Activated skill at index ${index} must be a string`);
53
+ }
54
+ const name = item.trim();
55
+ if (name.length === 0 || name.length > MAX_ACTIVATED_SKILL_NAME_LENGTH) {
56
+ throw new SkillActivationError(`Activated skill at index ${index} must contain between 1 and ${MAX_ACTIVATED_SKILL_NAME_LENGTH} characters`);
57
+ }
58
+ if (seen.has(name)) {
59
+ throw new SkillActivationError(`Duplicate activated skill: ${name}`);
60
+ }
61
+ seen.add(name);
62
+ normalized.push(name);
63
+ }
64
+ return normalized;
65
+ }
66
+ /** Validate that explicit activation cannot grant a skill the agent was not assigned. */
67
+ export function requireAssignedActivatedSkills(requested, assigned) {
68
+ const normalized = normalizeActivatedSkills(requested);
69
+ if (!normalized)
70
+ return undefined;
71
+ const assignedNames = new Set((assigned ?? []).filter((name) => typeof name === "string"));
72
+ const missing = normalized.find((name) => !assignedNames.has(name));
73
+ if (missing) {
74
+ throw new SkillActivationError(`Skill "${missing}" is not assigned to the selected agent`);
75
+ }
76
+ return normalized;
77
+ }
78
+ //# sourceMappingURL=skill-activation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-activation.js","sourceRoot":"","sources":["../src/skill-activation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=skill-activation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-activation.test.d.ts","sourceRoot":"","sources":["../src/skill-activation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { MAX_ACTIVATED_SKILLS, normalizeActivatedSkillReferences, normalizeActivatedSkills, requireAssignedActivatedSkills, } from "./skill-activation.js";
3
+ describe("skill activation", () => {
4
+ it("normalizes a bounded additive selection", () => {
5
+ expect(normalizeActivatedSkills([" frontend-design ", "testing"])).toEqual([
6
+ "frontend-design",
7
+ "testing",
8
+ ]);
9
+ expect(normalizeActivatedSkills(undefined)).toBeUndefined();
10
+ });
11
+ it.each([
12
+ { skills: [] },
13
+ { skills: [""] },
14
+ { skills: ["frontend-design", " frontend-design "] },
15
+ { skills: Array.from({ length: MAX_ACTIVATED_SKILLS + 1 }, (_, index) => `skill-${index}`) },
16
+ { skills: [42] },
17
+ ])("rejects an invalid selection: $skills", ({ skills }) => {
18
+ expect(() => normalizeActivatedSkills(skills)).toThrow();
19
+ });
20
+ it("rejects activation of a skill not assigned to the agent", () => {
21
+ expect(() => requireAssignedActivatedSkills(["security-review"], ["frontend-design"])).toThrow(/not assigned/i);
22
+ expect(requireAssignedActivatedSkills(["frontend-design"], ["frontend-design", "testing"])).toEqual(["frontend-design"]);
23
+ });
24
+ it("normalizes immutable activation references used by checkpoints", () => {
25
+ const digest = `sha256:${"a".repeat(64)}`;
26
+ expect(normalizeActivatedSkillReferences([
27
+ { name: "frontend-design", digest },
28
+ { name: "legacy-skill" },
29
+ ])).toEqual([
30
+ { name: "frontend-design", digest },
31
+ { name: "legacy-skill" },
32
+ ]);
33
+ });
34
+ it.each([
35
+ { references: [{ name: "frontend-design", digest: "sha256:bad" }] },
36
+ { references: [{ name: "" }] },
37
+ { references: [{ name: "frontend-design" }, { name: "frontend-design" }] },
38
+ { references: ["frontend-design"] },
39
+ ])("rejects malformed immutable activation references: $references", ({ references }) => {
40
+ expect(() => normalizeActivatedSkillReferences(references)).toThrow();
41
+ });
42
+ });
43
+ //# sourceMappingURL=skill-activation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-activation.test.js","sourceRoot":"","sources":["../src/skill-activation.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type SkillBundle } from "./skill-bundle.js";
2
+ import { type SkillDiagnostic, type SkillManifest } from "./skill-manifest.js";
3
+ export declare const SKILL_ARCHIVE_MAX_COMPRESSED_BYTES: number;
4
+ export declare const SKILL_ARCHIVE_MAX_COMPRESSION_RATIO = 200;
5
+ export type SkillArchiveErrorCode = "invalid_archive" | "encrypted_entry" | "unsupported_entry" | "archive_limit_exceeded" | "ambiguous_root" | "invalid_bundle" | "invalid_manifest";
6
+ export declare class SkillArchiveError extends Error {
7
+ readonly code: SkillArchiveErrorCode;
8
+ constructor(code: SkillArchiveErrorCode, message: string);
9
+ }
10
+ export interface UnpackedSkillArchive {
11
+ bundle: SkillBundle;
12
+ manifest: SkillManifest;
13
+ diagnostics: SkillDiagnostic[];
14
+ digest: string;
15
+ uncompressedBytes: number;
16
+ }
17
+ export declare function unpackSkillArchive(input: Uint8Array): Promise<UnpackedSkillArchive>;
18
+ export declare function packSkillArchive(bundle: SkillBundle): Promise<Uint8Array>;
19
+ //# sourceMappingURL=skill-archive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-archive.d.ts","sourceRoot":"","sources":["../src/skill-archive.ts"],"names":[],"mappings":"AACA,OAAO,EASL,KAAK,WAAW,EAEjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAsB,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEnG,eAAO,MAAM,kCAAkC,QAAmB,CAAC;AACnE,eAAO,MAAM,mCAAmC,MAAM,CAAC;AAEvD,MAAM,MAAM,qBAAqB,GAC7B,iBAAiB,GACjB,iBAAiB,GACjB,mBAAmB,GACnB,wBAAwB,GACxB,gBAAgB,GAChB,gBAAgB,GAChB,kBAAkB,CAAC;AAEvB,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,IAAI,EAAE,qBAAqB;gBAA3B,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM;CAIlE;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AASD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAgEzF;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAuB/E"}
@@ -0,0 +1,230 @@
1
+ import { unzipSync, zipSync } from "fflate";
2
+ import { SKILL_BUNDLE_MAX_FILES, SKILL_BUNDLE_MAX_FILE_BYTES, SKILL_BUNDLE_MAX_PATH_LENGTH, SKILL_BUNDLE_MAX_TOTAL_BYTES, decodeBase64, digestSkillBundle, encodeBase64, validateSkillBundleFiles, } from "./skill-bundle.js";
3
+ import { parseSkillManifest } from "./skill-manifest.js";
4
+ export const SKILL_ARCHIVE_MAX_COMPRESSED_BYTES = 30 * 1024 * 1024;
5
+ export const SKILL_ARCHIVE_MAX_COMPRESSION_RATIO = 200;
6
+ export class SkillArchiveError extends Error {
7
+ code;
8
+ constructor(code, message) {
9
+ super(message);
10
+ this.code = code;
11
+ this.name = "SkillArchiveError";
12
+ }
13
+ }
14
+ export async function unpackSkillArchive(input) {
15
+ if (input.byteLength === 0 || input.byteLength > SKILL_ARCHIVE_MAX_COMPRESSED_BYTES) {
16
+ throw new SkillArchiveError("archive_limit_exceeded", "Skill archive compressed size is outside the supported limit");
17
+ }
18
+ const inventory = inspectCentralDirectory(input);
19
+ const files = inventory.filter((entry) => !entry.directory);
20
+ if (files.length === 0 || files.length > SKILL_BUNDLE_MAX_FILES) {
21
+ throw new SkillArchiveError("archive_limit_exceeded", `Skill archive must contain 1 to ${SKILL_BUNDLE_MAX_FILES} files`);
22
+ }
23
+ let totalBytes = 0;
24
+ for (const entry of files) {
25
+ if (entry.uncompressedBytes > SKILL_BUNDLE_MAX_FILE_BYTES) {
26
+ throw new SkillArchiveError("archive_limit_exceeded", `Skill archive file is too large: ${entry.path}`);
27
+ }
28
+ if (entry.compressedBytes === 0 && entry.uncompressedBytes > 0) {
29
+ throw new SkillArchiveError("archive_limit_exceeded", `Skill archive entry has an invalid compression ratio: ${entry.path}`);
30
+ }
31
+ if (entry.compressedBytes > 0 && entry.uncompressedBytes / entry.compressedBytes > SKILL_ARCHIVE_MAX_COMPRESSION_RATIO) {
32
+ throw new SkillArchiveError("archive_limit_exceeded", `Skill archive entry exceeds the compression-ratio limit: ${entry.path}`);
33
+ }
34
+ totalBytes += entry.uncompressedBytes;
35
+ if (totalBytes > SKILL_BUNDLE_MAX_TOTAL_BYTES) {
36
+ throw new SkillArchiveError("archive_limit_exceeded", "Skill archive exceeds the uncompressed size limit");
37
+ }
38
+ }
39
+ const root = resolveArchiveRoot(files.map((entry) => entry.path));
40
+ let expanded;
41
+ try {
42
+ expanded = unzipSync(input);
43
+ }
44
+ catch (error) {
45
+ throw new SkillArchiveError("invalid_archive", `Skill archive could not be decompressed: ${errorMessage(error)}`);
46
+ }
47
+ const bundleFiles = [];
48
+ for (const entry of files) {
49
+ const bytes = expanded[entry.path];
50
+ if (!bytes || bytes.byteLength !== entry.uncompressedBytes) {
51
+ throw new SkillArchiveError("invalid_archive", `Skill archive entry is missing or has an invalid size: ${entry.path}`);
52
+ }
53
+ const path = root ? entry.path.slice(root.length + 1) : entry.path;
54
+ bundleFiles.push({ path, content: encodeBase64(bytes), encoding: "base64" });
55
+ }
56
+ bundleFiles.sort((left, right) => compareStrings(left.path, right.path));
57
+ const skillFile = bundleFiles.find((file) => file.path === "SKILL.md");
58
+ if (!skillFile)
59
+ throw new SkillArchiveError("ambiguous_root", "Skill archive must contain one root SKILL.md");
60
+ let parsed;
61
+ try {
62
+ const candidate = new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64(skillFile.content));
63
+ parsed = parseSkillManifest(candidate, { mode: "strict", directoryName: root || undefined });
64
+ }
65
+ catch (error) {
66
+ throw new SkillArchiveError("invalid_manifest", errorMessage(error));
67
+ }
68
+ const bundle = { name: parsed.manifest.name, files: bundleFiles };
69
+ const validationError = validateSkillBundleFiles(bundle.files);
70
+ if (validationError)
71
+ throw new SkillArchiveError("invalid_bundle", validationError);
72
+ return {
73
+ bundle,
74
+ manifest: parsed.manifest,
75
+ diagnostics: parsed.diagnostics,
76
+ digest: await digestSkillBundle(bundle),
77
+ uncompressedBytes: totalBytes,
78
+ };
79
+ }
80
+ export async function packSkillArchive(bundle) {
81
+ const validationError = validateSkillBundleFiles(bundle.files);
82
+ if (validationError)
83
+ throw new SkillArchiveError("invalid_bundle", validationError);
84
+ const skillFile = bundle.files.find((file) => file.path === "SKILL.md");
85
+ try {
86
+ const content = new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64(skillFile.content));
87
+ parseSkillManifest(content, { mode: "strict", directoryName: bundle.name });
88
+ }
89
+ catch (error) {
90
+ throw new SkillArchiveError("invalid_manifest", errorMessage(error));
91
+ }
92
+ const archive = {};
93
+ for (const file of [...bundle.files].sort((left, right) => compareStrings(left.path, right.path))) {
94
+ archive[`${bundle.name}/${file.path}`] = [decodeBase64(file.content), {
95
+ level: 6,
96
+ // fflate writes DOS timestamps through local Date getters. Constructing
97
+ // local midnight keeps the archive bytes stable across host timezones.
98
+ mtime: new Date(1980, 0, 1, 0, 0, 0),
99
+ os: 3,
100
+ attrs: 0o100644 << 16,
101
+ }];
102
+ }
103
+ return zipSync(archive, { level: 6 });
104
+ }
105
+ function resolveArchiveRoot(paths) {
106
+ if (paths.includes("SKILL.md")) {
107
+ if (paths.some((path) => path !== "SKILL.md" && !path.includes("/"))) {
108
+ throw new SkillArchiveError("ambiguous_root", "Root-layout skill archives cannot contain unrelated root files");
109
+ }
110
+ return "";
111
+ }
112
+ const roots = new Set(paths.map((path) => path.split("/", 1)[0]));
113
+ if (roots.size !== 1)
114
+ throw new SkillArchiveError("ambiguous_root", "Skill archive must contain exactly one skill root");
115
+ const root = [...roots][0];
116
+ if (!paths.includes(`${root}/SKILL.md`)) {
117
+ throw new SkillArchiveError("ambiguous_root", "Skill archive must contain SKILL.md at its root");
118
+ }
119
+ return root;
120
+ }
121
+ function inspectCentralDirectory(input) {
122
+ const view = new DataView(input.buffer, input.byteOffset, input.byteLength);
123
+ const eocd = findEndOfCentralDirectory(view);
124
+ const disk = view.getUint16(eocd + 4, true);
125
+ const centralDisk = view.getUint16(eocd + 6, true);
126
+ const diskEntries = view.getUint16(eocd + 8, true);
127
+ const totalEntries = view.getUint16(eocd + 10, true);
128
+ const centralSize = view.getUint32(eocd + 12, true);
129
+ const centralOffset = view.getUint32(eocd + 16, true);
130
+ if (disk !== 0 || centralDisk !== 0 || diskEntries !== totalEntries) {
131
+ throw new SkillArchiveError("unsupported_entry", "Multi-disk ZIP archives are not supported");
132
+ }
133
+ if (totalEntries === 0xffff || centralSize === 0xffffffff || centralOffset === 0xffffffff) {
134
+ throw new SkillArchiveError("unsupported_entry", "ZIP64 archives are not supported");
135
+ }
136
+ if (centralOffset + centralSize > eocd || totalEntries > SKILL_BUNDLE_MAX_FILES * 2) {
137
+ throw new SkillArchiveError("invalid_archive", "ZIP central directory is outside the archive bounds");
138
+ }
139
+ const decoder = new TextDecoder("utf-8", { fatal: true });
140
+ const paths = new Set();
141
+ const foldedPaths = new Set();
142
+ const entries = [];
143
+ let offset = centralOffset;
144
+ for (let index = 0; index < totalEntries; index += 1) {
145
+ if (offset + 46 > eocd || view.getUint32(offset, true) !== 0x02014b50) {
146
+ throw new SkillArchiveError("invalid_archive", "ZIP central directory entry is invalid");
147
+ }
148
+ const madeBy = view.getUint16(offset + 4, true);
149
+ const flags = view.getUint16(offset + 8, true);
150
+ const method = view.getUint16(offset + 10, true);
151
+ const compressedBytes = view.getUint32(offset + 20, true);
152
+ const uncompressedBytes = view.getUint32(offset + 24, true);
153
+ const nameLength = view.getUint16(offset + 28, true);
154
+ const extraLength = view.getUint16(offset + 30, true);
155
+ const commentLength = view.getUint16(offset + 32, true);
156
+ const diskStart = view.getUint16(offset + 34, true);
157
+ const externalAttributes = view.getUint32(offset + 38, true);
158
+ const end = offset + 46 + nameLength + extraLength + commentLength;
159
+ if (end > eocd)
160
+ throw new SkillArchiveError("invalid_archive", "ZIP entry metadata is truncated");
161
+ if ((flags & 1) !== 0)
162
+ throw new SkillArchiveError("encrypted_entry", "Encrypted skill archive entries are not supported");
163
+ if (method !== 0 && method !== 8)
164
+ throw new SkillArchiveError("unsupported_entry", `Unsupported ZIP compression method: ${method}`);
165
+ if (diskStart !== 0 || compressedBytes === 0xffffffff || uncompressedBytes === 0xffffffff) {
166
+ throw new SkillArchiveError("unsupported_entry", "ZIP64 or multi-disk entries are not supported");
167
+ }
168
+ let path;
169
+ try {
170
+ path = decoder.decode(input.subarray(offset + 46, offset + 46 + nameLength));
171
+ }
172
+ catch {
173
+ throw new SkillArchiveError("invalid_archive", "ZIP entry names must be valid UTF-8");
174
+ }
175
+ const directory = path.endsWith("/");
176
+ const normalized = directory ? path.slice(0, -1) : path;
177
+ validateArchivePath(normalized);
178
+ const host = madeBy >>> 8;
179
+ const unixMode = host === 3 ? externalAttributes >>> 16 : 0;
180
+ const kind = unixMode & 0o170000;
181
+ if (kind !== 0 && kind !== 0o100000 && !(directory && kind === 0o040000)) {
182
+ throw new SkillArchiveError("unsupported_entry", `Skill archive contains a non-regular entry: ${path}`);
183
+ }
184
+ if (!directory) {
185
+ if (paths.has(normalized))
186
+ throw new SkillArchiveError("invalid_archive", `Duplicate ZIP entry: ${normalized}`);
187
+ const folded = normalized.toLocaleLowerCase("en-US");
188
+ if (foldedPaths.has(folded))
189
+ throw new SkillArchiveError("invalid_archive", `Case-colliding ZIP entry: ${normalized}`);
190
+ paths.add(normalized);
191
+ foldedPaths.add(folded);
192
+ }
193
+ entries.push({ path, compressedBytes, uncompressedBytes, directory });
194
+ offset = end;
195
+ }
196
+ if (offset !== centralOffset + centralSize) {
197
+ throw new SkillArchiveError("invalid_archive", "ZIP central directory size does not match its entries");
198
+ }
199
+ return entries;
200
+ }
201
+ function validateArchivePath(path) {
202
+ if (!path || path.startsWith("/") || path.includes("\\") || path.includes("\0") || path !== path.normalize("NFC")) {
203
+ throw new SkillArchiveError("invalid_archive", `Invalid skill archive path: ${path}`);
204
+ }
205
+ const segments = path.split("/");
206
+ if (segments.some((segment) => !segment || segment === "." || segment === "..")) {
207
+ throw new SkillArchiveError("invalid_archive", `Invalid skill archive path: ${path}`);
208
+ }
209
+ if (new TextEncoder().encode(path).byteLength > SKILL_BUNDLE_MAX_PATH_LENGTH + 65) {
210
+ throw new SkillArchiveError("archive_limit_exceeded", `Skill archive path is too long: ${path}`);
211
+ }
212
+ }
213
+ function findEndOfCentralDirectory(view) {
214
+ const minimum = Math.max(0, view.byteLength - 65_557);
215
+ for (let offset = view.byteLength - 22; offset >= minimum; offset -= 1) {
216
+ if (view.getUint32(offset, true) === 0x06054b50) {
217
+ const commentLength = view.getUint16(offset + 20, true);
218
+ if (offset + 22 + commentLength === view.byteLength)
219
+ return offset;
220
+ }
221
+ }
222
+ throw new SkillArchiveError("invalid_archive", "ZIP end-of-central-directory record was not found");
223
+ }
224
+ function errorMessage(error) {
225
+ return error instanceof Error ? error.message : String(error);
226
+ }
227
+ function compareStrings(left, right) {
228
+ return left < right ? -1 : left > right ? 1 : 0;
229
+ }
230
+ //# sourceMappingURL=skill-archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-archive.js","sourceRoot":"","sources":["../src/skill-archive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import type { SkillBundle, SkillBundleReceipt, SkillBundleSource } from "./skill-bundle.js";
2
+ import type { SkillManifest } from "./skill-manifest.js";
3
+ /** A bundle that has passed the canonical manifest, path, size and digest checks. */
4
+ export interface ValidatedSkillBundle {
5
+ bundle: SkillBundle;
6
+ manifest: SkillManifest;
7
+ digest: string;
8
+ uncompressedBytes: number;
9
+ source: SkillBundleSource | string;
10
+ }
11
+ /** One immutable version returned by a SkillBundleStore. */
12
+ export interface StoredSkillBundle extends ValidatedSkillBundle {
13
+ /** Host-specific immutable root when resources can be mounted into a sandbox. */
14
+ root?: string;
15
+ createdAt?: string;
16
+ }
17
+ export interface StoredSkillSummary {
18
+ name: string;
19
+ description: string;
20
+ digest: string;
21
+ files: number;
22
+ uncompressedBytes: number;
23
+ source: SkillBundleSource | string;
24
+ allowedTools?: string[];
25
+ root?: string;
26
+ createdAt?: string;
27
+ }
28
+ export interface SkillBundlePutOptions {
29
+ conflict: "error" | "replace";
30
+ /** Compare-and-swap precondition for the currently active digest. */
31
+ expectedDigest?: string;
32
+ }
33
+ export interface SkillBundleDeleteOptions {
34
+ /** Compare-and-swap precondition for the currently active digest. */
35
+ expectedDigest?: string;
36
+ }
37
+ /**
38
+ * Portable content-addressed skill storage contract.
39
+ *
40
+ * `get(name)` resolves the active version. `get(name, digest)` resolves that
41
+ * exact immutable version so a checkpoint can resume without drifting after
42
+ * a replacement. Implementations must never expose a partially written
43
+ * bundle as active.
44
+ */
45
+ export interface SkillBundleStore {
46
+ get(name: string, digest?: string): Promise<StoredSkillBundle | null>;
47
+ put(input: ValidatedSkillBundle, options: SkillBundlePutOptions): Promise<SkillBundleReceipt>;
48
+ delete(name: string, options?: SkillBundleDeleteOptions): Promise<boolean>;
49
+ list(): Promise<StoredSkillSummary[]>;
50
+ }
51
+ export type SkillBundleStoreConflictCode = "skill_conflict" | "skill_digest_conflict";
52
+ export declare class SkillBundleStoreConflictError extends Error {
53
+ readonly code: SkillBundleStoreConflictCode;
54
+ readonly currentDigest?: string | undefined;
55
+ constructor(code: SkillBundleStoreConflictCode, message: string, currentDigest?: string | undefined);
56
+ }
57
+ //# sourceMappingURL=skill-bundle-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-bundle-store.d.ts","sourceRoot":"","sources":["../src/skill-bundle-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,qFAAqF;AACrF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAAC;CACpC;AAED,4DAA4D;AAC5D,MAAM,WAAW,iBAAkB,SAAQ,oBAAoB;IAC7D,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACtE,GAAG,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC9F,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3E,IAAI,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,4BAA4B,GAAG,gBAAgB,GAAG,uBAAuB,CAAC;AAEtF,qBAAa,6BAA8B,SAAQ,KAAK;IAEpD,QAAQ,CAAC,IAAI,EAAE,4BAA4B;IAE3C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM;gBAFtB,IAAI,EAAE,4BAA4B,EAC3C,OAAO,EAAE,MAAM,EACN,aAAa,CAAC,EAAE,MAAM,YAAA;CAKlC"}
@@ -0,0 +1,11 @@
1
+ export class SkillBundleStoreConflictError extends Error {
2
+ code;
3
+ currentDigest;
4
+ constructor(code, message, currentDigest) {
5
+ super(message);
6
+ this.code = code;
7
+ this.currentDigest = currentDigest;
8
+ this.name = "SkillBundleStoreConflictError";
9
+ }
10
+ }
11
+ //# sourceMappingURL=skill-bundle-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-bundle-store.js","sourceRoot":"","sources":["../src/skill-bundle-store.ts"],"names":[],"mappings":"AA2DA,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAE3C;IAEA;IAHX,YACW,IAAkC,EAC3C,OAAe,EACN,aAAsB;QAE/B,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,SAAI,GAAJ,IAAI,CAA8B;QAElC,kBAAa,GAAb,aAAa,CAAS;QAG/B,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;IAC9C,CAAC;CACF"}
@@ -10,6 +10,21 @@ export interface SkillBundle {
10
10
  name: string;
11
11
  files: SkillBundleFile[];
12
12
  }
13
+ export type SkillBundleSource = "archive" | "directory" | "git" | "builder" | "bundle";
14
+ export interface SkillBundleReceipt {
15
+ name: string;
16
+ digest: string;
17
+ files: number;
18
+ uncompressedBytes: number;
19
+ changed: boolean;
20
+ source: SkillBundleSource | string;
21
+ assignedTo?: string[];
22
+ warnings: Array<{
23
+ code: string;
24
+ message: string;
25
+ severity: "warning";
26
+ }>;
27
+ }
13
28
  export declare const SKILL_BUNDLE_MAX_FILES = 512;
14
29
  export declare const SKILL_BUNDLE_MAX_FILE_BYTES: number;
15
30
  export declare const SKILL_BUNDLE_MAX_TOTAL_BYTES: number;
@@ -18,4 +33,8 @@ export declare function validateSkillName(name: string): string | null;
18
33
  export declare function decodedBase64Size(value: string): number;
19
34
  /** Validate a complete bundle before any filesystem mutation occurs. */
20
35
  export declare function validateSkillBundleFiles(files: readonly SkillBundleFile[]): string | null;
36
+ /** Compute a stable content digest independent of archive metadata and file order. */
37
+ export declare function digestSkillBundle(bundle: SkillBundle): Promise<string>;
38
+ export declare function encodeBase64(bytes: Uint8Array): string;
39
+ export declare function decodeBase64(value: string): Uint8Array;
21
40
  //# sourceMappingURL=skill-bundle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill-bundle.d.ts","sourceRoot":"","sources":["../src/skill-bundle.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,2BAA2B,QAAkB,CAAC;AAC3D,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAC7D,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAKhD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK7D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED,wEAAwE;AACxE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,GAAG,IAAI,CA2CzF"}
1
+ {"version":3,"file":"skill-bundle.d.ts","sourceRoot":"","sources":["../src/skill-bundle.ts"],"names":[],"mappings":"AAEA,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEvF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;CACzE;AAED,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,2BAA2B,QAAmB,CAAC;AAC5D,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAC7D,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAIhD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIvD;AAED,wEAAwE;AACxE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,GAAG,IAAI,CAkDzF;AAED,sFAAsF;AACtF,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB5E;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAQtD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAKtD"}
@@ -1,14 +1,11 @@
1
+ import { validateAgentSkillName } from "./skill-manifest.js";
1
2
  export const SKILL_BUNDLE_MAX_FILES = 512;
2
- export const SKILL_BUNDLE_MAX_FILE_BYTES = 5 * 1024 * 1024;
3
- export const SKILL_BUNDLE_MAX_TOTAL_BYTES = 10 * 1024 * 1024;
3
+ export const SKILL_BUNDLE_MAX_FILE_BYTES = 10 * 1024 * 1024;
4
+ export const SKILL_BUNDLE_MAX_TOTAL_BYTES = 30 * 1024 * 1024;
4
5
  export const SKILL_BUNDLE_MAX_PATH_LENGTH = 240;
5
- const SAFE_SKILL_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
6
6
  const BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
7
7
  export function validateSkillName(name) {
8
- if (!SAFE_SKILL_NAME.test(name) || name === "." || name === "..") {
9
- return "Skill name must be a safe directory name";
10
- }
11
- return null;
8
+ return validateAgentSkillName(name);
12
9
  }
13
10
  export function decodedBase64Size(value) {
14
11
  if (value.length === 0)
@@ -24,6 +21,7 @@ export function validateSkillBundleFiles(files) {
24
21
  return `Skill bundle exceeds the ${SKILL_BUNDLE_MAX_FILES}-file limit`;
25
22
  }
26
23
  const paths = new Set();
24
+ const foldedPaths = new Map();
27
25
  let totalBytes = 0;
28
26
  for (const file of files) {
29
27
  if (!file || file.encoding !== "base64" || typeof file.path !== "string" || typeof file.content !== "string") {
@@ -33,7 +31,9 @@ export function validateSkillBundleFiles(files) {
33
31
  file.path.length > SKILL_BUNDLE_MAX_PATH_LENGTH ||
34
32
  file.path.startsWith("/") ||
35
33
  file.path.includes("\\") ||
36
- file.path.includes("\0")) {
34
+ file.path.includes("\0") ||
35
+ file.path !== file.path.normalize("NFC") ||
36
+ new TextEncoder().encode(file.path).byteLength > SKILL_BUNDLE_MAX_PATH_LENGTH) {
37
37
  return `Invalid skill bundle path: ${file.path}`;
38
38
  }
39
39
  const segments = file.path.split("/");
@@ -43,6 +43,11 @@ export function validateSkillBundleFiles(files) {
43
43
  if (paths.has(file.path))
44
44
  return `Duplicate skill bundle path: ${file.path}`;
45
45
  paths.add(file.path);
46
+ const folded = file.path.toLocaleLowerCase("en-US");
47
+ const collision = foldedPaths.get(folded);
48
+ if (collision)
49
+ return `Skill bundle path has a case-insensitive collision: ${collision} and ${file.path}`;
50
+ foldedPaths.set(folded, file.path);
46
51
  if (file.content.length % 4 !== 0 || !BASE64.test(file.content)) {
47
52
  return `Invalid base64 content for ${file.path}`;
48
53
  }
@@ -59,4 +64,49 @@ export function validateSkillBundleFiles(files) {
59
64
  return "Skill bundle must contain SKILL.md at its root";
60
65
  return null;
61
66
  }
67
+ /** Compute a stable content digest independent of archive metadata and file order. */
68
+ export async function digestSkillBundle(bundle) {
69
+ const nameError = validateSkillName(bundle.name);
70
+ if (nameError)
71
+ throw new TypeError(nameError);
72
+ const bundleError = validateSkillBundleFiles(bundle.files);
73
+ if (bundleError)
74
+ throw new TypeError(bundleError);
75
+ const files = [];
76
+ for (const file of [...bundle.files].sort((left, right) => compareStrings(left.path, right.path))) {
77
+ const bytes = decodeBase64(file.content);
78
+ files.push({
79
+ path: file.path,
80
+ bytes: bytes.byteLength,
81
+ sha256: await sha256Hex(bytes),
82
+ });
83
+ }
84
+ const canonical = new TextEncoder().encode(JSON.stringify({ version: 1, name: bundle.name, files }));
85
+ return `sha256:${await sha256Hex(canonical)}`;
86
+ }
87
+ export function encodeBase64(bytes) {
88
+ let binary = "";
89
+ const chunkSize = 0x8000;
90
+ for (let offset = 0; offset < bytes.byteLength; offset += chunkSize) {
91
+ const chunk = bytes.subarray(offset, Math.min(offset + chunkSize, bytes.byteLength));
92
+ binary += String.fromCharCode(...chunk);
93
+ }
94
+ return btoa(binary);
95
+ }
96
+ export function decodeBase64(value) {
97
+ const binary = atob(value);
98
+ const bytes = new Uint8Array(binary.length);
99
+ for (let index = 0; index < binary.length; index += 1)
100
+ bytes[index] = binary.charCodeAt(index);
101
+ return bytes;
102
+ }
103
+ async function sha256Hex(value) {
104
+ const input = new ArrayBuffer(value.byteLength);
105
+ new Uint8Array(input).set(value);
106
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", input);
107
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
108
+ }
109
+ function compareStrings(left, right) {
110
+ return left < right ? -1 : left > right ? 1 : 0;
111
+ }
62
112
  //# sourceMappingURL=skill-bundle.js.map