@senior-skills/core 1.0.0
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.
- package/dist/application/agent-selection.d.ts +42 -0
- package/dist/application/agent-selection.d.ts.map +1 -0
- package/dist/application/agent-selection.js +143 -0
- package/dist/application/agent-selection.js.map +1 -0
- package/dist/application/apply-skill-updates.d.ts +10 -0
- package/dist/application/apply-skill-updates.d.ts.map +1 -0
- package/dist/application/apply-skill-updates.js +75 -0
- package/dist/application/apply-skill-updates.js.map +1 -0
- package/dist/application/check-updates.d.ts +40 -0
- package/dist/application/check-updates.d.ts.map +1 -0
- package/dist/application/check-updates.js +130 -0
- package/dist/application/check-updates.js.map +1 -0
- package/dist/application/context.d.ts +28 -0
- package/dist/application/context.d.ts.map +1 -0
- package/dist/application/context.js +2 -0
- package/dist/application/context.js.map +1 -0
- package/dist/application/create-skill.d.ts +33 -0
- package/dist/application/create-skill.d.ts.map +1 -0
- package/dist/application/create-skill.js +58 -0
- package/dist/application/create-skill.js.map +1 -0
- package/dist/application/diagnose.d.ts +44 -0
- package/dist/application/diagnose.d.ts.map +1 -0
- package/dist/application/diagnose.js +228 -0
- package/dist/application/diagnose.js.map +1 -0
- package/dist/application/install-skills.d.ts +59 -0
- package/dist/application/install-skills.d.ts.map +1 -0
- package/dist/application/install-skills.js +191 -0
- package/dist/application/install-skills.js.map +1 -0
- package/dist/application/list-installed.d.ts +39 -0
- package/dist/application/list-installed.d.ts.map +1 -0
- package/dist/application/list-installed.js +68 -0
- package/dist/application/list-installed.js.map +1 -0
- package/dist/application/package-loader.d.ts +42 -0
- package/dist/application/package-loader.d.ts.map +1 -0
- package/dist/application/package-loader.js +320 -0
- package/dist/application/package-loader.js.map +1 -0
- package/dist/application/publish-skill.d.ts +41 -0
- package/dist/application/publish-skill.d.ts.map +1 -0
- package/dist/application/publish-skill.js +112 -0
- package/dist/application/publish-skill.js.map +1 -0
- package/dist/application/remove-skills.d.ts +34 -0
- package/dist/application/remove-skills.d.ts.map +1 -0
- package/dist/application/remove-skills.js +95 -0
- package/dist/application/remove-skills.js.map +1 -0
- package/dist/application/resolution-source.d.ts +25 -0
- package/dist/application/resolution-source.d.ts.map +1 -0
- package/dist/application/resolution-source.js +60 -0
- package/dist/application/resolution-source.js.map +1 -0
- package/dist/application/resolve-suggestions.d.ts +17 -0
- package/dist/application/resolve-suggestions.d.ts.map +1 -0
- package/dist/application/resolve-suggestions.js +77 -0
- package/dist/application/resolve-suggestions.js.map +1 -0
- package/dist/application/search-skills.d.ts +36 -0
- package/dist/application/search-skills.d.ts.map +1 -0
- package/dist/application/search-skills.js +78 -0
- package/dist/application/search-skills.js.map +1 -0
- package/dist/application/update-skills.d.ts +55 -0
- package/dist/application/update-skills.d.ts.map +1 -0
- package/dist/application/update-skills.js +115 -0
- package/dist/application/update-skills.js.map +1 -0
- package/dist/application/validate-package.d.ts +27 -0
- package/dist/application/validate-package.d.ts.map +1 -0
- package/dist/application/validate-package.js +165 -0
- package/dist/application/validate-package.js.map +1 -0
- package/dist/application/workspace.d.ts +22 -0
- package/dist/application/workspace.d.ts.map +1 -0
- package/dist/application/workspace.js +66 -0
- package/dist/application/workspace.js.map +1 -0
- package/dist/domain/agent.d.ts +89 -0
- package/dist/domain/agent.d.ts.map +1 -0
- package/dist/domain/agent.js +20 -0
- package/dist/domain/agent.js.map +1 -0
- package/dist/domain/errors.d.ts +91 -0
- package/dist/domain/errors.d.ts.map +1 -0
- package/dist/domain/errors.js +121 -0
- package/dist/domain/errors.js.map +1 -0
- package/dist/domain/integrity.d.ts +19 -0
- package/dist/domain/integrity.d.ts.map +1 -0
- package/dist/domain/integrity.js +0 -0
- package/dist/domain/integrity.js.map +1 -0
- package/dist/domain/js-literal.d.ts +22 -0
- package/dist/domain/js-literal.d.ts.map +1 -0
- package/dist/domain/js-literal.js +221 -0
- package/dist/domain/js-literal.js.map +1 -0
- package/dist/domain/lockfile.d.ts +36 -0
- package/dist/domain/lockfile.d.ts.map +1 -0
- package/dist/domain/lockfile.js +148 -0
- package/dist/domain/lockfile.js.map +1 -0
- package/dist/domain/manifest.d.ts +96 -0
- package/dist/domain/manifest.d.ts.map +1 -0
- package/dist/domain/manifest.js +448 -0
- package/dist/domain/manifest.js.map +1 -0
- package/dist/domain/path-safety.d.ts +19 -0
- package/dist/domain/path-safety.d.ts.map +1 -0
- package/dist/domain/path-safety.js +125 -0
- package/dist/domain/path-safety.js.map +1 -0
- package/dist/domain/posix-path.d.ts +28 -0
- package/dist/domain/posix-path.d.ts.map +1 -0
- package/dist/domain/posix-path.js +84 -0
- package/dist/domain/posix-path.js.map +1 -0
- package/dist/domain/receipt.d.ts +41 -0
- package/dist/domain/receipt.d.ts.map +1 -0
- package/dist/domain/receipt.js +93 -0
- package/dist/domain/receipt.js.map +1 -0
- package/dist/domain/registry-index.d.ts +41 -0
- package/dist/domain/registry-index.d.ts.map +1 -0
- package/dist/domain/registry-index.js +150 -0
- package/dist/domain/registry-index.js.map +1 -0
- package/dist/domain/resolver.d.ts +54 -0
- package/dist/domain/resolver.d.ts.map +1 -0
- package/dist/domain/resolver.js +238 -0
- package/dist/domain/resolver.js.map +1 -0
- package/dist/domain/skill-document.d.ts +16 -0
- package/dist/domain/skill-document.d.ts.map +1 -0
- package/dist/domain/skill-document.js +60 -0
- package/dist/domain/skill-document.js.map +1 -0
- package/dist/domain/skill-package.d.ts +43 -0
- package/dist/domain/skill-package.d.ts.map +1 -0
- package/dist/domain/skill-package.js +63 -0
- package/dist/domain/skill-package.js.map +1 -0
- package/dist/domain/skill-ref.d.ts +30 -0
- package/dist/domain/skill-ref.d.ts.map +1 -0
- package/dist/domain/skill-ref.js +119 -0
- package/dist/domain/skill-ref.js.map +1 -0
- package/dist/domain/validation.d.ts +30 -0
- package/dist/domain/validation.d.ts.map +1 -0
- package/dist/domain/validation.js +32 -0
- package/dist/domain/validation.js.map +1 -0
- package/dist/domain/version.d.ts +23 -0
- package/dist/domain/version.d.ts.map +1 -0
- package/dist/domain/version.js +81 -0
- package/dist/domain/version.js.map +1 -0
- package/dist/domain/workflow-document.d.ts +23 -0
- package/dist/domain/workflow-document.d.ts.map +1 -0
- package/dist/domain/workflow-document.js +56 -0
- package/dist/domain/workflow-document.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/ports/agent-adapter.d.ts +65 -0
- package/dist/ports/agent-adapter.d.ts.map +1 -0
- package/dist/ports/agent-adapter.js +28 -0
- package/dist/ports/agent-adapter.js.map +1 -0
- package/dist/ports/config-store.d.ts +27 -0
- package/dist/ports/config-store.d.ts.map +1 -0
- package/dist/ports/config-store.js +2 -0
- package/dist/ports/config-store.js.map +1 -0
- package/dist/ports/infrastructure.d.ts +123 -0
- package/dist/ports/infrastructure.d.ts.map +1 -0
- package/dist/ports/infrastructure.js +9 -0
- package/dist/ports/infrastructure.js.map +1 -0
- package/dist/ports/installation.d.ts +86 -0
- package/dist/ports/installation.d.ts.map +1 -0
- package/dist/ports/installation.js +2 -0
- package/dist/ports/installation.js.map +1 -0
- package/dist/ports/skill-registry.d.ts +74 -0
- package/dist/ports/skill-registry.d.ts.map +1 -0
- package/dist/ports/skill-registry.js +2 -0
- package/dist/ports/skill-registry.js.map +1 -0
- package/dist/ports/updates.d.ts +31 -0
- package/dist/ports/updates.d.ts.map +1 -0
- package/dist/ports/updates.js +4 -0
- package/dist/ports/updates.js.map +1 -0
- package/dist/testing/doubles.d.ts +127 -0
- package/dist/testing/doubles.d.ts.map +1 -0
- package/dist/testing/doubles.js +299 -0
- package/dist/testing/doubles.js.map +1 -0
- package/dist/testing/in-memory-file-system.d.ts +61 -0
- package/dist/testing/in-memory-file-system.d.ts.map +1 -0
- package/dist/testing/in-memory-file-system.js +297 -0
- package/dist/testing/in-memory-file-system.js.map +1 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +10 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { AgentSkillsError, ErrorCode } from "./errors.js";
|
|
2
|
+
import { LATEST } from "./skill-ref.js";
|
|
3
|
+
import { compareVersions, intersects, maxSatisfying } from "./version.js";
|
|
4
|
+
const DIRECT_REQUESTER = '<requested>';
|
|
5
|
+
const MAX_ITERATIONS = 1000;
|
|
6
|
+
/**
|
|
7
|
+
* Breadth-first constraint resolution without backtracking.
|
|
8
|
+
*
|
|
9
|
+
* Adding a constraint can only lower the chosen version, never raise it, so the fixed-point
|
|
10
|
+
* loop terminates; the iteration cap exists to turn a hypothetical resolver bug into a clear
|
|
11
|
+
* error rather than a hang.
|
|
12
|
+
*/
|
|
13
|
+
export class Resolver {
|
|
14
|
+
source;
|
|
15
|
+
constructor(source) {
|
|
16
|
+
this.source = source;
|
|
17
|
+
}
|
|
18
|
+
async resolve(refs, options = {}) {
|
|
19
|
+
const constraints = new Map();
|
|
20
|
+
const registryHint = new Map();
|
|
21
|
+
const chosen = new Map();
|
|
22
|
+
const directNames = new Set();
|
|
23
|
+
const warnings = [];
|
|
24
|
+
const pinned = options.pinned ?? {};
|
|
25
|
+
for (const ref of refs) {
|
|
26
|
+
directNames.add(ref.name);
|
|
27
|
+
if (ref.registry !== undefined)
|
|
28
|
+
registryHint.set(ref.name, ref.registry);
|
|
29
|
+
addConstraint(constraints, ref.name, {
|
|
30
|
+
range: rangeFor(ref, pinned[ref.name]),
|
|
31
|
+
requester: DIRECT_REQUESTER,
|
|
32
|
+
optional: false,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
for (let iteration = 0; iteration <= MAX_ITERATIONS; iteration += 1) {
|
|
36
|
+
const stale = this.findStale(constraints, chosen);
|
|
37
|
+
if (stale === undefined) {
|
|
38
|
+
return { order: topologicalOrder(chosen, directNames), warnings };
|
|
39
|
+
}
|
|
40
|
+
if (iteration === MAX_ITERATIONS)
|
|
41
|
+
break;
|
|
42
|
+
const skillConstraints = constraints.get(stale);
|
|
43
|
+
const resolved = await this.choose(stale, skillConstraints, registryHint.get(stale));
|
|
44
|
+
if (resolved === undefined) {
|
|
45
|
+
// Every constraint on this name came from optional dependencies: drop it.
|
|
46
|
+
constraints.delete(stale);
|
|
47
|
+
chosen.delete(stale);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
chosen.set(stale, {
|
|
51
|
+
...resolved,
|
|
52
|
+
direct: directNames.has(stale),
|
|
53
|
+
requiredBy: skillConstraints
|
|
54
|
+
.filter((constraint) => constraint.requester !== DIRECT_REQUESTER)
|
|
55
|
+
.map((constraint) => constraint.requester),
|
|
56
|
+
});
|
|
57
|
+
if (options.skipDependencies === true)
|
|
58
|
+
continue;
|
|
59
|
+
const requester = `${resolved.name}@${resolved.version}`;
|
|
60
|
+
for (const dependency of resolved.manifest.dependencies) {
|
|
61
|
+
addConstraint(constraints, dependency.name, {
|
|
62
|
+
range: pinned[dependency.name] ?? dependency.version,
|
|
63
|
+
requester,
|
|
64
|
+
optional: false,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
for (const dependency of resolved.manifest.optionalDependencies) {
|
|
68
|
+
addConstraint(constraints, dependency.name, {
|
|
69
|
+
range: pinned[dependency.name] ?? dependency.version,
|
|
70
|
+
requester,
|
|
71
|
+
optional: true,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
assertNoCycle(chosen, constraints);
|
|
75
|
+
}
|
|
76
|
+
throw new AgentSkillsError(ErrorCode.INTERNAL, 'Dependency resolution did not converge', {
|
|
77
|
+
details: [`Gave up after ${MAX_ITERATIONS} iterations.`],
|
|
78
|
+
hints: ['Please report this with the skills you were installing'],
|
|
79
|
+
data: { names: [...constraints.keys()] },
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** The first name (alphabetically, for determinism) whose choice does not satisfy its constraints. */
|
|
83
|
+
findStale(constraints, chosen) {
|
|
84
|
+
for (const name of [...constraints.keys()].sort()) {
|
|
85
|
+
const current = chosen.get(name);
|
|
86
|
+
if (current === undefined)
|
|
87
|
+
return name;
|
|
88
|
+
const ranges = constraints.get(name).map((constraint) => constraint.range);
|
|
89
|
+
if (!ranges.every((range) => satisfiesRange(current.version, range)))
|
|
90
|
+
return name;
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
async choose(name, constraints, registry) {
|
|
95
|
+
const allOptional = constraints.every((constraint) => constraint.optional);
|
|
96
|
+
let listed;
|
|
97
|
+
try {
|
|
98
|
+
listed = await this.source.listVersions(name, registry);
|
|
99
|
+
}
|
|
100
|
+
catch (cause) {
|
|
101
|
+
if (allOptional)
|
|
102
|
+
return undefined;
|
|
103
|
+
throw cause;
|
|
104
|
+
}
|
|
105
|
+
const ranges = constraints.map((constraint) => constraint.range);
|
|
106
|
+
if (!intersects(ranges)) {
|
|
107
|
+
if (allOptional)
|
|
108
|
+
return undefined;
|
|
109
|
+
throw conflictError(name, constraints, listed.versions);
|
|
110
|
+
}
|
|
111
|
+
// Deprecated versions stay resolvable only when a constraint names one exactly, so an
|
|
112
|
+
// existing lockfile keeps working while `latest` moves on.
|
|
113
|
+
const candidates = listed.versions
|
|
114
|
+
.filter((entry) => !entry.deprecated || ranges.some((range) => range === entry.version))
|
|
115
|
+
.map((entry) => entry.version);
|
|
116
|
+
// Filter by the whole constraint set at once, so the pick is order-independent.
|
|
117
|
+
const best = candidates
|
|
118
|
+
.filter((version) => ranges.every((range) => satisfiesRange(version, range)))
|
|
119
|
+
.sort((a, b) => compareVersions(b, a))[0];
|
|
120
|
+
if (best === undefined) {
|
|
121
|
+
if (allOptional)
|
|
122
|
+
return undefined;
|
|
123
|
+
throw conflictError(name, constraints, listed.versions);
|
|
124
|
+
}
|
|
125
|
+
const entry = listed.versions.find((candidate) => candidate.version === best);
|
|
126
|
+
const manifest = await this.source.loadManifest(name, best, listed.registry);
|
|
127
|
+
return { name, version: best, registry: listed.registry, entry, manifest };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function rangeFor(ref, pinnedVersion) {
|
|
131
|
+
if (ref.range !== undefined && ref.range !== LATEST)
|
|
132
|
+
return ref.range;
|
|
133
|
+
// An explicit `@latest` deliberately ignores the lockfile pin; a bare name honours it.
|
|
134
|
+
if (ref.range === LATEST)
|
|
135
|
+
return '*';
|
|
136
|
+
return pinnedVersion ?? '*';
|
|
137
|
+
}
|
|
138
|
+
function addConstraint(constraints, name, constraint) {
|
|
139
|
+
const existing = constraints.get(name);
|
|
140
|
+
if (existing === undefined) {
|
|
141
|
+
constraints.set(name, [constraint]);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const duplicate = existing.some((item) => item.range === constraint.range && item.requester === constraint.requester);
|
|
145
|
+
if (!duplicate)
|
|
146
|
+
existing.push(constraint);
|
|
147
|
+
}
|
|
148
|
+
function satisfiesRange(version, range) {
|
|
149
|
+
return maxSatisfying([version], range) !== undefined;
|
|
150
|
+
}
|
|
151
|
+
function conflictError(name, constraints, available) {
|
|
152
|
+
const width = Math.max(...constraints.map((constraint) => constraint.requester.length));
|
|
153
|
+
const lines = constraints.map((constraint) => ` ${constraint.requester.padEnd(width)} requires ${constraint.range}`);
|
|
154
|
+
const versions = available.map((entry) => entry.version).join(', ');
|
|
155
|
+
return new AgentSkillsError(ErrorCode.DEPENDENCY_CONFLICT, `Version conflict for "${name}"`, {
|
|
156
|
+
details: [
|
|
157
|
+
...lines,
|
|
158
|
+
'',
|
|
159
|
+
` No published version satisfies all of them.`,
|
|
160
|
+
` Available: ${versions === '' ? '(none)' : versions}`,
|
|
161
|
+
],
|
|
162
|
+
hints: [
|
|
163
|
+
`senior-skills info ${name} to see every published version`,
|
|
164
|
+
'Relax a constraint, or install a newer version of the skill that requires the old range',
|
|
165
|
+
],
|
|
166
|
+
data: {
|
|
167
|
+
name,
|
|
168
|
+
constraints: constraints.map((constraint) => ({
|
|
169
|
+
requester: constraint.requester,
|
|
170
|
+
range: constraint.range,
|
|
171
|
+
})),
|
|
172
|
+
available: available.map((entry) => entry.version),
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/** Depth-first cycle detection over the graph implied by the manifests chosen so far. */
|
|
177
|
+
function assertNoCycle(chosen, constraints) {
|
|
178
|
+
const edges = new Map();
|
|
179
|
+
for (const [name, skill] of chosen) {
|
|
180
|
+
edges.set(name, [...skill.manifest.dependencies, ...skill.manifest.optionalDependencies]
|
|
181
|
+
.map((dependency) => dependency.name)
|
|
182
|
+
.filter((dependency) => constraints.has(dependency)));
|
|
183
|
+
}
|
|
184
|
+
const visiting = new Set();
|
|
185
|
+
const done = new Set();
|
|
186
|
+
const path = [];
|
|
187
|
+
const visit = (name) => {
|
|
188
|
+
if (done.has(name))
|
|
189
|
+
return;
|
|
190
|
+
if (visiting.has(name)) {
|
|
191
|
+
const start = path.indexOf(name);
|
|
192
|
+
const cycle = [...path.slice(start), name].join(' → ');
|
|
193
|
+
throw new AgentSkillsError(ErrorCode.DEPENDENCY_CYCLE, 'Circular dependency detected', {
|
|
194
|
+
details: [` ${cycle}`],
|
|
195
|
+
hints: ['Break the cycle by removing one of these dependencies'],
|
|
196
|
+
data: { cycle: [...path.slice(start), name] },
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
visiting.add(name);
|
|
200
|
+
path.push(name);
|
|
201
|
+
for (const next of edges.get(name) ?? [])
|
|
202
|
+
visit(next);
|
|
203
|
+
path.pop();
|
|
204
|
+
visiting.delete(name);
|
|
205
|
+
done.add(name);
|
|
206
|
+
};
|
|
207
|
+
for (const name of [...edges.keys()].sort())
|
|
208
|
+
visit(name);
|
|
209
|
+
}
|
|
210
|
+
/** Dependencies first. Cycles are already rejected, so a stable topological order exists. */
|
|
211
|
+
function topologicalOrder(chosen, directNames) {
|
|
212
|
+
const ordered = [];
|
|
213
|
+
const emitted = new Set();
|
|
214
|
+
const emit = (name) => {
|
|
215
|
+
if (emitted.has(name))
|
|
216
|
+
return;
|
|
217
|
+
const skill = chosen.get(name);
|
|
218
|
+
if (skill === undefined)
|
|
219
|
+
return;
|
|
220
|
+
emitted.add(name);
|
|
221
|
+
for (const dependency of [
|
|
222
|
+
...skill.manifest.dependencies,
|
|
223
|
+
...skill.manifest.optionalDependencies,
|
|
224
|
+
]
|
|
225
|
+
.map((dep) => dep.name)
|
|
226
|
+
.sort()) {
|
|
227
|
+
emit(dependency);
|
|
228
|
+
}
|
|
229
|
+
ordered.push(skill);
|
|
230
|
+
};
|
|
231
|
+
// Seed with direct requests first so the order is stable regardless of map insertion order.
|
|
232
|
+
for (const name of [...directNames].sort())
|
|
233
|
+
emit(name);
|
|
234
|
+
for (const name of [...chosen.keys()].sort())
|
|
235
|
+
emit(name);
|
|
236
|
+
return ordered;
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/domain/resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `SKILL.md` is the agent-facing entrypoint: YAML frontmatter plus a Markdown body.
|
|
3
|
+
* Both Claude Code and Codex require `name` and `description` and ignore the rest, which
|
|
4
|
+
* is why the neutral format keeps distribution metadata in `skill.yaml` instead.
|
|
5
|
+
*/
|
|
6
|
+
export interface SkillDocument {
|
|
7
|
+
readonly frontmatter: Readonly<Record<string, unknown>>;
|
|
8
|
+
readonly body: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function parseSkillDocument(text: string, source?: string): SkillDocument;
|
|
11
|
+
export declare function stringifySkillDocument(doc: SkillDocument): string;
|
|
12
|
+
/** Reads the frontmatter `name`, which must agree with the manifest and directory name. */
|
|
13
|
+
export declare function documentName(doc: SkillDocument): string | undefined;
|
|
14
|
+
export declare function documentDescription(doc: SkillDocument): string | undefined;
|
|
15
|
+
export declare function documentVersion(doc: SkillDocument): string | undefined;
|
|
16
|
+
//# sourceMappingURL=skill-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-document.d.ts","sourceRoot":"","sources":["../../src/domain/skill-document.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAa,GAAG,aAAa,CAgDnF;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAIjE;AAED,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAGnE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAG1E;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAGtE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
2
|
+
import { AgentSkillsError, ErrorCode } from "./errors.js";
|
|
3
|
+
const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
4
|
+
export function parseSkillDocument(text, source = 'SKILL.md') {
|
|
5
|
+
// A BOM before `---` would otherwise defeat the delimiter match.
|
|
6
|
+
const normalized = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
|
|
7
|
+
const match = FRONTMATTER_PATTERN.exec(normalized);
|
|
8
|
+
if (match === null) {
|
|
9
|
+
throw new AgentSkillsError(ErrorCode.INVALID_PACKAGE, `${source} has no YAML frontmatter`, {
|
|
10
|
+
details: ['The file must start with a --- delimited YAML block.'],
|
|
11
|
+
hints: [
|
|
12
|
+
'Example:',
|
|
13
|
+
'---',
|
|
14
|
+
'name: my-skill',
|
|
15
|
+
'description: What it does and when to use it.',
|
|
16
|
+
'---',
|
|
17
|
+
],
|
|
18
|
+
data: { source },
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
let frontmatter;
|
|
22
|
+
try {
|
|
23
|
+
frontmatter = parseYaml(match[1] ?? '');
|
|
24
|
+
}
|
|
25
|
+
catch (cause) {
|
|
26
|
+
throw new AgentSkillsError(ErrorCode.INVALID_PACKAGE, `${source} has invalid frontmatter YAML`, {
|
|
27
|
+
details: [cause instanceof Error ? cause.message : String(cause)],
|
|
28
|
+
cause,
|
|
29
|
+
data: { source },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (frontmatter === null || typeof frontmatter !== 'object' || Array.isArray(frontmatter)) {
|
|
33
|
+
throw new AgentSkillsError(ErrorCode.INVALID_PACKAGE, `${source} frontmatter must be a mapping`, {
|
|
34
|
+
data: { source },
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
frontmatter: frontmatter,
|
|
39
|
+
body: normalized.slice(match[0].length),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function stringifySkillDocument(doc) {
|
|
43
|
+
const yaml = stringifyYaml(doc.frontmatter, { lineWidth: 100, singleQuote: false }).trimEnd();
|
|
44
|
+
const body = doc.body.startsWith('\n') ? doc.body.slice(1) : doc.body;
|
|
45
|
+
return `---\n${yaml}\n---\n\n${body.trimStart()}`;
|
|
46
|
+
}
|
|
47
|
+
/** Reads the frontmatter `name`, which must agree with the manifest and directory name. */
|
|
48
|
+
export function documentName(doc) {
|
|
49
|
+
const name = doc.frontmatter['name'];
|
|
50
|
+
return typeof name === 'string' ? name.trim() : undefined;
|
|
51
|
+
}
|
|
52
|
+
export function documentDescription(doc) {
|
|
53
|
+
const description = doc.frontmatter['description'];
|
|
54
|
+
return typeof description === 'string' ? description.trim() : undefined;
|
|
55
|
+
}
|
|
56
|
+
export function documentVersion(doc) {
|
|
57
|
+
const version = doc.frontmatter['version'];
|
|
58
|
+
return typeof version === 'string' ? version.trim() : undefined;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=skill-document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-document.js","sourceRoot":"","sources":["../../src/domain/skill-document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAY1D,MAAM,mBAAmB,GAAG,mCAAmC,CAAC;AAEhE,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,MAAM,GAAG,UAAU;IAClE,iEAAiE;IACjE,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxE,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEnD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,gBAAgB,CAAC,SAAS,CAAC,eAAe,EAAE,GAAG,MAAM,0BAA0B,EAAE;YACzF,OAAO,EAAE,CAAC,sDAAsD,CAAC;YACjE,KAAK,EAAE;gBACL,UAAU;gBACV,KAAK;gBACL,gBAAgB;gBAChB,+CAA+C;gBAC/C,KAAK;aACN;YACD,IAAI,EAAE,EAAE,MAAM,EAAE;SACjB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,WAAoB,CAAC;IACzB,IAAI,CAAC;QACH,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,gBAAgB,CACxB,SAAS,CAAC,eAAe,EACzB,GAAG,MAAM,+BAA+B,EACxC;YACE,OAAO,EAAE,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACjE,KAAK;YACL,IAAI,EAAE,EAAE,MAAM,EAAE;SACjB,CACF,CAAC;IACJ,CAAC;IAED,IAAI,WAAW,KAAK,IAAI,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1F,MAAM,IAAI,gBAAgB,CACxB,SAAS,CAAC,eAAe,EACzB,GAAG,MAAM,gCAAgC,EACzC;YACE,IAAI,EAAE,EAAE,MAAM,EAAE;SACjB,CACF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,WAAW,EAAE,WAAsC;QACnD,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;KACxC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,GAAkB;IACvD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IAC9F,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IACtE,OAAO,QAAQ,IAAI,YAAY,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;AACpD,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,YAAY,CAAC,GAAkB;IAC7C,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAkB;IACpD,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IACnD,OAAO,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAkB;IAChD,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAC3C,OAAO,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type PackageKind, type SkillManifest } from './manifest.ts';
|
|
2
|
+
import { type SkillDocument } from './skill-document.ts';
|
|
3
|
+
/**
|
|
4
|
+
* One file inside a package. Paths are always POSIX and relative to the package root;
|
|
5
|
+
* content is bytes so that `assets/` can hold images without a lossy round-trip.
|
|
6
|
+
*/
|
|
7
|
+
export interface PackageFile {
|
|
8
|
+
readonly path: string;
|
|
9
|
+
readonly bytes: Uint8Array;
|
|
10
|
+
/** Present for files that came from a real filesystem; used for streaming copies. */
|
|
11
|
+
readonly sourcePath?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A validated, in-memory skill package: the neutral artefact that registries produce and
|
|
15
|
+
* adapters project onto agent-specific layouts. Nothing here is agent-aware.
|
|
16
|
+
*/
|
|
17
|
+
export interface SkillPackage {
|
|
18
|
+
readonly manifest: SkillManifest;
|
|
19
|
+
readonly document: SkillDocument;
|
|
20
|
+
readonly files: readonly PackageFile[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Reads a kind's entrypoint into the one neutral shape the rest of the system understands.
|
|
24
|
+
*
|
|
25
|
+
* Markdown kinds carry their identity in YAML frontmatter; a workflow carries it in
|
|
26
|
+
* `export const meta`. Normalising here — rather than teaching every caller about both — is
|
|
27
|
+
* what keeps validation, search and `info` identical across kinds.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseEntrypoint(kind: PackageKind, text: string, source: string): SkillDocument;
|
|
30
|
+
export declare function decodeText(bytes: Uint8Array): string;
|
|
31
|
+
export declare function encodeText(text: string): Uint8Array;
|
|
32
|
+
export declare function findFile(pkg: SkillPackage, path: string): PackageFile | undefined;
|
|
33
|
+
export declare function readTextFile(pkg: SkillPackage, path: string): string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Assembles a package from raw files, parsing the entrypoint. Structural validation beyond
|
|
36
|
+
* "can this be loaded at all" belongs to `ValidatePackage`, which reports every problem
|
|
37
|
+
* rather than failing on the first.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildSkillPackage(manifest: SkillManifest, files: readonly PackageFile[]): SkillPackage;
|
|
40
|
+
/** Total uncompressed size, used for reporting and for archive-bomb limits. */
|
|
41
|
+
export declare function packageSize(pkg: SkillPackage): number;
|
|
42
|
+
export declare function isManifestFile(path: string): boolean;
|
|
43
|
+
//# sourceMappingURL=skill-package.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-package.d.ts","sourceRoot":"","sources":["../../src/domain/skill-package.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAK7E;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;CACxC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAI9F;AAID,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEpD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEnD;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAGjF;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGhF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,SAAS,WAAW,EAAE,GAC5B,YAAY,CA2Bd;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAErD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { MANIFEST_FILENAME, entrypointFor, } from "./manifest.js";
|
|
2
|
+
import { parseSkillDocument } from "./skill-document.js";
|
|
3
|
+
import { parseWorkflowDocument } from "./workflow-document.js";
|
|
4
|
+
import { AgentSkillsError, ErrorCode } from "./errors.js";
|
|
5
|
+
import { normalize } from "./posix-path.js";
|
|
6
|
+
/**
|
|
7
|
+
* Reads a kind's entrypoint into the one neutral shape the rest of the system understands.
|
|
8
|
+
*
|
|
9
|
+
* Markdown kinds carry their identity in YAML frontmatter; a workflow carries it in
|
|
10
|
+
* `export const meta`. Normalising here — rather than teaching every caller about both — is
|
|
11
|
+
* what keeps validation, search and `info` identical across kinds.
|
|
12
|
+
*/
|
|
13
|
+
export function parseEntrypoint(kind, text, source) {
|
|
14
|
+
return kind === 'workflow'
|
|
15
|
+
? parseWorkflowDocument(text, source)
|
|
16
|
+
: parseSkillDocument(text, source);
|
|
17
|
+
}
|
|
18
|
+
const decoder = new TextDecoder('utf-8', { fatal: false });
|
|
19
|
+
export function decodeText(bytes) {
|
|
20
|
+
return decoder.decode(bytes);
|
|
21
|
+
}
|
|
22
|
+
export function encodeText(text) {
|
|
23
|
+
return new TextEncoder().encode(text);
|
|
24
|
+
}
|
|
25
|
+
export function findFile(pkg, path) {
|
|
26
|
+
const target = normalize(path);
|
|
27
|
+
return pkg.files.find((file) => file.path === target);
|
|
28
|
+
}
|
|
29
|
+
export function readTextFile(pkg, path) {
|
|
30
|
+
const file = findFile(pkg, path);
|
|
31
|
+
return file === undefined ? undefined : decodeText(file.bytes);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Assembles a package from raw files, parsing the entrypoint. Structural validation beyond
|
|
35
|
+
* "can this be loaded at all" belongs to `ValidatePackage`, which reports every problem
|
|
36
|
+
* rather than failing on the first.
|
|
37
|
+
*/
|
|
38
|
+
export function buildSkillPackage(manifest, files) {
|
|
39
|
+
const normalizedFiles = files
|
|
40
|
+
.map((file) => ({ ...file, path: normalize(file.path) }))
|
|
41
|
+
.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
42
|
+
const entrypoint = entrypointFor(manifest.kind);
|
|
43
|
+
const entry = normalizedFiles.find((file) => file.path === entrypoint);
|
|
44
|
+
if (entry === undefined) {
|
|
45
|
+
throw new AgentSkillsError(ErrorCode.INVALID_PACKAGE, `Package "${manifest.name}" is missing ${entrypoint}`, {
|
|
46
|
+
hints: [`Every ${manifest.kind} package must contain a ${entrypoint} at its root`],
|
|
47
|
+
data: { name: manifest.name, kind: manifest.kind },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
manifest,
|
|
52
|
+
document: parseEntrypoint(manifest.kind, decodeText(entry.bytes), `${manifest.name}/${entrypoint}`),
|
|
53
|
+
files: normalizedFiles,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** Total uncompressed size, used for reporting and for archive-bomb limits. */
|
|
57
|
+
export function packageSize(pkg) {
|
|
58
|
+
return pkg.files.reduce((total, file) => total + file.bytes.byteLength, 0);
|
|
59
|
+
}
|
|
60
|
+
export function isManifestFile(path) {
|
|
61
|
+
return normalize(path) === MANIFEST_FILENAME;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=skill-package.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-package.js","sourceRoot":"","sources":["../../src/domain/skill-package.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const SKILL_NAME_MIN_LENGTH = 2;
|
|
2
|
+
export declare const SKILL_NAME_MAX_LENGTH = 64;
|
|
3
|
+
export declare function isValidSkillName(name: string): boolean;
|
|
4
|
+
/** Returns human-readable reasons the name is unusable, or an empty list when it is fine. */
|
|
5
|
+
export declare function validateSkillName(name: string): readonly string[];
|
|
6
|
+
export declare function assertValidSkillName(name: string): void;
|
|
7
|
+
/** `latest` is a resolution instruction, not a version; it is modelled explicitly. */
|
|
8
|
+
export declare const LATEST = "latest";
|
|
9
|
+
export interface SkillRef {
|
|
10
|
+
/** Registry name when the reference was qualified (`company:java-perf`), else undefined. */
|
|
11
|
+
readonly registry?: string;
|
|
12
|
+
readonly name: string;
|
|
13
|
+
/** A semver range, or `latest`. Undefined means "whatever the lockfile or latest says". */
|
|
14
|
+
readonly range?: string;
|
|
15
|
+
/** The original text, preserved for error messages. */
|
|
16
|
+
readonly raw: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Parses `[registry:]name[@range]`.
|
|
20
|
+
*
|
|
21
|
+
* Examples:
|
|
22
|
+
* java-performance
|
|
23
|
+
* java-performance@1.2.0
|
|
24
|
+
* java-performance@^1.2.0
|
|
25
|
+
* java-performance@latest
|
|
26
|
+
* company:java-performance@~1.0
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseSkillRef(raw: string): SkillRef;
|
|
29
|
+
export declare function formatSkillRef(ref: SkillRef): string;
|
|
30
|
+
//# sourceMappingURL=skill-ref.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-ref.d.ts","sourceRoot":"","sources":["../../src/domain/skill-ref.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAKxC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAoBjE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQvD;AAED,sFAAsF;AACtF,eAAO,MAAM,MAAM,WAAW,CAAC;AAE/B,MAAM,WAAW,QAAQ;IACvB,4FAA4F;IAC5F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2FAA2F;IAC3F,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CA2DnD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAIpD"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import semver from 'semver';
|
|
2
|
+
import { AgentSkillsError, ErrorCode } from "./errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Skill names are directory names on three operating systems and identifiers in YAML,
|
|
5
|
+
* URLs and lockfiles. The grammar is therefore the intersection of what is safe
|
|
6
|
+
* everywhere: lowercase alphanumerics and single inner hyphens.
|
|
7
|
+
*
|
|
8
|
+
* `@` and `/` are deliberately excluded and reserved for a future `@org/skill` scoping
|
|
9
|
+
* scheme, so adding scopes later is not a breaking change.
|
|
10
|
+
*/
|
|
11
|
+
const SKILL_NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
12
|
+
const REGISTRY_NAME_PATTERN = /^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/;
|
|
13
|
+
export const SKILL_NAME_MIN_LENGTH = 2;
|
|
14
|
+
export const SKILL_NAME_MAX_LENGTH = 64;
|
|
15
|
+
/** Names that would collide with our own on-disk bookkeeping or with OS reserved words. */
|
|
16
|
+
const RESERVED_SKILL_NAMES = new Set(['senior-skills', 'con', 'prn', 'aux', 'nul', 'node-modules']);
|
|
17
|
+
export function isValidSkillName(name) {
|
|
18
|
+
return validateSkillName(name).length === 0;
|
|
19
|
+
}
|
|
20
|
+
/** Returns human-readable reasons the name is unusable, or an empty list when it is fine. */
|
|
21
|
+
export function validateSkillName(name) {
|
|
22
|
+
const problems = [];
|
|
23
|
+
if (name.length < SKILL_NAME_MIN_LENGTH) {
|
|
24
|
+
problems.push(`must be at least ${SKILL_NAME_MIN_LENGTH} characters`);
|
|
25
|
+
}
|
|
26
|
+
if (name.length > SKILL_NAME_MAX_LENGTH) {
|
|
27
|
+
problems.push(`must be at most ${SKILL_NAME_MAX_LENGTH} characters`);
|
|
28
|
+
}
|
|
29
|
+
if (!SKILL_NAME_PATTERN.test(name)) {
|
|
30
|
+
problems.push('must be lowercase alphanumerics separated by single hyphens (e.g. "java-performance")');
|
|
31
|
+
}
|
|
32
|
+
if (name.includes('--')) {
|
|
33
|
+
problems.push('must not contain consecutive hyphens');
|
|
34
|
+
}
|
|
35
|
+
if (RESERVED_SKILL_NAMES.has(name)) {
|
|
36
|
+
problems.push(`"${name}" is reserved`);
|
|
37
|
+
}
|
|
38
|
+
return problems;
|
|
39
|
+
}
|
|
40
|
+
export function assertValidSkillName(name) {
|
|
41
|
+
const problems = validateSkillName(name);
|
|
42
|
+
if (problems.length === 0)
|
|
43
|
+
return;
|
|
44
|
+
throw new AgentSkillsError(ErrorCode.INVALID_SKILL_NAME, `Invalid skill name "${name}"`, {
|
|
45
|
+
details: problems.map((problem) => `- ${problem}`),
|
|
46
|
+
hints: ['Skill names look like: java-performance, jvm-gc-tuning, react-testing'],
|
|
47
|
+
data: { name, problems },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** `latest` is a resolution instruction, not a version; it is modelled explicitly. */
|
|
51
|
+
export const LATEST = 'latest';
|
|
52
|
+
/**
|
|
53
|
+
* Parses `[registry:]name[@range]`.
|
|
54
|
+
*
|
|
55
|
+
* Examples:
|
|
56
|
+
* java-performance
|
|
57
|
+
* java-performance@1.2.0
|
|
58
|
+
* java-performance@^1.2.0
|
|
59
|
+
* java-performance@latest
|
|
60
|
+
* company:java-performance@~1.0
|
|
61
|
+
*/
|
|
62
|
+
export function parseSkillRef(raw) {
|
|
63
|
+
const text = raw.trim();
|
|
64
|
+
if (text === '') {
|
|
65
|
+
throw new AgentSkillsError(ErrorCode.USAGE, 'Empty skill reference', {
|
|
66
|
+
hints: ['Expected something like: java-performance or java-performance@1.2.0'],
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
let rest = text;
|
|
70
|
+
let registry;
|
|
71
|
+
const colon = rest.indexOf(':');
|
|
72
|
+
if (colon !== -1) {
|
|
73
|
+
registry = rest.slice(0, colon);
|
|
74
|
+
rest = rest.slice(colon + 1);
|
|
75
|
+
if (!REGISTRY_NAME_PATTERN.test(registry)) {
|
|
76
|
+
throw new AgentSkillsError(ErrorCode.USAGE, `Invalid registry qualifier "${registry}" in "${raw}"`, {
|
|
77
|
+
hints: ['Registry names are lowercase, e.g. official:java-performance'],
|
|
78
|
+
data: { raw },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
let range;
|
|
83
|
+
const at = rest.lastIndexOf('@');
|
|
84
|
+
if (at > 0) {
|
|
85
|
+
range = rest.slice(at + 1);
|
|
86
|
+
rest = rest.slice(0, at);
|
|
87
|
+
}
|
|
88
|
+
assertValidSkillName(rest);
|
|
89
|
+
if (range !== undefined) {
|
|
90
|
+
if (range === '') {
|
|
91
|
+
throw new AgentSkillsError(ErrorCode.USAGE, `Missing version after "@" in "${raw}"`, {
|
|
92
|
+
hints: [`Use ${rest}@latest, ${rest}@1.2.0 or ${rest}@^1.2.0`],
|
|
93
|
+
data: { raw },
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (range !== LATEST && semver.validRange(range) === null) {
|
|
97
|
+
throw new AgentSkillsError(ErrorCode.INVALID_VERSION, `Invalid version range "${range}"`, {
|
|
98
|
+
details: [`In reference: ${raw}`],
|
|
99
|
+
hints: ['Valid forms: 1.2.0, ^1.2.0, ~1.2, >=1.0.0 <2.0.0, latest'],
|
|
100
|
+
data: { raw, range },
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const ref = {
|
|
105
|
+
name: rest,
|
|
106
|
+
raw: text,
|
|
107
|
+
};
|
|
108
|
+
if (registry !== undefined)
|
|
109
|
+
ref.registry = registry;
|
|
110
|
+
if (range !== undefined)
|
|
111
|
+
ref.range = range;
|
|
112
|
+
return ref;
|
|
113
|
+
}
|
|
114
|
+
export function formatSkillRef(ref) {
|
|
115
|
+
const qualifier = ref.registry === undefined ? '' : `${ref.registry}:`;
|
|
116
|
+
const range = ref.range === undefined ? '' : `@${ref.range}`;
|
|
117
|
+
return `${qualifier}${ref.name}${range}`;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=skill-ref.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-ref.js","sourceRoot":"","sources":["../../src/domain/skill-ref.ts"],"names":[],"mappings":"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"}
|