skillset 0.14.0 → 0.15.1
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 +615 -110
- package/dist/create.js +615 -110
- 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";
|
|
@@ -7206,7 +7206,7 @@ var skillsetFeatureRegistry = defineFeatureRegistry([
|
|
|
7206
7206
|
id: "output-safety",
|
|
7207
7207
|
kind: "workflow",
|
|
7208
7208
|
renderOwner: "packages/core/src/output-safety.ts",
|
|
7209
|
-
sourceShape: "generated
|
|
7209
|
+
sourceShape: "generated skillset.lock ownership plus current rendered output paths",
|
|
7210
7210
|
status: "implemented",
|
|
7211
7211
|
summary: "Protects unmanaged generated-output collisions and target-side edits with reversible backups.",
|
|
7212
7212
|
targetSupport: notTargetRuntime(),
|
|
@@ -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)
|
|
@@ -9111,7 +9145,7 @@ function targetNativeSurface(relativePath) {
|
|
|
9111
9145
|
}
|
|
9112
9146
|
|
|
9113
9147
|
// packages/core/src/render-result-collector.ts
|
|
9114
|
-
var LOCK_FILE = "
|
|
9148
|
+
var LOCK_FILE = "skillset.lock";
|
|
9115
9149
|
var TARGETS2 = ["claude", "codex"];
|
|
9116
9150
|
function collectRenderResults(graph, rendered, options) {
|
|
9117
9151
|
const mapOutputPath = options.mapOutputPath ?? ((path) => path);
|
|
@@ -9705,7 +9739,7 @@ function renderValidatedToml(value, label) {
|
|
|
9705
9739
|
function validateGeneratedStructuredOutput(args) {
|
|
9706
9740
|
const label = structuredOutputLabel(args);
|
|
9707
9741
|
try {
|
|
9708
|
-
if (args.targetPath.endsWith(".json") || args.targetPath.endsWith("
|
|
9742
|
+
if (args.targetPath.endsWith(".json") || args.targetPath.endsWith("skillset.lock")) {
|
|
9709
9743
|
validateJson(args.content, label);
|
|
9710
9744
|
} else if (args.targetPath.endsWith(".yaml") || args.targetPath.endsWith(".yml")) {
|
|
9711
9745
|
validateYaml(args.content, label);
|
|
@@ -9807,7 +9841,7 @@ function structuredOutputLabel(args) {
|
|
|
9807
9841
|
}
|
|
9808
9842
|
|
|
9809
9843
|
// packages/core/src/output-safety.ts
|
|
9810
|
-
var WORKSPACE_LOCK_FILE = "
|
|
9844
|
+
var WORKSPACE_LOCK_FILE = "skillset.lock";
|
|
9811
9845
|
var OUTPUT_BACKUP_ROOT = ".skillset/build/backups";
|
|
9812
9846
|
async function readManagedOutputState(rootPath, liveOutputRoots, includeWorkspaceLock, outPath) {
|
|
9813
9847
|
const paths = new Set;
|
|
@@ -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(".")) {
|
|
@@ -12110,7 +12161,7 @@ function renderRepositoryReadmes(graph) {
|
|
|
12110
12161
|
"",
|
|
12111
12162
|
"- `.claude-plugin/marketplace.json` indexes the generated plugins.",
|
|
12112
12163
|
"- `plugins/<plugin-id>/` contains each Claude plugin bundle.",
|
|
12113
|
-
"-
|
|
12164
|
+
"- `skillset.lock` records deterministic generated-state provenance.",
|
|
12114
12165
|
""
|
|
12115
12166
|
].join(`
|
|
12116
12167
|
`)));
|
|
@@ -12122,7 +12173,7 @@ function renderRepositoryReadmes(graph) {
|
|
|
12122
12173
|
"Generated Codex plugin repository.",
|
|
12123
12174
|
"",
|
|
12124
12175
|
"- `plugins/<plugin-id>/` contains each Codex plugin bundle.",
|
|
12125
|
-
"-
|
|
12176
|
+
"- `skillset.lock` records deterministic generated-state provenance.",
|
|
12126
12177
|
""
|
|
12127
12178
|
].join(`
|
|
12128
12179
|
`)));
|
|
@@ -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],
|
|
@@ -13106,7 +13175,7 @@ function renderLockFiles(graph, lockRoots) {
|
|
|
13106
13175
|
sourceRoot: graph.sourceRoot,
|
|
13107
13176
|
target: lock.target
|
|
13108
13177
|
};
|
|
13109
|
-
rendered.push(textFile(join6(outputRoot, "
|
|
13178
|
+
rendered.push(textFile(join6(outputRoot, "skillset.lock"), renderValidatedJson(value, `${outputRoot}/skillset.lock`)));
|
|
13110
13179
|
}
|
|
13111
13180
|
return rendered;
|
|
13112
13181
|
}
|
|
@@ -13514,7 +13583,7 @@ async function exists3(path) {
|
|
|
13514
13583
|
}
|
|
13515
13584
|
}
|
|
13516
13585
|
function validateRenderedFile(file) {
|
|
13517
|
-
if (file.sourcePath !== undefined || file.path.endsWith("
|
|
13586
|
+
if (file.sourcePath !== undefined || file.path.endsWith("skillset.lock")) {
|
|
13518
13587
|
validateGeneratedStructuredOutput({
|
|
13519
13588
|
content: textDecoder.decode(file.content),
|
|
13520
13589
|
targetPath: file.path,
|
|
@@ -14413,7 +14482,7 @@ async function outputRootsFor(rootPath, outputs, plugins, standaloneSkills, rule
|
|
|
14413
14482
|
for (const outputRoot of configuredOutputRoots(outputs)) {
|
|
14414
14483
|
if (roots.has(outputRoot.path))
|
|
14415
14484
|
continue;
|
|
14416
|
-
if (await exists5(join8(resolveInside(rootPath, outputRoot.path), "
|
|
14485
|
+
if (await exists5(join8(resolveInside(rootPath, outputRoot.path), "skillset.lock"))) {
|
|
14417
14486
|
roots.set(outputRoot.path, outputRoot);
|
|
14418
14487
|
}
|
|
14419
14488
|
}
|
|
@@ -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",
|
|
@@ -14853,12 +14922,12 @@ function outputPathsForLock(outputRoot, lock) {
|
|
|
14853
14922
|
return paths;
|
|
14854
14923
|
}
|
|
14855
14924
|
function outputRootForLockPath(lockPath) {
|
|
14856
|
-
if (lockPath === "
|
|
14925
|
+
if (lockPath === "skillset.lock")
|
|
14857
14926
|
return ".";
|
|
14858
14927
|
return dirname7(lockPath).replaceAll("\\", "/");
|
|
14859
14928
|
}
|
|
14860
14929
|
function isLockFilePath(path) {
|
|
14861
|
-
return path === "
|
|
14930
|
+
return path === "skillset.lock" || path.endsWith("/skillset.lock");
|
|
14862
14931
|
}
|
|
14863
14932
|
async function diagnoseMissingManagedOutputs(rootPath, rendered, previousManagedPaths) {
|
|
14864
14933
|
const diagnostics = [];
|
|
@@ -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,
|
|
@@ -16036,7 +16125,7 @@ function errorMessage(error) {
|
|
|
16036
16125
|
function collectLockItems(rendered) {
|
|
16037
16126
|
const matches = [];
|
|
16038
16127
|
for (const file of rendered) {
|
|
16039
|
-
if (!file.path.endsWith("
|
|
16128
|
+
if (!file.path.endsWith("skillset.lock"))
|
|
16040
16129
|
continue;
|
|
16041
16130
|
let parsed;
|
|
16042
16131
|
try {
|
|
@@ -16105,7 +16194,7 @@ function joinOutputRoot2(outputRoot, file) {
|
|
|
16105
16194
|
function lockPathForEntry(entry) {
|
|
16106
16195
|
if (entry === undefined)
|
|
16107
16196
|
return;
|
|
16108
|
-
return joinOutputRoot2(entry.outputRoot, "
|
|
16197
|
+
return joinOutputRoot2(entry.outputRoot, "skillset.lock");
|
|
16109
16198
|
}
|
|
16110
16199
|
function refusedSourceSuggestion(generatedPath, entries, message, nextSteps, sourcePath) {
|
|
16111
16200
|
const lockPath = lockPathForEntry(entries[0]);
|
|
@@ -16244,7 +16333,7 @@ function normalizeRepoPath(rootPath, inputPath) {
|
|
|
16244
16333
|
var textDecoder4 = new TextDecoder;
|
|
16245
16334
|
|
|
16246
16335
|
// packages/core/src/normalized-output-tree.ts
|
|
16247
|
-
var DEFAULT_STRUCTURED_JSON_BASENAMES = new Set(["
|
|
16336
|
+
var DEFAULT_STRUCTURED_JSON_BASENAMES = new Set(["skillset.lock"]);
|
|
16248
16337
|
|
|
16249
16338
|
// packages/core/src/deterministic-projection.ts
|
|
16250
16339
|
var textEncoder4 = new TextEncoder;
|
|
@@ -17601,7 +17690,7 @@ function kindForSourceUnitId(id) {
|
|
|
17601
17690
|
return "root-config";
|
|
17602
17691
|
}
|
|
17603
17692
|
async function sourceInventoryFromLock(rootPath, _options) {
|
|
17604
|
-
const lockPath = resolveInside(rootPath, "
|
|
17693
|
+
const lockPath = resolveInside(rootPath, "skillset.lock");
|
|
17605
17694
|
if (!await exists7(lockPath))
|
|
17606
17695
|
return;
|
|
17607
17696
|
let parsed;
|
|
@@ -17642,7 +17731,7 @@ async function sourceInventoryFromLock(rootPath, _options) {
|
|
|
17642
17731
|
if (units.length === 0)
|
|
17643
17732
|
return;
|
|
17644
17733
|
return {
|
|
17645
|
-
baseline: { hashSchema, kind: "source-inventory", label: "
|
|
17734
|
+
baseline: { hashSchema, kind: "source-inventory", label: "skillset.lock" },
|
|
17646
17735
|
inventory: { hashSchema, units }
|
|
17647
17736
|
};
|
|
17648
17737
|
}
|
|
@@ -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,
|
|
@@ -19415,7 +19504,7 @@ async function maybeCandidate(candidates, rootPath, path2, kind) {
|
|
|
19415
19504
|
candidates.push({ kind, path: relative14(rootPath, absolutePath).replaceAll("\\", "/") });
|
|
19416
19505
|
}
|
|
19417
19506
|
async function isManagedCandidate(path2) {
|
|
19418
|
-
return await pathExists(join15(path2, "
|
|
19507
|
+
return await pathExists(join15(path2, "skillset.lock")) || await pathExists(join15(dirname11(path2), "skillset.lock"));
|
|
19419
19508
|
}
|
|
19420
19509
|
function compareCandidate(left, right) {
|
|
19421
19510
|
return `${left.kind}:${left.path}` < `${right.kind}:${right.path}` ? -1 : `${left.kind}:${left.path}` > `${right.kind}:${right.path}` ? 1 : 0;
|
|
@@ -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) {
|
|
@@ -20025,7 +20153,7 @@ function renderAdoptReportMarkdown(report, opts) {
|
|
|
20025
20153
|
lines.push(`- ${summary}`);
|
|
20026
20154
|
}
|
|
20027
20155
|
lines.push("");
|
|
20028
|
-
lines.push("Full structured render results are in `report.json` and in the isolated
|
|
20156
|
+
lines.push("Full structured render results are in `report.json` and in the isolated `skillset.lock` files when the isolated build completes.", "");
|
|
20029
20157
|
}
|
|
20030
20158
|
lines.push("## Cutover", "");
|
|
20031
20159
|
lines.push(`1. Review the generated mirror under \`${ISOLATED_OUT_ROOT}/\` against the originals.`);
|
|
@@ -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,17 @@ 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
|
|
21569
|
-
const sourcePath = resolveInside(rootPath, sourceDir);
|
|
21570
|
-
const workspaceLockPath = resolveInside(rootPath, ".skillset.lock");
|
|
21571
|
-
const ignoredSourceBuildPath = resolveInside(rootPath, join20(sourceDir, "build"));
|
|
21905
|
+
const buildRoot = resolveInside(rootPath, testBuildRoot(sourceDir));
|
|
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 workspaceLockPath = resolveInside(rootPath, "skillset.lock");
|
|
21572
21912
|
try {
|
|
21573
|
-
await
|
|
21574
|
-
await
|
|
21575
|
-
|
|
21576
|
-
recursive: true
|
|
21577
|
-
});
|
|
21578
|
-
await copyIfExists(workspaceLockPath, join20(stagingWorkspacePath, ".skillset.lock"));
|
|
21913
|
+
await mkdir11(stagingWorkspacePath, { recursive: true });
|
|
21914
|
+
await copyTestSource(graph, stagingWorkspacePath);
|
|
21915
|
+
await copyIfExists(workspaceLockPath, join21(stagingWorkspacePath, "skillset.lock"));
|
|
21579
21916
|
await copyWorkspaceManagedFiles(rootPath, stagingWorkspacePath, workspaceLockPath, sourceDir);
|
|
21580
21917
|
const assertions = [];
|
|
21581
21918
|
let generatedFiles = 0;
|
|
@@ -21595,13 +21932,13 @@ async function runSkillsetTest(rootPath, name, options = {}) {
|
|
|
21595
21932
|
if (assertions.every((assertion) => assertion.ok)) {
|
|
21596
21933
|
await validateActivationExpectations(stagingWorkspacePath, declaration, buildOptions);
|
|
21597
21934
|
}
|
|
21598
|
-
await
|
|
21935
|
+
await mkdir11(runPath, { recursive: true });
|
|
21599
21936
|
await cp(stagingWorkspacePath, workspacePath, { recursive: true });
|
|
21600
21937
|
const activationPath = await writeActivationProbes(runPath, declaration);
|
|
21601
21938
|
const ok = assertions.every((assertion) => assertion.ok);
|
|
21602
|
-
const reportPath =
|
|
21603
|
-
const reportMarkdownPath =
|
|
21604
|
-
const latestPath =
|
|
21939
|
+
const reportPath = join21(runPath, "report.json");
|
|
21940
|
+
const reportMarkdownPath = join21(runPath, "report.md");
|
|
21941
|
+
const latestPath = join21(buildRoot, "latest");
|
|
21605
21942
|
const activationReport = activationPath === undefined ? {} : {
|
|
21606
21943
|
activation: {
|
|
21607
21944
|
path: relative16(rootPath, activationPath),
|
|
@@ -21620,8 +21957,8 @@ async function runSkillsetTest(rootPath, name, options = {}) {
|
|
|
21620
21957
|
...activationReport,
|
|
21621
21958
|
workspacePath: relative16(rootPath, workspacePath)
|
|
21622
21959
|
};
|
|
21623
|
-
await
|
|
21624
|
-
await
|
|
21960
|
+
await writeFile12(reportPath, renderValidatedJson(report, relative16(rootPath, reportPath)), "utf8");
|
|
21961
|
+
await writeFile12(reportMarkdownPath, renderMarkdownReport(report), "utf8");
|
|
21625
21962
|
await refreshLatest(buildRoot, runPath, latestPath, report, rootPath);
|
|
21626
21963
|
return {
|
|
21627
21964
|
assertions,
|
|
@@ -21866,11 +22203,11 @@ function activationExpectationCandidatePaths(graph, target, expect) {
|
|
|
21866
22203
|
}
|
|
21867
22204
|
if (expect.kind === "agent") {
|
|
21868
22205
|
const projectRoot = targetProjectRoot4(graph, target);
|
|
21869
|
-
return graph.projectAgents.filter((agent) => agent.name === expect.name || agent.outputName === expect.name).map((agent) =>
|
|
22206
|
+
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
22207
|
}
|
|
21871
22208
|
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) =>
|
|
22209
|
+
...graph.standaloneSkills.filter((skill) => skill.id === expect.name).map((skill) => join21(graph.root.outputs.skills[target], dirname16(skill.relativePath), "SKILL.md")),
|
|
22210
|
+
...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
22211
|
];
|
|
21875
22212
|
}
|
|
21876
22213
|
function targetProjectRoot4(graph, target) {
|
|
@@ -21879,22 +22216,22 @@ function targetProjectRoot4(graph, target) {
|
|
|
21879
22216
|
async function writeActivationProbes(runPath, declaration) {
|
|
21880
22217
|
if (declaration.activationProbes.length === 0)
|
|
21881
22218
|
return;
|
|
21882
|
-
const activationRoot =
|
|
22219
|
+
const activationRoot = join21(runPath, "activation");
|
|
21883
22220
|
for (const target of declaration.targets) {
|
|
21884
22221
|
const probes = declaration.activationProbes.filter((probe) => probe.targets.includes(target));
|
|
21885
22222
|
if (probes.length === 0)
|
|
21886
22223
|
continue;
|
|
21887
|
-
const targetRoot =
|
|
21888
|
-
await
|
|
22224
|
+
const targetRoot = join21(activationRoot, target);
|
|
22225
|
+
await mkdir11(targetRoot, { recursive: true });
|
|
21889
22226
|
const records = probes.map((probe) => activationProbeRecord(probe, target));
|
|
21890
|
-
await
|
|
22227
|
+
await writeFile12(join21(targetRoot, "probes.json"), renderValidatedJson({
|
|
21891
22228
|
probes: records,
|
|
21892
22229
|
schemaVersion: TEST_SCHEMA,
|
|
21893
22230
|
target
|
|
21894
22231
|
}, `activation ${target} probes`), "utf8");
|
|
21895
22232
|
for (const record of records) {
|
|
21896
22233
|
const name = typeof record.name === "string" ? record.name : "probe";
|
|
21897
|
-
await
|
|
22234
|
+
await writeFile12(join21(targetRoot, `${name}.md`), renderActivationProbeMarkdown(record), "utf8");
|
|
21898
22235
|
}
|
|
21899
22236
|
}
|
|
21900
22237
|
return activationRoot;
|
|
@@ -21951,14 +22288,14 @@ async function refreshLatest(buildRoot, runPath, latestPath, report, rootPath) {
|
|
|
21951
22288
|
const latest = {
|
|
21952
22289
|
name: report.name,
|
|
21953
22290
|
ok: report.ok,
|
|
21954
|
-
reportPath: relative16(rootPath,
|
|
22291
|
+
reportPath: relative16(rootPath, join21(latestPath, "report.json")),
|
|
21955
22292
|
runId: report.runId,
|
|
21956
22293
|
runPath: relative16(rootPath, runPath),
|
|
21957
22294
|
schemaVersion: TEST_SCHEMA,
|
|
21958
22295
|
source: report.source,
|
|
21959
|
-
workspacePath: relative16(rootPath,
|
|
22296
|
+
workspacePath: relative16(rootPath, join21(latestPath, "workspace"))
|
|
21960
22297
|
};
|
|
21961
|
-
await
|
|
22298
|
+
await writeFile12(join21(buildRoot, "latest.json"), renderValidatedJson(latest, relative16(rootPath, join21(buildRoot, "latest.json"))), "utf8");
|
|
21962
22299
|
}
|
|
21963
22300
|
function renderMarkdownReport(report) {
|
|
21964
22301
|
const assertions = Array.isArray(report.assertions) ? report.assertions : [];
|
|
@@ -21995,7 +22332,7 @@ function activationProbeCount(report) {
|
|
|
21995
22332
|
}
|
|
21996
22333
|
async function pathExists2(path2) {
|
|
21997
22334
|
try {
|
|
21998
|
-
await
|
|
22335
|
+
await stat18(path2);
|
|
21999
22336
|
return true;
|
|
22000
22337
|
} catch {
|
|
22001
22338
|
return false;
|
|
@@ -22004,8 +22341,21 @@ async function pathExists2(path2) {
|
|
|
22004
22341
|
async function copyIfExists(sourcePath, targetPath) {
|
|
22005
22342
|
if (!await pathExists2(sourcePath))
|
|
22006
22343
|
return;
|
|
22007
|
-
await
|
|
22008
|
-
await cp(sourcePath, targetPath);
|
|
22344
|
+
await mkdir11(dirname16(targetPath), { recursive: true });
|
|
22345
|
+
await cp(sourcePath, targetPath, { recursive: true });
|
|
22346
|
+
}
|
|
22347
|
+
async function copyTestSource(graph, stagingWorkspacePath) {
|
|
22348
|
+
const ignoredSourceBuildPath = resolveInside(graph.rootPath, sourceBuildRoot(graph.sourceDir));
|
|
22349
|
+
if (graph.sourceDir !== ".") {
|
|
22350
|
+
await cp(graph.sourcePath, join21(stagingWorkspacePath, graph.sourceDir), {
|
|
22351
|
+
filter: (path2) => !isSameOrInside2(ignoredSourceBuildPath, path2),
|
|
22352
|
+
recursive: true
|
|
22353
|
+
});
|
|
22354
|
+
return;
|
|
22355
|
+
}
|
|
22356
|
+
await copyIfExists(graph.rootConfigPath, join21(stagingWorkspacePath, "skillset.yaml"));
|
|
22357
|
+
await copyIfExists(graph.sourceRootPath, join21(stagingWorkspacePath, graph.sourceRoot));
|
|
22358
|
+
await copyIfExists(resolveInside(graph.rootPath, "changes"), join21(stagingWorkspacePath, "changes"));
|
|
22009
22359
|
}
|
|
22010
22360
|
async function copyWorkspaceManagedFiles(rootPath, stagingWorkspacePath, workspaceLockPath, sourceDir) {
|
|
22011
22361
|
if (!await pathExists2(workspaceLockPath))
|
|
@@ -22018,7 +22368,7 @@ async function copyWorkspaceManagedFiles(rootPath, stagingWorkspacePath, workspa
|
|
|
22018
22368
|
}
|
|
22019
22369
|
if (!isJsonRecord(lock) || !Array.isArray(lock.items))
|
|
22020
22370
|
return;
|
|
22021
|
-
const ignoredSourceBuildPath = resolveInside(rootPath,
|
|
22371
|
+
const ignoredSourceBuildPath = resolveInside(rootPath, sourceBuildRoot(sourceDir));
|
|
22022
22372
|
for (const item of lock.items) {
|
|
22023
22373
|
if (!isJsonRecord(item) || !Array.isArray(item.files))
|
|
22024
22374
|
continue;
|
|
@@ -22028,10 +22378,16 @@ async function copyWorkspaceManagedFiles(rootPath, stagingWorkspacePath, workspa
|
|
|
22028
22378
|
const sourcePath = resolveInside(rootPath, file);
|
|
22029
22379
|
if (isSameOrInside2(ignoredSourceBuildPath, sourcePath))
|
|
22030
22380
|
continue;
|
|
22031
|
-
await copyIfExists(sourcePath,
|
|
22381
|
+
await copyIfExists(sourcePath, join21(stagingWorkspacePath, file));
|
|
22032
22382
|
}
|
|
22033
22383
|
}
|
|
22034
22384
|
}
|
|
22385
|
+
function testBuildRoot(sourceDir) {
|
|
22386
|
+
return sourceDir === "." ? join21(".skillset", TEST_BUILD_DIR) : join21(sourceDir, TEST_BUILD_DIR);
|
|
22387
|
+
}
|
|
22388
|
+
function sourceBuildRoot(sourceDir) {
|
|
22389
|
+
return sourceDir === "." ? ".skillset/build" : join21(sourceDir, "build");
|
|
22390
|
+
}
|
|
22035
22391
|
function makeRunId(name) {
|
|
22036
22392
|
const stamp = new Date().toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
22037
22393
|
const digest2 = createHash8("sha256").update(`${name}:${stamp}:${randomBytes2(8).toString("hex")}`).digest("hex").slice(0, 8);
|
|
@@ -22048,8 +22404,10 @@ function messageFor(error) {
|
|
|
22048
22404
|
// apps/skillset/src/cli-core.ts
|
|
22049
22405
|
var USAGE = [
|
|
22050
22406
|
"usage: skillset build [--yes|--dry-run] [--updated|--all] [--isolated] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22051
|
-
" skillset
|
|
22052
|
-
" skillset
|
|
22407
|
+
" skillset verify [--updated|--all] [--isolated] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22408
|
+
" skillset diff [--updated|--all] [--isolated] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22409
|
+
" skillset <check|lint> [--root <path>] [--source <dir>]",
|
|
22410
|
+
" skillset list [--updated|--all] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22053
22411
|
" skillset doctor [--json] [--updated|--all] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22054
22412
|
" skillset ci [--fix] [--since <ref>] [--report <path>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
22055
22413
|
" skillset change status [--since <ref>] [--root <path>] [--source <dir>] [--dist <dir>]",
|
|
@@ -22075,6 +22433,7 @@ var USAGE = [
|
|
|
22075
22433
|
" skillset adopt <path> [--yes|--dry-run] [--targets claude,codex] [--root <path>]",
|
|
22076
22434
|
" skillset init [path] [--yes|--dry-run] [--targets claude,codex] [--include ci] [--name <name>] [--root <path>]",
|
|
22077
22435
|
" skillset create [path|--global] [--yes|--dry-run] [--targets claude,codex] [--include ci] [--name <name>] [--root <path>]",
|
|
22436
|
+
" skillset new <skill|agent|hook> [name] [--id <id>] [--name <name>] [--in <container>] [--scope repo] [--preset <preset>] [--yes|--dry-run] [--root <path>] [--source <dir>]",
|
|
22078
22437
|
" skillset explain <path> [--json] [--scope <scope>] [--root <path>] [--source <dir>]",
|
|
22079
22438
|
" skillset import <path> [--kind <skill|skills|plugin|plugins>] [--from <provider>] [--name <name>] [--root <path>] [--source <dir>]",
|
|
22080
22439
|
" skillset import <claude|codex|agents> [--root <path>] [--source <dir>]"
|
|
@@ -22114,6 +22473,12 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22114
22473
|
importName,
|
|
22115
22474
|
importProvider,
|
|
22116
22475
|
jsonOutput,
|
|
22476
|
+
newContainer,
|
|
22477
|
+
newId,
|
|
22478
|
+
newKind,
|
|
22479
|
+
newName,
|
|
22480
|
+
newPresets,
|
|
22481
|
+
newScope,
|
|
22117
22482
|
options,
|
|
22118
22483
|
rootPath,
|
|
22119
22484
|
rootExplicit,
|
|
@@ -22156,8 +22521,8 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22156
22521
|
});
|
|
22157
22522
|
if (ciReportPath !== undefined) {
|
|
22158
22523
|
const reportPath = resolve10(ciReportPath);
|
|
22159
|
-
await
|
|
22160
|
-
await
|
|
22524
|
+
await mkdir12(dirname17(reportPath), { recursive: true });
|
|
22525
|
+
await writeFile13(reportPath, renderCiReportMarkdown(report));
|
|
22161
22526
|
}
|
|
22162
22527
|
printCiReport(report);
|
|
22163
22528
|
if (!report.ok)
|
|
@@ -22334,6 +22699,16 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22334
22699
|
console.log(`skillset: linted ${result3.checkedSkills} source skills`);
|
|
22335
22700
|
return;
|
|
22336
22701
|
}
|
|
22702
|
+
if (command === "check") {
|
|
22703
|
+
const result3 = await lintSkillset(rootPath, options);
|
|
22704
|
+
for (const issue of result3.issues) {
|
|
22705
|
+
if (issue.severity !== "warn")
|
|
22706
|
+
continue;
|
|
22707
|
+
console.log(` warn: ${issue.path}: ${issue.code}: ${issue.message}`);
|
|
22708
|
+
}
|
|
22709
|
+
console.log(`skillset: checked ${result3.checkedSkills} source skills`);
|
|
22710
|
+
return;
|
|
22711
|
+
}
|
|
22337
22712
|
if (command === "adopt") {
|
|
22338
22713
|
const writeMode = yes && !dryRun;
|
|
22339
22714
|
const report = await adoptSkillset(importPath === undefined ? rootPath : importPath, {
|
|
@@ -22395,6 +22770,25 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22395
22770
|
console.warn(` warning: ${warning}`);
|
|
22396
22771
|
return;
|
|
22397
22772
|
}
|
|
22773
|
+
if (command === "new") {
|
|
22774
|
+
if (newKind === undefined)
|
|
22775
|
+
throw new Error("skillset: expected new kind skill, agent, or hook");
|
|
22776
|
+
const report = await scaffoldSourceUnit(rootPath, {
|
|
22777
|
+
...newContainer === undefined ? {} : { container: newContainer },
|
|
22778
|
+
...newId === undefined ? {} : { id: newId },
|
|
22779
|
+
kind: newKind,
|
|
22780
|
+
...newName === undefined ? {} : { displayName: newName },
|
|
22781
|
+
...importPath === undefined ? {} : { name: importPath },
|
|
22782
|
+
...newPresets === undefined ? {} : { presets: newPresets },
|
|
22783
|
+
...newScope === undefined ? {} : { scope: newScope },
|
|
22784
|
+
skillsetOptions: options,
|
|
22785
|
+
write: yes && !dryRun
|
|
22786
|
+
});
|
|
22787
|
+
printNewSourceReport(report, dryRun ? "dry run" : yes ? "written" : "write confirmation required");
|
|
22788
|
+
if (!yes || dryRun)
|
|
22789
|
+
console.log("skillset: rerun new with --yes to write source files");
|
|
22790
|
+
return;
|
|
22791
|
+
}
|
|
22398
22792
|
if (command === "diff") {
|
|
22399
22793
|
const result3 = await diffSkillsetResult(rootPath, options);
|
|
22400
22794
|
printDiagnostics(result3.diagnostics);
|
|
@@ -22563,9 +22957,9 @@ async function runCli(rawArgs = process.argv.slice(2), invokedName = basename9(p
|
|
|
22563
22957
|
}
|
|
22564
22958
|
return;
|
|
22565
22959
|
}
|
|
22566
|
-
const result2 = await
|
|
22960
|
+
const result2 = await verifySkillsetResult(rootPath, options);
|
|
22567
22961
|
printDiagnostics(result2.diagnostics);
|
|
22568
|
-
console.log(`skillset:
|
|
22962
|
+
console.log(`skillset: verified ${result2.data.checkedFiles} generated files`);
|
|
22569
22963
|
if (!result2.ok) {
|
|
22570
22964
|
console.error(`skillset: generated output is not current`);
|
|
22571
22965
|
for (const failure of result2.data.failures)
|
|
@@ -22930,6 +23324,18 @@ function printSetupReport(result2, reason) {
|
|
|
22930
23324
|
console.log(`skillset: ${result2.kind} ${details.join(", ")} (${reason})`);
|
|
22931
23325
|
console.log(` root: ${result2.rootPath}`);
|
|
22932
23326
|
}
|
|
23327
|
+
function printNewSourceReport(result2, reason) {
|
|
23328
|
+
for (const file of result2.files)
|
|
23329
|
+
console.log(` + ${file.path}`);
|
|
23330
|
+
const action = result2.write ? "created" : "planned";
|
|
23331
|
+
console.log(`skillset: ${action} ${result2.kind} ${result2.id} (${reason})`);
|
|
23332
|
+
console.log(` source: ${result2.sourceRoot}`);
|
|
23333
|
+
console.log(` name: ${result2.displayName}`);
|
|
23334
|
+
if (result2.write) {
|
|
23335
|
+
console.log(" next: skillset check");
|
|
23336
|
+
console.log(" next: skillset verify");
|
|
23337
|
+
}
|
|
23338
|
+
}
|
|
22933
23339
|
function printRestoreReport(report) {
|
|
22934
23340
|
const mode = report.write ? "restored" : "restore preview";
|
|
22935
23341
|
console.log(`skillset: ${mode} ${report.restoredPaths.length} file${report.restoredPaths.length === 1 ? "" : "s"} from backup ${report.runId}`);
|
|
@@ -22984,8 +23390,8 @@ function printRenderResult(outcome) {
|
|
|
22984
23390
|
}
|
|
22985
23391
|
function parseArgs(args) {
|
|
22986
23392
|
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
|
|
23393
|
+
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") {
|
|
23394
|
+
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
23395
|
` + USAGE);
|
|
22990
23396
|
}
|
|
22991
23397
|
let changeSubcommand;
|
|
@@ -23016,6 +23422,12 @@ function parseArgs(args) {
|
|
|
23016
23422
|
let importPath;
|
|
23017
23423
|
let importProvider;
|
|
23018
23424
|
let jsonOutput = false;
|
|
23425
|
+
let newContainer;
|
|
23426
|
+
let newId;
|
|
23427
|
+
let newKind;
|
|
23428
|
+
let newName;
|
|
23429
|
+
let newPresets;
|
|
23430
|
+
let newScope;
|
|
23019
23431
|
let rootPath = process.cwd();
|
|
23020
23432
|
let rootExplicit = false;
|
|
23021
23433
|
let sourceDir;
|
|
@@ -23139,6 +23551,19 @@ function parseArgs(args) {
|
|
|
23139
23551
|
index += 1;
|
|
23140
23552
|
}
|
|
23141
23553
|
}
|
|
23554
|
+
if (command === "new") {
|
|
23555
|
+
const rawKind = args[index];
|
|
23556
|
+
if (!isNewSourceKind(rawKind)) {
|
|
23557
|
+
throw new Error("skillset: expected new kind skill, agent, or hook");
|
|
23558
|
+
}
|
|
23559
|
+
newKind = rawKind;
|
|
23560
|
+
index += 1;
|
|
23561
|
+
const rawName = args[index];
|
|
23562
|
+
if (rawName !== undefined && !rawName.startsWith("--")) {
|
|
23563
|
+
importPath = rawName;
|
|
23564
|
+
index += 1;
|
|
23565
|
+
}
|
|
23566
|
+
}
|
|
23142
23567
|
for (;index < args.length; index += 1) {
|
|
23143
23568
|
const arg = args[index];
|
|
23144
23569
|
if (arg === undefined)
|
|
@@ -23146,7 +23571,7 @@ function parseArgs(args) {
|
|
|
23146
23571
|
const equalsIndex = arg.indexOf("=");
|
|
23147
23572
|
const flag = equalsIndex === -1 ? arg : arg.slice(0, equalsIndex);
|
|
23148
23573
|
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") {
|
|
23574
|
+
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
23575
|
throw new Error(`skillset: unknown option ${arg}`);
|
|
23151
23576
|
}
|
|
23152
23577
|
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 +23636,8 @@ function parseArgs(args) {
|
|
|
23211
23636
|
throw new Error(`skillset: change ${changeSubcommand} is a whole-source command; --scope is not supported`);
|
|
23212
23637
|
} else if (command === "change") {
|
|
23213
23638
|
throw new Error("skillset: --scope is only supported with change add source-unit entries");
|
|
23639
|
+
} else if (command === "new") {
|
|
23640
|
+
newScope = readNewSourceScope(value);
|
|
23214
23641
|
} else {
|
|
23215
23642
|
scopes = readBuildScopes(value);
|
|
23216
23643
|
}
|
|
@@ -23243,8 +23670,18 @@ function parseArgs(args) {
|
|
|
23243
23670
|
setupTargets = readSetupTargets(value);
|
|
23244
23671
|
if (flag === "--include")
|
|
23245
23672
|
setupIncludes = mergeSetupIncludes(setupIncludes, value);
|
|
23246
|
-
if (flag === "--
|
|
23247
|
-
|
|
23673
|
+
if (flag === "--id")
|
|
23674
|
+
newId = value;
|
|
23675
|
+
if (flag === "--in")
|
|
23676
|
+
newContainer = value;
|
|
23677
|
+
if (flag === "--name") {
|
|
23678
|
+
if (command === "new")
|
|
23679
|
+
newName = value;
|
|
23680
|
+
else
|
|
23681
|
+
importName = value;
|
|
23682
|
+
}
|
|
23683
|
+
if (flag === "--preset")
|
|
23684
|
+
newPresets = [...newPresets ?? [], value];
|
|
23248
23685
|
if (flag === "--kind") {
|
|
23249
23686
|
if (!isImportKind(value)) {
|
|
23250
23687
|
throw new Error("skillset: expected --kind skill, skills, plugin, or plugins");
|
|
@@ -23307,6 +23744,13 @@ function parseArgs(args) {
|
|
|
23307
23744
|
...scopes === undefined ? {} : { scopes }
|
|
23308
23745
|
});
|
|
23309
23746
|
validateJsonFlags(command, jsonOutput);
|
|
23747
|
+
validateSourceDiagnosticFlags(command, {
|
|
23748
|
+
...buildMode === undefined ? {} : { buildMode },
|
|
23749
|
+
...distDir === undefined ? {} : { distDir },
|
|
23750
|
+
dryRun,
|
|
23751
|
+
...scopes === undefined ? {} : { scopes },
|
|
23752
|
+
yes
|
|
23753
|
+
});
|
|
23310
23754
|
validateIsolatedFlag(command, isolated);
|
|
23311
23755
|
validateDistributionFlags(command, {
|
|
23312
23756
|
...buildMode === undefined ? {} : { buildMode },
|
|
@@ -23348,6 +23792,18 @@ function parseArgs(args) {
|
|
|
23348
23792
|
write: sourceSuggestionWrite,
|
|
23349
23793
|
yes
|
|
23350
23794
|
});
|
|
23795
|
+
validateNewSourceFlags(command, {
|
|
23796
|
+
...buildMode === undefined ? {} : { buildMode },
|
|
23797
|
+
...distDir === undefined ? {} : { distDir },
|
|
23798
|
+
...newContainer === undefined ? {} : { container: newContainer },
|
|
23799
|
+
...newId === undefined ? {} : { id: newId },
|
|
23800
|
+
...importKind === undefined ? {} : { importKind },
|
|
23801
|
+
...importProvider === undefined ? {} : { importProvider },
|
|
23802
|
+
...newKind === undefined ? {} : { kind: newKind },
|
|
23803
|
+
...newName === undefined ? {} : { name: newName },
|
|
23804
|
+
...newPresets === undefined ? {} : { presets: newPresets },
|
|
23805
|
+
...newScope === undefined ? {} : { scope: newScope }
|
|
23806
|
+
});
|
|
23351
23807
|
const options = {
|
|
23352
23808
|
...buildMode === undefined ? {} : { buildMode },
|
|
23353
23809
|
...scopes === undefined ? {} : { scopes },
|
|
@@ -23383,6 +23839,12 @@ function parseArgs(args) {
|
|
|
23383
23839
|
...importPath === undefined ? {} : { importPath },
|
|
23384
23840
|
...importProvider === undefined ? {} : { importProvider },
|
|
23385
23841
|
jsonOutput,
|
|
23842
|
+
...newContainer === undefined ? {} : { newContainer },
|
|
23843
|
+
...newId === undefined ? {} : { newId },
|
|
23844
|
+
...newKind === undefined ? {} : { newKind },
|
|
23845
|
+
...newName === undefined ? {} : { newName },
|
|
23846
|
+
...newPresets === undefined ? {} : { newPresets },
|
|
23847
|
+
...newScope === undefined ? {} : { newScope },
|
|
23386
23848
|
options,
|
|
23387
23849
|
...releaseSubcommand === undefined ? {} : { releaseSubcommand },
|
|
23388
23850
|
...releaseReason === undefined ? {} : { releaseReason },
|
|
@@ -23403,6 +23865,14 @@ function isReleaseSubcommand(value) {
|
|
|
23403
23865
|
function isChangeSubcommand(value) {
|
|
23404
23866
|
return value === "add" || value === "amend" || value === "check" || value === "history" || value === "list" || value === "reason" || value === "show" || value === "status";
|
|
23405
23867
|
}
|
|
23868
|
+
function isNewSourceKind(value) {
|
|
23869
|
+
return value === "agent" || value === "hook" || value === "skill";
|
|
23870
|
+
}
|
|
23871
|
+
function readNewSourceScope(value) {
|
|
23872
|
+
if (value === "repo")
|
|
23873
|
+
return value;
|
|
23874
|
+
throw new Error("skillset: new currently supports only --scope repo");
|
|
23875
|
+
}
|
|
23406
23876
|
function readChangeScopes(value) {
|
|
23407
23877
|
const scopes = value.split(",").map((scope) => scope.trim()).filter((scope) => scope.length > 0);
|
|
23408
23878
|
if (scopes.length === 0)
|
|
@@ -23497,6 +23967,23 @@ function validateTestFlags(command, test2) {
|
|
|
23497
23967
|
throw new Error("skillset: build/write options are not supported with test; test output always writes under .skillset/build/tests");
|
|
23498
23968
|
}
|
|
23499
23969
|
}
|
|
23970
|
+
function validateSourceDiagnosticFlags(command, sourceCheck) {
|
|
23971
|
+
if (command !== "check" && command !== "lint")
|
|
23972
|
+
return;
|
|
23973
|
+
const label = `skillset ${command}`;
|
|
23974
|
+
if (sourceCheck.buildMode !== undefined) {
|
|
23975
|
+
throw new Error(`${label} does not support --updated or --all; it checks source diagnostics`);
|
|
23976
|
+
}
|
|
23977
|
+
if (sourceCheck.scopes !== undefined) {
|
|
23978
|
+
throw new Error(`${label} does not support --scope; it checks source diagnostics`);
|
|
23979
|
+
}
|
|
23980
|
+
if (sourceCheck.distDir !== undefined) {
|
|
23981
|
+
throw new Error(`${label} does not support --dist; it checks source diagnostics`);
|
|
23982
|
+
}
|
|
23983
|
+
if (sourceCheck.dryRun || sourceCheck.yes) {
|
|
23984
|
+
throw new Error(`${label} is read-only and does not support --yes or --dry-run`);
|
|
23985
|
+
}
|
|
23986
|
+
}
|
|
23500
23987
|
function validateRestoreFlags(command, restore) {
|
|
23501
23988
|
if (command !== "restore")
|
|
23502
23989
|
return;
|
|
@@ -23523,6 +24010,24 @@ function validateSuggestSourceFlags(command, suggestion) {
|
|
|
23523
24010
|
if (suggestion.write && !suggestion.yes)
|
|
23524
24011
|
throw new Error("skillset: suggest-source --write requires --yes");
|
|
23525
24012
|
}
|
|
24013
|
+
function validateNewSourceFlags(command, source2) {
|
|
24014
|
+
const hasNewFlag = source2.container !== undefined || source2.id !== undefined || source2.kind !== undefined || source2.name !== undefined || source2.presets !== undefined || source2.scope !== undefined;
|
|
24015
|
+
if (hasNewFlag && command !== "new") {
|
|
24016
|
+
throw new Error("skillset: new options are only supported with new");
|
|
24017
|
+
}
|
|
24018
|
+
if (command !== "new")
|
|
24019
|
+
return;
|
|
24020
|
+
if (source2.buildMode !== undefined)
|
|
24021
|
+
throw new Error("skillset: --updated and --all are not supported with new");
|
|
24022
|
+
if (source2.distDir !== undefined)
|
|
24023
|
+
throw new Error("skillset: --dist is not supported with new");
|
|
24024
|
+
if (source2.importKind !== undefined)
|
|
24025
|
+
throw new Error("skillset: --kind is only supported with import");
|
|
24026
|
+
if (source2.importProvider !== undefined)
|
|
24027
|
+
throw new Error("skillset: --from is only supported with import");
|
|
24028
|
+
if (source2.kind === undefined)
|
|
24029
|
+
throw new Error("skillset: expected new kind skill, agent, or hook");
|
|
24030
|
+
}
|
|
23526
24031
|
function setBuildMode(current, next) {
|
|
23527
24032
|
if (current !== undefined && current !== next) {
|
|
23528
24033
|
throw new Error(`skillset: conflicting build mode flags --${current} and --${next}`);
|
|
@@ -23589,9 +24094,9 @@ function readSetupTargets(value) {
|
|
|
23589
24094
|
function validateIsolatedFlag(command, isolated) {
|
|
23590
24095
|
if (!isolated)
|
|
23591
24096
|
return;
|
|
23592
|
-
if (command === "build" || command === "
|
|
24097
|
+
if (command === "build" || command === "diff" || command === "verify")
|
|
23593
24098
|
return;
|
|
23594
|
-
throw new Error("skillset: --isolated is only supported with build,
|
|
24099
|
+
throw new Error("skillset: --isolated is only supported with build, diff, or verify");
|
|
23595
24100
|
}
|
|
23596
24101
|
function validateCiFlags(command, ci) {
|
|
23597
24102
|
if (command !== "ci") {
|