@gobing-ai/superskill 0.2.4 → 0.2.6

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/README.md +41 -244
  2. package/dist/index.js +1235 -279
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2226,13 +2226,20 @@ import { rmSync } from "fs";
2226
2226
  async function backupFile(filePath) {
2227
2227
  let backupPath = `${filePath}.bak`;
2228
2228
  if (await Bun.file(backupPath).exists()) {
2229
- const ts = new Date().toISOString().replace(/[:.]/g, "").slice(0, 15);
2229
+ const ts = new Date().toISOString().replace(/[:.]/g, "").slice(0, 18);
2230
2230
  backupPath = `${filePath}.bak.${ts}`;
2231
+ let counter = 1;
2232
+ while (await Bun.file(backupPath).exists()) {
2233
+ backupPath = `${filePath}.bak.${ts}.${counter++}`;
2234
+ }
2231
2235
  }
2232
2236
  await Bun.write(backupPath, Bun.file(filePath));
2233
2237
  return backupPath;
2234
2238
  }
2235
2239
  async function restoreFromBackup(backupPath, originalPath) {
2240
+ if (!await Bun.file(backupPath).exists()) {
2241
+ throw new Error(`Backup file not found: ${backupPath} \u2014 cannot restore ${originalPath}`);
2242
+ }
2236
2243
  await Bun.write(originalPath, Bun.file(backupPath));
2237
2244
  rmSync(backupPath, { force: true });
2238
2245
  }
