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.
Files changed (3) hide show
  1. package/dist/cli.js +577 -85
  2. package/dist/create.js +577 -85
  3. 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 mkdir11, writeFile as writeFile12 } from "fs/promises";
7028
- import { basename as basename9, dirname as dirname16, resolve as resolve10 } from "path";
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: [test("apps/skillset/src/__tests__/ci.test.ts", "CI and build-scope coverage")],
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(?:\b|\[[^\]]+\]|\.[A-Za-z_][A-Za-z0-9_-]*)/gu
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$])\$[0-9]+\b/gu
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 dependencyNotice = target === "codex" && plugin !== undefined ? renderCodexDependencyNotice(graph, plugin) : undefined;
12672
- const body = dependencyNotice === undefined ? preprocessedBody : `${dependencyNotice}
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 checkSkillsetResult(rootPath, options = {}) {
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: "check",
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(?:\b|\[[^\]]+\]|\.[A-Za-z_][A-Za-z0-9_-]*)/
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$])\$[0-9]+\b/
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 searchableBody = maskMarkdownCodeRegions(skill.body);
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 check.`]
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 check` to inspect any remaining generated drift."],
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 check"
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("Bodies are untouched. Files with transformable constructs were marked `dialect: claude`; the build lowers their Codex projection through these forms.", "");
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 check --isolated`", "- `skillset ci`", "");
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
- return result({ context, event, exitCode: check, gate, ranCommands });
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 mkdir9, readFile as readFile20, rm as rm6, stat as stat16, writeFile as writeFile10 } from "fs/promises";
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 dirname14, join as join19 } from "path";
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 = join19(sourceDir, RELEASE_AMENDMENTS_FILE).replaceAll("\\", "/");
21493
+ const amendmentPath = join20(sourceDir, RELEASE_AMENDMENTS_FILE).replaceAll("\\", "/");
21151
21494
  const absolutePath = resolveInside(rootPath, amendmentPath);
21152
- await mkdir9(dirname14(absolutePath), { recursive: true });
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 = join19(sourceDir, HISTORY_FILE3).replaceAll("\\", "/");
21640
+ const relativePath2 = join20(sourceDir, HISTORY_FILE3).replaceAll("\\", "/");
21298
21641
  const absolutePath = resolveInside(rootPath, relativePath2);
21299
- await mkdir9(dirname14(absolutePath), { recursive: true });
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 = join19(sourceDir, RELEASES_FILE).replaceAll("\\", "/");
21665
+ const relativePath2 = join20(sourceDir, RELEASES_FILE).replaceAll("\\", "/");
21323
21666
  const absolutePath = resolveInside(rootPath, relativePath2);
21324
- await mkdir9(dirname14(absolutePath), { recursive: true });
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
- join19(sourceDir, HISTORY_FILE3).replaceAll("\\", "/"),
21687
+ join20(sourceDir, HISTORY_FILE3).replaceAll("\\", "/"),
21345
21688
  ...entries.map((entry) => entry.path)
21346
21689
  ]);
21347
21690
  if (includeReleaseState) {
21348
- paths.add(join19(sourceDir, STATE_FILE2).replaceAll("\\", "/"));
21349
- paths.add(join19(sourceDir, RELEASES_FILE).replaceAll("\\", "/"));
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 mkdir9(dirname14(absolutePath), { recursive: true });
21369
- await writeFile10(absolutePath, snapshot.content);
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 stat16(path2);
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 = join19(sourceDir, RELEASES_FILE).replaceAll("\\", "/");
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 = join19(sourceDir, RELEASE_AMENDMENTS_FILE).replaceAll("\\", "/");
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 mkdir10, mkdtemp as mkdtemp4, readFile as readFile21, rm as rm7, stat as stat17, writeFile as writeFile11 } from "fs/promises";
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 dirname15, join as join20, relative as relative16, resolve as resolve9 } from "path";
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, join20(sourceDir, TEST_BUILD_DIR));
21563
- const runsRoot = join20(buildRoot, "runs");
21564
- const runPath = join20(runsRoot, runId);
21565
- const workspacePath = join20(runPath, "workspace");
21566
- const stagingRoot = await mkdtemp4(join20(tmpdir3(), "skillset-test-"));
21567
- const stagingWorkspacePath = join20(stagingRoot, "workspace");
21568
- const stagingSourcePath = join20(stagingWorkspacePath, sourceDir);
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, join20(sourceDir, "build"));
21914
+ const ignoredSourceBuildPath = resolveInside(rootPath, join21(sourceDir, "build"));
21572
21915
  try {
21573
- await mkdir10(stagingWorkspacePath, { recursive: true });
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, join20(stagingWorkspacePath, ".skillset.lock"));
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 mkdir10(runPath, { recursive: true });
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 = join20(runPath, "report.json");
21603
- const reportMarkdownPath = join20(runPath, "report.md");
21604
- const latestPath = join20(buildRoot, "latest");
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 writeFile11(reportPath, renderValidatedJson(report, relative16(rootPath, reportPath)), "utf8");
21624
- await writeFile11(reportMarkdownPath, renderMarkdownReport(report), "utf8");
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) => join20(projectRoot, "agents", `${agent.outputName}.${target === "claude" ? "md" : "toml"}`));
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) => join20(graph.root.outputs.skills[target], dirname15(skill.relativePath), "SKILL.md")),
21873
- ...graph.plugins.flatMap((plugin) => plugin.skills.filter((skill) => skill.id === expect.name).map((skill) => join20(graph.root.outputs.plugins[target], "plugins", plugin.id, dirname15(skill.relativePath), "SKILL.md")))
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 = join20(runPath, "activation");
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 = join20(activationRoot, target);
21888
- await mkdir10(targetRoot, { recursive: true });
22230
+ const targetRoot = join21(activationRoot, target);
22231
+ await mkdir11(targetRoot, { recursive: true });
21889
22232
  const records = probes.map((probe) => activationProbeRecord(probe, target));
21890
- await writeFile11(join20(targetRoot, "probes.json"), renderValidatedJson({
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 writeFile11(join20(targetRoot, `${name}.md`), renderActivationProbeMarkdown(record), "utf8");
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, join20(latestPath, "report.json")),
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, join20(latestPath, "workspace"))
22302
+ workspacePath: relative16(rootPath, join21(latestPath, "workspace"))
21960
22303
  };
21961
- await writeFile11(join20(buildRoot, "latest.json"), renderValidatedJson(latest, relative16(rootPath, join20(buildRoot, "latest.json"))), "utf8");
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 stat17(path2);
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 mkdir10(dirname15(targetPath), { recursive: true });
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, join20(sourceDir, "build"));
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, join20(stagingWorkspacePath, file));
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 <check|diff> [--updated|--all] [--isolated] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
22052
- " skillset <lint|list> [--updated|--all] [--scope <scope>] [--root <path>] [--source <dir>] [--dist <dir>]",
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 mkdir11(dirname16(reportPath), { recursive: true });
22160
- await writeFile12(reportPath, renderCiReportMarkdown(report));
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 checkSkillsetResult(rootPath, options);
22947
+ const result2 = await verifySkillsetResult(rootPath, options);
22567
22948
  printDiagnostics(result2.diagnostics);
22568
- console.log(`skillset: checked ${result2.data.checkedFiles} generated files`);
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 test
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 === "--name")
23247
- importName = value;
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 === "check" || command === "diff")
24084
+ if (command === "build" || command === "diff" || command === "verify")
23593
24085
  return;
23594
- throw new Error("skillset: --isolated is only supported with build, check, or diff");
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") {