skillset 0.14.0 → 0.15.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/cli.js +577 -85
- package/dist/create.js +577 -85
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7024,8 +7024,8 @@ var require_dist = __commonJS((exports) => {
|
|
|
7024
7024
|
});
|
|
7025
7025
|
|
|
7026
7026
|
// apps/skillset/src/cli-core.ts
|
|
7027
|
-
import { mkdir as
|
|
7028
|
-
import { basename as basename9, dirname as
|
|
7027
|
+
import { mkdir as mkdir12, writeFile as writeFile13 } from "fs/promises";
|
|
7028
|
+
import { basename as basename9, dirname as dirname17, resolve as resolve10 } from "path";
|
|
7029
7029
|
|
|
7030
7030
|
// packages/core/src/authoring.ts
|
|
7031
7031
|
import { readFile as readFile10, writeFile as writeFile4 } from "fs/promises";
|
|
@@ -7656,8 +7656,20 @@ var skillsetFeatureRegistry = defineFeatureRegistry([
|
|
|
7656
7656
|
validationOwner: "packages/core/src/version-audit.ts"
|
|
7657
7657
|
}),
|
|
7658
7658
|
feature({
|
|
7659
|
-
docs: ["docs/features/ci.md", "docs/features/build-scopes.md"],
|
|
7660
|
-
evidence: [
|
|
7659
|
+
docs: ["docs/features/ci.md", "docs/features/build-scopes.md", "docs/features/workbench.md"],
|
|
7660
|
+
evidence: [
|
|
7661
|
+
test("apps/skillset/src/__tests__/ci.test.ts", "CI and build-scope coverage"),
|
|
7662
|
+
test("apps/skillset/src/__tests__/contract.test.ts", "CLI check/verify command coverage"),
|
|
7663
|
+
test("packages/workbench/src/__tests__/presets.test.ts", "Workbench presets"),
|
|
7664
|
+
test("packages/workbench/src/__tests__/lint-bridge.test.ts", "Workbench lint bridge"),
|
|
7665
|
+
test("packages/workbench/src/__tests__/parser.test.ts", "Workbench parser diagnostics"),
|
|
7666
|
+
test("packages/workbench/src/__tests__/schema.test.ts", "Workbench source contract diagnostics"),
|
|
7667
|
+
test("packages/workbench/src/__tests__/compatibility.test.ts", "Workbench provider compatibility diagnostics"),
|
|
7668
|
+
test("packages/workbench/src/__tests__/resource-runtime.test.ts", "Workbench resource and runtime diagnostics"),
|
|
7669
|
+
test("packages/workbench/src/__tests__/fixtures.test.ts", "Workbench clean and invalid fixtures"),
|
|
7670
|
+
test("packages/workbench/src/__tests__/ast-grep.test.ts", "Workbench ast-grep adapter proof"),
|
|
7671
|
+
test("packages/workbench/src/__tests__/markdown.test.ts", "Workbench Markdown diagnostics")
|
|
7672
|
+
],
|
|
7661
7673
|
id: "workflows",
|
|
7662
7674
|
kind: "workflow",
|
|
7663
7675
|
renderOwner: "apps/skillset/src/cli-core.ts",
|
|
@@ -8047,13 +8059,14 @@ function readCompileConfig(record, label) {
|
|
|
8047
8059
|
if (compile === undefined) {
|
|
8048
8060
|
return {
|
|
8049
8061
|
build: "updated",
|
|
8062
|
+
features: { promptArguments: true },
|
|
8050
8063
|
skillset: { metadata: true },
|
|
8051
8064
|
targets: [...TARGET_NAMES],
|
|
8052
8065
|
unsupportedDestination: "error"
|
|
8053
8066
|
};
|
|
8054
8067
|
}
|
|
8055
8068
|
for (const key of Object.keys(compile)) {
|
|
8056
|
-
if (key !== "build" && key !== "skillset" && key !== "targets" && key !== "unsupportedDestination") {
|
|
8069
|
+
if (key !== "build" && key !== "features" && key !== "skillset" && key !== "targets" && key !== "unsupportedDestination") {
|
|
8057
8070
|
throw new Error(`skillset: unsupported compile key ${key} in ${label}`);
|
|
8058
8071
|
}
|
|
8059
8072
|
}
|
|
@@ -8063,6 +8076,7 @@ function readCompileConfig(record, label) {
|
|
|
8063
8076
|
}
|
|
8064
8077
|
return {
|
|
8065
8078
|
build: readCompileBuildMode(compile, `${label}.compile.build`),
|
|
8079
|
+
features: readCompileFeatureConfig(compile, `${label}.compile.features`),
|
|
8066
8080
|
skillset: readCompileSkillsetConfig(compile, `${label}.compile.skillset`),
|
|
8067
8081
|
targets: readCompileTargetNames(compile, `${label}.compile.targets`),
|
|
8068
8082
|
unsupportedDestination
|
|
@@ -8356,6 +8370,26 @@ function readCompileSkillsetConfig(record, label) {
|
|
|
8356
8370
|
}
|
|
8357
8371
|
return { metadata };
|
|
8358
8372
|
}
|
|
8373
|
+
function readCompileFeatureConfig(record, label) {
|
|
8374
|
+
const value = record.features;
|
|
8375
|
+
if (value === undefined)
|
|
8376
|
+
return { promptArguments: true };
|
|
8377
|
+
if (!isJsonRecord(value)) {
|
|
8378
|
+
throw new Error(`skillset: expected ${label} to be an object`);
|
|
8379
|
+
}
|
|
8380
|
+
for (const key of Object.keys(value)) {
|
|
8381
|
+
if (key !== "promptArguments") {
|
|
8382
|
+
throw new Error(`skillset: unsupported compile feature key ${key} in ${label}`);
|
|
8383
|
+
}
|
|
8384
|
+
}
|
|
8385
|
+
const promptArguments = value.promptArguments;
|
|
8386
|
+
if (promptArguments === undefined)
|
|
8387
|
+
return { promptArguments: true };
|
|
8388
|
+
if (typeof promptArguments !== "boolean") {
|
|
8389
|
+
throw new Error(`skillset: expected ${label}.promptArguments to be a boolean`);
|
|
8390
|
+
}
|
|
8391
|
+
return { promptArguments };
|
|
8392
|
+
}
|
|
8359
8393
|
function readUnsupportedDestinationPolicy(record, label) {
|
|
8360
8394
|
const value = record.unsupportedDestination;
|
|
8361
8395
|
if (value === undefined)
|
|
@@ -10318,7 +10352,7 @@ var dynamicArgumentsEntry = {
|
|
|
10318
10352
|
evidence: DYNAMIC_EVIDENCE,
|
|
10319
10353
|
forms: {
|
|
10320
10354
|
claude: {
|
|
10321
|
-
pattern: /\$ARGUMENTS(?:\
|
|
10355
|
+
pattern: /\$ARGUMENTS(?:\[[^\]]+\]|\.[A-Za-z_][A-Za-z0-9_-]*|\b)/gu
|
|
10322
10356
|
}
|
|
10323
10357
|
},
|
|
10324
10358
|
intent: "dynamic.arguments",
|
|
@@ -10330,7 +10364,7 @@ var dynamicPositionalEntry = {
|
|
|
10330
10364
|
evidence: DYNAMIC_EVIDENCE,
|
|
10331
10365
|
forms: {
|
|
10332
10366
|
claude: {
|
|
10333
|
-
pattern: /(?<![\w$])\$[
|
|
10367
|
+
pattern: /(?<![\w$])\$[01]\b(?!\.\d)/gu
|
|
10334
10368
|
}
|
|
10335
10369
|
},
|
|
10336
10370
|
intent: "dynamic.positional",
|
|
@@ -11459,8 +11493,25 @@ async function resolveVariable(token, key, context, renderContext) {
|
|
|
11459
11493
|
if (value !== undefined)
|
|
11460
11494
|
return value;
|
|
11461
11495
|
}
|
|
11496
|
+
if (key.startsWith("$ARGUMENTS")) {
|
|
11497
|
+
return promptArgumentsVariable(token, key, context);
|
|
11498
|
+
}
|
|
11462
11499
|
throw new Error(`skillset: unknown preprocess variable ${token} in ${relative5(context.rootPath, context.sourcePath)}`);
|
|
11463
11500
|
}
|
|
11501
|
+
function promptArgumentsVariable(token, key, context) {
|
|
11502
|
+
if (!isPromptArgumentsVariable(key)) {
|
|
11503
|
+
throw new Error(`skillset: invalid prompt arguments variable ${token} in ${relative5(context.rootPath, context.sourcePath)}`);
|
|
11504
|
+
}
|
|
11505
|
+
if (context.promptArguments === false) {
|
|
11506
|
+
throw new Error(`skillset: prompt arguments variable ${token} in ${relative5(context.rootPath, context.sourcePath)} requires compile.features.promptArguments`);
|
|
11507
|
+
}
|
|
11508
|
+
if (context.target === "claude")
|
|
11509
|
+
return key;
|
|
11510
|
+
return `{{${key}}}`;
|
|
11511
|
+
}
|
|
11512
|
+
function isPromptArgumentsVariable(key) {
|
|
11513
|
+
return /^\$ARGUMENTS(?:\b|\[[0-9]+\]|\.[A-Za-z_][A-Za-z0-9_-]*)$/u.test(key);
|
|
11514
|
+
}
|
|
11464
11515
|
function readPathValue(record, path) {
|
|
11465
11516
|
let current = record;
|
|
11466
11517
|
for (const segment of path.split(".")) {
|
|
@@ -12666,10 +12717,17 @@ async function renderSkillMarkdown(graph, plugin, skill, target) {
|
|
|
12666
12717
|
rootPath: graph.rootPath,
|
|
12667
12718
|
sourcePath: skill.sourcePath,
|
|
12668
12719
|
sourceRoot: graph.sourceRoot,
|
|
12720
|
+
target,
|
|
12721
|
+
promptArguments: graph.root.compile.features.promptArguments,
|
|
12669
12722
|
...plugin === undefined ? {} : { pluginPath: plugin.path }
|
|
12670
12723
|
});
|
|
12671
|
-
const
|
|
12672
|
-
|
|
12724
|
+
const notices = [
|
|
12725
|
+
target === "codex" && plugin !== undefined ? renderCodexDependencyNotice(graph, plugin) : undefined,
|
|
12726
|
+
target === "codex" ? renderCodexPromptArgumentsNotice(preprocessedBody) : undefined
|
|
12727
|
+
].filter((notice) => notice !== undefined);
|
|
12728
|
+
const body = notices.length === 0 ? preprocessedBody : `${notices.join(`
|
|
12729
|
+
|
|
12730
|
+
`)}
|
|
12673
12731
|
|
|
12674
12732
|
${preprocessedBody}`;
|
|
12675
12733
|
const linkedBody = rewriteResourceLinks(body, skill.resources, skill.sourcePath);
|
|
@@ -12680,6 +12738,12 @@ ${preprocessedBody}`;
|
|
|
12680
12738
|
transforms: translated.transforms
|
|
12681
12739
|
};
|
|
12682
12740
|
}
|
|
12741
|
+
function renderCodexPromptArgumentsNotice(body) {
|
|
12742
|
+
if (!/\{\{\$ARGUMENTS(?:\}\}|\[[0-9]+\]\}\}|\.[A-Za-z_][A-Za-z0-9_-]*\}\})/u.test(body)) {
|
|
12743
|
+
return;
|
|
12744
|
+
}
|
|
12745
|
+
return "Before using commands, replace `{{$ARGUMENTS...}}` placeholders with the user's supplied arguments.";
|
|
12746
|
+
}
|
|
12683
12747
|
function renderClaudeSkillPolicy(skill, targetOptions) {
|
|
12684
12748
|
const label = skill.sourcePath;
|
|
12685
12749
|
const implicitInvocation = readImplicitInvocation(skill.frontmatter, "claude", label);
|
|
@@ -12717,6 +12781,8 @@ async function renderCodexSkillAgentFile(graph, plugin, skill, target, sourceDir
|
|
|
12717
12781
|
rootPath: graph.rootPath,
|
|
12718
12782
|
sourcePath: sourceOpenAiPath,
|
|
12719
12783
|
sourceRoot: graph.sourceRoot,
|
|
12784
|
+
target,
|
|
12785
|
+
promptArguments: graph.root.compile.features.promptArguments,
|
|
12720
12786
|
...plugin === undefined ? {} : { pluginPath: plugin.path }
|
|
12721
12787
|
}), sourceOpenAiPath) : {};
|
|
12722
12788
|
const merged = mergeRecords(source2, generated);
|
|
@@ -13097,6 +13163,9 @@ function renderLockFiles(graph, lockRoots) {
|
|
|
13097
13163
|
for (const [outputRoot, lock] of [...lockRoots.entries()].sort(([left], [right]) => compareStrings(left, right))) {
|
|
13098
13164
|
const value = {
|
|
13099
13165
|
buildMode: graph.root.compile.build,
|
|
13166
|
+
features: {
|
|
13167
|
+
promptArguments: graph.root.compile.features.promptArguments
|
|
13168
|
+
},
|
|
13100
13169
|
generatedBy: GENERATED_BY2,
|
|
13101
13170
|
items: lock.items.map((item) => stripUndefinedLockItem(item)).sort((left, right) => compareStrings(String(left.outputPath), String(right.outputPath))),
|
|
13102
13171
|
selectedTargets: [...graph.root.compile.targets],
|
|
@@ -14671,7 +14740,7 @@ async function diffSkillsetResult(rootPath, options = {}) {
|
|
|
14671
14740
|
}
|
|
14672
14741
|
};
|
|
14673
14742
|
}
|
|
14674
|
-
async function
|
|
14743
|
+
async function verifySkillsetResult(rootPath, options = {}) {
|
|
14675
14744
|
const graph = await loadBuildGraph(rootPath, options);
|
|
14676
14745
|
const diagnostics = [...graph.warnings.map(sourceWarningDiagnostic)];
|
|
14677
14746
|
const outPath = outPathMapper(options);
|
|
@@ -14724,7 +14793,7 @@ async function checkSkillsetResult(rootPath, options = {}) {
|
|
|
14724
14793
|
diagnostics: [...diagnostics, ...driftDiagnostics],
|
|
14725
14794
|
renderResults: renderResultsWithDiagnostics,
|
|
14726
14795
|
ok: failures.length === 0,
|
|
14727
|
-
operation: "
|
|
14796
|
+
operation: "verify",
|
|
14728
14797
|
writes: {
|
|
14729
14798
|
deletedPaths: [],
|
|
14730
14799
|
mode: "read",
|
|
@@ -15492,12 +15561,12 @@ var CLAUDE_DYNAMIC_PATTERNS = [
|
|
|
15492
15561
|
{
|
|
15493
15562
|
code: "claude-arguments",
|
|
15494
15563
|
label: "$ARGUMENTS",
|
|
15495
|
-
pattern: /\$ARGUMENTS(?:\
|
|
15564
|
+
pattern: /\$ARGUMENTS(?:\[[^\]]+\]|\.[A-Za-z_][A-Za-z0-9_-]*|\b)/
|
|
15496
15565
|
},
|
|
15497
15566
|
{
|
|
15498
15567
|
code: "claude-positional-argument",
|
|
15499
15568
|
label: "$0/$1 positional arguments",
|
|
15500
|
-
pattern: /(^|[^\w$])\$[
|
|
15569
|
+
pattern: /(^|[^\w$])\$[01]\b(?!\.\d)/
|
|
15501
15570
|
},
|
|
15502
15571
|
{
|
|
15503
15572
|
code: "claude-env-substitution",
|
|
@@ -15512,6 +15581,7 @@ var CLAUDE_DYNAMIC_PATTERNS = [
|
|
|
15512
15581
|
];
|
|
15513
15582
|
var FENCE_PATTERN2 = /^\s*(?:```|~~~)/u;
|
|
15514
15583
|
var INLINE_CODE_PATTERN2 = /`[^`]*`/gu;
|
|
15584
|
+
var SKILLSET_PROMPT_ARGUMENT_PATTERN = /\{\{\s*\$ARGUMENTS(?:\b|\[[0-9]+\]|\.[A-Za-z_][A-Za-z0-9_-]*)\s*\}\}/gu;
|
|
15515
15585
|
async function lintSkillset(rootPath, options = {}) {
|
|
15516
15586
|
const graph = await loadBuildGraph(rootPath, options);
|
|
15517
15587
|
const result = await inspectBuildGraph(graph);
|
|
@@ -15696,7 +15766,18 @@ function lintSkill(graph, skill, featureId) {
|
|
|
15696
15766
|
if (!skill.targets.codex.enabled)
|
|
15697
15767
|
return issues;
|
|
15698
15768
|
issues.push(...lintCodexAllowedTools(graph, skill));
|
|
15699
|
-
const
|
|
15769
|
+
const markdownSearchableBody = maskMarkdownCodeRegions(skill.body);
|
|
15770
|
+
if (!graph.root.compile.features.promptArguments && hasSkillsetPromptArguments(skill.body)) {
|
|
15771
|
+
const path2 = relative10(graph.rootPath, skill.sourcePath);
|
|
15772
|
+
issues.push({
|
|
15773
|
+
code: "prompt-arguments-disabled",
|
|
15774
|
+
featureId,
|
|
15775
|
+
severity: "error",
|
|
15776
|
+
path: path2,
|
|
15777
|
+
message: `${path2} uses Skillset prompt argument placeholders while compile.features.promptArguments is false. ` + "Enable compile.features.promptArguments or remove the {{$ARGUMENTS...}} placeholders."
|
|
15778
|
+
});
|
|
15779
|
+
}
|
|
15780
|
+
const searchableBody = maskSkillsetPromptArguments(markdownSearchableBody);
|
|
15700
15781
|
const matches = CLAUDE_DYNAMIC_PATTERNS.filter(({ pattern }) => pattern.test(searchableBody));
|
|
15701
15782
|
if (matches.length === 0)
|
|
15702
15783
|
return issues;
|
|
@@ -15711,6 +15792,14 @@ function lintSkill(graph, skill, featureId) {
|
|
|
15711
15792
|
});
|
|
15712
15793
|
return issues;
|
|
15713
15794
|
}
|
|
15795
|
+
function maskSkillsetPromptArguments(body) {
|
|
15796
|
+
SKILLSET_PROMPT_ARGUMENT_PATTERN.lastIndex = 0;
|
|
15797
|
+
return body.replaceAll(SKILLSET_PROMPT_ARGUMENT_PATTERN, "");
|
|
15798
|
+
}
|
|
15799
|
+
function hasSkillsetPromptArguments(body) {
|
|
15800
|
+
SKILLSET_PROMPT_ARGUMENT_PATTERN.lastIndex = 0;
|
|
15801
|
+
return SKILLSET_PROMPT_ARGUMENT_PATTERN.test(body);
|
|
15802
|
+
}
|
|
15714
15803
|
function maskMarkdownCodeRegions(body) {
|
|
15715
15804
|
let inFence = false;
|
|
15716
15805
|
return body.split(/\r?\n/u).map((line) => {
|
|
@@ -15803,7 +15892,7 @@ async function explainPath(rootPath, inputPath, options = {}) {
|
|
|
15803
15892
|
entries: asGenerated.map((item) => item.entry),
|
|
15804
15893
|
features: featureCapabilitiesForPath(graph, target, asGenerated, matchedRenderResults),
|
|
15805
15894
|
renderResults: matchedRenderResults,
|
|
15806
|
-
notes: [`Generated output; rebuild with skillset build, verify with skillset
|
|
15895
|
+
notes: [`Generated output; rebuild with skillset build, verify with skillset verify.`]
|
|
15807
15896
|
};
|
|
15808
15897
|
}
|
|
15809
15898
|
const prefixMatch = items.filter((item) => item.sourcePath.startsWith(`${target}/`));
|
|
@@ -15902,7 +15991,7 @@ async function suggestSource(rootPath, inputPath, options = {}) {
|
|
|
15902
15991
|
generatedPath,
|
|
15903
15992
|
...lockPath2 === undefined ? {} : { lockPath: lockPath2 },
|
|
15904
15993
|
message: "Generated body matches the source body; no source edit is needed.",
|
|
15905
|
-
nextSteps: ["Run `skillset diff` or `skillset
|
|
15994
|
+
nextSteps: ["Run `skillset diff` or `skillset verify` to inspect any remaining generated drift."],
|
|
15906
15995
|
sourcePath,
|
|
15907
15996
|
status: "suggestible",
|
|
15908
15997
|
wouldWrite: false,
|
|
@@ -18377,7 +18466,7 @@ async function importSource(options) {
|
|
|
18377
18466
|
nextChecks: [
|
|
18378
18467
|
"skillset lint",
|
|
18379
18468
|
"skillset build",
|
|
18380
|
-
"skillset
|
|
18469
|
+
"skillset verify"
|
|
18381
18470
|
],
|
|
18382
18471
|
preservedTargetNativeFields: classification.targetNative,
|
|
18383
18472
|
sourcePath,
|
|
@@ -19544,6 +19633,7 @@ function createReadme(name, targets) {
|
|
|
19544
19633
|
"skillset build --dry-run",
|
|
19545
19634
|
"skillset build --yes",
|
|
19546
19635
|
"skillset check",
|
|
19636
|
+
"skillset verify",
|
|
19547
19637
|
"skillset change status",
|
|
19548
19638
|
"```",
|
|
19549
19639
|
"",
|
|
@@ -19574,7 +19664,7 @@ function createAgentsGuide(name) {
|
|
|
19574
19664
|
"- Treat `changes/` as Skillset-managed change and release state.",
|
|
19575
19665
|
"- Treat generated target directories as outputs; do not hand-edit them as source truth.",
|
|
19576
19666
|
"- Run `skillset build --dry-run` before writing generated outputs.",
|
|
19577
|
-
"- Run `skillset check` before committing source changes.",
|
|
19667
|
+
"- Run `skillset check` and `skillset verify` before committing source changes.",
|
|
19578
19668
|
"- Add pending change entries with `skillset change add` when source units change and the repo uses Skillset release tracking.",
|
|
19579
19669
|
""
|
|
19580
19670
|
].join(`
|
|
@@ -19785,6 +19875,7 @@ async function importCandidate(rootPath, acquisition, candidate, cutover, previe
|
|
|
19785
19875
|
try {
|
|
19786
19876
|
const destination = await importInstructionFile(rootPath, candidate.path);
|
|
19787
19877
|
await writeMarkdownSourceOrigin2(join16(rootPath, destination), sourceOriginFor(acquisition, candidate.path));
|
|
19878
|
+
await normalizeImportedPromptArguments(join16(rootPath, destination));
|
|
19788
19879
|
cutover.push(candidate.path);
|
|
19789
19880
|
previewSources.push(destination);
|
|
19790
19881
|
return { candidate, destination, detail: destination, renderResults: [], ok: true, units: [] };
|
|
@@ -19811,6 +19902,7 @@ async function importCandidate(rootPath, acquisition, candidate, cutover, previe
|
|
|
19811
19902
|
for (const file of report.copiedFiles) {
|
|
19812
19903
|
if (basename8(file) !== "SKILL.md")
|
|
19813
19904
|
continue;
|
|
19905
|
+
await normalizeImportedPromptArguments(join16(report.targetPath, file));
|
|
19814
19906
|
previewSources.push(relative15(rootPath, join16(report.targetPath, file)).replaceAll("\\", "/"));
|
|
19815
19907
|
}
|
|
19816
19908
|
}
|
|
@@ -19865,12 +19957,45 @@ function sourceOriginRecord3(origin) {
|
|
|
19865
19957
|
...origin.repo === undefined ? {} : { repo: origin.repo }
|
|
19866
19958
|
};
|
|
19867
19959
|
}
|
|
19960
|
+
async function normalizeImportedPromptArguments(path2) {
|
|
19961
|
+
const raw = await readFile17(path2, "utf8");
|
|
19962
|
+
let updated;
|
|
19963
|
+
try {
|
|
19964
|
+
const parts = parseMarkdown(raw, path2);
|
|
19965
|
+
const body = rewriteClaudePromptArguments(parts.body);
|
|
19966
|
+
updated = body === parts.body ? raw : stringifyMarkdown(parts.frontmatter, body);
|
|
19967
|
+
} catch {
|
|
19968
|
+
updated = rewriteClaudePromptArguments(raw);
|
|
19969
|
+
}
|
|
19970
|
+
if (updated !== raw)
|
|
19971
|
+
await writeFile8(path2, updated);
|
|
19972
|
+
}
|
|
19973
|
+
function rewriteClaudePromptArguments(content) {
|
|
19974
|
+
const pattern = /\$ARGUMENTS(?:\[[0-9]+\]|\.[A-Za-z_][A-Za-z0-9_-]*|\b(?![\[.]))/gu;
|
|
19975
|
+
let rewritten = "";
|
|
19976
|
+
let cursor = 0;
|
|
19977
|
+
for (const match of content.matchAll(pattern)) {
|
|
19978
|
+
const token = match[0];
|
|
19979
|
+
const index = match.index;
|
|
19980
|
+
if (isAlreadySkillsetPromptArgument(content, index, index + token.length))
|
|
19981
|
+
continue;
|
|
19982
|
+
rewritten += content.slice(cursor, index);
|
|
19983
|
+
rewritten += `{{${token}}}`;
|
|
19984
|
+
cursor = index + token.length;
|
|
19985
|
+
}
|
|
19986
|
+
return `${rewritten}${content.slice(cursor)}`;
|
|
19987
|
+
}
|
|
19988
|
+
function isAlreadySkillsetPromptArgument(content, start, end) {
|
|
19989
|
+
const before = content.slice(Math.max(0, start - 4), start);
|
|
19990
|
+
const after = content.slice(end, Math.min(content.length, end + 4));
|
|
19991
|
+
return /\{\{\s*$/u.test(before) && /^\s*\}\}/u.test(after);
|
|
19992
|
+
}
|
|
19868
19993
|
async function buildTransformPreviews(rootPath, paths) {
|
|
19869
19994
|
const previews = [];
|
|
19870
19995
|
for (const path2 of paths) {
|
|
19871
19996
|
const raw = await readFile17(join16(rootPath, path2), "utf8");
|
|
19872
19997
|
const body = basename8(path2) === "SKILL.md" ? markdownBody(raw, path2) : raw;
|
|
19873
|
-
const matches = recognizeTransforms(body, "claude");
|
|
19998
|
+
const matches = recognizeTransforms(maskSkillsetPromptArguments2(body), "claude");
|
|
19874
19999
|
if (matches.length === 0)
|
|
19875
20000
|
continue;
|
|
19876
20001
|
const transformable = matches.some((match) => match.lowering !== "none");
|
|
@@ -19892,6 +20017,9 @@ async function buildTransformPreviews(rootPath, paths) {
|
|
|
19892
20017
|
}
|
|
19893
20018
|
return previews;
|
|
19894
20019
|
}
|
|
20020
|
+
function maskSkillsetPromptArguments2(body) {
|
|
20021
|
+
return body.replaceAll(/\{\{\s*\$ARGUMENTS(?:\[[0-9]+\]|\.[A-Za-z_][A-Za-z0-9_-]*|\b)\s*\}\}/gu, "");
|
|
20022
|
+
}
|
|
19895
20023
|
async function declareClaudeDialect(path2) {
|
|
19896
20024
|
const raw = await readFile17(path2, "utf8");
|
|
19897
20025
|
try {
|
|
@@ -19986,7 +20114,7 @@ function renderAdoptReportMarkdown(report, opts) {
|
|
|
19986
20114
|
}
|
|
19987
20115
|
if (report.transformPreviews.length > 0) {
|
|
19988
20116
|
lines.push("## Transforms (preview)", "");
|
|
19989
|
-
lines.push("
|
|
20117
|
+
lines.push("Claude `$ARGUMENTS` forms are normalized to Skillset prompt argument placeholders. Other bodies are untouched. Files with transformable constructs were marked `dialect: claude`; the build lowers their Codex projection through these forms.", "");
|
|
19990
20118
|
for (const preview of report.transformPreviews) {
|
|
19991
20119
|
lines.push(`### \`${preview.path}\``, "");
|
|
19992
20120
|
if (preview.dialectDeclared) {
|
|
@@ -20038,7 +20166,7 @@ function renderAdoptReportMarkdown(report, opts) {
|
|
|
20038
20166
|
lines.push("2. No original paths need to move before a live build.");
|
|
20039
20167
|
}
|
|
20040
20168
|
lines.push("3. Run `skillset build --yes` to write live output.", "", "Until the originals move, live builds refuse to overwrite them as unmanaged files \u2014 that protection is the safety net; nothing is lost by building too early.", "");
|
|
20041
|
-
lines.push("## Next steps", "", "- `skillset lint`", "- `skillset
|
|
20169
|
+
lines.push("## Next steps", "", "- `skillset lint`", "- `skillset verify --isolated`", "- `skillset ci`", "");
|
|
20042
20170
|
return `${lines.join(`
|
|
20043
20171
|
`).trimEnd()}
|
|
20044
20172
|
`;
|
|
@@ -20803,7 +20931,7 @@ function readHookRunEvent(value) {
|
|
|
20803
20931
|
}
|
|
20804
20932
|
// apps/skillset/src/runtime-hooks/print.ts
|
|
20805
20933
|
var PRE_COMMIT_COMMAND = "skillset change check --staged";
|
|
20806
|
-
var PRE_PUSH_COMMAND = "skillset change check --since origin/main && skillset check && skillset doctor";
|
|
20934
|
+
var PRE_PUSH_COMMAND = "skillset change check --since origin/main && skillset check && skillset verify && skillset doctor";
|
|
20807
20935
|
var RUNTIME_POST_TOOL_USE_COMMAND = "skillset hooks run post-tool-use";
|
|
20808
20936
|
var RUNTIME_STOP_COMMAND = "skillset hooks run stop";
|
|
20809
20937
|
function renderHookPrint(options) {
|
|
@@ -21041,7 +21169,12 @@ async function runHookEvent(event, options = {}) {
|
|
|
21041
21169
|
const checkArgs = ["check", "--root", "."];
|
|
21042
21170
|
ranCommands.push(checkArgs.join(" "));
|
|
21043
21171
|
const check = await runner(checkArgs, commandOptions({ allowFailure: false, options, rootPath }));
|
|
21044
|
-
|
|
21172
|
+
if (check !== 0)
|
|
21173
|
+
return result({ context, event, exitCode: check, gate, ranCommands });
|
|
21174
|
+
const verifyArgs = ["verify", "--root", "."];
|
|
21175
|
+
ranCommands.push(verifyArgs.join(" "));
|
|
21176
|
+
const verify = await runner(verifyArgs, commandOptions({ allowFailure: false, options, rootPath }));
|
|
21177
|
+
return result({ context, event, exitCode: verify, gate, ranCommands });
|
|
21045
21178
|
}
|
|
21046
21179
|
function commandOptions(args) {
|
|
21047
21180
|
return {
|
|
@@ -21060,10 +21193,220 @@ function result(args) {
|
|
|
21060
21193
|
sourceGateOk: args.gate.ok
|
|
21061
21194
|
};
|
|
21062
21195
|
}
|
|
21196
|
+
// apps/skillset/src/new-source.ts
|
|
21197
|
+
import { mkdir as mkdir9, stat as stat16, writeFile as writeFile10 } from "fs/promises";
|
|
21198
|
+
import { dirname as dirname14, join as join19 } from "path";
|
|
21199
|
+
var SKILL_PRESETS = new Set([
|
|
21200
|
+
"assets",
|
|
21201
|
+
"evals",
|
|
21202
|
+
"examples-file",
|
|
21203
|
+
"minimal",
|
|
21204
|
+
"reference-file",
|
|
21205
|
+
"references",
|
|
21206
|
+
"scripts",
|
|
21207
|
+
"support"
|
|
21208
|
+
]);
|
|
21209
|
+
async function scaffoldSourceUnit(rootPath, options) {
|
|
21210
|
+
if (options.scope !== undefined && options.scope !== "repo") {
|
|
21211
|
+
throw new Error("skillset: new currently supports only --scope repo");
|
|
21212
|
+
}
|
|
21213
|
+
if (options.kind === "hook") {
|
|
21214
|
+
throw new Error("skillset: new hook is not available yet; current hook source is hooks/hooks.json");
|
|
21215
|
+
}
|
|
21216
|
+
const id = resolveSourceId(options);
|
|
21217
|
+
const displayName = resolveDisplayName(options, id);
|
|
21218
|
+
const sourceDir = await detectWorkspaceSourceDir(rootPath, options.skillsetOptions ?? {});
|
|
21219
|
+
await assertWorkspaceInitialized(rootPath, sourceDir);
|
|
21220
|
+
const sourceRoot = sourceDir === "." ? "skillset" : join19(sourceDir, "src");
|
|
21221
|
+
const plans = options.kind === "skill" ? await planSkill(rootPath, sourceRoot, id, displayName, options) : planAgent(sourceRoot, id, displayName, options);
|
|
21222
|
+
for (const plan of plans) {
|
|
21223
|
+
if (await fileExists2(resolveInside(rootPath, plan.path))) {
|
|
21224
|
+
throw new Error(`skillset: refusing to overwrite existing source file ${plan.path}`);
|
|
21225
|
+
}
|
|
21226
|
+
}
|
|
21227
|
+
if (options.write === true) {
|
|
21228
|
+
for (const plan of plans) {
|
|
21229
|
+
const absolutePath = resolveInside(rootPath, plan.path);
|
|
21230
|
+
await mkdir9(dirname14(absolutePath), { recursive: true });
|
|
21231
|
+
await writeFile10(absolutePath, plan.content);
|
|
21232
|
+
}
|
|
21233
|
+
}
|
|
21234
|
+
return {
|
|
21235
|
+
displayName,
|
|
21236
|
+
files: plans.map((plan) => ({ path: plan.path })),
|
|
21237
|
+
id,
|
|
21238
|
+
kind: options.kind,
|
|
21239
|
+
rootPath,
|
|
21240
|
+
sourceRoot,
|
|
21241
|
+
write: options.write === true
|
|
21242
|
+
};
|
|
21243
|
+
}
|
|
21244
|
+
function resolveSourceId(options) {
|
|
21245
|
+
if (options.id !== undefined)
|
|
21246
|
+
return validateSlug(options.id, `${options.kind} id`);
|
|
21247
|
+
const name = options.name ?? options.displayName;
|
|
21248
|
+
if (name === undefined || name.trim().length === 0) {
|
|
21249
|
+
throw new Error(`skillset: new ${options.kind} requires a name or --id`);
|
|
21250
|
+
}
|
|
21251
|
+
return validateSlug(kebabCase(name), `${options.kind} id`);
|
|
21252
|
+
}
|
|
21253
|
+
function resolveDisplayName(options, id) {
|
|
21254
|
+
if (options.displayName !== undefined && options.displayName.trim().length > 0) {
|
|
21255
|
+
return options.displayName.trim();
|
|
21256
|
+
}
|
|
21257
|
+
if (options.name !== undefined && options.name.trim().length > 0)
|
|
21258
|
+
return options.name.trim();
|
|
21259
|
+
return titleFromId(id);
|
|
21260
|
+
}
|
|
21261
|
+
async function planSkill(rootPath, sourceRoot, id, displayName, options) {
|
|
21262
|
+
const container = options.container === undefined ? undefined : validateSlug(options.container, "new --in container");
|
|
21263
|
+
if (container !== undefined)
|
|
21264
|
+
await assertPluginContainer(rootPath, sourceRoot, container);
|
|
21265
|
+
const skillRoot = container === undefined ? join19(sourceRoot, "skills", id) : join19(sourceRoot, "plugins", container, "skills", id);
|
|
21266
|
+
const presets = readSkillPresets(options.presets);
|
|
21267
|
+
const files = [
|
|
21268
|
+
{
|
|
21269
|
+
content: renderSkill(id, displayName),
|
|
21270
|
+
path: join19(skillRoot, "SKILL.md")
|
|
21271
|
+
}
|
|
21272
|
+
];
|
|
21273
|
+
for (const preset of presets) {
|
|
21274
|
+
if (preset === "minimal")
|
|
21275
|
+
continue;
|
|
21276
|
+
if (preset === "support" || preset === "references") {
|
|
21277
|
+
files.push({ content: "", path: join19(skillRoot, "references", ".gitkeep") });
|
|
21278
|
+
}
|
|
21279
|
+
if (preset === "support" || preset === "assets") {
|
|
21280
|
+
files.push({ content: "", path: join19(skillRoot, "assets", ".gitkeep") });
|
|
21281
|
+
}
|
|
21282
|
+
if (preset === "support" || preset === "scripts") {
|
|
21283
|
+
files.push({ content: "", path: join19(skillRoot, "scripts", ".gitkeep") });
|
|
21284
|
+
}
|
|
21285
|
+
if (preset === "evals") {
|
|
21286
|
+
files.push({ content: `{
|
|
21287
|
+
"evals": []
|
|
21288
|
+
}
|
|
21289
|
+
`, path: join19(skillRoot, "evals", "evals.json") });
|
|
21290
|
+
}
|
|
21291
|
+
if (preset === "reference-file") {
|
|
21292
|
+
files.push({ content: `# ${displayName} Reference
|
|
21293
|
+
|
|
21294
|
+
Add concise reference material here.
|
|
21295
|
+
`, path: join19(skillRoot, "REFERENCE.md") });
|
|
21296
|
+
}
|
|
21297
|
+
if (preset === "examples-file") {
|
|
21298
|
+
files.push({ content: `# ${displayName} Examples
|
|
21299
|
+
|
|
21300
|
+
Add examples here.
|
|
21301
|
+
`, path: join19(skillRoot, "EXAMPLES.md") });
|
|
21302
|
+
}
|
|
21303
|
+
}
|
|
21304
|
+
return uniquePlans(files);
|
|
21305
|
+
}
|
|
21306
|
+
function planAgent(sourceRoot, id, displayName, options) {
|
|
21307
|
+
if (options.container !== undefined) {
|
|
21308
|
+
throw new Error("skillset: new agent does not support --in; project agents live at the repo source root");
|
|
21309
|
+
}
|
|
21310
|
+
if (options.presets !== undefined && options.presets.length > 0) {
|
|
21311
|
+
throw new Error("skillset: new agent does not support --preset");
|
|
21312
|
+
}
|
|
21313
|
+
return [
|
|
21314
|
+
{
|
|
21315
|
+
content: renderAgent(id, displayName),
|
|
21316
|
+
path: join19(sourceRoot, "agents", `${id}.md`)
|
|
21317
|
+
}
|
|
21318
|
+
];
|
|
21319
|
+
}
|
|
21320
|
+
async function assertPluginContainer(rootPath, sourceRoot, container) {
|
|
21321
|
+
const pluginPath = join19(sourceRoot, "plugins", container);
|
|
21322
|
+
try {
|
|
21323
|
+
const stats = await stat16(resolveInside(rootPath, pluginPath));
|
|
21324
|
+
if (stats.isDirectory() && await hasPluginManifest(rootPath, pluginPath))
|
|
21325
|
+
return;
|
|
21326
|
+
} catch {}
|
|
21327
|
+
throw new Error(`skillset: new --in container does not exist or has no skillset.yaml/config.yaml: ${pluginPath}`);
|
|
21328
|
+
}
|
|
21329
|
+
async function assertWorkspaceInitialized(rootPath, sourceDir) {
|
|
21330
|
+
const manifests = sourceDir === "." ? ["skillset.yaml"] : [join19(sourceDir, "skillset.yaml"), join19(sourceDir, "config.yaml")];
|
|
21331
|
+
for (const manifest of manifests) {
|
|
21332
|
+
if (await fileExists2(resolveInside(rootPath, manifest)))
|
|
21333
|
+
return;
|
|
21334
|
+
}
|
|
21335
|
+
throw new Error("skillset: new requires an initialized Skillset workspace; run skillset init --yes for an existing repo or skillset create for a dedicated repo");
|
|
21336
|
+
}
|
|
21337
|
+
function readSkillPresets(values) {
|
|
21338
|
+
const raw = values === undefined || values.length === 0 ? ["minimal"] : values.flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
|
|
21339
|
+
const presets = [];
|
|
21340
|
+
const seen = new Set;
|
|
21341
|
+
for (const value of raw) {
|
|
21342
|
+
if (!SKILL_PRESETS.has(value)) {
|
|
21343
|
+
throw new Error("skillset: expected --preset minimal, support, references, assets, scripts, evals, reference-file, or examples-file");
|
|
21344
|
+
}
|
|
21345
|
+
if (seen.has(value))
|
|
21346
|
+
continue;
|
|
21347
|
+
seen.add(value);
|
|
21348
|
+
presets.push(value);
|
|
21349
|
+
}
|
|
21350
|
+
return presets;
|
|
21351
|
+
}
|
|
21352
|
+
function uniquePlans(plans) {
|
|
21353
|
+
const seen = new Set;
|
|
21354
|
+
const unique = [];
|
|
21355
|
+
for (const plan of plans) {
|
|
21356
|
+
if (seen.has(plan.path))
|
|
21357
|
+
continue;
|
|
21358
|
+
seen.add(plan.path);
|
|
21359
|
+
unique.push(plan);
|
|
21360
|
+
}
|
|
21361
|
+
return unique;
|
|
21362
|
+
}
|
|
21363
|
+
function renderSkill(id, displayName) {
|
|
21364
|
+
const description = `Use when working with ${displayName} workflows.`;
|
|
21365
|
+
return `---
|
|
21366
|
+
name: ${id}
|
|
21367
|
+
title: ${yamlString(displayName)}
|
|
21368
|
+
description: ${yamlString(description)}
|
|
21369
|
+
---
|
|
21370
|
+
|
|
21371
|
+
# ${displayName}
|
|
21372
|
+
|
|
21373
|
+
Use this skill when working with ${displayName} workflows.
|
|
21374
|
+
|
|
21375
|
+
## Workflow
|
|
21376
|
+
|
|
21377
|
+
- Add the domain-specific guidance here.
|
|
21378
|
+
`;
|
|
21379
|
+
}
|
|
21380
|
+
function renderAgent(id, displayName) {
|
|
21381
|
+
const description = `Use this agent for ${displayName} work.`;
|
|
21382
|
+
return `---
|
|
21383
|
+
name: ${id}
|
|
21384
|
+
description: ${yamlString(description)}
|
|
21385
|
+
---
|
|
21386
|
+
|
|
21387
|
+
Use this agent for ${displayName} work.
|
|
21388
|
+
`;
|
|
21389
|
+
}
|
|
21390
|
+
function kebabCase(value) {
|
|
21391
|
+
return value.trim().toLowerCase().replace(/['\u2019]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
21392
|
+
}
|
|
21393
|
+
function titleFromId(id) {
|
|
21394
|
+
return id.split("-").filter((part) => part.length > 0).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
21395
|
+
}
|
|
21396
|
+
function yamlString(value) {
|
|
21397
|
+
return JSON.stringify(value);
|
|
21398
|
+
}
|
|
21399
|
+
async function fileExists2(path2) {
|
|
21400
|
+
return Bun.file(path2).exists();
|
|
21401
|
+
}
|
|
21402
|
+
async function hasPluginManifest(rootPath, pluginPath) {
|
|
21403
|
+
return await fileExists2(resolveInside(rootPath, join19(pluginPath, "skillset.yaml"))) || await fileExists2(resolveInside(rootPath, join19(pluginPath, "config.yaml")));
|
|
21404
|
+
}
|
|
21405
|
+
|
|
21063
21406
|
// apps/skillset/src/release.ts
|
|
21064
|
-
import { appendFile as appendFile2, mkdir as
|
|
21407
|
+
import { appendFile as appendFile2, mkdir as mkdir10, readFile as readFile20, rm as rm6, stat as stat17, writeFile as writeFile11 } from "fs/promises";
|
|
21065
21408
|
import { createHash as createHash7 } from "crypto";
|
|
21066
|
-
import { dirname as
|
|
21409
|
+
import { dirname as dirname15, join as join20 } from "path";
|
|
21067
21410
|
var HISTORY_FILE3 = "changes/history.jsonl";
|
|
21068
21411
|
var RELEASES_FILE = "changes/releases.jsonl";
|
|
21069
21412
|
var RELEASE_AMENDMENTS_FILE = "changes/release-amendments.jsonl";
|
|
@@ -21147,9 +21490,9 @@ async function amendReleaseRecord(rootPath, options) {
|
|
|
21147
21490
|
const notes = await resolveChangeReason(rootPath, options.reason);
|
|
21148
21491
|
const now = new Date().toISOString();
|
|
21149
21492
|
const sourceDir = storageOptions.sourceDir ?? ".skillset";
|
|
21150
|
-
const amendmentPath =
|
|
21493
|
+
const amendmentPath = join20(sourceDir, RELEASE_AMENDMENTS_FILE).replaceAll("\\", "/");
|
|
21151
21494
|
const absolutePath = resolveInside(rootPath, amendmentPath);
|
|
21152
|
-
await
|
|
21495
|
+
await mkdir10(dirname15(absolutePath), { recursive: true });
|
|
21153
21496
|
await appendFile2(absolutePath, `${JSON.stringify({
|
|
21154
21497
|
amendedAt: now,
|
|
21155
21498
|
id: release.id,
|
|
@@ -21294,9 +21637,9 @@ function nextReleaseState(state, scopesToWrite, updatedAt) {
|
|
|
21294
21637
|
async function appendHistory(rootPath, sourceDir, entries, appliedAt, files) {
|
|
21295
21638
|
if (entries.length === 0)
|
|
21296
21639
|
return;
|
|
21297
|
-
const relativePath2 =
|
|
21640
|
+
const relativePath2 = join20(sourceDir, HISTORY_FILE3).replaceAll("\\", "/");
|
|
21298
21641
|
const absolutePath = resolveInside(rootPath, relativePath2);
|
|
21299
|
-
await
|
|
21642
|
+
await mkdir10(dirname15(absolutePath), { recursive: true });
|
|
21300
21643
|
const lines = entries.flatMap((entry) => entry.id === undefined || entry.bump === undefined ? [] : [
|
|
21301
21644
|
JSON.stringify({
|
|
21302
21645
|
appliedAt,
|
|
@@ -21319,9 +21662,9 @@ async function appendHistory(rootPath, sourceDir, entries, appliedAt, files) {
|
|
|
21319
21662
|
async function appendReleaseRecord(rootPath, sourceDir, plan, appliedAt, files) {
|
|
21320
21663
|
if (plan.scopes.length === 0)
|
|
21321
21664
|
return;
|
|
21322
|
-
const relativePath2 =
|
|
21665
|
+
const relativePath2 = join20(sourceDir, RELEASES_FILE).replaceAll("\\", "/");
|
|
21323
21666
|
const absolutePath = resolveInside(rootPath, relativePath2);
|
|
21324
|
-
await
|
|
21667
|
+
await mkdir10(dirname15(absolutePath), { recursive: true });
|
|
21325
21668
|
await appendFile2(absolutePath, `${JSON.stringify({
|
|
21326
21669
|
appliedAt,
|
|
21327
21670
|
baseline: { hashSchema: SOURCE_HASH_SCHEMA, kind: "source-hashes" },
|
|
@@ -21341,12 +21684,12 @@ async function appendReleaseRecord(rootPath, sourceDir, plan, appliedAt, files)
|
|
|
21341
21684
|
}
|
|
21342
21685
|
async function snapshotReleaseFiles(rootPath, sourceDir, entries, includeReleaseState) {
|
|
21343
21686
|
const paths = new Set([
|
|
21344
|
-
|
|
21687
|
+
join20(sourceDir, HISTORY_FILE3).replaceAll("\\", "/"),
|
|
21345
21688
|
...entries.map((entry) => entry.path)
|
|
21346
21689
|
]);
|
|
21347
21690
|
if (includeReleaseState) {
|
|
21348
|
-
paths.add(
|
|
21349
|
-
paths.add(
|
|
21691
|
+
paths.add(join20(sourceDir, STATE_FILE2).replaceAll("\\", "/"));
|
|
21692
|
+
paths.add(join20(sourceDir, RELEASES_FILE).replaceAll("\\", "/"));
|
|
21350
21693
|
}
|
|
21351
21694
|
const snapshots = [];
|
|
21352
21695
|
for (const path2 of [...paths].sort(compareStrings)) {
|
|
@@ -21365,13 +21708,13 @@ async function restoreSnapshots(rootPath, snapshots) {
|
|
|
21365
21708
|
await rm6(absolutePath, { force: true });
|
|
21366
21709
|
continue;
|
|
21367
21710
|
}
|
|
21368
|
-
await
|
|
21369
|
-
await
|
|
21711
|
+
await mkdir10(dirname15(absolutePath), { recursive: true });
|
|
21712
|
+
await writeFile11(absolutePath, snapshot.content);
|
|
21370
21713
|
}
|
|
21371
21714
|
}
|
|
21372
21715
|
async function exists13(path2) {
|
|
21373
21716
|
try {
|
|
21374
|
-
await
|
|
21717
|
+
await stat17(path2);
|
|
21375
21718
|
return true;
|
|
21376
21719
|
} catch (error) {
|
|
21377
21720
|
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
|
|
@@ -21411,7 +21754,7 @@ function releaseIdFor(scopes) {
|
|
|
21411
21754
|
}
|
|
21412
21755
|
async function readReleaseRecords(rootPath, options = {}) {
|
|
21413
21756
|
const sourceDir = options.sourceDir ?? ".skillset";
|
|
21414
|
-
const path2 =
|
|
21757
|
+
const path2 = join20(sourceDir, RELEASES_FILE).replaceAll("\\", "/");
|
|
21415
21758
|
const absolutePath = resolveInside(rootPath, path2);
|
|
21416
21759
|
if (!await exists13(absolutePath))
|
|
21417
21760
|
return [];
|
|
@@ -21437,7 +21780,7 @@ async function readReleaseRecords(rootPath, options = {}) {
|
|
|
21437
21780
|
}
|
|
21438
21781
|
async function readReleaseAmendments(rootPath, options = {}) {
|
|
21439
21782
|
const sourceDir = options.sourceDir ?? ".skillset";
|
|
21440
|
-
const path2 =
|
|
21783
|
+
const path2 = join20(sourceDir, RELEASE_AMENDMENTS_FILE).replaceAll("\\", "/");
|
|
21441
21784
|
const absolutePath = resolveInside(rootPath, path2);
|
|
21442
21785
|
if (!await exists13(absolutePath))
|
|
21443
21786
|
return new Map;
|
|
@@ -21539,9 +21882,9 @@ function isChangeBump(value) {
|
|
|
21539
21882
|
return value === "major" || value === "minor" || value === "patch" || value === "none";
|
|
21540
21883
|
}
|
|
21541
21884
|
// apps/skillset/src/test-runner.ts
|
|
21542
|
-
import { cp, mkdir as
|
|
21885
|
+
import { cp, mkdir as mkdir11, mkdtemp as mkdtemp4, readFile as readFile21, rm as rm7, stat as stat18, writeFile as writeFile12 } from "fs/promises";
|
|
21543
21886
|
import { createHash as createHash8, randomBytes as randomBytes2 } from "crypto";
|
|
21544
|
-
import { dirname as
|
|
21887
|
+
import { dirname as dirname16, join as join21, relative as relative16, resolve as resolve9 } from "path";
|
|
21545
21888
|
import { tmpdir as tmpdir3 } from "os";
|
|
21546
21889
|
var TEST_BUILD_DIR = "build/tests";
|
|
21547
21890
|
var TEST_SCHEMA = 1;
|
|
@@ -21559,23 +21902,23 @@ async function runSkillsetTest(rootPath, name, options = {}) {
|
|
|
21559
21902
|
targetFilter: declaration.targets
|
|
21560
21903
|
};
|
|
21561
21904
|
const runId = makeRunId(declaration.name);
|
|
21562
|
-
const buildRoot = resolveInside(rootPath,
|
|
21563
|
-
const runsRoot =
|
|
21564
|
-
const runPath =
|
|
21565
|
-
const workspacePath =
|
|
21566
|
-
const stagingRoot = await mkdtemp4(
|
|
21567
|
-
const stagingWorkspacePath =
|
|
21568
|
-
const stagingSourcePath =
|
|
21905
|
+
const buildRoot = resolveInside(rootPath, join21(sourceDir, TEST_BUILD_DIR));
|
|
21906
|
+
const runsRoot = join21(buildRoot, "runs");
|
|
21907
|
+
const runPath = join21(runsRoot, runId);
|
|
21908
|
+
const workspacePath = join21(runPath, "workspace");
|
|
21909
|
+
const stagingRoot = await mkdtemp4(join21(tmpdir3(), "skillset-test-"));
|
|
21910
|
+
const stagingWorkspacePath = join21(stagingRoot, "workspace");
|
|
21911
|
+
const stagingSourcePath = join21(stagingWorkspacePath, sourceDir);
|
|
21569
21912
|
const sourcePath = resolveInside(rootPath, sourceDir);
|
|
21570
21913
|
const workspaceLockPath = resolveInside(rootPath, ".skillset.lock");
|
|
21571
|
-
const ignoredSourceBuildPath = resolveInside(rootPath,
|
|
21914
|
+
const ignoredSourceBuildPath = resolveInside(rootPath, join21(sourceDir, "build"));
|
|
21572
21915
|
try {
|
|
21573
|
-
await
|
|
21916
|
+
await mkdir11(stagingWorkspacePath, { recursive: true });
|
|
21574
21917
|
await cp(sourcePath, stagingSourcePath, {
|
|
21575
21918
|
filter: (path2) => !isSameOrInside2(ignoredSourceBuildPath, path2),
|
|
21576
21919
|
recursive: true
|
|
21577
21920
|
});
|
|
21578
|
-
await copyIfExists(workspaceLockPath,
|
|
21921
|
+
await copyIfExists(workspaceLockPath, join21(stagingWorkspacePath, ".skillset.lock"));
|
|
21579
21922
|
await copyWorkspaceManagedFiles(rootPath, stagingWorkspacePath, workspaceLockPath, sourceDir);
|
|
21580
21923
|
const assertions = [];
|
|
21581
21924
|
let generatedFiles = 0;
|
|
@@ -21595,13 +21938,13 @@ async function runSkillsetTest(rootPath, name, options = {}) {
|
|
|
21595
21938
|
if (assertions.every((assertion) => assertion.ok)) {
|
|
21596
21939
|
await validateActivationExpectations(stagingWorkspacePath, declaration, buildOptions);
|
|
21597
21940
|
}
|
|
21598
|
-
await
|
|
21941
|
+
await mkdir11(runPath, { recursive: true });
|
|
21599
21942
|
await cp(stagingWorkspacePath, workspacePath, { recursive: true });
|
|
21600
21943
|
const activationPath = await writeActivationProbes(runPath, declaration);
|
|
21601
21944
|
const ok = assertions.every((assertion) => assertion.ok);
|
|
21602
|
-
const reportPath =
|
|
21603
|
-
const reportMarkdownPath =
|
|
21604
|
-
const latestPath =
|
|
21945
|
+
const reportPath = join21(runPath, "report.json");
|
|
21946
|
+
const reportMarkdownPath = join21(runPath, "report.md");
|
|
21947
|
+
const latestPath = join21(buildRoot, "latest");
|
|
21605
21948
|
const activationReport = activationPath === undefined ? {} : {
|
|
21606
21949
|
activation: {
|
|
21607
21950
|
path: relative16(rootPath, activationPath),
|
|
@@ -21620,8 +21963,8 @@ async function runSkillsetTest(rootPath, name, options = {}) {
|
|
|
21620
21963
|
...activationReport,
|
|
21621
21964
|
workspacePath: relative16(rootPath, workspacePath)
|
|
21622
21965
|
};
|
|
21623
|
-
await
|
|
21624
|
-
await
|
|
21966
|
+
await writeFile12(reportPath, renderValidatedJson(report, relative16(rootPath, reportPath)), "utf8");
|
|
21967
|
+
await writeFile12(reportMarkdownPath, renderMarkdownReport(report), "utf8");
|
|
21625
21968
|
await refreshLatest(buildRoot, runPath, latestPath, report, rootPath);
|
|
21626
21969
|
return {
|
|
21627
21970
|
assertions,
|
|
@@ -21866,11 +22209,11 @@ function activationExpectationCandidatePaths(graph, target, expect) {
|
|
|
21866
22209
|
}
|
|
21867
22210
|
if (expect.kind === "agent") {
|
|
21868
22211
|
const projectRoot = targetProjectRoot4(graph, target);
|
|
21869
|
-
return graph.projectAgents.filter((agent) => agent.name === expect.name || agent.outputName === expect.name).map((agent) =>
|
|
22212
|
+
return graph.projectAgents.filter((agent) => agent.name === expect.name || agent.outputName === expect.name).map((agent) => join21(projectRoot, "agents", `${agent.outputName}.${target === "claude" ? "md" : "toml"}`));
|
|
21870
22213
|
}
|
|
21871
22214
|
return [
|
|
21872
|
-
...graph.standaloneSkills.filter((skill) => skill.id === expect.name).map((skill) =>
|
|
21873
|
-
...graph.plugins.flatMap((plugin) => plugin.skills.filter((skill) => skill.id === expect.name).map((skill) =>
|
|
22215
|
+
...graph.standaloneSkills.filter((skill) => skill.id === expect.name).map((skill) => join21(graph.root.outputs.skills[target], dirname16(skill.relativePath), "SKILL.md")),
|
|
22216
|
+
...graph.plugins.flatMap((plugin) => plugin.skills.filter((skill) => skill.id === expect.name).map((skill) => join21(graph.root.outputs.plugins[target], "plugins", plugin.id, dirname16(skill.relativePath), "SKILL.md")))
|
|
21874
22217
|
];
|
|
21875
22218
|
}
|
|
21876
22219
|
function targetProjectRoot4(graph, target) {
|
|
@@ -21879,22 +22222,22 @@ function targetProjectRoot4(graph, target) {
|
|
|
21879
22222
|
async function writeActivationProbes(runPath, declaration) {
|
|
21880
22223
|
if (declaration.activationProbes.length === 0)
|
|
21881
22224
|
return;
|
|
21882
|
-
const activationRoot =
|
|
22225
|
+
const activationRoot = join21(runPath, "activation");
|
|
21883
22226
|
for (const target of declaration.targets) {
|
|
21884
22227
|
const probes = declaration.activationProbes.filter((probe) => probe.targets.includes(target));
|
|
21885
22228
|
if (probes.length === 0)
|
|
21886
22229
|
continue;
|
|
21887
|
-
const targetRoot =
|
|
21888
|
-
await
|
|
22230
|
+
const targetRoot = join21(activationRoot, target);
|
|
22231
|
+
await mkdir11(targetRoot, { recursive: true });
|
|
21889
22232
|
const records = probes.map((probe) => activationProbeRecord(probe, target));
|
|
21890
|
-
await
|
|
22233
|
+
await writeFile12(join21(targetRoot, "probes.json"), renderValidatedJson({
|
|
21891
22234
|
probes: records,
|
|
21892
22235
|
schemaVersion: TEST_SCHEMA,
|
|
21893
22236
|
target
|
|
21894
22237
|
}, `activation ${target} probes`), "utf8");
|
|
21895
22238
|
for (const record of records) {
|
|
21896
22239
|
const name = typeof record.name === "string" ? record.name : "probe";
|
|
21897
|
-
await
|
|
22240
|
+
await writeFile12(join21(targetRoot, `${name}.md`), renderActivationProbeMarkdown(record), "utf8");
|
|
21898
22241
|
}
|
|
21899
22242
|
}
|
|
21900
22243
|
return activationRoot;
|
|
@@ -21951,14 +22294,14 @@ async function refreshLatest(buildRoot, runPath, latestPath, report, rootPath) {
|
|
|
21951
22294
|
const latest = {
|
|
21952
22295
|
name: report.name,
|
|
21953
22296
|
ok: report.ok,
|
|
21954
|
-
reportPath: relative16(rootPath,
|
|
22297
|
+
reportPath: relative16(rootPath, join21(latestPath, "report.json")),
|
|
21955
22298
|
runId: report.runId,
|
|
21956
22299
|
runPath: relative16(rootPath, runPath),
|
|
21957
22300
|
schemaVersion: TEST_SCHEMA,
|
|
21958
22301
|
source: report.source,
|
|
21959
|
-
workspacePath: relative16(rootPath,
|
|
22302
|
+
workspacePath: relative16(rootPath, join21(latestPath, "workspace"))
|
|
21960
22303
|
};
|
|
21961
|
-
await
|
|
22304
|
+
await writeFile12(join21(buildRoot, "latest.json"), renderValidatedJson(latest, relative16(rootPath, join21(buildRoot, "latest.json"))), "utf8");
|
|
21962
22305
|
}
|
|
21963
22306
|
function renderMarkdownReport(report) {
|
|
21964
22307
|
const assertions = Array.isArray(report.assertions) ? report.assertions : [];
|
|
@@ -21995,7 +22338,7 @@ function activationProbeCount(report) {
|
|
|
21995
22338
|
}
|
|
21996
22339
|
async function pathExists2(path2) {
|
|
21997
22340
|
try {
|
|
21998
|
-
await
|
|
22341
|
+
await stat18(path2);
|
|
21999
22342
|
return true;
|
|
22000
22343
|
} catch {
|
|
22001
22344
|
return false;
|
|
@@ -22004,7 +22347,7 @@ async function pathExists2(path2) {
|
|
|
22004
22347
|
async function copyIfExists(sourcePath, targetPath) {
|
|
22005
22348
|
if (!await pathExists2(sourcePath))
|
|
22006
22349
|
return;
|
|
22007
|
-
await
|
|
22350
|
+
await mkdir11(dirname16(targetPath), { recursive: true });
|
|
22008
22351
|
await cp(sourcePath, targetPath);
|
|
22009
22352
|
}
|
|
22010
22353
|
async function copyWorkspaceManagedFiles(rootPath, stagingWorkspacePath, workspaceLockPath, sourceDir) {
|
|
@@ -22018,7 +22361,7 @@ async function copyWorkspaceManagedFiles(rootPath, stagingWorkspacePath, workspa
|
|
|
22018
22361
|
}
|
|
22019
22362
|
if (!isJsonRecord(lock) || !Array.isArray(lock.items))
|
|
22020
22363
|
return;
|
|
22021
|
-
const ignoredSourceBuildPath = resolveInside(rootPath,
|
|
22364
|
+
const ignoredSourceBuildPath = resolveInside(rootPath, join21(sourceDir, "build"));
|
|
22022
22365
|
for (const item of lock.items) {
|
|
22023
22366
|
if (!isJsonRecord(item) || !Array.isArray(item.files))
|
|
22024
22367
|
continue;
|
|
@@ -22028,7 +22371,7 @@ async function copyWorkspaceManagedFiles(rootPath, stagingWorkspacePath, workspa
|
|
|
22028
22371
|
const sourcePath = resolveInside(rootPath, file);
|
|
22029
22372
|
if (isSameOrInside2(ignoredSourceBuildPath, sourcePath))
|
|
22030
22373
|
continue;
|
|
22031
|
-
await copyIfExists(sourcePath,
|
|
22374
|
+
await copyIfExists(sourcePath, join21(stagingWorkspacePath, file));
|
|
22032
22375
|
}
|
|
22033
22376
|
}
|
|
22034
22377
|
}
|
|
@@ -22048,8 +22391,10 @@ function messageFor(error) {
|
|
|
22048
22391
|
// apps/skillset/src/cli-core.ts
|
|
22049
22392
|
var USAGE = [
|
|
22050
22393
|
"usage: skillset build [--yes|--dry-run] [--updated|--all] [--isolated] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22051
|
-
" skillset
|
|
22052
|
-
" skillset
|
|
22394
|
+
" skillset verify [--updated|--all] [--isolated] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22395
|
+
" skillset diff [--updated|--all] [--isolated] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22396
|
+
" skillset <check|lint> [--root <path>] [--source <dir>]",
|
|
22397
|
+
" skillset list [--updated|--all] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22053
22398
|
" skillset doctor [--json] [--updated|--all] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22054
22399
|
" skillset ci [--fix] [--since <ref>] [--report <path>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22055
22400
|
" skillset change status [--since <ref>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
@@ -22075,6 +22420,7 @@ var USAGE = [
|
|
|
22075
22420
|
" skillset adopt <path> [--yes|--dry-run] [--targets claude,codex] [--root <path>]",
|
|
22076
22421
|
" skillset init [path] [--yes|--dry-run] [--targets claude,codex] [--include ci] [--name <name>] [--root <path>]",
|
|
22077
22422
|
" skillset create [path|--global] [--yes|--dry-run] [--targets claude,codex] [--include ci] [--name <name>] [--root <path>]",
|
|
22423
|
+
" skillset new <skill|agent|hook> [name] [--id <id>] [--name <name>] [--in <container>] [--scope repo] [--preset <preset>] [--yes|--dry-run] [--root <path>] [--source <dir>]",
|
|
22078
22424
|
" skillset explain <path> [--json] [--scope <scope>] [--root <path>] [--source <dir>]",
|
|
22079
22425
|
" skillset import <path> [--kind <skill|skills|plugin|plugins>] [--from <provider>] [--name <name>] [--root <path>] [--source <dir>]",
|
|
22080
22426
|
" skillset import <claude|codex|agents> [--root <path>] [--source <dir>]"
|
|
@@ -22114,6 +22460,12 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22114
22460
|
importName,
|
|
22115
22461
|
importProvider,
|
|
22116
22462
|
jsonOutput,
|
|
22463
|
+
newContainer,
|
|
22464
|
+
newId,
|
|
22465
|
+
newKind,
|
|
22466
|
+
newName,
|
|
22467
|
+
newPresets,
|
|
22468
|
+
newScope,
|
|
22117
22469
|
options,
|
|
22118
22470
|
rootPath,
|
|
22119
22471
|
rootExplicit,
|
|
@@ -22156,8 +22508,8 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22156
22508
|
});
|
|
22157
22509
|
if (ciReportPath !== undefined) {
|
|
22158
22510
|
const reportPath = resolve10(ciReportPath);
|
|
22159
|
-
await
|
|
22160
|
-
await
|
|
22511
|
+
await mkdir12(dirname17(reportPath), { recursive: true });
|
|
22512
|
+
await writeFile13(reportPath, renderCiReportMarkdown(report));
|
|
22161
22513
|
}
|
|
22162
22514
|
printCiReport(report);
|
|
22163
22515
|
if (!report.ok)
|
|
@@ -22334,6 +22686,16 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22334
22686
|
console.log(`skillset: linted ${result3.checkedSkills} source skills`);
|
|
22335
22687
|
return;
|
|
22336
22688
|
}
|
|
22689
|
+
if (command === "check") {
|
|
22690
|
+
const result3 = await lintSkillset(rootPath, options);
|
|
22691
|
+
for (const issue of result3.issues) {
|
|
22692
|
+
if (issue.severity !== "warn")
|
|
22693
|
+
continue;
|
|
22694
|
+
console.log(` warn: ${issue.path}: ${issue.code}: ${issue.message}`);
|
|
22695
|
+
}
|
|
22696
|
+
console.log(`skillset: checked ${result3.checkedSkills} source skills`);
|
|
22697
|
+
return;
|
|
22698
|
+
}
|
|
22337
22699
|
if (command === "adopt") {
|
|
22338
22700
|
const writeMode = yes && !dryRun;
|
|
22339
22701
|
const report = await adoptSkillset(importPath === undefined ? rootPath : importPath, {
|
|
@@ -22395,6 +22757,25 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22395
22757
|
console.warn(` warning: ${warning}`);
|
|
22396
22758
|
return;
|
|
22397
22759
|
}
|
|
22760
|
+
if (command === "new") {
|
|
22761
|
+
if (newKind === undefined)
|
|
22762
|
+
throw new Error("skillset: expected new kind skill, agent, or hook");
|
|
22763
|
+
const report = await scaffoldSourceUnit(rootPath, {
|
|
22764
|
+
...newContainer === undefined ? {} : { container: newContainer },
|
|
22765
|
+
...newId === undefined ? {} : { id: newId },
|
|
22766
|
+
kind: newKind,
|
|
22767
|
+
...newName === undefined ? {} : { displayName: newName },
|
|
22768
|
+
...importPath === undefined ? {} : { name: importPath },
|
|
22769
|
+
...newPresets === undefined ? {} : { presets: newPresets },
|
|
22770
|
+
...newScope === undefined ? {} : { scope: newScope },
|
|
22771
|
+
skillsetOptions: options,
|
|
22772
|
+
write: yes && !dryRun
|
|
22773
|
+
});
|
|
22774
|
+
printNewSourceReport(report, dryRun ? "dry run" : yes ? "written" : "write confirmation required");
|
|
22775
|
+
if (!yes || dryRun)
|
|
22776
|
+
console.log("skillset: rerun new with --yes to write source files");
|
|
22777
|
+
return;
|
|
22778
|
+
}
|
|
22398
22779
|
if (command === "diff") {
|
|
22399
22780
|
const result3 = await diffSkillsetResult(rootPath, options);
|
|
22400
22781
|
printDiagnostics(result3.diagnostics);
|
|
@@ -22563,9 +22944,9 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22563
22944
|
}
|
|
22564
22945
|
return;
|
|
22565
22946
|
}
|
|
22566
|
-
const result2 = await
|
|
22947
|
+
const result2 = await verifySkillsetResult(rootPath, options);
|
|
22567
22948
|
printDiagnostics(result2.diagnostics);
|
|
22568
|
-
console.log(`skillset:
|
|
22949
|
+
console.log(`skillset: verified ${result2.data.checkedFiles} generated files`);
|
|
22569
22950
|
if (!result2.ok) {
|
|
22570
22951
|
console.error(`skillset: generated output is not current`);
|
|
22571
22952
|
for (const failure of result2.data.failures)
|
|
@@ -22930,6 +23311,18 @@ function printSetupReport(result2, reason) {
|
|
|
22930
23311
|
console.log(`skillset: ${result2.kind} ${details.join(", ")} (${reason})`);
|
|
22931
23312
|
console.log(` root: ${result2.rootPath}`);
|
|
22932
23313
|
}
|
|
23314
|
+
function printNewSourceReport(result2, reason) {
|
|
23315
|
+
for (const file of result2.files)
|
|
23316
|
+
console.log(` + ${file.path}`);
|
|
23317
|
+
const action = result2.write ? "created" : "planned";
|
|
23318
|
+
console.log(`skillset: ${action} ${result2.kind} ${result2.id} (${reason})`);
|
|
23319
|
+
console.log(` source: ${result2.sourceRoot}`);
|
|
23320
|
+
console.log(` name: ${result2.displayName}`);
|
|
23321
|
+
if (result2.write) {
|
|
23322
|
+
console.log(" next: skillset check");
|
|
23323
|
+
console.log(" next: skillset verify");
|
|
23324
|
+
}
|
|
23325
|
+
}
|
|
22933
23326
|
function printRestoreReport(report) {
|
|
22934
23327
|
const mode = report.write ? "restored" : "restore preview";
|
|
22935
23328
|
console.log(`skillset: ${mode} ${report.restoredPaths.length} file${report.restoredPaths.length === 1 ? "" : "s"} from backup ${report.runId}`);
|
|
@@ -22984,8 +23377,8 @@ function printRenderResult(outcome) {
|
|
|
22984
23377
|
}
|
|
22985
23378
|
function parseArgs(args) {
|
|
22986
23379
|
const command = args[0];
|
|
22987
|
-
if (command !== "adopt" && command !== "build" && command !== "change" && command !== "check" && command !== "ci" && command !== "create" && command !== "diff" && command !== "distribute" && command !== "doctor" && command !== "explain" && command !== "features" && command !== "hooks" && command !== "import" && command !== "init" && command !== "lint" && command !== "list" && command !== "release" && command !== "restore" && command !== "suggest-source" && command !== "test") {
|
|
22988
|
-
throw new Error(`skillset: expected command adopt, build, change, check, ci, create, diff, distribute, doctor, explain, features, hooks, import, init, lint, list, release, restore, suggest-source, or
|
|
23380
|
+
if (command !== "adopt" && command !== "build" && command !== "change" && command !== "check" && command !== "ci" && command !== "create" && command !== "diff" && command !== "distribute" && command !== "doctor" && command !== "explain" && command !== "features" && command !== "hooks" && command !== "import" && command !== "init" && command !== "lint" && command !== "list" && command !== "new" && command !== "release" && command !== "restore" && command !== "suggest-source" && command !== "test" && command !== "verify") {
|
|
23381
|
+
throw new Error(`skillset: expected command adopt, build, change, check, ci, create, diff, distribute, doctor, explain, features, hooks, import, init, lint, list, new, release, restore, suggest-source, test, or verify
|
|
22989
23382
|
` + USAGE);
|
|
22990
23383
|
}
|
|
22991
23384
|
let changeSubcommand;
|
|
@@ -23016,6 +23409,12 @@ function parseArgs(args) {
|
|
|
23016
23409
|
let importPath;
|
|
23017
23410
|
let importProvider;
|
|
23018
23411
|
let jsonOutput = false;
|
|
23412
|
+
let newContainer;
|
|
23413
|
+
let newId;
|
|
23414
|
+
let newKind;
|
|
23415
|
+
let newName;
|
|
23416
|
+
let newPresets;
|
|
23417
|
+
let newScope;
|
|
23019
23418
|
let rootPath = process.cwd();
|
|
23020
23419
|
let rootExplicit = false;
|
|
23021
23420
|
let sourceDir;
|
|
@@ -23139,6 +23538,19 @@ function parseArgs(args) {
|
|
|
23139
23538
|
index += 1;
|
|
23140
23539
|
}
|
|
23141
23540
|
}
|
|
23541
|
+
if (command === "new") {
|
|
23542
|
+
const rawKind = args[index];
|
|
23543
|
+
if (!isNewSourceKind(rawKind)) {
|
|
23544
|
+
throw new Error("skillset: expected new kind skill, agent, or hook");
|
|
23545
|
+
}
|
|
23546
|
+
newKind = rawKind;
|
|
23547
|
+
index += 1;
|
|
23548
|
+
const rawName = args[index];
|
|
23549
|
+
if (rawName !== undefined && !rawName.startsWith("--")) {
|
|
23550
|
+
importPath = rawName;
|
|
23551
|
+
index += 1;
|
|
23552
|
+
}
|
|
23553
|
+
}
|
|
23142
23554
|
for (;index < args.length; index += 1) {
|
|
23143
23555
|
const arg = args[index];
|
|
23144
23556
|
if (arg === undefined)
|
|
@@ -23146,7 +23558,7 @@ function parseArgs(args) {
|
|
|
23146
23558
|
const equalsIndex = arg.indexOf("=");
|
|
23147
23559
|
const flag = equalsIndex === -1 ? arg : arg.slice(0, equalsIndex);
|
|
23148
23560
|
const inlineValue = equalsIndex === -1 ? undefined : arg.slice(equalsIndex + 1);
|
|
23149
|
-
if (flag !== "--root" && flag !== "--source" && flag !== "--dist" && flag !== "--name" && flag !== "--kind" && flag !== "--from" && flag !== "--append" && flag !== "--bump" && flag !== "--group" && flag !== "--reason" && flag !== "--reason-file" && flag !== "--ref" && flag !== "--since" && flag !== "--staged" && flag !== "--yes" && flag !== "--dry-run" && flag !== "--updated" && flag !== "--all" && flag !== "--isolated" && flag !== "--scope" && flag !== "--global" && flag !== "--targets" && flag !== "--include" && flag !== "--fix" && flag !== "--report" && flag !== "--json" && flag !== "--runner" && flag !== "--target" && flag !== "--agent-runtime" && flag !== "--pre-commit" && flag !== "--pre-push" && flag !== "--write") {
|
|
23561
|
+
if (flag !== "--root" && flag !== "--source" && flag !== "--dist" && flag !== "--id" && flag !== "--name" && flag !== "--in" && flag !== "--kind" && flag !== "--from" && flag !== "--preset" && flag !== "--append" && flag !== "--bump" && flag !== "--group" && flag !== "--reason" && flag !== "--reason-file" && flag !== "--ref" && flag !== "--since" && flag !== "--staged" && flag !== "--yes" && flag !== "--dry-run" && flag !== "--updated" && flag !== "--all" && flag !== "--isolated" && flag !== "--scope" && flag !== "--global" && flag !== "--targets" && flag !== "--include" && flag !== "--fix" && flag !== "--report" && flag !== "--json" && flag !== "--runner" && flag !== "--target" && flag !== "--agent-runtime" && flag !== "--pre-commit" && flag !== "--pre-push" && flag !== "--write") {
|
|
23150
23562
|
throw new Error(`skillset: unknown option ${arg}`);
|
|
23151
23563
|
}
|
|
23152
23564
|
if (flag === "--yes" || flag === "--dry-run" || flag === "--updated" || flag === "--all" || flag === "--isolated" || flag === "--append" || flag === "--staged" || flag === "--global" || flag === "--fix" || flag === "--json" || flag === "--agent-runtime" || flag === "--pre-commit" || flag === "--pre-push" || flag === "--write") {
|
|
@@ -23211,6 +23623,8 @@ function parseArgs(args) {
|
|
|
23211
23623
|
throw new Error(`skillset: change ${changeSubcommand} is a whole-source command; --scope is not supported`);
|
|
23212
23624
|
} else if (command === "change") {
|
|
23213
23625
|
throw new Error("skillset: --scope is only supported with change add source-unit entries");
|
|
23626
|
+
} else if (command === "new") {
|
|
23627
|
+
newScope = readNewSourceScope(value);
|
|
23214
23628
|
} else {
|
|
23215
23629
|
scopes = readBuildScopes(value);
|
|
23216
23630
|
}
|
|
@@ -23243,8 +23657,18 @@ function parseArgs(args) {
|
|
|
23243
23657
|
setupTargets = readSetupTargets(value);
|
|
23244
23658
|
if (flag === "--include")
|
|
23245
23659
|
setupIncludes = mergeSetupIncludes(setupIncludes, value);
|
|
23246
|
-
if (flag === "--
|
|
23247
|
-
|
|
23660
|
+
if (flag === "--id")
|
|
23661
|
+
newId = value;
|
|
23662
|
+
if (flag === "--in")
|
|
23663
|
+
newContainer = value;
|
|
23664
|
+
if (flag === "--name") {
|
|
23665
|
+
if (command === "new")
|
|
23666
|
+
newName = value;
|
|
23667
|
+
else
|
|
23668
|
+
importName = value;
|
|
23669
|
+
}
|
|
23670
|
+
if (flag === "--preset")
|
|
23671
|
+
newPresets = [...newPresets ?? [], value];
|
|
23248
23672
|
if (flag === "--kind") {
|
|
23249
23673
|
if (!isImportKind(value)) {
|
|
23250
23674
|
throw new Error("skillset: expected --kind skill, skills, plugin, or plugins");
|
|
@@ -23307,6 +23731,13 @@ function parseArgs(args) {
|
|
|
23307
23731
|
...scopes === undefined ? {} : { scopes }
|
|
23308
23732
|
});
|
|
23309
23733
|
validateJsonFlags(command, jsonOutput);
|
|
23734
|
+
validateSourceDiagnosticFlags(command, {
|
|
23735
|
+
...buildMode === undefined ? {} : { buildMode },
|
|
23736
|
+
...distDir === undefined ? {} : { distDir },
|
|
23737
|
+
dryRun,
|
|
23738
|
+
...scopes === undefined ? {} : { scopes },
|
|
23739
|
+
yes
|
|
23740
|
+
});
|
|
23310
23741
|
validateIsolatedFlag(command, isolated);
|
|
23311
23742
|
validateDistributionFlags(command, {
|
|
23312
23743
|
...buildMode === undefined ? {} : { buildMode },
|
|
@@ -23348,6 +23779,18 @@ function parseArgs(args) {
|
|
|
23348
23779
|
write: sourceSuggestionWrite,
|
|
23349
23780
|
yes
|
|
23350
23781
|
});
|
|
23782
|
+
validateNewSourceFlags(command, {
|
|
23783
|
+
...buildMode === undefined ? {} : { buildMode },
|
|
23784
|
+
...distDir === undefined ? {} : { distDir },
|
|
23785
|
+
...newContainer === undefined ? {} : { container: newContainer },
|
|
23786
|
+
...newId === undefined ? {} : { id: newId },
|
|
23787
|
+
...importKind === undefined ? {} : { importKind },
|
|
23788
|
+
...importProvider === undefined ? {} : { importProvider },
|
|
23789
|
+
...newKind === undefined ? {} : { kind: newKind },
|
|
23790
|
+
...newName === undefined ? {} : { name: newName },
|
|
23791
|
+
...newPresets === undefined ? {} : { presets: newPresets },
|
|
23792
|
+
...newScope === undefined ? {} : { scope: newScope }
|
|
23793
|
+
});
|
|
23351
23794
|
const options = {
|
|
23352
23795
|
...buildMode === undefined ? {} : { buildMode },
|
|
23353
23796
|
...scopes === undefined ? {} : { scopes },
|
|
@@ -23383,6 +23826,12 @@ function parseArgs(args) {
|
|
|
23383
23826
|
...importPath === undefined ? {} : { importPath },
|
|
23384
23827
|
...importProvider === undefined ? {} : { importProvider },
|
|
23385
23828
|
jsonOutput,
|
|
23829
|
+
...newContainer === undefined ? {} : { newContainer },
|
|
23830
|
+
...newId === undefined ? {} : { newId },
|
|
23831
|
+
...newKind === undefined ? {} : { newKind },
|
|
23832
|
+
...newName === undefined ? {} : { newName },
|
|
23833
|
+
...newPresets === undefined ? {} : { newPresets },
|
|
23834
|
+
...newScope === undefined ? {} : { newScope },
|
|
23386
23835
|
options,
|
|
23387
23836
|
...releaseSubcommand === undefined ? {} : { releaseSubcommand },
|
|
23388
23837
|
...releaseReason === undefined ? {} : { releaseReason },
|
|
@@ -23403,6 +23852,14 @@ function isReleaseSubcommand(value) {
|
|
|
23403
23852
|
function isChangeSubcommand(value) {
|
|
23404
23853
|
return value === "add" || value === "amend" || value === "check" || value === "history" || value === "list" || value === "reason" || value === "show" || value === "status";
|
|
23405
23854
|
}
|
|
23855
|
+
function isNewSourceKind(value) {
|
|
23856
|
+
return value === "agent" || value === "hook" || value === "skill";
|
|
23857
|
+
}
|
|
23858
|
+
function readNewSourceScope(value) {
|
|
23859
|
+
if (value === "repo")
|
|
23860
|
+
return value;
|
|
23861
|
+
throw new Error("skillset: new currently supports only --scope repo");
|
|
23862
|
+
}
|
|
23406
23863
|
function readChangeScopes(value) {
|
|
23407
23864
|
const scopes = value.split(",").map((scope) => scope.trim()).filter((scope) => scope.length > 0);
|
|
23408
23865
|
if (scopes.length === 0)
|
|
@@ -23497,6 +23954,23 @@ function validateTestFlags(command, test2) {
|
|
|
23497
23954
|
throw new Error("skillset: build/write options are not supported with test; test output always writes under .skillset/build/tests");
|
|
23498
23955
|
}
|
|
23499
23956
|
}
|
|
23957
|
+
function validateSourceDiagnosticFlags(command, sourceCheck) {
|
|
23958
|
+
if (command !== "check" && command !== "lint")
|
|
23959
|
+
return;
|
|
23960
|
+
const label = `skillset ${command}`;
|
|
23961
|
+
if (sourceCheck.buildMode !== undefined) {
|
|
23962
|
+
throw new Error(`${label} does not support --updated or --all; it checks source diagnostics`);
|
|
23963
|
+
}
|
|
23964
|
+
if (sourceCheck.scopes !== undefined) {
|
|
23965
|
+
throw new Error(`${label} does not support --scope; it checks source diagnostics`);
|
|
23966
|
+
}
|
|
23967
|
+
if (sourceCheck.distDir !== undefined) {
|
|
23968
|
+
throw new Error(`${label} does not support --dist; it checks source diagnostics`);
|
|
23969
|
+
}
|
|
23970
|
+
if (sourceCheck.dryRun || sourceCheck.yes) {
|
|
23971
|
+
throw new Error(`${label} is read-only and does not support --yes or --dry-run`);
|
|
23972
|
+
}
|
|
23973
|
+
}
|
|
23500
23974
|
function validateRestoreFlags(command, restore) {
|
|
23501
23975
|
if (command !== "restore")
|
|
23502
23976
|
return;
|
|
@@ -23523,6 +23997,24 @@ function validateSuggestSourceFlags(command, suggestion) {
|
|
|
23523
23997
|
if (suggestion.write && !suggestion.yes)
|
|
23524
23998
|
throw new Error("skillset: suggest-source --write requires --yes");
|
|
23525
23999
|
}
|
|
24000
|
+
function validateNewSourceFlags(command, source2) {
|
|
24001
|
+
const hasNewFlag = source2.container !== undefined || source2.id !== undefined || source2.kind !== undefined || source2.name !== undefined || source2.presets !== undefined || source2.scope !== undefined;
|
|
24002
|
+
if (hasNewFlag && command !== "new") {
|
|
24003
|
+
throw new Error("skillset: new options are only supported with new");
|
|
24004
|
+
}
|
|
24005
|
+
if (command !== "new")
|
|
24006
|
+
return;
|
|
24007
|
+
if (source2.buildMode !== undefined)
|
|
24008
|
+
throw new Error("skillset: --updated and --all are not supported with new");
|
|
24009
|
+
if (source2.distDir !== undefined)
|
|
24010
|
+
throw new Error("skillset: --dist is not supported with new");
|
|
24011
|
+
if (source2.importKind !== undefined)
|
|
24012
|
+
throw new Error("skillset: --kind is only supported with import");
|
|
24013
|
+
if (source2.importProvider !== undefined)
|
|
24014
|
+
throw new Error("skillset: --from is only supported with import");
|
|
24015
|
+
if (source2.kind === undefined)
|
|
24016
|
+
throw new Error("skillset: expected new kind skill, agent, or hook");
|
|
24017
|
+
}
|
|
23526
24018
|
function setBuildMode(current, next) {
|
|
23527
24019
|
if (current !== undefined && current !== next) {
|
|
23528
24020
|
throw new Error(`skillset: conflicting build mode flags --${current} and --${next}`);
|
|
@@ -23589,9 +24081,9 @@ function readSetupTargets(value) {
|
|
|
23589
24081
|
function validateIsolatedFlag(command, isolated) {
|
|
23590
24082
|
if (!isolated)
|
|
23591
24083
|
return;
|
|
23592
|
-
if (command === "build" || command === "
|
|
24084
|
+
if (command === "build" || command === "diff" || command === "verify")
|
|
23593
24085
|
return;
|
|
23594
|
-
throw new Error("skillset: --isolated is only supported with build,
|
|
24086
|
+
throw new Error("skillset: --isolated is only supported with build, diff, or verify");
|
|
23595
24087
|
}
|
|
23596
24088
|
function validateCiFlags(command, ci) {
|
|
23597
24089
|
if (command !== "ci") {
|