@@ -9230,11 +9237,10 @@ var init_dist2 = __esm(() => {
9230
9237
 
9231
9238
  // ../../packages/core/src/content/frontmatter.ts
9232
9239
  function parseFrontmatter(content) {
9233
- if (!content.startsWith(`---
9234
- `)) {
9240
+ if (!/^---\r?\n/.test(content)) {
9235
9241
  throw new FrontmatterError("Missing frontmatter: content must start with ---");
9236
9242
  }
9237
- const closerMatch = content.slice(4).match(/\n---(?=\n|$)/);
9243
+ const closerMatch = content.slice(4).match(/\r?\n---(?=\r?\n|$)/);
9238
9244
  if (closerMatch?.index === undefined) {
9239
9245
  throw new FrontmatterError("Missing frontmatter closing delimiter (---)");
9240
9246
  }
@@ -9445,7 +9451,7 @@ function walkFrontmatter(content, opts) {
9445
9451
  }
9446
9452
  out.push(line);
9447
9453
  }
9448
- if (!injectedName) {
9454
+ if (!injectedName || inFrontmatter) {
9449
9455
  return `${opts.fallbackBlock}
9450
9456
 
9451
9457
  ${content}`;
@@ -9469,6 +9475,12 @@ var init_rewrite_references = __esm(() => {
9469
9475
  SLASH_COMMAND_LINE_RE = /^\s*\/[a-zA-Z0-9._-]+:[a-zA-Z0-9._-]+(\s|$)/;
9470
9476
  });
9471
9477
 
9478
+ // ../../packages/core/src/pipeline/yaml-utils.ts
9479
+ function quoteYaml(value) {
9480
+ const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
9481
+ return `"${escaped}"`;
9482
+ }
9483
+
9472
9484
  // ../../packages/core/src/pipeline/adapt-command.ts
9473
9485
  function adaptCommandToSkill(source, expectedName, pluginPrefix) {
9474
9486
  let result;
@@ -9480,7 +9492,7 @@ function adaptCommandToSkill(source, expectedName, pluginPrefix) {
9480
9492
  const description = firstLine?.trim() || `${expectedName} command`;
9481
9493
  result = `---
9482
9494
  name: ${expectedName}
9483
- description: "${description}"
9495
+ description: ${quoteYaml(description)}
9484
9496
  disable-model-invocation: true
9485
9497
  ---
9486
9498
 
@@ -9502,7 +9514,8 @@ function normalizeCommandFrontmatter(content, expectedName) {
9502
9514
  const value = line.slice(line.indexOf(":") + 1).trim();
9503
9515
  if (value.startsWith("["))
9504
9516
  return line;
9505
- const parts = value.split(/,\s*/).map((p) => p.trim()).filter(Boolean);
9517
+ const unquoted = value.replace(/^["']|["']$/g, "");
9518
+ const parts = unquoted.split(/,\s*/).map((p) => p.trim()).filter(Boolean);
9506
9519
  return `allowed-tools: [${parts.join(", ")}]`;
9507
9520
  }
9508
9521
  }
@@ -9517,10 +9530,6 @@ disable-model-invocation: true
9517
9530
  ---`
9518
9531
  });
9519
9532
  }
9520
- function quoteYaml(value) {
9521
- const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
9522
- return `"${escaped}"`;
9523
- }
9524
9533
  var init_adapt_command = __esm(() => {
9525
9534
  init_rewrite_references();
9526
9535
  });
@@ -9603,7 +9612,7 @@ function adaptSubagentToSkill(source, expectedName, pluginPrefix) {
9603
9612
  const description = firstLine?.trim() || `${expectedName} subagent`;
9604
9613
  result = `---
9605
9614
  name: ${expectedName}
9606
- description: "${description}"
9615
+ description: ${quoteYaml(description)}
9607
9616
  ---
9608
9617
 
9609
9618
  ${source}`;
@@ -9637,17 +9646,17 @@ ${source}`;
9637
9646
  const piTools = normalizePiToolList(rawToolsStr);
9638
9647
  const description = asString(data.description) || `${expectedName} subagent`;
9639
9648
  let model = asString(data.model);
9640
- if (model === "inherit")
9649
+ if (model.toLowerCase() === "inherit")
9641
9650
  model = "";
9642
9651
  const skillsList = resolvePiSkills(data, body, pluginPrefix, skillExists);
9643
9652
  const skillsCsv = skillsList.join(", ");
9644
9653
  const fields = [`name: ${expectedName}`];
9645
9654
  if (description)
9646
- fields.push(`description: ${description}`);
9655
+ fields.push(`description: ${quoteYaml(description)}`);
9647
9656
  if (piTools)
9648
9657
  fields.push(`tools: ${piTools}`);
9649
9658
  if (model)
9650
- fields.push(`model: ${model}`);
9659
+ fields.push(`model: ${quoteYaml(model)}`);
9651
9660
  if (skillsCsv)
9652
9661
  fields.push(`skill: ${skillsCsv}`);
9653
9662
  const runtimeNotes = buildPiRuntimeNotes(parseToolsList(rawToolsStr), skillsCsv);
@@ -9731,8 +9740,9 @@ var init_adapt_subagent = __esm(() => {
9731
9740
  });
9732
9741
 
9733
9742
  // ../../packages/core/src/mapper.ts
9734
- import { existsSync as existsSync3, mkdirSync, readdirSync, readFileSync as readFileSync2, rmSync as rmSync2, statSync as statSync2, writeFileSync } from "fs";
9735
- import { join as join3 } from "path";
9743
+ import { existsSync as existsSync3, lstatSync, mkdirSync, readdirSync, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync } from "fs";
9744
+ import { homedir as homedir2 } from "os";
9745
+ import { join as join3, resolve } from "path";
9736
9746
  function convertClaudeHooksToCanonical(claudeJson) {
9737
9747
  const claudeHooks = claudeJson.hooks;
9738
9748
  if (!claudeHooks || typeof claudeHooks !== "object")
@@ -9771,10 +9781,15 @@ function convertClaudeHooksToCanonical(claudeJson) {
9771
9781
  return { hooks: canonical };
9772
9782
  }
9773
9783
  function setSkillName(content, newName) {
9774
- return content.replace(/^name:\s*.+$/m, `name: ${newName}`);
9784
+ if (/^name:\s*.+$/m.test(content)) {
9785
+ return content.replace(/^name:\s*.+$/m, `name: ${newName}`);
9786
+ }
9787
+ return content.replace(/^---\s*$/m, `---
9788
+ name: ${newName}`);
9775
9789
  }
9776
9790
  function mapPluginToRulesync(pluginPath, pluginName, outputDir) {
9777
9791
  assertSafePathSegment(pluginName, "plugin name");
9792
+ assertSafeOutputDir(outputDir);
9778
9793
  if (existsSync3(outputDir)) {
9779
9794
  rmSync2(outputDir, { recursive: true, force: true });
9780
9795
  }
@@ -9875,7 +9890,12 @@ function deepMergeJsonFile(sourcePath, targetPath) {
9875
9890
  `);
9876
9891
  }
9877
9892
  function readJsonObject(path) {
9878
- const value = JSON.parse(readFileSync2(path, "utf-8"));
9893
+ let value;
9894
+ try {
9895
+ value = JSON.parse(readFileSync2(path, "utf-8"));
9896
+ } catch (e) {
9897
+ throw new Error(`Failed to parse JSON in ${path}: ${e instanceof Error ? e.message : String(e)}`);
9898
+ }
9879
9899
  if (!isJsonObject(value)) {
9880
9900
  throw new Error(`Expected JSON object in ${path}`);
9881
9901
  }
@@ -9892,20 +9912,44 @@ function deepMerge2(target, source) {
9892
9912
  function isJsonObject(value) {
9893
9913
  return typeof value === "object" && value !== null && !Array.isArray(value);
9894
9914
  }
9915
+ function assertSafeOutputDir(outputDir) {
9916
+ const resolved = resolve(outputDir);
9917
+ const home = homedir2();
9918
+ const dangerous = [home, process.cwd(), "/", "/home", "/Users"];
9919
+ for (const danger of dangerous) {
9920
+ if (resolved === resolve(danger)) {
9921
+ throw new Error(`Refusing to delete output directory '${resolved}': resolves to a protected path ` + `(home, cwd, or filesystem root). Use a subdirectory.`);
9922
+ }
9923
+ }
9924
+ }
9895
9925
  function copyAndRewriteDirectory(source, destination, pluginName) {
9896
9926
  mkdirSync(destination, { recursive: true });
9897
9927
  for (const entry of readdirSync(source)) {
9898
9928
  const srcPath = join3(source, entry);
9899
9929
  const destPath = join3(destination, entry);
9900
- if (statSync2(srcPath).isDirectory()) {
9930
+ const stat = lstatSync(srcPath);
9931
+ if (stat.isSymbolicLink())
9932
+ continue;
9933
+ if (stat.isDirectory()) {
9901
9934
  copyAndRewriteDirectory(srcPath, destPath, pluginName);
9902
9935
  } else {
9903
- const content = readFileSync2(srcPath, "utf-8");
9904
- writeFileSync(destPath, rewriteSkillReferences(content, pluginName));
9936
+ const bytes = readFileSync2(srcPath);
9937
+ if (isTextFile(entry, bytes)) {
9938
+ const content = bytes.toString("utf-8");
9939
+ writeFileSync(destPath, rewriteSkillReferences(content, pluginName));
9940
+ } else {
9941
+ writeFileSync(destPath, bytes);
9942
+ }
9905
9943
  }
9906
9944
  }
9907
9945
  }
9908
- var CLAUDE_TO_CANONICAL_EVENT;
9946
+ function isTextFile(filename, bytes) {
9947
+ const ext = filename.slice(filename.lastIndexOf("."));
9948
+ if (TEXT_EXTENSIONS.has(ext))
9949
+ return true;
9950
+ return !bytes.subarray(0, 8192).includes(0);
9951
+ }
9952
+ var CLAUDE_TO_CANONICAL_EVENT, TEXT_EXTENSIONS;
9909
9953
  var init_mapper = __esm(() => {
9910
9954
  init_identity();
9911
9955
  init_adapt_command();
@@ -9927,6 +9971,34 @@ var init_mapper = __esm(() => {
9927
9971
  WorktreeRemove: "worktreeRemove",
9928
9972
  MessageDisplay: "messageDisplay"
9929
9973
  };
9974
+ TEXT_EXTENSIONS = new Set([
9975
+ ".md",
9976
+ ".ts",
9977
+ ".js",
9978
+ ".json",
9979
+ ".yaml",
9980
+ ".yml",
9981
+ ".txt",
9982
+ ".sh",
9983
+ ".bash",
9984
+ ".py",
9985
+ ".rb",
9986
+ ".go",
9987
+ ".rs",
9988
+ ".java",
9989
+ ".c",
9990
+ ".cpp",
9991
+ ".h",
9992
+ ".css",
9993
+ ".html",
9994
+ ".xml",
9995
+ ".toml",
9996
+ ".ini",
9997
+ ".cfg",
9998
+ ".env",
9999
+ ".gitignore",
10000
+ ".dockerfile"
10001
+ ]);
9930
10002
  });
9931
10003
 
9932
10004
  // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
@@ -13897,20 +13969,20 @@ var init_zod = __esm(() => {
13897
13969
 
13898
13970
  // ../../packages/core/src/marketplace.ts
13899
13971
  import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
13900
- import { join as join4, resolve } from "path";
13972
+ import { join as join4, resolve as resolve2 } from "path";
13901
13973
  function resolvePlugin(marketplacePath, pluginName) {
13902
13974
  let manifestPath = null;
13903
13975
  if (marketplacePath) {
13904
13976
  if (marketplacePath.endsWith("marketplace.json")) {
13905
- manifestPath = resolve(marketplacePath);
13977
+ manifestPath = resolve2(marketplacePath);
13906
13978
  } else {
13907
- manifestPath = resolve(join4(marketplacePath, "marketplace.json"));
13979
+ manifestPath = resolve2(join4(marketplacePath, "marketplace.json"));
13908
13980
  }
13909
13981
  if (!existsSync4(manifestPath)) {
13910
13982
  throw new Error(`Marketplace manifest not found at: ${manifestPath}`);
13911
13983
  }
13912
13984
  } else {
13913
- const cwdManifest = resolve(".claude-plugin", "marketplace.json");
13985
+ const cwdManifest = resolve2(".claude-plugin", "marketplace.json");
13914
13986
  if (existsSync4(cwdManifest)) {
13915
13987
  manifestPath = cwdManifest;
13916
13988
  }
@@ -13937,12 +14009,15 @@ function resolvePlugin(marketplacePath, pluginName) {
13937
14009
  if (!source.startsWith("./")) {
13938
14010
  throw new Error(`Remote sources not yet supported for plugin '${pluginName}'. Phase 1 only supports relative-path sources (starting with './').`);
13939
14011
  }
13940
- if (/(?:^|\/)\.\.(?:\/|$)/.test(source)) {
14012
+ if (/(?:^|[\\/])\.\.(?:[\\/]|$)/.test(source)) {
13941
14013
  throw new Error(`Plugin source for '${pluginName}' escapes the marketplace root: '${source}'.`);
13942
14014
  }
13943
- const marketplaceRoot = resolve(manifestPath, "..", "..");
13944
14015
  const pluginRootBase = manifest.metadata?.pluginRoot ?? "";
13945
- const pluginRoot = resolve(marketplaceRoot, pluginRootBase, source);
14016
+ if (pluginRootBase && /(?:^|[\\/])\.\.(?:[\\/]|$)/.test(pluginRootBase)) {
14017
+ throw new Error(`Plugin root for '${pluginName}' escapes the marketplace root: '${pluginRootBase}'.`);
14018
+ }
14019
+ const marketplaceRoot = resolve2(manifestPath, "..", "..");
14020
+ const pluginRoot = resolve2(marketplaceRoot, pluginRootBase, source);
13946
14021
  let dirents;
13947
14022
  try {
13948
14023
  dirents = readdirSync2(pluginRoot);
@@ -13962,11 +14037,11 @@ function resolvePlugin(marketplacePath, pluginName) {
13962
14037
  function listResolvablePlugins(marketplacePath) {
13963
14038
  let manifestPath = null;
13964
14039
  if (marketplacePath) {
13965
- manifestPath = marketplacePath.endsWith("marketplace.json") ? resolve(marketplacePath) : resolve(join4(marketplacePath, "marketplace.json"));
14040
+ manifestPath = marketplacePath.endsWith("marketplace.json") ? resolve2(marketplacePath) : resolve2(join4(marketplacePath, "marketplace.json"));
13966
14041
  if (!existsSync4(manifestPath))
13967
14042
  return [];
13968
14043
  } else {
13969
- const cwdManifest = resolve(".claude-plugin", "marketplace.json");
14044
+ const cwdManifest = resolve2(".claude-plugin", "marketplace.json");
13970
14045
  if (existsSync4(cwdManifest))
13971
14046
  manifestPath = cwdManifest;
13972
14047
  }
@@ -14106,7 +14181,7 @@ var init_migrate = __esm(() => {
14106
14181
  });
14107
14182
 
14108
14183
  // ../../packages/core/src/operations/package.ts
14109
- import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync3, statSync as statSync3 } from "fs";
14184
+ import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync3, rmSync as rmSync3, statSync as statSync2 } from "fs";
14110
14185
  import { basename as basename2, dirname as dirname3, join as join5 } from "path";
14111
14186
  import { cwd as cwd3 } from "process";
14112
14187
  function resolveSkillDir(name) {
@@ -14114,7 +14189,7 @@ function resolveSkillDir(name) {
14114
14189
  if (!skillPath) {
14115
14190
  throw Object.assign(new Error(`Skill not found: ${name}`), { code: "ENOENT" });
14116
14191
  }
14117
- const dir = statSync3(skillPath).isDirectory() ? skillPath : dirname3(skillPath);
14192
+ const dir = statSync2(skillPath).isDirectory() ? skillPath : dirname3(skillPath);
14118
14193
  return { dir, name: basename2(dir) };
14119
14194
  }
14120
14195
  function copyDirIfExists(src, dest) {
@@ -14130,6 +14205,9 @@ function copyFileIfExists(src, dest) {
14130
14205
  async function packageSkill(name, opts = {}) {
14131
14206
  const { dir: skillDir, name: skillName } = resolveSkillDir(name);
14132
14207
  const outputDir = join5(opts.output ?? cwd3(), skillName);
14208
+ if (existsSync6(outputDir)) {
14209
+ rmSync3(outputDir, { recursive: true, force: true });
14210
+ }
14133
14211
  mkdirSync3(outputDir, { recursive: true });
14134
14212
  copyFileIfExists(join5(skillDir, "SKILL.md"), join5(outputDir, "SKILL.md"));
14135
14213
  copyDirIfExists(join5(skillDir, "references"), join5(outputDir, "references"));
@@ -14152,7 +14230,7 @@ var init_package = __esm(() => {
14152
14230
 
14153
14231
  // ../../packages/core/src/operations/scaffold.ts
14154
14232
  import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
14155
- import { homedir as homedir2 } from "os";
14233
+ import { homedir as homedir3 } from "os";
14156
14234
  import { join as join6 } from "path";
14157
14235
  import { cwd as cwd4 } from "process";
14158
14236
  function parseList(value) {
@@ -14192,8 +14270,10 @@ function mergeFrontmatterList(content, key, items) {
14192
14270
  return content.slice(0, fmStart) + newFmBody + content.slice(closePos);
14193
14271
  }
14194
14272
  function resolveTemplate(type, tier) {
14195
- const homeDir = process.env.HOME ?? homedir2();
14273
+ const homeDir = process.env.HOME ?? homedir3();
14196
14274
  const tierName = tier?.trim();
14275
+ if (tierName)
14276
+ assertSafePathSegment(tierName, "template tier");
14197
14277
  if (tierName && tierName !== "default") {
14198
14278
  const userTierPath = join6(homeDir, ".superskill", "templates", type, `${tierName}.md`);
14199
14279
  if (existsSync7(userTierPath)) {
@@ -14296,10 +14376,7 @@ function scoreClarityFromDensities(body) {
14296
14376
  function parseFrontmatterSafe(content) {
14297
14377
  try {
14298
14378
  return parseFrontmatter(content).data;
14299
- } catch (e) {
14300
- if (e instanceof FrontmatterError) {
14301
- return null;
14302
- }
14379
+ } catch {
14303
14380
  return null;
14304
14381
  }
14305
14382
  }
@@ -14413,7 +14490,7 @@ function parseHookEntries(raw) {
14413
14490
  function scoreCorrectness(entries) {
14414
14491
  let valid = 0;
14415
14492
  for (const e of entries) {
14416
- if (e.type === "command" && e.command.length > 0 && e.matcher.length > 0)
14493
+ if ((e.type === "command" || e.type === "prompt") && e.command.length > 0 && e.matcher.length > 0)
14417
14494
  valid++;
14418
14495
  }
14419
14496
  const score = entries.length > 0 ? clamp(valid / entries.length) : 0;
@@ -14423,7 +14500,7 @@ function scoreCorrectness(entries) {
14423
14500
  function scoreEventCoverage(entries) {
14424
14501
  const events = new Set(entries.map((e) => e.event));
14425
14502
  const covered = KNOWN_HOOK_EVENTS.filter((e) => events.has(e)).length;
14426
- const score = clamp(Math.min(events.size / 3, 1));
14503
+ const score = clamp(Math.min(covered / 3, 1));
14427
14504
  const note = `${covered} of ${KNOWN_HOOK_EVENTS.length} known events covered (${events.size} total)`;
14428
14505
  return { score, note };
14429
14506
  }
@@ -14578,7 +14655,7 @@ var init_hook = __esm(() => {
14578
14655
  });
14579
14656
 
14580
14657
  // ../../packages/core/src/operations/validate.ts
14581
- import { existsSync as existsSync8, statSync as statSync4 } from "fs";
14658
+ import { existsSync as existsSync8, statSync as statSync3 } from "fs";
14582
14659
  import { dirname as dirname4, join as join7 } from "path";
14583
14660
  function checkBodyLinks(body, baseDir) {
14584
14661
  const findings = [];
@@ -14616,7 +14693,7 @@ async function validate(type, nameOrPath, opts) {
14616
14693
  }
14617
14694
  let stat;
14618
14695
  try {
14619
- stat = statSync4(resolvedPath);
14696
+ stat = statSync3(resolvedPath);
14620
14697
  } catch {
14621
14698
  return sentinelResult(`File not found: ${resolvedPath}`);
14622
14699
  }
@@ -14638,13 +14715,14 @@ async function validate(type, nameOrPath, opts) {
14638
14715
  const baseDir = dirname4(resolvedPath);
14639
14716
  const result = _validateContent(type, content, {
14640
14717
  ...opts,
14641
- referenceChecker: (refType, refName) => resolveContentPath(refType, refName, { baseDir }) !== null
14718
+ referenceChecker: opts?.referenceChecker ?? ((refType, refName) => resolveContentPath(refType, refName, { baseDir }) !== null)
14642
14719
  });
14643
- const bodyStart = content.indexOf(`
14644
- ---
14645
- `);
14646
- const body = bodyStart >= 0 ? content.slice(bodyStart + 5) : content;
14647
- const linkFindings = checkBodyLinks(body, baseDir);
14720
+ let bodyForLinks = content;
14721
+ try {
14722
+ const { body } = parseFrontmatter(content);
14723
+ bodyForLinks = body;
14724
+ } catch {}
14725
+ const linkFindings = checkBodyLinks(bodyForLinks, baseDir);
14648
14726
  result.findings.push(...linkFindings);
14649
14727
  return result;
14650
14728
  }
@@ -14652,7 +14730,9 @@ function _validateContent(type, content, opts) {
14652
14730
  const findings = [];
14653
14731
  let data;
14654
14732
  let body;
14655
- const frontmatterPresent = /^---\s*$/m.test(content);
14733
+ const frontmatterPresent = content.startsWith(`---
14734
+ `) || content.startsWith(`---\r
14735
+ `);
14656
14736
  try {
14657
14737
  if (frontmatterPresent) {
14658
14738
  const parsed = parseFrontmatter(content);
@@ -14832,7 +14912,12 @@ function strictChecks(type, data, body) {
14832
14912
  message: `Body content is too short (${trimmedBody.length} chars). Recommended minimum is 20 characters.`
14833
14913
  });
14834
14914
  }
14835
- for (const key of Object.keys(data)) {
14915
+ const recognized = new Set([
14916
+ ...Object.keys(FIELD_TYPES[type] ?? {}),
14917
+ ...REQUIRED_FIELDS[type],
14918
+ ...KNOWN_OPTIONAL[type] ?? []
14919
+ ]);
14920
+ for (const [key, value] of Object.entries(data)) {
14836
14921
  const replacement = DEPRECATED_FIELDS[key];
14837
14922
  if (replacement) {
14838
14923
  findings.push({
@@ -14841,31 +14926,20 @@ function strictChecks(type, data, body) {
14841
14926
  message: `'${key}' is deprecated. ${replacement}`
14842
14927
  });
14843
14928
  }
14844
- }
14845
- for (const [field, value] of Object.entries(data)) {
14846
14929
  if (typeof value === "string" && value !== value.trimEnd()) {
14847
14930
  findings.push({
14848
14931
  severity: "warning",
14849
- field,
14850
- message: `'${field}' has trailing whitespace`
14932
+ field: key,
14933
+ message: `'${key}' has trailing whitespace`
14934
+ });
14935
+ }
14936
+ if (!recognized.has(key) && DEPRECATED_FIELDS[key] === undefined) {
14937
+ findings.push({
14938
+ severity: "warning",
14939
+ field: key,
14940
+ message: `Unknown frontmatter key '${key}'`
14851
14941
  });
14852
14942
  }
14853
- }
14854
- const recognized = new Set([
14855
- ...Object.keys(FIELD_TYPES[type] ?? {}),
14856
- ...REQUIRED_FIELDS[type],
14857
- ...KNOWN_OPTIONAL[type] ?? []
14858
- ]);
14859
- for (const key of Object.keys(data)) {
14860
- if (recognized.has(key))
14861
- continue;
14862
- if (DEPRECATED_FIELDS[key] !== undefined)
14863
- continue;
14864
- findings.push({
14865
- severity: "warning",
14866
- field: key,
14867
- message: `Unknown frontmatter key '${key}'`
14868
- });
14869
14943
  }
14870
14944
  return findings;
14871
14945
  }
@@ -17290,8 +17364,12 @@ function getTelemetryConfig(configPartial = {}) {
17290
17364
  function getResolvedConfig() {
17291
17365
  return resolvedConfig;
17292
17366
  }
17293
- var CONFIG_DEFAULTS, resolvedConfig;
17367
+ function getTracer() {
17368
+ return import_api.trace.getTracer(TRACER_NAME, TRACER_VERSION);
17369
+ }
17370
+ var import_api, CONFIG_DEFAULTS, TRACER_NAME = "@gobing-ai/ts-infra", TRACER_VERSION = "0.1.0", resolvedConfig;
17294
17371
  var init_sdk = __esm(() => {
17372
+ import_api = __toESM(require_src(), 1);
17295
17373
  CONFIG_DEFAULTS = {
17296
17374
  enabled: true,
17297
17375
  serviceName: "ts-libs",
@@ -17300,13 +17378,41 @@ var init_sdk = __esm(() => {
17300
17378
  resolvedConfig = getTelemetryConfig();
17301
17379
  });
17302
17380
 
17381
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.3.21+3246782889eb34e0/node_modules/@gobing-ai/ts-infra/dist/telemetry/tracing.js
17382
+ function isSuppressed(tracer) {
17383
+ return tracer === undefined && !getResolvedConfig().enabled;
17384
+ }
17385
+ function nonRecordingSpan() {
17386
+ return import_api2.trace.wrapSpanContext(import_api2.INVALID_SPAN_CONTEXT);
17387
+ }
17388
+ async function traceAsync(name, fn, options2, tracer) {
17389
+ if (isSuppressed(tracer))
17390
+ return fn(nonRecordingSpan());
17391
+ const resolvedTracer = tracer ?? getTracer();
17392
+ return resolvedTracer.startActiveSpan(name, options2 ?? {}, async (span) => {
17393
+ try {
17394
+ return await fn(span);
17395
+ } catch (err) {
17396
+ span.setStatus({ code: 2, message: err instanceof Error ? err.message : String(err) });
17397
+ throw err;
17398
+ } finally {
17399
+ span.end();
17400
+ }
17401
+ });
17402
+ }
17403
+ var import_api2;
17404
+ var init_tracing = __esm(() => {
17405
+ init_sdk();
17406
+ import_api2 = __toESM(require_src(), 1);
17407
+ });
17408
+
17303
17409
  // ../../node_modules/.bun/@gobing-ai+ts-infra@0.3.21+3246782889eb34e0/node_modules/@gobing-ai/ts-infra/dist/telemetry/metrics.js
17304
17410
  function getMeter() {
17305
- return import_api.metrics.getMeter(METER_NAME, METER_VERSION);
17411
+ return import_api3.metrics.getMeter(METER_NAME, METER_VERSION);
17306
17412
  }
17307
17413
  function noopCounter() {
17308
17414
  if (!_noopCounter)
17309
- _noopCounter = import_api.createNoopMeter().createCounter("noop");
17415
+ _noopCounter = import_api3.createNoopMeter().createCounter("noop");
17310
17416
  return _noopCounter;
17311
17417
  }
17312
17418
  function getOrCreateCounter(key, name, description, unit = "{operation}") {
@@ -17323,10 +17429,10 @@ function getEventbusEmitsTotal() {
17323
17429
  function getEventbusErrorsTotal() {
17324
17430
  return getOrCreateCounter("ebErr", "eventbus.errors.total", "Event bus errors", "{error}");
17325
17431
  }
17326
- var import_api, METER_NAME = "@gobing-ai/ts-infra", METER_VERSION = "0.1.0", instruments, _noopCounter;
17432
+ var import_api3, METER_NAME = "@gobing-ai/ts-infra", METER_VERSION = "0.1.0", instruments, _noopCounter;
17327
17433
  var init_metrics = __esm(() => {
17328
17434
  init_sdk();
17329
- import_api = __toESM(require_src(), 1);
17435
+ import_api3 = __toESM(require_src(), 1);
17330
17436
  instruments = {};
17331
17437
  });
17332
17438
 
@@ -17580,10 +17686,16 @@ var init_event_bus2 = __esm(() => {
17580
17686
  init_event_bus();
17581
17687
  });
17582
17688
 
17689
+ // ../../node_modules/.bun/@gobing-ai+ts-infra@0.3.21+3246782889eb34e0/node_modules/@gobing-ai/ts-infra/dist/telemetry/index.js
17690
+ var init_telemetry = __esm(() => {
17691
+ init_tracing();
17692
+ });
17693
+
17583
17694
  // ../../node_modules/.bun/@gobing-ai+ts-infra@0.3.21+3246782889eb34e0/node_modules/@gobing-ai/ts-infra/dist/index.js
17584
17695
  var init_dist3 = __esm(() => {
17585
17696
  init_event_bus2();
17586
17697
  init_logger2();
17698
+ init_telemetry();
17587
17699
  });
17588
17700
 
17589
17701
  // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.3.21+5a4f8cc6c6b198a4/node_modules/@gobing-ai/ts-ai-runner/dist/agents/shims.js
@@ -32516,7 +32628,7 @@ var init_config = __esm(() => {
32516
32628
  });
32517
32629
 
32518
32630
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.3.21/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
32519
- import { appendFileSync, cpSync as cpSync2, createWriteStream, existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync6, renameSync, rmSync as rmSync3, statSync as statSync5, writeFileSync as writeFileSync4 } from "fs";
32631
+ import { appendFileSync, cpSync as cpSync2, createWriteStream, existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync6, renameSync, rmSync as rmSync4, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
32520
32632
  import { dirname as dirname5, resolve as resolvePath } from "path";
32521
32633
  function createNodeFileSystem(root) {
32522
32634
  const projectRoot = root ?? findProjectRoot(process.cwd());
@@ -32538,7 +32650,7 @@ function createNodeFileSystem(root) {
32538
32650
  },
32539
32651
  readDir: (path) => readdirSync3(path),
32540
32652
  deleteFile: (path) => {
32541
- rmSync3(path, { recursive: true, force: true });
32653
+ rmSync4(path, { recursive: true, force: true });
32542
32654
  },
32543
32655
  rename: (src, dest) => {
32544
32656
  renameSync(src, dest);
@@ -32552,7 +32664,7 @@ function createNodeFileSystem(root) {
32552
32664
  },
32553
32665
  stat: (path) => {
32554
32666
  try {
32555
- const s = statSync5(path);
32667
+ const s = statSync4(path);
32556
32668
  return {
32557
32669
  isFile: () => s.isFile(),
32558
32670
  isDirectory: () => s.isDirectory(),
@@ -33518,12 +33630,12 @@ var require_isexe = __commonJS((exports, module) => {
33518
33630
  if (typeof Promise !== "function") {
33519
33631
  throw new TypeError("callback not provided");
33520
33632
  }
33521
- return new Promise(function(resolve2, reject) {
33633
+ return new Promise(function(resolve3, reject) {
33522
33634
  isexe(path, options2 || {}, function(er, is) {
33523
33635
  if (er) {
33524
33636
  reject(er);
33525
33637
  } else {
33526
- resolve2(is);
33638
+ resolve3(is);
33527
33639
  }
33528
33640
  });
33529
33641
  });
@@ -33585,27 +33697,27 @@ var require_which = __commonJS((exports, module) => {
33585
33697
  opt = {};
33586
33698
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
33587
33699
  const found = [];
33588
- const step = (i) => new Promise((resolve2, reject) => {
33700
+ const step = (i) => new Promise((resolve3, reject) => {
33589
33701
  if (i === pathEnv.length)
33590
- return opt.all && found.length ? resolve2(found) : reject(getNotFoundError(cmd));
33702
+ return opt.all && found.length ? resolve3(found) : reject(getNotFoundError(cmd));
33591
33703
  const ppRaw = pathEnv[i];
33592
33704
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
33593
33705
  const pCmd = path.join(pathPart, cmd);
33594
33706
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
33595
- resolve2(subStep(p, i, 0));
33707
+ resolve3(subStep(p, i, 0));
33596
33708
  });
33597
- const subStep = (p, i, ii) => new Promise((resolve2, reject) => {
33709
+ const subStep = (p, i, ii) => new Promise((resolve3, reject) => {
33598
33710
  if (ii === pathExt.length)
33599
- return resolve2(step(i + 1));
33711
+ return resolve3(step(i + 1));
33600
33712
  const ext = pathExt[ii];
33601
33713
  isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
33602
33714
  if (!er && is) {
33603
33715
  if (opt.all)
33604
33716
  found.push(p + ext);
33605
33717
  else
33606
- return resolve2(p + ext);
33718
+ return resolve3(p + ext);
33607
33719
  }
33608
- return resolve2(subStep(p, i, ii + 1));
33720
+ return resolve3(subStep(p, i, ii + 1));
33609
33721
  });
33610
33722
  });
33611
33723
  return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
@@ -34411,7 +34523,7 @@ var normalizeForceKillAfterDelay = (forceKillAfterDelay) => {
34411
34523
  throw new TypeError(`Expected the \`forceKillAfterDelay\` option to be a non-negative integer, got \`${forceKillAfterDelay}\` (${typeof forceKillAfterDelay})`);
34412
34524
  }
34413
34525
  return forceKillAfterDelay;
34414
- }, DEFAULT_FORCE_KILL_TIMEOUT, subprocessKill = ({ kill, options: { forceKillAfterDelay, killSignal }, onInternalError, context, controller }, signalOrError, errorArgument) => {
34526
+ }, DEFAULT_FORCE_KILL_TIMEOUT, subprocessKill = ({ kill, options: { forceKillAfterDelay, killSignal }, onInternalError, context: context2, controller }, signalOrError, errorArgument) => {
34415
34527
  const { signal, error: error51 } = parseKillArguments(signalOrError, errorArgument, killSignal);
34416
34528
  emitKillError(error51, onInternalError);
34417
34529
  const killResult = kill(signal);
@@ -34421,7 +34533,7 @@ var normalizeForceKillAfterDelay = (forceKillAfterDelay) => {
34421
34533
  forceKillAfterDelay,
34422
34534
  killSignal,
34423
34535
  killResult,
34424
- context,
34536
+ context: context2,
34425
34537
  controller
34426
34538
  });
34427
34539
  return killResult;
@@ -34438,23 +34550,23 @@ var normalizeForceKillAfterDelay = (forceKillAfterDelay) => {
34438
34550
  if (error51 !== undefined) {
34439
34551
  onInternalError.reject(error51);
34440
34552
  }
34441
- }, setKillTimeout = async ({ kill, signal, forceKillAfterDelay, killSignal, killResult, context, controller }) => {
34553
+ }, setKillTimeout = async ({ kill, signal, forceKillAfterDelay, killSignal, killResult, context: context2, controller }) => {
34442
34554
  if (signal === killSignal && killResult) {
34443
34555
  killOnTimeout({
34444
34556
  kill,
34445
34557
  forceKillAfterDelay,
34446
- context,
34558
+ context: context2,
34447
34559
  controllerSignal: controller.signal
34448
34560
  });
34449
34561
  }
34450
- }, killOnTimeout = async ({ kill, forceKillAfterDelay, context, controllerSignal }) => {
34562
+ }, killOnTimeout = async ({ kill, forceKillAfterDelay, context: context2, controllerSignal }) => {
34451
34563
  if (forceKillAfterDelay === false) {
34452
34564
  return;
34453
34565
  }
34454
34566
  try {
34455
34567
  await setTimeout2(forceKillAfterDelay, undefined, { signal: controllerSignal });
34456
34568
  if (kill("SIGKILL")) {
34457
- context.isForcefullyTerminated ??= true;
34569
+ context2.isForcefullyTerminated ??= true;
34458
34570
  }
34459
34571
  } catch {}
34460
34572
  };
@@ -34478,9 +34590,9 @@ var validateCancelSignal = ({ cancelSignal }) => {
34478
34590
  if (cancelSignal !== undefined && Object.prototype.toString.call(cancelSignal) !== "[object AbortSignal]") {
34479
34591
  throw new Error(`The \`cancelSignal\` option must be an AbortSignal: ${String(cancelSignal)}`);
34480
34592
  }
34481
- }, throwOnCancel = ({ subprocess, cancelSignal, gracefulCancel, context, controller }) => cancelSignal === undefined || gracefulCancel ? [] : [terminateOnCancel(subprocess, cancelSignal, context, controller)], terminateOnCancel = async (subprocess, cancelSignal, context, { signal }) => {
34593
+ }, throwOnCancel = ({ subprocess, cancelSignal, gracefulCancel, context: context2, controller }) => cancelSignal === undefined || gracefulCancel ? [] : [terminateOnCancel(subprocess, cancelSignal, context2, controller)], terminateOnCancel = async (subprocess, cancelSignal, context2, { signal }) => {
34482
34594
  await onAbortedSignal(cancelSignal, signal);
34483
- context.terminationReason ??= "cancel";
34595
+ context2.terminationReason ??= "cancel";
34484
34596
  subprocess.kill();
34485
34597
  throw cancelSignal.reason;
34486
34598
  };
@@ -34544,8 +34656,8 @@ var init_validation = __esm(() => {
34544
34656
  // ../../node_modules/.bun/execa@9.6.1/node_modules/execa/lib/utils/deferred.js
34545
34657
  var createDeferred = () => {
34546
34658
  const methods = {};
34547
- const promise2 = new Promise((resolve2, reject) => {
34548
- Object.assign(methods, { resolve: resolve2, reject });
34659
+ const promise2 = new Promise((resolve3, reject) => {
34660
+ Object.assign(methods, { resolve: resolve3, reject });
34549
34661
  });
34550
34662
  return Object.assign(promise2, methods);
34551
34663
  };
@@ -35005,25 +35117,25 @@ var validateGracefulCancel = ({ gracefulCancel, cancelSignal, ipc, serialization
35005
35117
  cancelSignal,
35006
35118
  gracefulCancel,
35007
35119
  forceKillAfterDelay,
35008
- context,
35120
+ context: context2,
35009
35121
  controller
35010
35122
  }) => gracefulCancel ? [sendOnAbort({
35011
35123
  subprocess,
35012
35124
  cancelSignal,
35013
35125
  forceKillAfterDelay,
35014
- context,
35126
+ context: context2,
35015
35127
  controller
35016
- })] : [], sendOnAbort = async ({ subprocess, cancelSignal, forceKillAfterDelay, context, controller: { signal } }) => {
35128
+ })] : [], sendOnAbort = async ({ subprocess, cancelSignal, forceKillAfterDelay, context: context2, controller: { signal } }) => {
35017
35129
  await onAbortedSignal(cancelSignal, signal);
35018
35130
  const reason = getReason(cancelSignal);
35019
35131
  await sendAbort(subprocess, reason);
35020
35132
  killOnTimeout({
35021
35133
  kill: subprocess.kill,
35022
35134
  forceKillAfterDelay,
35023
- context,
35135
+ context: context2,
35024
35136
  controllerSignal: signal
35025
35137
  });
35026
- context.terminationReason ??= "gracefulCancel";
35138
+ context2.terminationReason ??= "gracefulCancel";
35027
35139
  throw cancelSignal.reason;
35028
35140
  }, getReason = ({ reason }) => {
35029
35141
  if (!(reason instanceof DOMException)) {
@@ -35050,9 +35162,9 @@ var validateTimeout = ({ timeout }) => {
35050
35162
  if (timeout !== undefined && (!Number.isFinite(timeout) || timeout < 0)) {
35051
35163
  throw new TypeError(`Expected the \`timeout\` option to be a non-negative integer, got \`${timeout}\` (${typeof timeout})`);
35052
35164
  }
35053
- }, throwOnTimeout = (subprocess, timeout, context, controller) => timeout === 0 || timeout === undefined ? [] : [killAfterTimeout(subprocess, timeout, context, controller)], killAfterTimeout = async (subprocess, timeout, context, { signal }) => {
35165
+ }, throwOnTimeout = (subprocess, timeout, context2, controller) => timeout === 0 || timeout === undefined ? [] : [killAfterTimeout(subprocess, timeout, context2, controller)], killAfterTimeout = async (subprocess, timeout, context2, { signal }) => {
35054
35166
  await setTimeout3(timeout, undefined, { signal });
35055
- context.terminationReason ??= "timeout";
35167
+ context2.terminationReason ??= "timeout";
35056
35168
  subprocess.kill();
35057
35169
  throw new DiscardedError;
35058
35170
  };
@@ -35180,7 +35292,7 @@ var init_encoding_option = __esm(() => {
35180
35292
  });
35181
35293
 
35182
35294
  // ../../node_modules/.bun/execa@9.6.1/node_modules/execa/lib/arguments/cwd.js
35183
- import { statSync as statSync6 } from "fs";
35295
+ import { statSync as statSync5 } from "fs";
35184
35296
  import path4 from "path";
35185
35297
  import process6 from "process";
35186
35298
  var normalizeCwd = (cwd5 = getDefaultCwd()) => {
@@ -35200,7 +35312,7 @@ ${error51.message}`;
35200
35312
  }
35201
35313
  let cwdStat;
35202
35314
  try {
35203
- cwdStat = statSync6(cwd5);
35315
+ cwdStat = statSync5(cwd5);
35204
35316
  } catch (error51) {
35205
35317
  return `The "cwd" option is invalid: ${cwd5}.
35206
35318
  ${error51.message}
@@ -37409,9 +37521,9 @@ var init_all_sync = __esm(() => {
37409
37521
 
37410
37522
  // ../../node_modules/.bun/execa@9.6.1/node_modules/execa/lib/resolve/exit-async.js
37411
37523
  import { once as once4 } from "events";
37412
- var waitForExit = async (subprocess, context) => {
37524
+ var waitForExit = async (subprocess, context2) => {
37413
37525
  const [exitCode, signal] = await waitForExitOrError(subprocess);
37414
- context.isForcefullyTerminated ??= false;
37526
+ context2.isForcefullyTerminated ??= false;
37415
37527
  return [exitCode, signal];
37416
37528
  }, waitForExitOrError = async (subprocess) => {
37417
37529
  const [spawnPayload, exitPayload] = await Promise.allSettled([
@@ -39020,14 +39132,14 @@ var waitForSubprocessResult = async ({
39020
39132
  ipc,
39021
39133
  ipcInput
39022
39134
  },
39023
- context,
39135
+ context: context2,
39024
39136
  verboseInfo,
39025
39137
  fileDescriptors,
39026
39138
  originalStreams,
39027
39139
  onInternalError,
39028
39140
  controller
39029
39141
  }) => {
39030
- const exitPromise = waitForExit(subprocess, context);
39142
+ const exitPromise = waitForExit(subprocess, context2);
39031
39143
  const streamInfo = {
39032
39144
  originalStreams,
39033
39145
  fileDescriptors,
@@ -39080,12 +39192,12 @@ var waitForSubprocessResult = async ({
39080
39192
  ]),
39081
39193
  onInternalError,
39082
39194
  throwOnSubprocessError(subprocess, controller),
39083
- ...throwOnTimeout(subprocess, timeout, context, controller),
39195
+ ...throwOnTimeout(subprocess, timeout, context2, controller),
39084
39196
  ...throwOnCancel({
39085
39197
  subprocess,
39086
39198
  cancelSignal,
39087
39199
  gracefulCancel,
39088
- context,
39200
+ context: context2,
39089
39201
  controller
39090
39202
  }),
39091
39203
  ...throwOnGracefulCancel({
@@ -39093,12 +39205,12 @@ var waitForSubprocessResult = async ({
39093
39205
  cancelSignal,
39094
39206
  gracefulCancel,
39095
39207
  forceKillAfterDelay,
39096
- context,
39208
+ context: context2,
39097
39209
  controller
39098
39210
  })
39099
39211
  ]);
39100
39212
  } catch (error51) {
39101
- context.terminationReason ??= "other";
39213
+ context2.terminationReason ??= "other";
39102
39214
  return Promise.all([
39103
39215
  { error: error51 },
39104
39216
  exitPromise,
@@ -39144,10 +39256,10 @@ var initializeConcurrentStreams = () => ({
39144
39256
  const promises = weakMap.get(stream);
39145
39257
  const promise2 = createDeferred();
39146
39258
  promises.push(promise2);
39147
- const resolve2 = promise2.resolve.bind(promise2);
39148
- return { resolve: resolve2, promises };
39149
- }, waitForConcurrentStreams = async ({ resolve: resolve2, promises }, subprocess) => {
39150
- resolve2();
39259
+ const resolve3 = promise2.resolve.bind(promise2);
39260
+ return { resolve: resolve3, promises };
39261
+ }, waitForConcurrentStreams = async ({ resolve: resolve3, promises }, subprocess) => {
39262
+ resolve3();
39151
39263
  const [isSubprocessExit] = await Promise.race([
39152
39264
  Promise.allSettled([true, subprocess]),
39153
39265
  Promise.all([false, ...promises])
@@ -39529,13 +39641,13 @@ var execaCoreAsync = (rawFile, rawArguments, rawOptions, createNested) => {
39529
39641
  const originalStreams = [...subprocess.stdio];
39530
39642
  pipeOutputAsync(subprocess, fileDescriptors, controller);
39531
39643
  cleanupOnExit(subprocess, options2, controller);
39532
- const context = {};
39644
+ const context2 = {};
39533
39645
  const onInternalError = createDeferred();
39534
39646
  subprocess.kill = subprocessKill.bind(undefined, {
39535
39647
  kill: subprocess.kill.bind(subprocess),
39536
39648
  options: options2,
39537
39649
  onInternalError,
39538
- context,
39650
+ context: context2,
39539
39651
  controller
39540
39652
  });
39541
39653
  subprocess.all = makeAllStream(subprocess, options2);
@@ -39550,12 +39662,12 @@ var execaCoreAsync = (rawFile, rawArguments, rawOptions, createNested) => {
39550
39662
  originalStreams,
39551
39663
  command,
39552
39664
  escapedCommand,
39553
- context,
39665
+ context: context2,
39554
39666
  onInternalError,
39555
39667
  controller
39556
39668
  });
39557
39669
  return { subprocess, promise: promise2 };
39558
- }, handlePromise = async ({ subprocess, options: options2, startTime, verboseInfo, fileDescriptors, originalStreams, command, escapedCommand, context, onInternalError, controller }) => {
39670
+ }, handlePromise = async ({ subprocess, options: options2, startTime, verboseInfo, fileDescriptors, originalStreams, command, escapedCommand, context: context2, onInternalError, controller }) => {
39559
39671
  const [
39560
39672
  errorInfo,
39561
39673
  [exitCode, signal],
@@ -39565,7 +39677,7 @@ var execaCoreAsync = (rawFile, rawArguments, rawOptions, createNested) => {
39565
39677
  ] = await waitForSubprocessResult({
39566
39678
  subprocess,
39567
39679
  options: options2,
39568
- context,
39680
+ context: context2,
39569
39681
  verboseInfo,
39570
39682
  fileDescriptors,
39571
39683
  originalStreams,
@@ -39583,22 +39695,22 @@ var execaCoreAsync = (rawFile, rawArguments, rawOptions, createNested) => {
39583
39695
  stdio,
39584
39696
  all,
39585
39697
  ipcOutput,
39586
- context,
39698
+ context: context2,
39587
39699
  options: options2,
39588
39700
  command,
39589
39701
  escapedCommand,
39590
39702
  startTime
39591
39703
  });
39592
39704
  return handleResult2(result, verboseInfo, options2);
39593
- }, getAsyncResult = ({ errorInfo, exitCode, signal, stdio, all, ipcOutput, context, options: options2, command, escapedCommand, startTime }) => ("error" in errorInfo) ? makeError({
39705
+ }, getAsyncResult = ({ errorInfo, exitCode, signal, stdio, all, ipcOutput, context: context2, options: options2, command, escapedCommand, startTime }) => ("error" in errorInfo) ? makeError({
39594
39706
  error: errorInfo.error,
39595
39707
  command,
39596
39708
  escapedCommand,
39597
- timedOut: context.terminationReason === "timeout",
39598
- isCanceled: context.terminationReason === "cancel" || context.terminationReason === "gracefulCancel",
39599
- isGracefullyCanceled: context.terminationReason === "gracefulCancel",
39709
+ timedOut: context2.terminationReason === "timeout",
39710
+ isCanceled: context2.terminationReason === "cancel" || context2.terminationReason === "gracefulCancel",
39711
+ isGracefullyCanceled: context2.terminationReason === "gracefulCancel",
39600
39712
  isMaxBuffer: errorInfo.error instanceof MaxBufferError,
39601
- isForcefullyTerminated: context.isForcefullyTerminated,
39713
+ isForcefullyTerminated: context2.isForcefullyTerminated,
39602
39714
  exitCode,
39603
39715
  signal,
39604
39716
  stdio,
@@ -39903,18 +40015,18 @@ class ObservedPipeProcess {
39903
40015
  inner;
39904
40016
  killedWith;
39905
40017
  exited;
39906
- constructor(inner, events, context) {
40018
+ constructor(inner, events, context2) {
39907
40019
  this.inner = inner;
39908
40020
  this.exited = inner.exited.then((exitCode) => {
39909
40021
  events?.emit("process.exited", {
39910
- command: context.command,
39911
- args: context.args,
40022
+ command: context2.command,
40023
+ args: context2.args,
39912
40024
  exitCode,
39913
40025
  ...this.killedWith !== undefined ? { signal: String(this.killedWith) } : {},
39914
- durationMs: Date.now() - context.startedAt,
40026
+ durationMs: Date.now() - context2.startedAt,
39915
40027
  reason: this.killedWith !== undefined ? "signal" : "exit",
39916
40028
  timestamp: new Date().toISOString(),
39917
- ...context.label !== undefined ? { label: context.label } : {}
40029
+ ...context2.label !== undefined ? { label: context2.label } : {}
39918
40030
  });
39919
40031
  return exitCode;
39920
40032
  });
@@ -40001,8 +40113,11 @@ function isTimedOut(error51) {
40001
40113
  function errorMessage(error51) {
40002
40114
  return error51 instanceof Error ? error51.message : String(error51);
40003
40115
  }
40116
+ var NodeProcessExecutor;
40004
40117
  var init_process_executor = __esm(() => {
40005
40118
  init_execa();
40119
+ NodeProcessExecutor = class NodeProcessExecutor extends ProcessExecutor {
40120
+ };
40006
40121
  });
40007
40122
 
40008
40123
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.3.21/node_modules/@gobing-ai/ts-runtime/dist/context.js
@@ -40159,6 +40274,7 @@ var init_types3 = () => {};
40159
40274
  var init_dist4 = __esm(() => {
40160
40275
  init_file_system_node();
40161
40276
  init_process_executor();
40277
+ init_process_executor();
40162
40278
  init_config();
40163
40279
  init_context2();
40164
40280
  init_path();
@@ -40234,19 +40350,101 @@ var init_slash_command = __esm(() => {
40234
40350
  });
40235
40351
 
40236
40352
  // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.3.21+5a4f8cc6c6b198a4/node_modules/@gobing-ai/ts-ai-runner/dist/ai-runner.js
40353
+ class AiRunner {
40354
+ processExecutor;
40355
+ defaultCwd;
40356
+ defaultTimeout;
40357
+ logger;
40358
+ events;
40359
+ constructor(options2 = {}) {
40360
+ this.processExecutor = options2.processExecutor ?? new NodeProcessExecutor({
40361
+ ...options2.processEvents !== undefined ? {
40362
+ events: {
40363
+ emit: (event, detail) => {
40364
+ options2.processEvents?.emit(event, detail);
40365
+ }
40366
+ }
40367
+ } : {},
40368
+ tracer: options2.tracer ?? {
40369
+ traceAsync: async (name, fn) => await traceAsync(name, (span) => fn(span))
40370
+ }
40371
+ });
40372
+ this.defaultCwd = options2.defaultCwd;
40373
+ this.defaultTimeout = options2.defaultTimeout;
40374
+ this.logger = options2.logger ?? getLogger2("ai-runner");
40375
+ this.events = options2.events;
40376
+ }
40377
+ runHelpCommand(agent, options2 = {}) {
40378
+ return this.invoke(agent, "help", getAgentShim(agent).getHelpCommand(), options2, true);
40379
+ }
40380
+ runVersionCommand(agent, options2 = {}) {
40381
+ return this.invoke(agent, "version", getAgentShim(agent).getVersionCommand(), options2, true);
40382
+ }
40383
+ runPromptCommand(agent, promptOptions, options2 = {}) {
40384
+ return this.invoke(agent, "prompt", this.buildPromptCommand(agent, promptOptions, options2), options2, false);
40385
+ }
40386
+ runSlashCommand(agent, input, promptOptions, options2 = {}) {
40387
+ return this.runPromptCommand(agent, { ...promptOptions, input: translateSlashCommand(agent, input) }, options2);
40388
+ }
40389
+ buildPromptCommand(agent, promptOptions, options2 = {}) {
40390
+ return buildAgentCommand(agent, promptOptions, {
40391
+ workspace: options2.cwd ?? this.defaultCwd ?? getProcessCwd()
40392
+ });
40393
+ }
40394
+ runAuthCommand(agent, options2 = {}) {
40395
+ const command = getAgentShim(agent).getAuthCommand();
40396
+ return command === null ? null : this.invoke(agent, "auth", command, options2, true);
40397
+ }
40398
+ async invoke(agent, operation, command, options2, forceBuffered) {
40399
+ const label = `ai-runner.${agent}.${operation}`;
40400
+ this.logger.debug("invoke", { label, command: command.command, args: command.args.join(" ") });
40401
+ this.events?.emit("agent.invoke.start", { agent, operation, label });
40402
+ const result = await this.processExecutor.run({
40403
+ command: command.command,
40404
+ args: command.args,
40405
+ label,
40406
+ rejectOnError: false,
40407
+ forceBuffered,
40408
+ cwd: options2.cwd ?? this.defaultCwd,
40409
+ timeout: options2.timeout ?? this.defaultTimeout
40410
+ });
40411
+ if (result.exitCode !== 0) {
40412
+ this.logger.error("invoke exited non-zero", {
40413
+ label,
40414
+ exitCode: result.exitCode,
40415
+ signal: result.signal
40416
+ });
40417
+ }
40418
+ this.events?.emit("agent.invoke.exit", {
40419
+ agent,
40420
+ operation,
40421
+ label,
40422
+ exitCode: result.exitCode,
40423
+ ...result.signal !== undefined ? { signal: result.signal } : {},
40424
+ durationMs: result.durationMs
40425
+ });
40426
+ return {
40427
+ exitCode: result.exitCode,
40428
+ stdout: result.stdout,
40429
+ stderr: result.stderr,
40430
+ ...result.signal !== undefined ? { signal: result.signal } : {},
40431
+ durationMs: result.durationMs
40432
+ };
40433
+ }
40434
+ }
40237
40435
  function hasIdentityOptions(options2) {
40238
40436
  return options2.purpose !== undefined || options2.systemPrompt !== undefined || options2.taskId !== undefined || options2.peers !== undefined && options2.peers.length > 0;
40239
40437
  }
40240
- function buildAgentCommand(agent, promptOptions, context2) {
40241
- return getAgentShim(agent).getPromptCommand(applyIdentityPreamble(agent, promptOptions, context2));
40438
+ function buildAgentCommand(agent, promptOptions, context3) {
40439
+ return getAgentShim(agent).getPromptCommand(applyIdentityPreamble(agent, promptOptions, context3));
40242
40440
  }
40243
- function applyIdentityPreamble(agent, promptOptions, context2) {
40441
+ function applyIdentityPreamble(agent, promptOptions, context3) {
40244
40442
  if (!hasIdentityOptions(promptOptions))
40245
40443
  return promptOptions;
40246
40444
  const preamble = buildIdentityPreamble({
40247
40445
  agentId: agent,
40248
40446
  agentType: agent,
40249
- workspace: context2.workspace,
40447
+ workspace: context3.workspace,
40250
40448
  purpose: promptOptions.purpose,
40251
40449
  systemPrompt: promptOptions.systemPrompt,
40252
40450
  taskId: promptOptions.taskId,
@@ -40257,8 +40455,11 @@ ${promptOptions.input}`;
40257
40455
  return { ...promptOptions, input };
40258
40456
  }
40259
40457
  var init_ai_runner = __esm(() => {
40458
+ init_dist3();
40459
+ init_dist4();
40260
40460
  init_shims();
40261
40461
  init_identity2();
40462
+ init_slash_command();
40262
40463
  });
40263
40464
 
40264
40465
  // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.3.21+5a4f8cc6c6b198a4/node_modules/@gobing-ai/ts-ai-runner/dist/agent-detector.js
@@ -40409,8 +40610,8 @@ class TeamAgentProcess {
40409
40610
  this.warn("stdin close failed", "stop.endStdin", error51);
40410
40611
  }
40411
40612
  process11.kill("SIGTERM");
40412
- const timeout = new Promise((resolve2) => {
40413
- setTimeout(() => resolve2("timeout"), 5000);
40613
+ const timeout = new Promise((resolve3) => {
40614
+ setTimeout(() => resolve3("timeout"), 5000);
40414
40615
  });
40415
40616
  const result = await Promise.race([process11.exited, timeout]);
40416
40617
  if (result === "timeout") {
@@ -40628,7 +40829,7 @@ var init_dist5 = __esm(() => {
40628
40829
  });
40629
40830
 
40630
40831
  // ../../packages/core/src/targets.ts
40631
- var TARGETS, TARGET_TO_RULESYNC, TARGET_SKILLS_RELDIR, TARGET_TO_AGENT_NAME;
40832
+ var TARGETS, TARGET_TO_RULESYNC, TARGET_TO_RULESYNC_HOOKS, TARGET_SKILLS_RELDIR, TARGET_TO_AGENT_NAME;
40632
40833
  var init_targets = __esm(() => {
40633
40834
  TARGETS = [
40634
40835
  "claude",
@@ -40647,6 +40848,12 @@ var init_targets = __esm(() => {
40647
40848
  "antigravity-cli": "codexcli",
40648
40849
  "antigravity-ide": "codexcli"
40649
40850
  };
40851
+ TARGET_TO_RULESYNC_HOOKS = {
40852
+ codex: "codexcli",
40853
+ opencode: "opencode",
40854
+ "antigravity-cli": "antigravity-cli",
40855
+ "antigravity-ide": "antigravity-ide"
40856
+ };
40650
40857
  TARGET_SKILLS_RELDIR = {
40651
40858
  codex: ".agents/skills",
40652
40859
  pi: ".agents/skills",
@@ -40766,7 +40973,7 @@ function scoreSkillLinkage(body) {
40766
40973
  function scoreModelFit(data) {
40767
40974
  const model = data.model;
40768
40975
  const recognizedAliases = { inherit: true, sonnet: true, opus: true, haiku: true };
40769
- const wellFormedPattern = /^claude-(sonnet|opus|haiku)-/i;
40976
+ const wellFormedPattern = /^claude-(\d+-\d+-)?(sonnet|opus|haiku)-/i;
40770
40977
  let score;
40771
40978
  let note;
40772
40979
  if (typeof model === "string") {
@@ -40957,6 +41164,127 @@ var init_command3 = __esm(() => {
40957
41164
  init_types2();
40958
41165
  });
40959
41166
 
41167
+ // ../../packages/core/src/quality/eval-cases.ts
41168
+ import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
41169
+ import { join as join8 } from "path";
41170
+ function isRuleJudge(value) {
41171
+ return typeof value === "object" && value !== null && "checks" in value && Array.isArray(value.checks);
41172
+ }
41173
+ function isRubricRef(value) {
41174
+ return typeof value === "object" && value !== null && "criterion" in value && typeof value.criterion === "string" && !("checks" in value);
41175
+ }
41176
+ function resolveEvalCasesPath(name, opts) {
41177
+ if (opts?.path) {
41178
+ if (!existsSync10(opts.path))
41179
+ return null;
41180
+ return opts.path;
41181
+ }
41182
+ assertSafePathSegment(name, "eval cases skill name");
41183
+ const coLocated = join8(process.cwd(), "skills", name, "eval", "cases.yaml");
41184
+ if (existsSync10(coLocated))
41185
+ return coLocated;
41186
+ return null;
41187
+ }
41188
+ function loadEvalCases(name, opts) {
41189
+ const resolvedPath = resolveEvalCasesPath(name, opts);
41190
+ if (!resolvedPath)
41191
+ return null;
41192
+ const raw = readFileSync9(resolvedPath, "utf-8");
41193
+ let parsed;
41194
+ try {
41195
+ parsed = $parse(raw);
41196
+ } catch (e) {
41197
+ throw new EvalCaseError(resolvedPath, null, `Failed to parse YAML: ${e instanceof Error ? e.message : String(e)}`);
41198
+ }
41199
+ const result = EvalCaseSetSchema.safeParse(parsed);
41200
+ if (!result.success) {
41201
+ const issue2 = result.error.issues[0];
41202
+ if (!issue2) {
41203
+ throw new EvalCaseError(resolvedPath, null, "Schema validation failed with no issue reported.");
41204
+ }
41205
+ const caseId = extractCaseIdFromPath(issue2.path, parsed);
41206
+ const field = issue2.path.length > 0 ? issue2.path.join(".") : "root";
41207
+ throw new EvalCaseError(resolvedPath, caseId, `Schema validation failed at "${field}": ${issue2.message}`);
41208
+ }
41209
+ const caseSet = result.data;
41210
+ const seen = new Set;
41211
+ for (const c3 of caseSet.cases) {
41212
+ if (seen.has(c3.id)) {
41213
+ throw new EvalCaseError(resolvedPath, c3.id, `Duplicate case id "${c3.id}"`);
41214
+ }
41215
+ seen.add(c3.id);
41216
+ }
41217
+ return caseSet;
41218
+ }
41219
+ function extractCaseIdFromPath(path7, parsed) {
41220
+ const casesIdx = path7.indexOf("cases");
41221
+ if (casesIdx >= 0 && path7.length > casesIdx + 1 && typeof path7[casesIdx + 1] === "number") {
41222
+ const caseIndex = path7[casesIdx + 1];
41223
+ if (typeof parsed === "object" && parsed !== null && "cases" in parsed && Array.isArray(parsed.cases)) {
41224
+ const candidate = parsed.cases[caseIndex];
41225
+ if (typeof candidate === "object" && candidate !== null && "id" in candidate && typeof candidate.id === "string") {
41226
+ return candidate.id;
41227
+ }
41228
+ }
41229
+ return `cases[${caseIndex}]`;
41230
+ }
41231
+ return null;
41232
+ }
41233
+ var RuleCheckSchema, RubricRefSchema, RuleJudgeSchema, EvalCaseSchema, EvalCaseSetSchema, EvalCaseError;
41234
+ var init_eval_cases = __esm(() => {
41235
+ init_dist2();
41236
+ init_zod();
41237
+ init_identity();
41238
+ RuleCheckSchema = exports_external.object({
41239
+ op: exports_external.enum(["contains", "regex", "equals", "not_contains", "tool_called"]),
41240
+ arg: exports_external.string().min(1)
41241
+ });
41242
+ RubricRefSchema = exports_external.object({
41243
+ criterion: exports_external.string().min(1),
41244
+ excellent: exports_external.string().optional(),
41245
+ poor: exports_external.string().optional()
41246
+ });
41247
+ RuleJudgeSchema = exports_external.object({
41248
+ checks: exports_external.array(RuleCheckSchema).min(1)
41249
+ });
41250
+ EvalCaseSchema = exports_external.object({
41251
+ id: exports_external.string().min(1),
41252
+ split: exports_external.enum(["train", "holdout"]),
41253
+ prompt: exports_external.string().min(1),
41254
+ reference_kind: exports_external.enum(["exact", "rule", "rubric"]),
41255
+ reference: exports_external.union([exports_external.string().min(1), RuleJudgeSchema, RubricRefSchema]),
41256
+ tags: exports_external.array(exports_external.string().min(1)).optional()
41257
+ }).refine((c3) => {
41258
+ if (c3.reference_kind === "exact" && typeof c3.reference !== "string") {
41259
+ return false;
41260
+ }
41261
+ if (c3.reference_kind === "rule" && !isRuleJudge(c3.reference)) {
41262
+ return false;
41263
+ }
41264
+ if (c3.reference_kind === "rubric" && !isRubricRef(c3.reference)) {
41265
+ return false;
41266
+ }
41267
+ return true;
41268
+ }, {
41269
+ message: 'reference must match reference_kind: string for "exact", RuleJudge for "rule", RubricRef for "rubric"'
41270
+ });
41271
+ EvalCaseSetSchema = exports_external.object({
41272
+ version: exports_external.literal(1),
41273
+ cases: exports_external.array(EvalCaseSchema).min(1)
41274
+ });
41275
+ EvalCaseError = class EvalCaseError extends Error {
41276
+ file;
41277
+ caseId;
41278
+ constructor(file2, caseId, message) {
41279
+ const prefix = caseId ? `${file2}: case "${caseId}" \u2014 ` : `${file2}: `;
41280
+ super(`${prefix}${message}`);
41281
+ this.file = file2;
41282
+ this.caseId = caseId;
41283
+ this.name = "EvalCaseError";
41284
+ }
41285
+ };
41286
+ });
41287
+
40960
41288
  // ../../packages/core/src/quality/magent.ts
40961
41289
  function scoreCompleteness3(body) {
40962
41290
  let found = 0;
@@ -40993,7 +41321,7 @@ function scorePlatformCoverage(data, body) {
40993
41321
  [/opencode/i, "opencode"],
40994
41322
  [/openclaw/i, "openclaw"],
40995
41323
  [/antigravity/i, "antigravity"],
40996
- [/pi\b/i, "pi"]
41324
+ [/\bpi\b/i, "pi"]
40997
41325
  ];
40998
41326
  for (const [re, name] of platformPatterns) {
40999
41327
  if (re.test(body))
@@ -41038,7 +41366,9 @@ function scoreSafety2(body) {
41038
41366
  }
41039
41367
  function evaluateMagent(content, target) {
41040
41368
  const body = extractBody(content);
41041
- const hasFrontmatter = /^---\s*$/m.test(content);
41369
+ const hasFrontmatter = content.startsWith(`---
41370
+ `) || content.startsWith(`---\r
41371
+ `);
41042
41372
  const fmResult = hasFrontmatter ? parseFrontmatterSafe(content) : undefined;
41043
41373
  const data = fmResult ?? {};
41044
41374
  const fmNote = hasFrontmatter && fmResult === null ? parseErrorNote(content, "Frontmatter parse error") : null;
@@ -41180,7 +41510,7 @@ function countTriggerPhrases(body) {
41180
41510
  if (headingMatch) {
41181
41511
  const depth = headingMatch[1]?.length ?? 0;
41182
41512
  const title = (headingMatch[2] ?? "").toLowerCase();
41183
- if (/\btrigger|when to use/i.test(title)) {
41513
+ if (/\b(?:trigger|when to use)/i.test(title)) {
41184
41514
  inTriggerSection = true;
41185
41515
  sectionDepth = depth;
41186
41516
  } else if (inTriggerSection && depth <= sectionDepth) {
@@ -41196,7 +41526,7 @@ function countTriggerPhrases(body) {
41196
41526
  }
41197
41527
  if (count2 === 0) {
41198
41528
  for (const line of lines) {
41199
- if (/^\s*[-*+]\s/.test(line)) {
41529
+ if (/^\s*[-*+]\s/.test(line) || /^\s*\d+[.)]\s/.test(line)) {
41200
41530
  count2++;
41201
41531
  }
41202
41532
  }
@@ -41228,29 +41558,77 @@ var init_evaluate = __esm(() => {
41228
41558
  };
41229
41559
  });
41230
41560
 
41561
+ // ../../packages/core/src/quality/replay.ts
41562
+ function scoreExact(output2, reference) {
41563
+ const normOut = normalize(output2);
41564
+ const normRef = normalize(reference);
41565
+ if (normOut === normRef)
41566
+ return 1;
41567
+ if (normOut.includes(normRef))
41568
+ return 1;
41569
+ return 0;
41570
+ }
41571
+ function scoreRule(output2, judge, toolsCalled) {
41572
+ for (const check2 of judge.checks) {
41573
+ if (!evaluateCheck(output2, check2.op, check2.arg, toolsCalled))
41574
+ return 0;
41575
+ }
41576
+ return 1;
41577
+ }
41578
+ function aggregateHard(scores) {
41579
+ if (scores.length === 0)
41580
+ return 0;
41581
+ const sum = scores.reduce((acc, s) => acc + s, 0);
41582
+ return sum / scores.length;
41583
+ }
41584
+ function normalize(text) {
41585
+ return text.trim().toLowerCase().replace(/\s+/g, " ");
41586
+ }
41587
+ function evaluateCheck(output2, op, arg, toolsCalled) {
41588
+ switch (op) {
41589
+ case "contains":
41590
+ return output2.toLowerCase().includes(arg.toLowerCase());
41591
+ case "regex": {
41592
+ try {
41593
+ return new RegExp(arg).test(output2);
41594
+ } catch {
41595
+ return false;
41596
+ }
41597
+ }
41598
+ case "equals":
41599
+ return normalize(output2) === normalize(arg);
41600
+ case "not_contains":
41601
+ return !output2.toLowerCase().includes(arg.toLowerCase());
41602
+ case "tool_called":
41603
+ return (toolsCalled ?? []).includes(arg);
41604
+ default:
41605
+ return false;
41606
+ }
41607
+ }
41608
+
41231
41609
  // ../../packages/core/src/quality/rubric.ts
41232
- import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
41233
- import { homedir as homedir3 } from "os";
41234
- import { join as join8 } from "path";
41610
+ import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
41611
+ import { homedir as homedir4 } from "os";
41612
+ import { join as join9 } from "path";
41235
41613
  function resolveRubricContent(type, opts) {
41236
41614
  if (opts?.path) {
41237
- if (!existsSync10(opts.path)) {
41615
+ if (!existsSync11(opts.path)) {
41238
41616
  throw new RubricError("path", `Rubric file not found: ${opts.path}`, opts.path);
41239
41617
  }
41240
- return readFileSync9(opts.path, "utf-8");
41618
+ return readFileSync10(opts.path, "utf-8");
41241
41619
  }
41242
- const homeDir = process.env.HOME ?? homedir3();
41243
- const userPath = join8(homeDir, ".superskill", "rubrics", `${type}.yaml`);
41244
- if (existsSync10(userPath)) {
41245
- return readFileSync9(userPath, "utf-8");
41620
+ const homeDir = process.env.HOME || homedir4();
41621
+ const userPath = join9(homeDir, ".superskill", "rubrics", `${type}.yaml`);
41622
+ if (existsSync11(userPath)) {
41623
+ return readFileSync10(userPath, "utf-8");
41246
41624
  }
41247
- const devPath = join8(import.meta.dir, "..", "rubrics", `${type}.yaml`);
41248
- if (existsSync10(devPath)) {
41249
- return readFileSync9(devPath, "utf-8");
41625
+ const devPath = join9(import.meta.dir, "..", "rubrics", `${type}.yaml`);
41626
+ if (existsSync11(devPath)) {
41627
+ return readFileSync10(devPath, "utf-8");
41250
41628
  }
41251
- const prodPath = join8(import.meta.dir, "..", "..", "rubrics", `${type}.yaml`);
41252
- if (existsSync10(prodPath)) {
41253
- return readFileSync9(prodPath, "utf-8");
41629
+ const prodPath = join9(import.meta.dir, "..", "..", "rubrics", `${type}.yaml`);
41630
+ if (existsSync11(prodPath)) {
41631
+ return readFileSync10(prodPath, "utf-8");
41254
41632
  }
41255
41633
  throw new RubricError("path", `No rubric found for type "${type}". Searched: ${opts?.path ?? "(no explicit path)"}, ${userPath}, ${devPath}, ${prodPath}`, type);
41256
41634
  }
@@ -47079,11 +47457,11 @@ var require_out = __commonJS((exports) => {
47079
47457
  async.read(path7, getSettings(optionsOrSettingsOrCallback), callback);
47080
47458
  }
47081
47459
  exports.stat = stat;
47082
- function statSync7(path7, optionsOrSettings) {
47460
+ function statSync6(path7, optionsOrSettings) {
47083
47461
  const settings = getSettings(optionsOrSettings);
47084
47462
  return sync.read(path7, settings);
47085
47463
  }
47086
- exports.statSync = statSync7;
47464
+ exports.statSync = statSync6;
47087
47465
  function getSettings(settingsOrOptions = {}) {
47088
47466
  if (settingsOrOptions instanceof settings_1.default) {
47089
47467
  return settingsOrOptions;
@@ -47487,11 +47865,11 @@ var require_reusify = __commonJS((exports, module) => {
47487
47865
  // ../../node_modules/.bun/fastq@1.20.1/node_modules/fastq/queue.js
47488
47866
  var require_queue = __commonJS((exports, module) => {
47489
47867
  var reusify = require_reusify();
47490
- function fastqueue(context2, worker, _concurrency) {
47491
- if (typeof context2 === "function") {
47868
+ function fastqueue(context3, worker, _concurrency) {
47869
+ if (typeof context3 === "function") {
47492
47870
  _concurrency = worker;
47493
- worker = context2;
47494
- context2 = null;
47871
+ worker = context3;
47872
+ context3 = null;
47495
47873
  }
47496
47874
  if (!(_concurrency >= 1)) {
47497
47875
  throw new Error("fastqueue concurrency must be equal to or greater than 1");
@@ -47578,7 +47956,7 @@ var require_queue = __commonJS((exports, module) => {
47578
47956
  }
47579
47957
  function push(value, done) {
47580
47958
  var current = cache.get();
47581
- current.context = context2;
47959
+ current.context = context3;
47582
47960
  current.release = release;
47583
47961
  current.value = value;
47584
47962
  current.callback = done || noop4;
@@ -47594,12 +47972,12 @@ var require_queue = __commonJS((exports, module) => {
47594
47972
  }
47595
47973
  } else {
47596
47974
  _running++;
47597
- worker.call(context2, current.value, current.worked);
47975
+ worker.call(context3, current.value, current.worked);
47598
47976
  }
47599
47977
  }
47600
47978
  function unshift(value, done) {
47601
47979
  var current = cache.get();
47602
- current.context = context2;
47980
+ current.context = context3;
47603
47981
  current.release = release;
47604
47982
  current.value = value;
47605
47983
  current.callback = done || noop4;
@@ -47615,7 +47993,7 @@ var require_queue = __commonJS((exports, module) => {
47615
47993
  }
47616
47994
  } else {
47617
47995
  _running++;
47618
- worker.call(context2, current.value, current.worked);
47996
+ worker.call(context3, current.value, current.worked);
47619
47997
  }
47620
47998
  }
47621
47999
  function release(holder) {
@@ -47630,7 +48008,7 @@ var require_queue = __commonJS((exports, module) => {
47630
48008
  }
47631
48009
  queueHead = next.next;
47632
48010
  next.next = null;
47633
- worker.call(context2, next.value, next.worked);
48011
+ worker.call(context3, next.value, next.worked);
47634
48012
  if (queueTail === null) {
47635
48013
  self2.empty();
47636
48014
  }
@@ -47661,14 +48039,14 @@ var require_queue = __commonJS((exports, module) => {
47661
48039
  var callback = current.callback;
47662
48040
  var errorHandler2 = current.errorHandler;
47663
48041
  var val = current.value;
47664
- var context3 = current.context;
48042
+ var context4 = current.context;
47665
48043
  current.value = null;
47666
48044
  current.callback = noop4;
47667
48045
  current.errorHandler = null;
47668
48046
  if (errorHandler2) {
47669
48047
  errorHandler2(new Error("abort"), val);
47670
48048
  }
47671
- callback.call(context3, new Error("abort"));
48049
+ callback.call(context4, new Error("abort"));
47672
48050
  current.release(current);
47673
48051
  current = next;
47674
48052
  }
@@ -47700,18 +48078,18 @@ var require_queue = __commonJS((exports, module) => {
47700
48078
  self2.release(self2);
47701
48079
  };
47702
48080
  }
47703
- function queueAsPromised(context2, worker, _concurrency) {
47704
- if (typeof context2 === "function") {
48081
+ function queueAsPromised(context3, worker, _concurrency) {
48082
+ if (typeof context3 === "function") {
47705
48083
  _concurrency = worker;
47706
- worker = context2;
47707
- context2 = null;
48084
+ worker = context3;
48085
+ context3 = null;
47708
48086
  }
47709
48087
  function asyncWrapper(arg, cb) {
47710
48088
  worker.call(this, arg).then(function(res) {
47711
48089
  cb(null, res);
47712
48090
  }, cb);
47713
48091
  }
47714
- var queue = fastqueue(context2, asyncWrapper, _concurrency);
48092
+ var queue = fastqueue(context3, asyncWrapper, _concurrency);
47715
48093
  var pushCb = queue.push;
47716
48094
  var unshiftCb = queue.unshift;
47717
48095
  queue.push = push;
@@ -47719,42 +48097,42 @@ var require_queue = __commonJS((exports, module) => {
47719
48097
  queue.drained = drained;
47720
48098
  return queue;
47721
48099
  function push(value) {
47722
- var p = new Promise(function(resolve2, reject) {
48100
+ var p = new Promise(function(resolve3, reject) {
47723
48101
  pushCb(value, function(err, result) {
47724
48102
  if (err) {
47725
48103
  reject(err);
47726
48104
  return;
47727
48105
  }
47728
- resolve2(result);
48106
+ resolve3(result);
47729
48107
  });
47730
48108
  });
47731
48109
  p.catch(noop4);
47732
48110
  return p;
47733
48111
  }
47734
48112
  function unshift(value) {
47735
- var p = new Promise(function(resolve2, reject) {
48113
+ var p = new Promise(function(resolve3, reject) {
47736
48114
  unshiftCb(value, function(err, result) {
47737
48115
  if (err) {
47738
48116
  reject(err);
47739
48117
  return;
47740
48118
  }
47741
- resolve2(result);
48119
+ resolve3(result);
47742
48120
  });
47743
48121
  });
47744
48122
  p.catch(noop4);
47745
48123
  return p;
47746
48124
  }
47747
48125
  function drained() {
47748
- var p = new Promise(function(resolve2) {
48126
+ var p = new Promise(function(resolve3) {
47749
48127
  process.nextTick(function() {
47750
48128
  if (queue.idle()) {
47751
- resolve2();
48129
+ resolve3();
47752
48130
  } else {
47753
48131
  var previousDrain = queue.drain;
47754
48132
  queue.drain = function() {
47755
48133
  if (typeof previousDrain === "function")
47756
48134
  previousDrain();
47757
- resolve2();
48135
+ resolve3();
47758
48136
  queue.drain = previousDrain;
47759
48137
  };
47760
48138
  }
@@ -48215,9 +48593,9 @@ var require_stream3 = __commonJS((exports) => {
48215
48593
  });
48216
48594
  }
48217
48595
  _getStat(filepath) {
48218
- return new Promise((resolve2, reject) => {
48596
+ return new Promise((resolve3, reject) => {
48219
48597
  this._stat(filepath, this._fsStatSettings, (error51, stats) => {
48220
- return error51 === null ? resolve2(stats) : reject(error51);
48598
+ return error51 === null ? resolve3(stats) : reject(error51);
48221
48599
  });
48222
48600
  });
48223
48601
  }
@@ -48239,10 +48617,10 @@ var require_async5 = __commonJS((exports) => {
48239
48617
  this._readerStream = new stream_1.default(this._settings);
48240
48618
  }
48241
48619
  dynamic(root, options2) {
48242
- return new Promise((resolve2, reject) => {
48620
+ return new Promise((resolve3, reject) => {
48243
48621
  this._walkAsync(root, options2, (error51, entries) => {
48244
48622
  if (error51 === null) {
48245
- resolve2(entries);
48623
+ resolve3(entries);
48246
48624
  } else {
48247
48625
  reject(error51);
48248
48626
  }
@@ -48252,10 +48630,10 @@ var require_async5 = __commonJS((exports) => {
48252
48630
  async static(patterns, options2) {
48253
48631
  const entries = [];
48254
48632
  const stream = this._readerStream.static(patterns, options2);
48255
- return new Promise((resolve2, reject) => {
48633
+ return new Promise((resolve3, reject) => {
48256
48634
  stream.once("error", reject);
48257
48635
  stream.on("data", (entry) => entries.push(entry));
48258
- stream.once("end", () => resolve2(entries));
48636
+ stream.once("end", () => resolve3(entries));
48259
48637
  });
48260
48638
  }
48261
48639
  }
@@ -49783,7 +50161,7 @@ var import_fast_glob2, import_ignore, defaultIgnoredDirectories, ignoreFilesGlob
49783
50161
  }
49784
50162
  throw createGitConfigReadError(normalizedPath, error51);
49785
50163
  }
49786
- }, getExcludesFileFromGitConfigSync = (filePath, readFileSync10, gitDirectory, options2 = {}) => {
50164
+ }, getExcludesFileFromGitConfigSync = (filePath, readFileSync11, gitDirectory, options2 = {}) => {
49787
50165
  const { suppressErrors, includeStack = new Set, depth = 0 } = options2;
49788
50166
  const normalizedPath = path9.resolve(filePath);
49789
50167
  if (includeStack.has(normalizedPath)) {
@@ -49793,14 +50171,14 @@ var import_fast_glob2, import_ignore, defaultIgnoredDirectories, ignoreFilesGlob
49793
50171
  return;
49794
50172
  }
49795
50173
  includeStack.add(normalizedPath);
49796
- const content = readGitConfigFile(normalizedPath, readFileSync10, suppressErrors);
50174
+ const content = readGitConfigFile(normalizedPath, readFileSync11, suppressErrors);
49797
50175
  if (content === undefined) {
49798
50176
  includeStack.delete(normalizedPath);
49799
50177
  return;
49800
50178
  }
49801
50179
  let { excludesFile, includePaths } = parseGitConfigForExcludesFile(content, normalizedPath, gitDirectory);
49802
50180
  for (const includePath of includePaths) {
49803
- const includedExcludesFile = getExcludesFileFromGitConfigSync(includePath, readFileSync10, gitDirectory, { suppressErrors, includeStack, depth: depth + 1 });
50181
+ const includedExcludesFile = getExcludesFileFromGitConfigSync(includePath, readFileSync11, gitDirectory, { suppressErrors, includeStack, depth: depth + 1 });
49804
50182
  if (includedExcludesFile !== undefined) {
49805
50183
  excludesFile = includedExcludesFile;
49806
50184
  }
@@ -49842,13 +50220,13 @@ var import_fast_glob2, import_ignore, defaultIgnoredDirectories, ignoreFilesGlob
49842
50220
  return gitFilePath;
49843
50221
  }
49844
50222
  return path9.resolve(path9.dirname(gitFilePath), match[1]);
49845
- }, getGitDirectorySync = (gitRoot, readFileSync10) => {
50223
+ }, getGitDirectorySync = (gitRoot, readFileSync11) => {
49846
50224
  if (!gitRoot) {
49847
50225
  return;
49848
50226
  }
49849
50227
  const gitFilePath = path9.join(gitRoot, ".git");
49850
50228
  try {
49851
- return resolveGitDirectoryFromFile(gitFilePath, readFileSync10(gitFilePath, "utf8"));
50229
+ return resolveGitDirectoryFromFile(gitFilePath, readFileSync11(gitFilePath, "utf8"));
49852
50230
  } catch {
49853
50231
  return gitFilePath;
49854
50232
  }
@@ -49891,18 +50269,18 @@ var import_fast_glob2, import_ignore, defaultIgnoredDirectories, ignoreFilesGlob
49891
50269
  }
49892
50270
  }, getGlobalGitignoreFile = (options2 = {}) => {
49893
50271
  const cwd5 = toPath2(options2.cwd) ?? process11.cwd();
49894
- const readFileSync10 = getReadFileSyncMethod(options2.fs);
50272
+ const readFileSync11 = getReadFileSyncMethod(options2.fs);
49895
50273
  const gitRoot = findGitRootSync(cwd5, options2.fs);
49896
- const gitDirectory = getGitDirectorySync(gitRoot, readFileSync10);
50274
+ const gitDirectory = getGitDirectorySync(gitRoot, readFileSync11);
49897
50275
  let excludesFileConfig;
49898
50276
  for (const gitConfigPath of getGitConfigPaths()) {
49899
- const value = getExcludesFileFromGitConfigSync(gitConfigPath, readFileSync10, gitDirectory, { suppressErrors: options2.suppressErrors });
50277
+ const value = getExcludesFileFromGitConfigSync(gitConfigPath, readFileSync11, gitDirectory, { suppressErrors: options2.suppressErrors });
49900
50278
  if (value !== undefined) {
49901
50279
  excludesFileConfig = value;
49902
50280
  }
49903
50281
  }
49904
50282
  const filePath = resolveExcludesFilePath(excludesFileConfig);
49905
- return filePath === undefined ? undefined : readGlobalGitignoreContent(filePath, readFileSync10, options2.suppressErrors);
50283
+ return filePath === undefined ? undefined : readGlobalGitignoreContent(filePath, readFileSync11, options2.suppressErrors);
49906
50284
  }, getGlobalGitignoreFileAsync = async (options2 = {}) => {
49907
50285
  const cwd5 = toPath2(options2.cwd) ?? process11.cwd();
49908
50286
  const readFile = getReadFileMethod(options2.fs);
@@ -58242,7 +58620,7 @@ import {
58242
58620
  writeFile
58243
58621
  } from "fs/promises";
58244
58622
  import os2 from "os";
58245
- import { dirname as dirname6, isAbsolute, join as join22, relative, resolve as resolve2 } from "path";
58623
+ import { dirname as dirname6, isAbsolute, join as join22, relative, resolve as resolve4 } from "path";
58246
58624
  import { isAbsolute as isAbsolute2, resolve as resolve22 } from "path";
58247
58625
  import { basename as basename3, join as join44, relative as relative3 } from "path";
58248
58626
  import { extname as extname2 } from "path";
@@ -58250,8 +58628,8 @@ import { isDeepStrictEqual } from "util";
58250
58628
  import { join as join62 } from "path";
58251
58629
  import { join as join42 } from "path";
58252
58630
  import { join as join52 } from "path";
58253
- import path10, { relative as relative2, resolve as resolve4 } from "path";
58254
- import { basename as basename4, join as join9 } from "path";
58631
+ import path10, { relative as relative2, resolve as resolve42 } from "path";
58632
+ import { basename as basename4, join as join92 } from "path";
58255
58633
  import { join as join72 } from "path";
58256
58634
  import { join as join82 } from "path";
58257
58635
  import { join as join10 } from "path";
@@ -58335,7 +58713,7 @@ import { join as join88 } from "path";
58335
58713
  import { join as join89 } from "path";
58336
58714
  import { join as join90 } from "path";
58337
58715
  import { join as join91 } from "path";
58338
- import { join as join92 } from "path";
58716
+ import { join as join922 } from "path";
58339
58717
  import { join as join93 } from "path";
58340
58718
  import { join as join94 } from "path";
58341
58719
  import { join as join95 } from "path";
@@ -58510,9 +58888,9 @@ function checkPathTraversal({
58510
58888
  if (segments.includes("..")) {
58511
58889
  throw new Error(`Path traversal detected: ${relativePath}`);
58512
58890
  }
58513
- const resolved = resolve2(intendedRootDir, relativePath);
58891
+ const resolved = resolve4(intendedRootDir, relativePath);
58514
58892
  const rel = relative(intendedRootDir, resolved);
58515
- if (rel.startsWith("..") || resolve2(resolved) !== resolved) {
58893
+ if (rel.startsWith("..") || resolve4(resolved) !== resolved) {
58516
58894
  throw new Error(`Path traversal detected: ${relativePath}`);
58517
58895
  }
58518
58896
  }
@@ -58520,7 +58898,7 @@ function resolvePath3(relativePath, outputRoot) {
58520
58898
  if (!outputRoot)
58521
58899
  return relativePath;
58522
58900
  checkPathTraversal({ relativePath, intendedRootDir: outputRoot });
58523
- return resolve2(outputRoot, relativePath);
58901
+ return resolve4(outputRoot, relativePath);
58524
58902
  }
58525
58903
  async function directoryExists(dirPath) {
58526
58904
  try {
@@ -58633,7 +59011,7 @@ function validateOutputRoot(outputRoot) {
58633
59011
  if (segments.includes("..")) {
58634
59012
  throw new Error(`Path traversal detected: ${outputRoot}`);
58635
59013
  }
58636
- const normalized = resolve2(outputRoot);
59014
+ const normalized = resolve4(outputRoot);
58637
59015
  if (normalized !== outputRoot) {
58638
59016
  throw new Error(`outputRoot must be a normalized absolute path: ${outputRoot} (normalized: ${normalized})`);
58639
59017
  }
@@ -63025,8 +63403,8 @@ var import_gray_matter, BaseLogger = class {
63025
63403
  }
63026
63404
  getFilePath() {
63027
63405
  const fullPath = path10.join(this.outputRoot, this.relativeDirPath, this.relativeFilePath);
63028
- const resolvedFull = resolve4(fullPath);
63029
- const resolvedBase = resolve4(this.outputRoot);
63406
+ const resolvedFull = resolve42(fullPath);
63407
+ const resolvedBase = resolve42(this.outputRoot);
63030
63408
  const rel = relative2(resolvedBase, resolvedFull);
63031
63409
  if (rel.startsWith("..") || path10.isAbsolute(rel)) {
63032
63410
  throw new Error(`Path traversal detected: Final path escapes outputRoot. outputRoot="${this.outputRoot}", relativeDirPath="${this.relativeDirPath}", relativeFilePath="${this.relativeFilePath}"`);
@@ -63958,7 +64336,7 @@ var init_chunk_QKQNZ6C3 = __esm(() => {
63958
64336
  if (rest2.validate) {
63959
64337
  const result = AntigravityCommandFrontmatterSchema.safeParse(frontmatter);
63960
64338
  if (!result.success) {
63961
- throw new Error(`Invalid frontmatter in ${join9(rest2.relativeDirPath, rest2.relativeFilePath)}: ${formatError2(result.error)}`);
64339
+ throw new Error(`Invalid frontmatter in ${join92(rest2.relativeDirPath, rest2.relativeFilePath)}: ${formatError2(result.error)}`);
63962
64340
  }
63963
64341
  }
63964
64342
  super({
@@ -64054,7 +64432,7 @@ ${body}${turboDirective}`;
64054
64432
  } else {
64055
64433
  return {
64056
64434
  success: false,
64057
- error: new Error(`Invalid frontmatter in ${join9(this.relativeDirPath, this.relativeFilePath)}: ${formatError2(result.error)}`)
64435
+ error: new Error(`Invalid frontmatter in ${join92(this.relativeDirPath, this.relativeFilePath)}: ${formatError2(result.error)}`)
64058
64436
  };
64059
64437
  }
64060
64438
  }
@@ -64069,7 +64447,7 @@ ${body}${turboDirective}`;
64069
64447
  relativeFilePath,
64070
64448
  validate: validate2 = true
64071
64449
  }) {
64072
- const filePath = join9(outputRoot, _AntigravityCommand.getSettablePaths().relativeDirPath, relativeFilePath);
64450
+ const filePath = join92(outputRoot, _AntigravityCommand.getSettablePaths().relativeDirPath, relativeFilePath);
64073
64451
  const fileContent = await readFileContent(filePath);
64074
64452
  const { frontmatter, body: content } = parseFrontmatter2(fileContent, filePath);
64075
64453
  const result = AntigravityCommandFrontmatterSchema.safeParse(frontmatter);
@@ -71258,7 +71636,7 @@ prompt = ""`;
71258
71636
  try {
71259
71637
  this.json = JSON.parse(this.fileContent);
71260
71638
  } catch (error51) {
71261
- throw new Error(`Failed to parse Cursor MCP config at ${join92(this.relativeDirPath, this.relativeFilePath)}: ${formatError2(error51)}`, { cause: error51 });
71639
+ throw new Error(`Failed to parse Cursor MCP config at ${join922(this.relativeDirPath, this.relativeFilePath)}: ${formatError2(error51)}`, { cause: error51 });
71262
71640
  }
71263
71641
  } else {
71264
71642
  this.json = {};
@@ -71282,13 +71660,13 @@ prompt = ""`;
71282
71660
  global: global3 = false
71283
71661
  }) {
71284
71662
  const paths = this.getSettablePaths({ global: global3 });
71285
- const filePath = join92(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
71663
+ const filePath = join922(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
71286
71664
  const fileContent = await readFileContentOrNull(filePath) ?? '{"mcpServers":{}}';
71287
71665
  let json3;
71288
71666
  try {
71289
71667
  json3 = JSON.parse(fileContent);
71290
71668
  } catch (error51) {
71291
- throw new Error(`Failed to parse Cursor MCP config at ${join92(paths.relativeDirPath, paths.relativeFilePath)}: ${formatError2(error51)}`, { cause: error51 });
71669
+ throw new Error(`Failed to parse Cursor MCP config at ${join922(paths.relativeDirPath, paths.relativeFilePath)}: ${formatError2(error51)}`, { cause: error51 });
71292
71670
  }
71293
71671
  const newJson = { ...json3, mcpServers: json3.mcpServers ?? {} };
71294
71672
  return new _CursorMcp({
@@ -71307,12 +71685,12 @@ prompt = ""`;
71307
71685
  global: global3 = false
71308
71686
  }) {
71309
71687
  const paths = this.getSettablePaths({ global: global3 });
71310
- const fileContent = await readOrInitializeFileContent(join92(outputRoot, paths.relativeDirPath, paths.relativeFilePath), JSON.stringify({ mcpServers: {} }, null, 2));
71688
+ const fileContent = await readOrInitializeFileContent(join922(outputRoot, paths.relativeDirPath, paths.relativeFilePath), JSON.stringify({ mcpServers: {} }, null, 2));
71311
71689
  let json3;
71312
71690
  try {
71313
71691
  json3 = JSON.parse(fileContent);
71314
71692
  } catch (error51) {
71315
- throw new Error(`Failed to parse Cursor MCP config at ${join92(paths.relativeDirPath, paths.relativeFilePath)}: ${formatError2(error51)}`, { cause: error51 });
71693
+ throw new Error(`Failed to parse Cursor MCP config at ${join922(paths.relativeDirPath, paths.relativeFilePath)}: ${formatError2(error51)}`, { cause: error51 });
71316
71694
  }
71317
71695
  const mcpServers = rulesyncMcp.getMcpServers();
71318
71696
  const transformedServers = convertEnvVarRefsToToolFormat({
@@ -89292,11 +89670,12 @@ var init_dist9 = __esm(() => {
89292
89670
  });
89293
89671
 
89294
89672
  // ../../packages/core/src/rulesync.ts
89295
- import { homedir as homedir4 } from "os";
89673
+ import { homedir as homedir5 } from "os";
89296
89674
  async function runRulesync(targets, features, inputRoot, options2) {
89675
+ const targetMap = options2.targetMap ?? TARGET_TO_RULESYNC;
89297
89676
  const mappedTargets = [];
89298
89677
  for (const target of targets) {
89299
- const rt = TARGET_TO_RULESYNC[target];
89678
+ const rt = targetMap[target];
89300
89679
  if (rt)
89301
89680
  mappedTargets.push(rt);
89302
89681
  }
@@ -89322,7 +89701,7 @@ async function runRulesync(targets, features, inputRoot, options2) {
89322
89701
  hasDiff: false
89323
89702
  };
89324
89703
  }
89325
- const root = options2.outputRoot ?? (options2.global ? homedir4() : process.cwd());
89704
+ const root = options2.outputRoot ?? (options2.global ? homedir5() : process.cwd());
89326
89705
  const rulesyncGlobal = options2.outputRoot ? false : options2.global;
89327
89706
  return generate2({
89328
89707
  targets: mappedTargets,
@@ -89361,6 +89740,7 @@ var init_src = __esm(() => {
89361
89740
  init_slash_command2();
89362
89741
  init_agent();
89363
89742
  init_command3();
89743
+ init_eval_cases();
89364
89744
  init_evaluate();
89365
89745
  init_heuristics();
89366
89746
  init_hook();
@@ -89740,7 +90120,7 @@ var init_version = () => {};
89740
90120
 
89741
90121
  // ../../node_modules/.bun/drizzle-orm@0.44.7+a0473b45aab9bf33/node_modules/drizzle-orm/tracing.js
89742
90122
  var otel, rawTracer, tracer;
89743
- var init_tracing = __esm(() => {
90123
+ var init_tracing2 = __esm(() => {
89744
90124
  init_tracing_utils();
89745
90125
  init_version();
89746
90126
  tracer = {
@@ -89830,7 +90210,7 @@ var init_sql = __esm(() => {
89830
90210
  init_entity();
89831
90211
  init_enum();
89832
90212
  init_subquery();
89833
- init_tracing();
90213
+ init_tracing2();
89834
90214
  init_view_common();
89835
90215
  init_column();
89836
90216
  init_table();
@@ -94967,13 +95347,13 @@ __export(exports_db, {
94967
95347
  openStore: () => openStore,
94968
95348
  getDBPath: () => getDBPath
94969
95349
  });
94970
- import { existsSync as existsSync11, mkdirSync as mkdirSync6 } from "fs";
95350
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6 } from "fs";
94971
95351
  import { dirname as dirname7 } from "path";
94972
95352
  async function openStore(opts) {
94973
95353
  const url3 = getDBPath(opts);
94974
95354
  if (url3 !== ":memory:") {
94975
95355
  const dir = dirname7(url3);
94976
- if (!existsSync11(dir)) {
95356
+ if (!existsSync12(dir)) {
94977
95357
  mkdirSync6(dir, { recursive: true });
94978
95358
  }
94979
95359
  }
@@ -95000,7 +95380,7 @@ var init_db2 = __esm(() => {
95000
95380
  });
95001
95381
 
95002
95382
  // src/cli.ts
95003
- import { readFileSync as readFileSync15 } from "fs";
95383
+ import { readFileSync as readFileSync16 } from "fs";
95004
95384
  import { join as join226 } from "path";
95005
95385
 
95006
95386
  // ../../node_modules/.bun/commander@14.0.3/node_modules/commander/esm.mjs
@@ -95026,7 +95406,7 @@ init_dist();
95026
95406
  init_src();
95027
95407
  init_dist();
95028
95408
  init_db2();
95029
- import { readFileSync as readFileSync10 } from "fs";
95409
+ import { readFileSync as readFileSync11 } from "fs";
95030
95410
 
95031
95411
  // src/store/evaluations.ts
95032
95412
  init_dist10();
@@ -95222,7 +95602,7 @@ async function ingestScores(type, resolvedPath, resolvedTarget, opts) {
95222
95602
  }
95223
95603
  let raw;
95224
95604
  try {
95225
- raw = readFileSync10(ingestPath, "utf-8");
95605
+ raw = readFileSync11(ingestPath, "utf-8");
95226
95606
  } catch {
95227
95607
  throw Object.assign(new Error(`Cannot read scores file: ${ingestPath}`), { code: 2 });
95228
95608
  }
@@ -95342,7 +95722,7 @@ function formatEvaluationReport(report, json3) {
95342
95722
  // src/operations/evolve.ts
95343
95723
  init_src();
95344
95724
  init_dist();
95345
- import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync11, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
95725
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync12, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
95346
95726
  import { join as join220 } from "path";
95347
95727
  import { createInterface } from "readline";
95348
95728
 
@@ -95410,6 +95790,149 @@ function deserializeProposal(row) {
95410
95790
  };
95411
95791
  }
95412
95792
 
95793
+ // src/operations/pairwise-judge.ts
95794
+ init_src();
95795
+ init_dist5();
95796
+ class TsAiRunnerJudgeBackend {
95797
+ runner;
95798
+ agent;
95799
+ constructor(agent2 = "claude", runner) {
95800
+ this.runner = runner ?? new AiRunner;
95801
+ this.agent = agent2;
95802
+ }
95803
+ async judge(rubric2, prompt, candOutput, baseOutput, options2) {
95804
+ const candidateFirst = options2?.order !== "baseline-first";
95805
+ const outputA = candidateFirst ? candOutput : baseOutput;
95806
+ const outputB = candidateFirst ? baseOutput : candOutput;
95807
+ const systemPrompt = [
95808
+ "You are a strict pairwise behavior judge.",
95809
+ "Compare two outputs for the same task against the rubric criterion.",
95810
+ 'Return only JSON: {"winner":"A"|"B"|"tie","margin":number}.',
95811
+ "The margin must be a number from 0 to 1."
95812
+ ].join(`
95813
+ `);
95814
+ const input = [
95815
+ `Criterion: ${rubric2.criterion}`,
95816
+ rubric2.excellent ? `Excellent anchor: ${rubric2.excellent}` : "",
95817
+ rubric2.poor ? `Poor anchor: ${rubric2.poor}` : "",
95818
+ `Task prompt:
95819
+ ${prompt}`,
95820
+ `Output A:
95821
+ ${outputA}`,
95822
+ `Output B:
95823
+ ${outputB}`
95824
+ ].filter(Boolean).join(`
95825
+
95826
+ `);
95827
+ const result = await this.runner.runPromptCommand(this.agent, {
95828
+ input,
95829
+ systemPrompt,
95830
+ ...options2?.seed !== undefined ? { seed: options2.seed } : {},
95831
+ ...options2?.temperature !== undefined ? { temperature: options2.temperature } : {}
95832
+ });
95833
+ return parseJudgeResponse(result.stdout, candidateFirst);
95834
+ }
95835
+ }
95836
+ function createJudgeBackend(target, injected) {
95837
+ return injected ?? new TsAiRunnerJudgeBackend(TARGET_TO_AGENT_NAME[target]);
95838
+ }
95839
+ async function pairwiseJudge(backend, rubric2, casePrompt, candOutput, baseOutput, options2 = {}) {
95840
+ const order = options2.order ?? (options2.seed !== undefined && options2.seed % 2 === 1 ? "baseline-first" : "candidate-first");
95841
+ return backend.judge(rubric2, casePrompt, candOutput, baseOutput, { ...options2, order });
95842
+ }
95843
+ function signedMargin(verdict) {
95844
+ if (verdict.winner === "candidate")
95845
+ return verdict.margin;
95846
+ if (verdict.winner === "baseline")
95847
+ return -verdict.margin;
95848
+ return 0;
95849
+ }
95850
+ function parseJudgeResponse(stdout, candidateFirst) {
95851
+ let parsed;
95852
+ try {
95853
+ parsed = JSON.parse(stdout.trim());
95854
+ } catch {
95855
+ throw new Error(`Pairwise judge returned invalid JSON: ${stdout.slice(0, 200)}`);
95856
+ }
95857
+ if (typeof parsed !== "object" || parsed === null) {
95858
+ throw new Error("Pairwise judge returned a non-object JSON payload.");
95859
+ }
95860
+ const value = parsed;
95861
+ if (value.winner !== "A" && value.winner !== "B" && value.winner !== "tie") {
95862
+ throw new Error('Pairwise judge JSON must include winner "A", "B", or "tie".');
95863
+ }
95864
+ if (typeof value.margin !== "number" || value.margin < 0 || value.margin > 1) {
95865
+ throw new Error("Pairwise judge JSON must include margin in [0,1].");
95866
+ }
95867
+ if (value.winner === "tie")
95868
+ return { winner: "tie", margin: 0 };
95869
+ if (value.winner === "A") {
95870
+ return { winner: candidateFirst ? "candidate" : "baseline", margin: value.margin };
95871
+ }
95872
+ return { winner: candidateFirst ? "baseline" : "candidate", margin: value.margin };
95873
+ }
95874
+
95875
+ // src/operations/noise-floor.ts
95876
+ async function estimateNoiseFloor(judge, rubric2, casePrompt, candOutput, baseOutput, n2 = 5) {
95877
+ const margins = [];
95878
+ for (let i2 = 0;i2 < n2; i2++) {
95879
+ const verdict = await pairwiseJudge(judge, rubric2, casePrompt, candOutput, baseOutput, {
95880
+ seed: i2 + 1,
95881
+ temperature: 0
95882
+ });
95883
+ margins.push(signedMargin(verdict));
95884
+ }
95885
+ if (margins.length < 2)
95886
+ return 0;
95887
+ const mean2 = margins.reduce((a2, b) => a2 + b, 0) / margins.length;
95888
+ const variance = margins.reduce((sum2, m) => sum2 + (m - mean2) ** 2, 0) / margins.length;
95889
+ return Math.sqrt(variance);
95890
+ }
95891
+ function rejectsWithinNoise(measuredDelta, noiseFloor) {
95892
+ return Math.abs(measuredDelta) < noiseFloor;
95893
+ }
95894
+
95895
+ // src/operations/replay-runner.ts
95896
+ init_src();
95897
+ init_dist5();
95898
+ class TsAiRunnerBackend {
95899
+ runner;
95900
+ agent;
95901
+ constructor(agent2 = "claude", runner) {
95902
+ this.runner = runner ?? new AiRunner;
95903
+ this.agent = agent2;
95904
+ }
95905
+ async run(systemPrompt, userPrompt) {
95906
+ const result = await this.runner.runPromptCommand(this.agent, {
95907
+ input: userPrompt,
95908
+ systemPrompt
95909
+ });
95910
+ return result.stdout;
95911
+ }
95912
+ }
95913
+ function createReplayBackend(target, injected) {
95914
+ return injected ?? new TsAiRunnerBackend(TARGET_TO_AGENT_NAME[target]);
95915
+ }
95916
+ async function replayCase(backend, skill2, ev, toolsCalled) {
95917
+ const prompt = `[case:${ev.id}] ${ev.prompt}`;
95918
+ const output2 = await backend.run(skill2, prompt);
95919
+ let hard;
95920
+ if (ev.reference_kind === "exact") {
95921
+ hard = scoreExact(output2, ev.reference);
95922
+ } else {
95923
+ hard = scoreRule(output2, ev.reference, toolsCalled);
95924
+ }
95925
+ return { hard, output: output2 };
95926
+ }
95927
+ async function replaySplit(backend, skill2, cases, split, toolsCalled) {
95928
+ const splitCases = cases.filter((c3) => c3.split === split);
95929
+ if (splitCases.length === 0)
95930
+ return { hard: 0, n: 0 };
95931
+ const results = await Promise.all(splitCases.map((c3) => replayCase(backend, skill2, c3, toolsCalled)));
95932
+ const scores = results.map((r) => r.hard);
95933
+ return { hard: aggregateHard(scores), n: splitCases.length };
95934
+ }
95935
+
95413
95936
  // src/operations/validate.ts
95414
95937
  init_src();
95415
95938
 
@@ -95591,6 +96114,106 @@ async function runGate(input) {
95591
96114
  reason: `\u0394-margin gate failed: \u0394${delta >= 0 ? "+" : ""}${delta.toFixed(2)} < required margin ${input.margin.toFixed(2)}.`
95592
96115
  };
95593
96116
  }
96117
+ let empiricalScores;
96118
+ if (input.evalGate) {
96119
+ const cases = loadEvalCases(input.evalGate.name);
96120
+ if (cases) {
96121
+ const holdout = cases.cases.filter((c3) => c3.split === "holdout");
96122
+ const rubricCases = holdout.filter((c3) => c3.reference_kind === "rubric");
96123
+ const detCases = holdout.filter((c3) => c3.reference_kind !== "rubric");
96124
+ const maxModelCalls = input.evalGate.judgeBudget?.maxModelCalls ?? Number.POSITIVE_INFINITY;
96125
+ let modelCalls = 0;
96126
+ const consumeModelCalls = (count3, reason) => {
96127
+ modelCalls += count3;
96128
+ if (modelCalls > maxModelCalls) {
96129
+ return {
96130
+ ok: false,
96131
+ failedGate: "empirical",
96132
+ reason: `Empirical gate budget cap hit: ${modelCalls} model call(s) for ${reason} exceeds max ${maxModelCalls}.`
96133
+ };
96134
+ }
96135
+ return null;
96136
+ };
96137
+ const replayBackend = createReplayBackend(input.evalGate.target, input.evalGate.replayBackend);
96138
+ let detBaseScore = 0;
96139
+ let detCandScore = 0;
96140
+ let detN = 0;
96141
+ if (detCases.length > 0) {
96142
+ const budgetResult = consumeModelCalls(detCases.length * 2, "deterministic replay");
96143
+ if (budgetResult)
96144
+ return budgetResult;
96145
+ const baseDet = await replaySplit(replayBackend, input.evalGate.baselineSkillText, detCases, "holdout");
96146
+ const candDet = await replaySplit(replayBackend, input.evalGate.candidateSkillText, detCases, "holdout");
96147
+ detBaseScore = baseDet.hard;
96148
+ detCandScore = candDet.hard;
96149
+ detN = detCases.length;
96150
+ }
96151
+ let rubricBaseScore = 0;
96152
+ let rubricCandScore = 0;
96153
+ let maxNoiseFloor = 0;
96154
+ let signedDeltaTotal = 0;
96155
+ let rubricN = 0;
96156
+ if (rubricCases.length > 0) {
96157
+ const judge = createJudgeBackend(input.evalGate.target, input.evalGate.judgeBackend);
96158
+ const judgeReplays = input.evalGate.judgeReplays ?? 3;
96159
+ for (const rc of rubricCases) {
96160
+ const replayBudget = consumeModelCalls(2, `rubric replay for ${rc.id}`);
96161
+ if (replayBudget)
96162
+ return replayBudget;
96163
+ const prompt = `[case:${rc.id}] ${rc.prompt}`;
96164
+ const [candOutput, baseOutput] = await Promise.all([
96165
+ replayBackend.run(input.evalGate.candidateSkillText, prompt),
96166
+ replayBackend.run(input.evalGate.baselineSkillText, prompt)
96167
+ ]);
96168
+ const rubricRef = rc.reference;
96169
+ const judgeBudget = consumeModelCalls(1, `pairwise rubric judge for ${rc.id}`);
96170
+ if (judgeBudget)
96171
+ return judgeBudget;
96172
+ const verdict = await pairwiseJudge(judge, rubricRef, prompt, candOutput, baseOutput, {
96173
+ seed: 0,
96174
+ temperature: 0
96175
+ });
96176
+ const noiseBudget = consumeModelCalls(judgeReplays, `noise-floor replay for ${rc.id}`);
96177
+ if (noiseBudget)
96178
+ return noiseBudget;
96179
+ const noiseFloor = await estimateNoiseFloor(judge, rubricRef, prompt, candOutput, baseOutput, judgeReplays);
96180
+ const delta2 = signedMargin(verdict);
96181
+ maxNoiseFloor = Math.max(maxNoiseFloor, noiseFloor);
96182
+ signedDeltaTotal += delta2;
96183
+ if (rejectsWithinNoise(delta2, noiseFloor)) {
96184
+ rubricCandScore += 0.5;
96185
+ rubricBaseScore += 0.5;
96186
+ } else if (verdict.winner === "candidate") {
96187
+ rubricCandScore += 1;
96188
+ } else if (verdict.winner === "baseline") {
96189
+ rubricBaseScore += 1;
96190
+ } else {
96191
+ rubricCandScore += 0.5;
96192
+ rubricBaseScore += 0.5;
96193
+ }
96194
+ rubricN++;
96195
+ }
96196
+ }
96197
+ const totalN = detN + rubricN;
96198
+ const baseHard = totalN > 0 ? (detBaseScore * detN + rubricBaseScore / Math.max(rubricN, 1) * rubricN) / totalN : 0;
96199
+ const candHard = totalN > 0 ? (detCandScore * detN + rubricCandScore / Math.max(rubricN, 1) * rubricN) / totalN : 0;
96200
+ const rubricDelta = rubricN > 0 ? signedDeltaTotal / rubricN : undefined;
96201
+ if (!(candHard > baseHard && candHard - baseHard >= input.evalGate.margin)) {
96202
+ return {
96203
+ ok: false,
96204
+ failedGate: "empirical",
96205
+ reason: `Empirical gate failed: candidate behavior ${candHard.toFixed(2)} \u2264 baseline ${baseHard.toFixed(2)} (margin ${input.evalGate.margin.toFixed(2)}${rubricDelta !== undefined ? `, rubric_delta=${rubricDelta.toFixed(2)}, noise_floor=${maxNoiseFloor.toFixed(2)}` : ""}).`
96206
+ };
96207
+ }
96208
+ const trainCases = cases.cases.filter((c3) => c3.split === "train");
96209
+ empiricalScores = {
96210
+ hard: candHard,
96211
+ holdout_n: totalN,
96212
+ train_n: trainCases.length,
96213
+ ...rubricN > 0 ? { noise_floor: maxNoiseFloor, rubric_delta: rubricDelta ?? 0 } : {}
96214
+ };
96215
+ }
96216
+ }
95594
96217
  if (input.ingestedAnchorHash !== undefined && input.baselineAnchorHash !== undefined) {
95595
96218
  if (input.ingestedAnchorHash !== input.baselineAnchorHash) {
95596
96219
  return {
@@ -95608,7 +96231,7 @@ async function runGate(input) {
95608
96231
  reason: `Skeptic gate failed: the Skeptic reported an anchor/invariant violation.${violations}`
95609
96232
  };
95610
96233
  }
95611
- return { ok: true };
96234
+ return { ok: true, ...empiricalScores ? { empirical: empiricalScores } : {} };
95612
96235
  }
95613
96236
  function emitGenerationEnvelope(type, resolvedPath, content, baseline, trends) {
95614
96237
  const rubric2 = loadRubric(type);
@@ -95666,7 +96289,7 @@ function emitGenerationEnvelope(type, resolvedPath, content, baseline, trends) {
95666
96289
  async function ingestProposal(db2, type, name, resolvedPath, ingestPath, opts, baselineScore) {
95667
96290
  let raw;
95668
96291
  try {
95669
- raw = readFileSync11(ingestPath, "utf-8");
96292
+ raw = readFileSync12(ingestPath, "utf-8");
95670
96293
  } catch {
95671
96294
  throw Object.assign(new Error(`Cannot read proposal file: ${ingestPath}`), { code: 2 });
95672
96295
  }
@@ -95708,10 +96331,22 @@ async function ingestProposal(db2, type, name, resolvedPath, ingestPath, opts, b
95708
96331
  if (opts?.acceptId) {
95709
96332
  const backupPath = await backupFile(resolvedPath);
95710
96333
  const appliedCount = await stepApply(parsed.changes, resolvedPath, proposalRecord.id, db2);
96334
+ const evalGate = opts?.evalGate ? {
96335
+ name,
96336
+ candidateSkillText: await Bun.file(resolvedPath).text(),
96337
+ baselineSkillText: readFileSync12(backupPath, "utf-8"),
96338
+ margin: opts?.margin ?? 0.05,
96339
+ target: opts?.target ?? "claude",
96340
+ replayBackend: opts?.replayBackend,
96341
+ judgeBackend: opts?.judgeBackend,
96342
+ judgeReplays: opts?.judgeReplays,
96343
+ judgeBudget: opts?.judgeBudget
96344
+ } : undefined;
95711
96345
  const verdict = await stepVerify(type, name, resolvedPath, baselineScore, proposalRecord.id, opts, db2, {
95712
96346
  backupPath,
95713
96347
  ingestedAnchorHash: parsed.anchor_hash,
95714
- skeptic: parsed.skeptic
96348
+ skeptic: parsed.skeptic,
96349
+ evalGate
95715
96350
  });
95716
96351
  if (!verdict.rejected && verdict.backupPath) {
95717
96352
  await persistVersionSnapshot(verdict.backupPath, resolvedPath, proposalId);
@@ -95928,7 +96563,7 @@ async function stepVerify(type, name, filePath, baselineScore, proposalDbId, opt
95928
96563
  const delta = postScore - baselineScore;
95929
96564
  if (gate) {
95930
96565
  const margin = opts?.margin ?? 0.05;
95931
- const baselineAnchorHash = gate.ingestedAnchorHash !== undefined ? computeBaselineAnchorHash(readFileSync11(gate.backupPath, "utf-8")) : undefined;
96566
+ const baselineAnchorHash = gate.ingestedAnchorHash !== undefined ? computeBaselineAnchorHash(readFileSync12(gate.backupPath, "utf-8")) : undefined;
95932
96567
  const gateResult = await runGate({
95933
96568
  type,
95934
96569
  resolvedPath: filePath,
@@ -95937,7 +96572,8 @@ async function stepVerify(type, name, filePath, baselineScore, proposalDbId, opt
95937
96572
  margin,
95938
96573
  ingestedAnchorHash: gate.ingestedAnchorHash,
95939
96574
  baselineAnchorHash,
95940
- skeptic: gate.skeptic
96575
+ skeptic: gate.skeptic,
96576
+ evalGate: gate.evalGate
95941
96577
  });
95942
96578
  if (!gateResult.ok) {
95943
96579
  await restoreFromBackup(gate.backupPath, filePath);
@@ -95945,6 +96581,31 @@ async function stepVerify(type, name, filePath, baselineScore, proposalDbId, opt
95945
96581
  echoError(`Gate rejected proposal \u2014 ${gateResult.reason} File restored; proposal stays draft.`);
95946
96582
  return { postScore: baselineScore, delta: 0, rejected: true, reason: gateResult.reason };
95947
96583
  }
96584
+ if (gateResult.empirical) {
96585
+ try {
96586
+ await new EvaluationDao(db2).insertEvaluation({
96587
+ content_type: type,
96588
+ content_name: name,
96589
+ target_agent: opts?.target ?? "claude",
96590
+ operation: "evolve",
96591
+ aggregate: gateResult.empirical.hard,
96592
+ dimensions: {
96593
+ empirical: {
96594
+ score: gateResult.empirical.hard,
96595
+ hard: gateResult.empirical.hard,
96596
+ holdout_n: gateResult.empirical.holdout_n,
96597
+ train_n: gateResult.empirical.train_n,
96598
+ ...gateResult.empirical.noise_floor !== undefined ? { noise_floor: gateResult.empirical.noise_floor } : {},
96599
+ ...gateResult.empirical.rubric_delta !== undefined ? { rubric_delta: gateResult.empirical.rubric_delta } : {},
96600
+ note: `Behavior gate: holdout_n=${gateResult.empirical.holdout_n}, train_n=${gateResult.empirical.train_n}${gateResult.empirical.noise_floor !== undefined ? `, noise_floor=${gateResult.empirical.noise_floor.toFixed(2)}` : ""}${gateResult.empirical.rubric_delta !== undefined ? `, rubric_delta=${gateResult.empirical.rubric_delta.toFixed(2)}` : ""}`
96601
+ }
96602
+ }
96603
+ });
96604
+ echo(`Empirical behavior: holdout ${gateResult.empirical.hard.toFixed(2)} (holdout_n=${gateResult.empirical.holdout_n}, train_n=${gateResult.empirical.train_n}${gateResult.empirical.noise_floor !== undefined ? `, noise_floor=${gateResult.empirical.noise_floor.toFixed(2)}` : ""})`);
96605
+ } catch {
96606
+ echoError("Cannot persist empirical behavior score.");
96607
+ }
96608
+ }
95948
96609
  }
95949
96610
  try {
95950
96611
  const verifyEval = await new EvaluationDao(db2).getLatestEvaluation(type, name);
@@ -95974,7 +96635,7 @@ function formatAnalyze(name, analysis) {
95974
96635
  const { trends, baselineScore, baselineDate, evaluations: evaluations2 } = analysis;
95975
96636
  const grade = scoreToGrade(baselineScore);
95976
96637
  const verdict = baselineScore >= 0.7 ? "PASS" : "FAIL";
95977
- const gitAvailable = existsSync12(join220(process.cwd(), ".git"));
96638
+ const gitAvailable = existsSync13(join220(process.cwd(), ".git"));
95978
96639
  const lines = [];
95979
96640
  lines.push("=== Evolution Analysis ===");
95980
96641
  lines.push(`Target: ${name} Score: ${(baselineScore * 100).toFixed(0)}% (${grade}) Status: ${verdict}`);
@@ -96004,12 +96665,12 @@ function formatAnalyze(name, analysis) {
96004
96665
  async function persistVersionSnapshot(backupPath, resolvedPath, proposalId) {
96005
96666
  const versionPath = `${resolvedPath}.version-${proposalId}`;
96006
96667
  await Bun.write(versionPath, Bun.file(backupPath));
96007
- rmSync4(backupPath, { force: true });
96668
+ rmSync5(backupPath, { force: true });
96008
96669
  return versionPath;
96009
96670
  }
96010
96671
  async function evolve(type, name, opts) {
96011
96672
  const resolvedPath = resolveContentPath(type, name);
96012
- if (!resolvedPath || !existsSync12(resolvedPath)) {
96673
+ if (!resolvedPath || !existsSync13(resolvedPath)) {
96013
96674
  echoError(`File not found: ${name}`);
96014
96675
  return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
96015
96676
  }
@@ -96044,7 +96705,7 @@ async function evolve(type, name, opts) {
96044
96705
  const versionId = proposalId2 ?? `#${p.id}`;
96045
96706
  const appliedAt = p.applied_at ?? "unknown";
96046
96707
  const versionPath = `${resolvedPath}.version-${versionId}`;
96047
- const hasSnapshot = existsSync12(versionPath) ? "\u2713" : "\u2717";
96708
+ const hasSnapshot = existsSync13(versionPath) ? "\u2713" : "\u2717";
96048
96709
  lines.push(`| ${versionId} | ${appliedAt} | ${hasSnapshot} |`);
96049
96710
  }
96050
96711
  echo(lines.join(`
@@ -96057,7 +96718,7 @@ async function evolve(type, name, opts) {
96057
96718
  return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
96058
96719
  }
96059
96720
  const versionPath = `${resolvedPath}.version-${opts.rollback}`;
96060
- if (!existsSync12(versionPath)) {
96721
+ if (!existsSync13(versionPath)) {
96061
96722
  echoError(`Version snapshot not found: ${opts.rollback}`);
96062
96723
  return { baselineScore: 0, postScore: 0, delta: 0, changesApplied: 0, proposalPath: "" };
96063
96724
  }
@@ -96137,10 +96798,22 @@ async function evolve(type, name, opts) {
96137
96798
  }
96138
96799
  const backupPath2 = await backupFile(resolvedPath);
96139
96800
  const appliedCount = await stepApply(acceptedFromStore, resolvedPath, target.id, db2);
96801
+ const evalGateCtx2 = opts?.evalGate ? {
96802
+ name: contentName,
96803
+ candidateSkillText: await Bun.file(resolvedPath).text(),
96804
+ baselineSkillText: readFileSync12(backupPath2, "utf-8"),
96805
+ margin: opts?.margin ?? 0.05,
96806
+ target: opts?.target ?? "claude",
96807
+ replayBackend: opts?.replayBackend,
96808
+ judgeBackend: opts?.judgeBackend,
96809
+ judgeReplays: opts?.judgeReplays,
96810
+ judgeBudget: opts?.judgeBudget
96811
+ } : undefined;
96140
96812
  const verdict = await stepVerify(type, contentName, resolvedPath, baselineScore, target.id, opts, db2, {
96141
96813
  backupPath: backupPath2,
96142
96814
  ingestedAnchorHash: storedAnchorHash,
96143
- skeptic: storedSkeptic
96815
+ skeptic: storedSkeptic,
96816
+ evalGate: evalGateCtx2
96144
96817
  });
96145
96818
  if (!verdict.rejected && verdict.backupPath) {
96146
96819
  await persistVersionSnapshot(verdict.backupPath, resolvedPath, opts.acceptId);
@@ -96163,7 +96836,18 @@ async function evolve(type, name, opts) {
96163
96836
  const { accepted: acceptedChanges } = await interactiveReview(changes, trends);
96164
96837
  const backupPath = await backupFile(resolvedPath);
96165
96838
  const changesApplied = await stepApply(acceptedChanges, resolvedPath, proposalDbId, db2);
96166
- const { postScore, delta } = await stepVerify(type, contentName, resolvedPath, baselineScore, proposalDbId, opts, db2);
96839
+ const evalGateCtx = opts?.evalGate ? {
96840
+ name: contentName,
96841
+ candidateSkillText: await Bun.file(resolvedPath).text(),
96842
+ baselineSkillText: readFileSync12(backupPath, "utf-8"),
96843
+ margin: opts?.margin ?? 0.05,
96844
+ target: opts?.target ?? "claude",
96845
+ replayBackend: opts?.replayBackend,
96846
+ judgeBackend: opts?.judgeBackend,
96847
+ judgeReplays: opts?.judgeReplays,
96848
+ judgeBudget: opts?.judgeBudget
96849
+ } : undefined;
96850
+ const { postScore, delta } = await stepVerify(type, contentName, resolvedPath, baselineScore, proposalDbId, opts, db2, evalGateCtx ? { backupPath, evalGate: evalGateCtx } : undefined);
96167
96851
  await persistVersionSnapshot(backupPath, resolvedPath, proposalId);
96168
96852
  return { baselineScore, postScore, delta, changesApplied, proposalPath };
96169
96853
  }
@@ -96580,7 +97264,7 @@ function addScaffoldOptions(cmd) {
96580
97264
  return cmd.option("-d, --description <text>", "Content description").option("-t, --target <agent>", "Target agent platform", "claude").option("-o, --output <dir>", "Output directory (default: cwd)").option("--template <tier>", "Template tier (e.g. minimal / standard / specialist)").option("--tools <list>", "Comma-separated tool names to pre-populate frontmatter").option("--force", "Overwrite existing file if present");
96581
97265
  }
96582
97266
  function addEvolveOptions(cmd) {
96583
- return cmd.option("-t, --target <agent>", "Target agent platform", "claude").option("--from <date>", "Analyze evaluations since date (ISO 8601)").option("--propose-only", "Generate proposal without applying").option("--accept <id>", "Accept a specific proposal by ID").option("--reject <id>", "Reject a specific proposal").option("--json", "Output machine-readable JSON (envelope-out with --propose-only)").option("--ingest <file>", "Agent-authored proposal JSON (ingest-in mode)").option("--margin <n>", "\u0394-margin gate threshold for accept (default 0.05)", Number.parseFloat, 0.05).option("--analyze", "Print analysis summary (trends, score, data sources) without writing a proposal").option("--history", "List applied proposal versions from the store").option("--rollback <id>", "Rollback to a prior version by proposal_id (requires --confirm)").option("--confirm", "Confirm a destructive operation (required for --rollback)");
97267
+ return cmd.option("-t, --target <agent>", "Target agent platform", "claude").option("--from <date>", "Analyze evaluations since date (ISO 8601)").option("--propose-only", "Generate proposal without applying").option("--accept <id>", "Accept a specific proposal by ID").option("--reject <id>", "Reject a specific proposal").option("--json", "Output machine-readable JSON (envelope-out with --propose-only)").option("--ingest <file>", "Agent-authored proposal JSON (ingest-in mode)").option("--margin <n>", "\u0394-margin gate threshold for accept (default 0.05)", Number.parseFloat, 0.05).option("--eval-gate", "Enable empirical behavior gate (requires skills/<name>/eval/cases.yaml)").option("--analyze", "Print analysis summary (trends, score, data sources) without writing a proposal").option("--history", "List applied proposal versions from the store").option("--rollback <id>", "Rollback to a prior version by proposal_id (requires --confirm)").option("--confirm", "Confirm a destructive operation (required for --rollback)");
96584
97268
  }
96585
97269
  function addHookEvolveOptions(cmd) {
96586
97270
  return cmd.option("-t, --target <agent>", "Target agent platform", "claude").option("--from <date>", "Analyze evaluations since date (ISO 8601)").option("--analyze", "Print analysis summary (trends, score, data sources) \u2014 analyze-only, no apply").option("--json", "Output machine-readable JSON");
@@ -96689,7 +97373,8 @@ async function agentEvolve(opts) {
96689
97373
  analyze: opts.analyze,
96690
97374
  history: opts.history,
96691
97375
  rollback: opts.rollback,
96692
- confirm: opts.confirm
97376
+ confirm: opts.confirm,
97377
+ evalGate: opts.evalGate
96693
97378
  });
96694
97379
  return;
96695
97380
  }
@@ -96785,7 +97470,8 @@ async function commandEvolve(opts) {
96785
97470
  analyze: opts.analyze,
96786
97471
  history: opts.history,
96787
97472
  rollback: opts.rollback,
96788
- confirm: opts.confirm
97473
+ confirm: opts.confirm,
97474
+ evalGate: opts.evalGate
96789
97475
  });
96790
97476
  return;
96791
97477
  }
@@ -96826,27 +97512,280 @@ function registerCommand(program2) {
96826
97512
  // src/commands/hook.ts
96827
97513
  init_src();
96828
97514
  init_dist();
96829
- import { homedir as homedir6 } from "os";
97515
+ import { homedir as homedir7 } from "os";
96830
97516
  import { join as join225 } from "path";
96831
97517
 
97518
+ // src/commands/hook-run.ts
97519
+ init_dist();
97520
+ import { spawnSync as spawnSync2 } from "child_process";
97521
+
97522
+ // ../../plugins/cc/scripts/anti-hallucination/ah_guard.ts
97523
+ var SOURCE_PATTERNS = [
97524
+ /\[Source:\s*[^\]]+\]/i,
97525
+ /Source:\s*\[?[^\n]+\]?/i,
97526
+ /Sources:\s*\n\s*-\s*\[?[^\n]+\]/i,
97527
+ /https?:\/\/[^\s)]+/i,
97528
+ /\*\*Source\*\*:\s*[^\n]+/i
97529
+ ];
97530
+ var CONFIDENCE_PATTERNS = [
97531
+ /Confidence:\s*(HIGH|MEDIUM|LOW)/i,
97532
+ /\*\*Confidence\*\*:\s*(HIGH|MEDIUM|LOW)/i,
97533
+ /### Confidence/i
97534
+ ];
97535
+ var TOOL_PATTERNS = [
97536
+ /ref_search_documentation/,
97537
+ /ref_read_url/,
97538
+ /searchCode/,
97539
+ /WebSearch/,
97540
+ /WebFetch/,
97541
+ /mcp__ref__ref_search_documentation/,
97542
+ /mcp__ref__ref_read_url/,
97543
+ /mcp__grep__searchCode/
97544
+ ];
97545
+ var RED_FLAG_PATTERNS = [
97546
+ /I (?:think|believe|recall) (?:that|the)?/gi,
97547
+ /(?:It|This) (?:should|might|may|could)/gi,
97548
+ /Probably|Likely|Possibly/gi,
97549
+ /(?:As far as|If I) (?:know|recall)/gi
97550
+ ];
97551
+ function extractLastAssistantMessage(context3) {
97552
+ const messages2 = context3.messages ?? [];
97553
+ for (let i2 = messages2.length - 1;i2 >= 0; i2--) {
97554
+ const message = messages2[i2];
97555
+ if (message?.role === "assistant") {
97556
+ const content = message.content;
97557
+ if (Array.isArray(content)) {
97558
+ const textParts = [];
97559
+ for (const part of content) {
97560
+ if (part.type === "text" && part.text) {
97561
+ textParts.push(part.text);
97562
+ }
97563
+ }
97564
+ return textParts.join(`
97565
+ `);
97566
+ }
97567
+ return String(content);
97568
+ }
97569
+ }
97570
+ const lastMsg = context3.last_message;
97571
+ if (lastMsg) {
97572
+ return String(lastMsg);
97573
+ }
97574
+ return;
97575
+ }
97576
+ function hasSourceCitations(text3) {
97577
+ if (!text3)
97578
+ return false;
97579
+ for (const pattern of SOURCE_PATTERNS) {
97580
+ if (pattern.test(text3)) {
97581
+ return true;
97582
+ }
97583
+ }
97584
+ return false;
97585
+ }
97586
+ function hasConfidenceLevel(text3) {
97587
+ if (!text3)
97588
+ return false;
97589
+ for (const pattern of CONFIDENCE_PATTERNS) {
97590
+ if (pattern.test(text3)) {
97591
+ return true;
97592
+ }
97593
+ }
97594
+ return false;
97595
+ }
97596
+ function hasToolUsageEvidence(text3) {
97597
+ if (!text3)
97598
+ return false;
97599
+ for (const pattern of TOOL_PATTERNS) {
97600
+ if (pattern.test(text3)) {
97601
+ return true;
97602
+ }
97603
+ }
97604
+ return false;
97605
+ }
97606
+ function hasRedFlags(text3) {
97607
+ if (!text3)
97608
+ return [];
97609
+ const foundFlags = [];
97610
+ for (const pattern of RED_FLAG_PATTERNS) {
97611
+ const matches = text3.match(pattern);
97612
+ if (matches) {
97613
+ foundFlags.push(...matches);
97614
+ }
97615
+ }
97616
+ return foundFlags;
97617
+ }
97618
+ function requiresExternalVerification(text3) {
97619
+ if (!text3)
97620
+ return false;
97621
+ const verificationKeywords = [
97622
+ "api",
97623
+ "library",
97624
+ "framework",
97625
+ "method",
97626
+ "function",
97627
+ "version",
97628
+ "documentation",
97629
+ "official",
97630
+ /recent\s+(?:change|update|release)/i,
97631
+ /\d+\.\d+(?:\.\d+)?/,
97632
+ /https?:\/\//
97633
+ ];
97634
+ const textLower = text3.toLowerCase();
97635
+ for (const keyword of verificationKeywords) {
97636
+ if (typeof keyword === "string") {
97637
+ if (textLower.includes(keyword)) {
97638
+ return true;
97639
+ }
97640
+ } else if (keyword.test(textLower)) {
97641
+ return true;
97642
+ }
97643
+ }
97644
+ return false;
97645
+ }
97646
+ function verifyAntiHallucinationProtocol(text3) {
97647
+ if (!text3 || text3.trim().length < 50) {
97648
+ return { ok: true, reason: "Task is complete" };
97649
+ }
97650
+ const needsVerification = requiresExternalVerification(text3);
97651
+ if (!needsVerification) {
97652
+ return { ok: true, reason: "Task is complete (internal discussion)" };
97653
+ }
97654
+ const hasSources = hasSourceCitations(text3);
97655
+ const hasConfidence = hasConfidenceLevel(text3);
97656
+ const hasTools = hasToolUsageEvidence(text3);
97657
+ const redFlags = hasRedFlags(text3);
97658
+ const issues = [];
97659
+ if (!hasSources) {
97660
+ issues.push("source citations for API/library claims");
97661
+ }
97662
+ if (!hasConfidence) {
97663
+ issues.push("confidence level (HIGH/MEDIUM/LOW)");
97664
+ }
97665
+ if (redFlags.length > 0 && !hasTools) {
97666
+ const uniqueFlags = Array.from(new Set(redFlags)).slice(0, 3);
97667
+ issues.push(`uncertainty phrases detected: ${uniqueFlags.join(", ")}`);
97668
+ }
97669
+ if (issues.length > 0) {
97670
+ const reason = `Add verification for: ${issues.join(", ")}`;
97671
+ return { ok: false, reason, issues };
97672
+ }
97673
+ return { ok: true, reason: "Task is complete" };
97674
+ }
97675
+ if (false) {}
97676
+
97677
+ // src/commands/hook-run.ts
97678
+ function preToolUseDecision(decision, reason) {
97679
+ const out = {
97680
+ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: decision }
97681
+ };
97682
+ if (reason !== undefined)
97683
+ out.systemMessage = reason;
97684
+ return { output: JSON.stringify(out), exitCode: 0 };
97685
+ }
97686
+ function resolveSpurTaskOwnership(filePath, cwd5) {
97687
+ const res = spawnSync2("spur", ["task", "resolve", filePath, "--strict", "--json"], {
97688
+ cwd: cwd5,
97689
+ encoding: "utf-8",
97690
+ timeout: 8000
97691
+ });
97692
+ if (res.error || typeof res.status !== "number")
97693
+ return "unknown";
97694
+ return res.status === 0 ? "owned" : "unowned";
97695
+ }
97696
+ function runSpTaskWriteGuard(env, stdinText, resolveTaskOwnership = resolveSpurTaskOwnership) {
97697
+ if (env.SPUR_WRITE_GUARD === "off")
97698
+ return preToolUseDecision("allow");
97699
+ let payload;
97700
+ try {
97701
+ payload = JSON.parse(stdinText);
97702
+ } catch {
97703
+ return preToolUseDecision("allow");
97704
+ }
97705
+ const toolName = payload.tool_name ?? "";
97706
+ if (toolName !== "Write" && toolName !== "Edit")
97707
+ return preToolUseDecision("allow");
97708
+ const filePath = payload.tool_input?.file_path ?? "";
97709
+ if (filePath === "")
97710
+ return preToolUseDecision("allow");
97711
+ const ownership = resolveTaskOwnership(filePath, env.CLAUDE_PROJECT_DIR ?? process.cwd());
97712
+ if (ownership === "owned") {
97713
+ return preToolUseDecision("deny", `${filePath} is a task file owned by the spur corpus. Edit it through the spur CLI ` + "(e.g. `spur task update <wbs> --section <name> --from-file <file>`), not a raw " + "Write/Edit. Set SPUR_WRITE_GUARD=off to bypass.");
97714
+ }
97715
+ return preToolUseDecision("allow");
97716
+ }
97717
+ var spTaskWriteGuard = {
97718
+ run: runSpTaskWriteGuard
97719
+ };
97720
+ var ccAntiHallucination = {
97721
+ run(env) {
97722
+ const argumentsJson = env.ARGUMENTS ?? "{}";
97723
+ const allowStop = (feedback, ok) => ({
97724
+ output: JSON.stringify({ hookSpecificOutput: { allowStop: ok, feedback } }),
97725
+ exitCode: ok ? 0 : 1
97726
+ });
97727
+ let context3;
97728
+ try {
97729
+ context3 = JSON.parse(argumentsJson);
97730
+ } catch {
97731
+ return allowStop("Task is complete (invalid context ignored)", true);
97732
+ }
97733
+ const content = extractLastAssistantMessage(context3);
97734
+ if (content === undefined)
97735
+ return allowStop("No content to verify", true);
97736
+ const result = verifyAntiHallucinationProtocol(content);
97737
+ return allowStop(result.reason, result.ok);
97738
+ }
97739
+ };
97740
+ var HOOK_RUNNERS = {
97741
+ "sp/task-write-guard": spTaskWriteGuard,
97742
+ "cc/anti-hallucination": ccAntiHallucination
97743
+ };
97744
+ function hookRun(plugin, hookId, env, stdinText) {
97745
+ const runner = HOOK_RUNNERS[`${plugin}/${hookId}`];
97746
+ if (!runner) {
97747
+ echoError(`Error: unknown hook '${plugin} ${hookId}'. Known hooks: ${Object.keys(HOOK_RUNNERS).join(", ")}`);
97748
+ return 2;
97749
+ }
97750
+ const result = runner.run(env, stdinText);
97751
+ echo(result.output);
97752
+ return result.exitCode;
97753
+ }
97754
+ function registerHookRun(cmd, readInput) {
97755
+ cmd.command("run <plugin> <hook-id>").description("Run a registered plugin hook runner (the runtime command installed hook configs call)").action((plugin, hookId) => {
97756
+ let stdinText = "";
97757
+ if (readInput) {
97758
+ stdinText = readInput();
97759
+ } else {
97760
+ try {
97761
+ stdinText = __require("fs").readFileSync(0, "utf-8");
97762
+ } catch {
97763
+ stdinText = "";
97764
+ }
97765
+ }
97766
+ const code = hookRun(plugin, hookId, process.env, stdinText);
97767
+ process.exit(code);
97768
+ });
97769
+ }
97770
+
96832
97771
  // src/commands/install.ts
96833
97772
  init_src();
96834
97773
  init_dist();
96835
97774
  import {
96836
97775
  copyFileSync as copyFileSync2,
96837
- existsSync as existsSync14,
97776
+ existsSync as existsSync15,
96838
97777
  mkdirSync as mkdirSync9,
96839
97778
  readdirSync as readdirSync4,
96840
- readFileSync as readFileSync13,
96841
- rmSync as rmSync5,
96842
- statSync as statSync7,
97779
+ readFileSync as readFileSync14,
97780
+ rmSync as rmSync6,
97781
+ statSync as statSync6,
96843
97782
  writeFileSync as writeFileSync8
96844
97783
  } from "fs";
96845
- import { homedir as homedir5 } from "os";
97784
+ import { homedir as homedir6 } from "os";
96846
97785
  import { join as join223 } from "path";
96847
97786
 
96848
97787
  // src/hooks.ts
96849
- import { copyFileSync, existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
97788
+ import { copyFileSync, existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
96850
97789
  import { join as join221 } from "path";
96851
97790
  var CANONICAL_TO_PI_EVENT = {
96852
97791
  sessionStart: "session_start",
@@ -96890,10 +97829,10 @@ function convertCanonicalToPiHooks(config3) {
96890
97829
  }
96891
97830
  function readCanonicalHooks(rulesyncDir) {
96892
97831
  const hooksPath = join221(rulesyncDir, "hooks.json");
96893
- if (!existsSync13(hooksPath))
97832
+ if (!existsSync14(hooksPath))
96894
97833
  return null;
96895
97834
  try {
96896
- return JSON.parse(readFileSync12(hooksPath, "utf-8"));
97835
+ return JSON.parse(readFileSync13(hooksPath, "utf-8"));
96897
97836
  } catch {
96898
97837
  return null;
96899
97838
  }
@@ -97008,7 +97947,7 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
97008
97947
  const targetInputRoot = prepareTargetRulesyncInput(outputDir, target, plugin);
97009
97948
  targetInputRoots.set(target, targetInputRoot);
97010
97949
  }
97011
- const rulesyncFeatures = ["skills", "hooks", ...mapResult.mcp ? ["mcp"] : []];
97950
+ const rulesyncFeatures = ["skills", ...mapResult.mcp ? ["mcp"] : []];
97012
97951
  const rulesyncTargets = targets2.filter((t) => t !== "claude" && t !== "hermes" && t !== "omp");
97013
97952
  if (targets2.includes("omp") && !targets2.includes("pi")) {
97014
97953
  if (!targetInputRoots.has("pi")) {
@@ -97047,11 +97986,25 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
97047
97986
  resultCounts.subagentsCount += result.subagentsCount;
97048
97987
  resultCounts.hooksCount += result.hooksCount;
97049
97988
  }
97989
+ if (mapResult.hooks) {
97990
+ for (const target of rulesyncTargets) {
97991
+ if (!TARGET_TO_RULESYNC_HOOKS[target])
97992
+ continue;
97993
+ const hookResult = await runRulesyncImpl([target], ["hooks"], targetInputRoots.get(target) ?? outputDir, {
97994
+ global: options2.global,
97995
+ dryRun: options2.dryRun,
97996
+ verbose: options2.verbose,
97997
+ outputRoot: options2.outputRoot,
97998
+ targetMap: TARGET_TO_RULESYNC_HOOKS
97999
+ });
98000
+ resultCounts.hooksCount += hookResult.hooksCount;
98001
+ }
98002
+ }
97050
98003
  if (options2.verbose) {
97051
98004
  echo(` Skills written: ${resultCounts.skillsCount}, Commands: ${resultCounts.commandsCount}, Subagents: ${resultCounts.subagentsCount}, Hooks: ${resultCounts.hooksCount}`);
97052
98005
  }
97053
98006
  }
97054
- const outputRoot = options2.outputRoot ?? (options2.global ? homedir5() : process.cwd());
98007
+ const outputRoot = options2.outputRoot ?? (options2.global ? homedir6() : process.cwd());
97055
98008
  const hookEmitResults = [];
97056
98009
  for (const target of targets2) {
97057
98010
  if (target === "claude") {
@@ -97060,9 +98013,9 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
97060
98013
  if (!options2.dryRun) {
97061
98014
  const marketplaceName = resolution.marketplaceName ?? "superskill";
97062
98015
  const marketplaceRoot = resolution.marketplaceRoot ?? process.cwd();
97063
- const cacheDir = join223(homedir5(), ".claude", "plugins", "cache", marketplaceName);
97064
- if (existsSync14(cacheDir))
97065
- rmSync5(cacheDir, { recursive: true, force: true });
98016
+ const cacheDir = join223(homedir6(), ".claude", "plugins", "cache", marketplaceName);
98017
+ if (existsSync15(cacheDir))
98018
+ rmSync6(cacheDir, { recursive: true, force: true });
97066
98019
  await runClaudeInstallImpl(marketplaceRoot, marketplaceName, plugin);
97067
98020
  }
97068
98021
  }
@@ -97090,7 +98043,7 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
97090
98043
  if (options2.verbose)
97091
98044
  echo(` ${hookResult.message}`);
97092
98045
  const agentsDir = join223(pluginRoot, "agents");
97093
- if (existsSync14(agentsDir) && !options2.dryRun) {
98046
+ if (existsSync15(agentsDir) && !options2.dryRun) {
97094
98047
  const piAgentsDir = join223(outputRoot, ".pi", "agent", "agents");
97095
98048
  mkdirSync9(piAgentsDir, { recursive: true });
97096
98049
  for (const entry of readdirSync4(agentsDir)) {
@@ -97098,8 +98051,8 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
97098
98051
  continue;
97099
98052
  const agentName = entry.replace(/\.md$/, "");
97100
98053
  const expectedName = `${plugin}-${agentName}`;
97101
- const source = readFileSync13(join223(agentsDir, entry), "utf-8");
97102
- const skillExists = (bare) => existsSync14(join223(pluginRoot, "skills", bare));
98054
+ const source = readFileSync14(join223(agentsDir, entry), "utf-8");
98055
+ const skillExists = (bare) => existsSync15(join223(pluginRoot, "skills", bare));
97103
98056
  const adapted = adaptSubagentToPi(source, expectedName, plugin, skillExists);
97104
98057
  writeFileSync8(join223(piAgentsDir, `${expectedName}.md`), adapted);
97105
98058
  }
@@ -97148,9 +98101,9 @@ function resolvePluginRoot(plugin, marketplacePath) {
97148
98101
  const manifestRoot = resolved.marketplaceRoot;
97149
98102
  const manifestPath = join223(manifestRoot, ".claude-plugin", "marketplace.json");
97150
98103
  let marketplaceName;
97151
- if (existsSync14(manifestPath)) {
98104
+ if (existsSync15(manifestPath)) {
97152
98105
  try {
97153
- const raw = readFileSync13(manifestPath, "utf-8");
98106
+ const raw = readFileSync14(manifestPath, "utf-8");
97154
98107
  const parsed = JSON.parse(raw);
97155
98108
  marketplaceName = parsed.name;
97156
98109
  } catch {}
@@ -97158,7 +98111,7 @@ function resolvePluginRoot(plugin, marketplacePath) {
97158
98111
  return { pluginRoot: resolved.pluginRoot, marketplaceRoot: manifestRoot, marketplaceName };
97159
98112
  }
97160
98113
  const fallback = join223("plugins", plugin);
97161
- if (existsSync14(fallback) && readdirSync4(fallback).some((d) => ["skills", "commands", "agents", "hooks", "hooks.json"].includes(d)))
98114
+ if (existsSync15(fallback) && readdirSync4(fallback).some((d) => ["skills", "commands", "agents", "hooks", "hooks.json"].includes(d)))
97162
98115
  return { pluginRoot: fallback };
97163
98116
  const available = listResolvablePlugins(marketplacePath);
97164
98117
  const msg = available.length > 0 ? `Available: ${available.join(", ")}` : "No marketplace manifest found and no plugins/<name>/ directory.";
@@ -97167,7 +98120,7 @@ function resolvePluginRoot(plugin, marketplacePath) {
97167
98120
  function prepareTargetRulesyncInput(sourceRoot, target, pluginName) {
97168
98121
  const targetRoot = join223(sourceRoot, ".targets", target);
97169
98122
  const targetRulesyncRoot = join223(targetRoot, ".rulesync");
97170
- rmSync5(targetRoot, { recursive: true, force: true });
98123
+ rmSync6(targetRoot, { recursive: true, force: true });
97171
98124
  copyDirectory(sourceRoot, targetRulesyncRoot, { skipDirectoryNames: new Set([".targets"]) });
97172
98125
  transformRulesyncMarkdown(targetRulesyncRoot, target, pluginName);
97173
98126
  return targetRoot;
@@ -97193,25 +98146,25 @@ function transformRulesyncMarkdown(root, target, pluginName) {
97193
98146
  transformMarkdownDirectory(join223(root, "skills"), target, pluginName);
97194
98147
  }
97195
98148
  function transformMarkdownDirectory(dir, target, pluginName) {
97196
- if (!existsSync14(dir))
98149
+ if (!existsSync15(dir))
97197
98150
  return;
97198
98151
  for (const entry of readdirSync4(dir)) {
97199
98152
  const path11 = join223(dir, entry);
97200
- const stats = statSync7(path11);
98153
+ const stats = statSync6(path11);
97201
98154
  if (stats.isDirectory()) {
97202
98155
  transformMarkdownDirectory(path11, target, pluginName);
97203
98156
  continue;
97204
98157
  }
97205
98158
  if (!entry.endsWith(".md"))
97206
98159
  continue;
97207
- const content = readFileSync13(path11, "utf-8");
98160
+ const content = readFileSync14(path11, "utf-8");
97208
98161
  const slashTranslated = translateSlashCommands(content, target);
97209
98162
  const transformed = rewriteSkillReferences(slashTranslated, pluginName);
97210
98163
  writeFileSync8(path11, transformed);
97211
98164
  }
97212
98165
  }
97213
98166
  function copyDirectory(source, destination, options2 = {}) {
97214
- if (!existsSync14(source))
98167
+ if (!existsSync15(source))
97215
98168
  return;
97216
98169
  mkdirSync9(destination, { recursive: true });
97217
98170
  for (const entry of readdirSync4(source)) {
@@ -97219,7 +98172,7 @@ function copyDirectory(source, destination, options2 = {}) {
97219
98172
  continue;
97220
98173
  const sourcePath = join223(source, entry);
97221
98174
  const destinationPath = join223(destination, entry);
97222
- if (statSync7(sourcePath).isDirectory()) {
98175
+ if (statSync6(sourcePath).isDirectory()) {
97223
98176
  copyDirectory(sourcePath, destinationPath, options2);
97224
98177
  } else {
97225
98178
  copyFileSync2(sourcePath, destinationPath);
@@ -97258,7 +98211,7 @@ async function emitHook(name, opts) {
97258
98211
  const target = resolveTarget(opts);
97259
98212
  const global3 = opts.global !== false;
97260
98213
  const dryRun = opts.dryRun === true;
97261
- const outputRoot = global3 ? homedir6() : process.cwd();
98214
+ const outputRoot = global3 ? homedir7() : process.cwd();
97262
98215
  const pluginRoot = resolvePluginRoot(name).pluginRoot;
97263
98216
  const outputDir = ".rulesync";
97264
98217
  mapPluginToRulesync(pluginRoot, name, outputDir);
@@ -97326,6 +98279,7 @@ function registerHook(program2) {
97326
98279
  addTargetOption(cmd.command("emit <name>").description("Emit a hook definition to a single target agent (thin wrapper over the install hook path)")).option("--global", "Install to user-level global directory (default)", true).option("--dry-run", "Preview without writing files", false).action(async (name, opts) => {
97327
98280
  await runOperation(() => hookEmit({ name, ...opts }));
97328
98281
  });
98282
+ registerHookRun(cmd);
97329
98283
  }
97330
98284
 
97331
98285
  // src/commands/magent.ts
@@ -97386,7 +98340,8 @@ async function magentEvolve(opts) {
97386
98340
  analyze: opts.analyze,
97387
98341
  history: opts.history,
97388
98342
  rollback: opts.rollback,
97389
- confirm: opts.confirm
98343
+ confirm: opts.confirm,
98344
+ evalGate: opts.evalGate
97390
98345
  });
97391
98346
  return;
97392
98347
  }
@@ -97430,9 +98385,9 @@ init_dist();
97430
98385
  // src/operations/migrate.ts
97431
98386
  init_src();
97432
98387
  init_dist();
97433
- import { readFileSync as readFileSync14 } from "fs";
98388
+ import { readFileSync as readFileSync15 } from "fs";
97434
98389
  function readProposalId(proposalPath) {
97435
- const raw = readFileSync14(proposalPath, "utf-8");
98390
+ const raw = readFileSync15(proposalPath, "utf-8");
97436
98391
  const parsed = JSON.parse(raw);
97437
98392
  if (parsed !== null && typeof parsed === "object" && "proposal_id" in parsed) {
97438
98393
  const id = parsed.proposal_id;
@@ -97537,7 +98492,8 @@ async function skillEvolve(opts) {
97537
98492
  analyze: opts.analyze,
97538
98493
  history: opts.history,
97539
98494
  rollback: opts.rollback,
97540
- confirm: opts.confirm
98495
+ confirm: opts.confirm,
98496
+ evalGate: opts.evalGate
97541
98497
  });
97542
98498
  return;
97543
98499
  }
@@ -97601,7 +98557,7 @@ function getPackageVersion() {
97601
98557
  if (packageVersion)
97602
98558
  return packageVersion;
97603
98559
  const packageJsonPath = join226(import.meta.dir, "..", "package.json");
97604
- const packageJson = JSON.parse(readFileSync15(packageJsonPath, "utf-8"));
98560
+ const packageJson = JSON.parse(readFileSync16(packageJsonPath, "utf-8"));
97605
98561
  if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
97606
98562
  throw new Error(`Invalid package version in ${packageJsonPath}`);
97607
98563
  }