@harness-engineering/cli 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +9 -8
  2. package/dist/agents/skills/claude-code/pre-merge-brief/SKILL.md +86 -0
  3. package/dist/agents/skills/claude-code/pre-merge-brief/skill.yaml +67 -0
  4. package/dist/agents/skills/claude-code/product-advisor/SKILL.md +202 -0
  5. package/dist/agents/skills/claude-code/product-advisor/skill.yaml +74 -0
  6. package/dist/agents/skills/codex/harness-autopilot/SKILL.md +9 -8
  7. package/dist/agents/skills/codex/pre-merge-brief/SKILL.md +86 -0
  8. package/dist/agents/skills/codex/pre-merge-brief/skill.yaml +67 -0
  9. package/dist/agents/skills/codex/product-advisor/SKILL.md +202 -0
  10. package/dist/agents/skills/codex/product-advisor/skill.yaml +74 -0
  11. package/dist/agents/skills/cursor/harness-autopilot/SKILL.md +9 -8
  12. package/dist/agents/skills/cursor/pre-merge-brief/SKILL.md +86 -0
  13. package/dist/agents/skills/cursor/pre-merge-brief/skill.yaml +67 -0
  14. package/dist/agents/skills/cursor/product-advisor/SKILL.md +202 -0
  15. package/dist/agents/skills/cursor/product-advisor/skill.yaml +74 -0
  16. package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +9 -8
  17. package/dist/agents/skills/gemini-cli/pre-merge-brief/SKILL.md +86 -0
  18. package/dist/agents/skills/gemini-cli/pre-merge-brief/skill.yaml +67 -0
  19. package/dist/agents/skills/gemini-cli/product-advisor/SKILL.md +202 -0
  20. package/dist/agents/skills/gemini-cli/product-advisor/skill.yaml +74 -0
  21. package/dist/{agents-md-7OSNWU52.js → agents-md-7L4PKKOM.js} +4 -4
  22. package/dist/analyzer-XRCV63KC-HLTEIKAJ.js +26 -0
  23. package/dist/{architecture-2XYGJGT3.js → architecture-RCHFDI7E.js} +5 -5
  24. package/dist/{assess-project-3KPP2D6M.js → assess-project-YUDPNRS6.js} +5 -3
  25. package/dist/bin/harness-mcp.js +16 -16
  26. package/dist/bin/harness.js +27 -27
  27. package/dist/{check-phase-gate-46U5AAXE.js → check-phase-gate-56GS3A72.js} +5 -5
  28. package/dist/{chunk-MSBJ445U.js → chunk-4SKWGVYD.js} +5 -5
  29. package/dist/{chunk-CLI4K2CH.js → chunk-4U5LDFCY.js} +1 -1
  30. package/dist/{chunk-6YXCZV33.js → chunk-ABRYIEWJ.js} +1090 -714
  31. package/dist/{chunk-AK67S3O4.js → chunk-AU4YPEIE.js} +3 -3
  32. package/dist/{chunk-BV45354Q.js → chunk-DGVT4DBI.js} +9 -9
  33. package/dist/{chunk-363V6GPR.js → chunk-GLHLXTKC.js} +9 -9
  34. package/dist/{chunk-VTUINXWR.js → chunk-GSYBGOY3.js} +1 -1
  35. package/dist/{chunk-FZ4Q73HA.js → chunk-IGWJRAJT.js} +1 -1
  36. package/dist/{chunk-S2RQPPL6.js → chunk-N4AI2WFH.js} +1 -1
  37. package/dist/{chunk-HXMAIVV2.js → chunk-NCMJXBEO.js} +1 -1
  38. package/dist/{chunk-ZEYAOYJL.js → chunk-OZSKLJQW.js} +1 -1
  39. package/dist/{chunk-VTU3QOJT.js → chunk-P4NA5OQX.js} +1 -1
  40. package/dist/{chunk-WL3O2PKJ.js → chunk-RY2U77OY.js} +8 -8
  41. package/dist/{chunk-TTWNGOBT.js → chunk-RZQZXWEL.js} +32 -7
  42. package/dist/{chunk-KLPX55TI.js → chunk-UACYZCW4.js} +239 -146
  43. package/dist/{chunk-IYWT3JJW.js → chunk-VG4G3R2V.js} +1 -1
  44. package/dist/{chunk-PP6ZRL5T.js → chunk-WZJR6SOI.js} +536 -422
  45. package/dist/{chunk-PHX45JYN.js → chunk-XW5XVVMI.js} +2 -2
  46. package/dist/{chunk-MYVTYFQD.js → chunk-XZNCONFG.js} +1 -1
  47. package/dist/{chunk-GXCPDAS5.js → chunk-Y33P35U3.js} +26 -8
  48. package/dist/{chunk-XFHZ7GCI.js → chunk-Y5HPJMTM.js} +19 -3
  49. package/dist/{chunk-N55WOGN3.js → chunk-YJYUJSWK.js} +59 -21
  50. package/dist/{chunk-SPE7P4GL.js → chunk-YWRPQZL7.js} +1 -1
  51. package/dist/{chunk-6NCREWWM.js → chunk-YXOPQEFZ.js} +3 -3
  52. package/dist/{chunk-2N4OENGE.js → chunk-YYFSFSB3.js} +1 -1
  53. package/dist/{chunk-ERILXQBP.js → chunk-Z4XWWNYX.js} +615 -433
  54. package/dist/{chunk-HMW3C5DP.js → chunk-ZU6T7W3U.js} +2 -2
  55. package/dist/{ci-workflow-XJN4UO3Q.js → ci-workflow-TFAA5BK7.js} +4 -4
  56. package/dist/{dist-OWHMNL4W.js → dist-DWBTZXR5.js} +1 -1
  57. package/dist/{dist-IPVFYGY2.js → dist-MCTEX5QH.js} +5 -3
  58. package/dist/{docs-RSFZTNPG.js → docs-BBMAN3CY.js} +5 -5
  59. package/dist/{engine-DJIHY4JT.js → engine-R2YH74AL.js} +4 -4
  60. package/dist/{entropy-EAEKJKRM.js → entropy-5UP5N6AF.js} +7 -4
  61. package/dist/{feedback-JT5X3DBC.js → feedback-6MDCCFZL.js} +1 -1
  62. package/dist/{generate-agent-definitions-CC6KED3E.js → generate-agent-definitions-KKAN5DB5.js} +5 -5
  63. package/dist/{glob-helper-GLZAURJC.js → glob-helper-VR6UCZZB.js} +1 -1
  64. package/dist/{graph-loader-HHXN5FLP.js → graph-loader-STFGYKZH.js} +1 -1
  65. package/dist/hooks/sentinel-pre.js +15 -138
  66. package/dist/index.d.ts +61 -0
  67. package/dist/index.js +27 -27
  68. package/dist/{loader-UWNVTYBY.js → loader-2WT2ZE2T.js} +4 -4
  69. package/dist/{mcp-TCLNK7HG.js → mcp-5V4LPMB3.js} +16 -16
  70. package/dist/{performance-R6O3N3UB.js → performance-2N3CFXLR.js} +5 -5
  71. package/dist/{review-pipeline-MOOWXWSQ.js → review-pipeline-XZIGBU3Q.js} +4 -4
  72. package/dist/{runtime-RIWQUKBQ.js → runtime-POME3GTR.js} +4 -4
  73. package/dist/{scan-P7YFKB77.js → scan-IYSVRPD2.js} +1 -1
  74. package/dist/{security-U76C54W6.js → security-QLJLMSIW.js} +1 -1
  75. package/dist/{state-events-F44CUUZG.js → state-events-YY5KBZTC.js} +4 -4
  76. package/dist/{validate-IUAV7MOU.js → validate-VZORVK43.js} +5 -5
  77. package/dist/{validate-cross-check-M2ZM6RFY.js → validate-cross-check-OYKEDCST.js} +4 -4
  78. package/package.json +5 -4
  79. package/dist/analyzer-V633GUHY-MBCQWKDU.js +0 -26
@@ -1,32 +1,32 @@
1
1
  import {
2
2
  generateRuntime
3
- } from "./chunk-S2RQPPL6.js";
3
+ } from "./chunk-N4AI2WFH.js";
4
4
  import {
5
5
  generateAgentsMd
6
- } from "./chunk-IYWT3JJW.js";
6
+ } from "./chunk-VG4G3R2V.js";
7
7
  import {
8
8
  generateCIWorkflow
9
- } from "./chunk-VTU3QOJT.js";
9
+ } from "./chunk-P4NA5OQX.js";
10
10
  import {
11
11
  readHarnessState
12
- } from "./chunk-SPE7P4GL.js";
12
+ } from "./chunk-YWRPQZL7.js";
13
13
  import {
14
14
  runCrossCheck
15
- } from "./chunk-VTUINXWR.js";
15
+ } from "./chunk-GSYBGOY3.js";
16
16
  import {
17
17
  createGenerateAgentDefinitionsCommand,
18
18
  generateAgentDefinitions
19
- } from "./chunk-MYVTYFQD.js";
19
+ } from "./chunk-XZNCONFG.js";
20
20
  import {
21
21
  toKebabCase
22
22
  } from "./chunk-KET4QQZB.js";
23
23
  import {
24
24
  createScanCommand,
25
25
  loadIngestOptions
26
- } from "./chunk-2N4OENGE.js";
26
+ } from "./chunk-YYFSFSB3.js";
27
27
  import {
28
28
  TemplateEngine
29
- } from "./chunk-FZ4Q73HA.js";
29
+ } from "./chunk-IGWJRAJT.js";
30
30
  import {
31
31
  generate,
32
32
  validate
@@ -37,7 +37,7 @@ import {
37
37
  import {
38
38
  listPersonas,
39
39
  loadPersona
40
- } from "./chunk-HXMAIVV2.js";
40
+ } from "./chunk-NCMJXBEO.js";
41
41
  import {
42
42
  runPersona
43
43
  } from "./chunk-GISMXMVL.js";
@@ -51,7 +51,7 @@ import {
51
51
  OutputFormatter,
52
52
  OutputMode,
53
53
  createCheckPhaseGateCommand
54
- } from "./chunk-PHX45JYN.js";
54
+ } from "./chunk-XW5XVVMI.js";
55
55
  import {
56
56
  appendFrameworkAgents,
57
57
  captureHealthSnapshot,
@@ -79,13 +79,13 @@ import {
79
79
  runSecurityCraft,
80
80
  runSpecCraft,
81
81
  runTestCraft
82
- } from "./chunk-ERILXQBP.js";
82
+ } from "./chunk-Z4XWWNYX.js";
83
83
  import {
84
84
  VALID_PLATFORMS
85
85
  } from "./chunk-3ISINLYT.js";
86
86
  import {
87
87
  loadGraphStore
88
- } from "./chunk-CLI4K2CH.js";
88
+ } from "./chunk-4U5LDFCY.js";
89
89
  import {
90
90
  loadOrRebuildIndex
91
91
  } from "./chunk-WBVCN35T.js";
@@ -108,7 +108,7 @@ import {
108
108
  BranchingConfigSchema,
109
109
  findConfigFile,
110
110
  resolveConfig
111
- } from "./chunk-XFHZ7GCI.js";
111
+ } from "./chunk-Y5HPJMTM.js";
112
112
  import {
113
113
  logger
114
114
  } from "./chunk-EBJQ6N4M.js";
@@ -188,6 +188,7 @@ import {
188
188
  parseDiff,
189
189
  parseFileRegions,
190
190
  parseManifest,
191
+ parseReferencedIssues,
191
192
  parseRoadmap,
192
193
  parseSecurityConfig,
193
194
  pruneLearnings,
@@ -224,7 +225,7 @@ import {
224
225
  writeConfig,
225
226
  writeLockfile,
226
227
  writeRegeneratedRoadmap
227
- } from "./chunk-KLPX55TI.js";
228
+ } from "./chunk-UACYZCW4.js";
228
229
  import {
229
230
  CLI_VERSION
230
231
  } from "./chunk-BM3PWGXQ.js";
@@ -237,7 +238,7 @@ import {
237
238
  detectDocDrift,
238
239
  generateSuggestions,
239
240
  validateDependencies
240
- } from "./chunk-N55WOGN3.js";
241
+ } from "./chunk-YJYUJSWK.js";
241
242
  import {
242
243
  Err,
243
244
  INDEXED_FILE_KINDS,
@@ -250,7 +251,7 @@ import {
250
251
  DesignConstraintAdapter,
251
252
  GraphStore,
252
253
  init_dist as init_dist2
253
- } from "./chunk-PP6ZRL5T.js";
254
+ } from "./chunk-WZJR6SOI.js";
254
255
  import {
255
256
  ArchConfigSchema,
256
257
  TimelineManager
@@ -261,7 +262,7 @@ import {
261
262
  } from "./chunk-KFQGP6VL.js";
262
263
 
263
264
  // src/index.ts
264
- import { Command as Command128 } from "commander";
265
+ import { Command as Command130 } from "commander";
265
266
 
266
267
  // src/commands/add.ts
267
268
  init_dist3();
@@ -450,7 +451,7 @@ function registerSkillsCommand(adoption) {
450
451
  const globalOpts = cmd.optsWithGlobals();
451
452
  const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
452
453
  const cwd = process.cwd();
453
- const { readAdoptionRecords, aggregateBySkill } = await import("./dist-IPVFYGY2.js");
454
+ const { readAdoptionRecords, aggregateBySkill } = await import("./dist-MCTEX5QH.js");
454
455
  const records = readAdoptionRecords(cwd);
455
456
  if (records.length === 0) {
456
457
  if (globalOpts.json) {
@@ -486,7 +487,7 @@ function registerRecentCommand(adoption) {
486
487
  const globalOpts = cmd.optsWithGlobals();
487
488
  const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
488
489
  const cwd = process.cwd();
489
- const { readAdoptionRecords } = await import("./dist-IPVFYGY2.js");
490
+ const { readAdoptionRecords } = await import("./dist-MCTEX5QH.js");
490
491
  const records = readAdoptionRecords(cwd);
491
492
  if (records.length === 0) {
492
493
  if (globalOpts.json) {
@@ -564,7 +565,7 @@ function registerSkillCommand(adoption) {
564
565
  adoption.command("skill <name>").description("Show detail for a specific skill").action(async (name, _opts, cmd) => {
565
566
  const globalOpts = cmd.optsWithGlobals();
566
567
  const cwd = process.cwd();
567
- const { readAdoptionRecords, aggregateBySkill } = await import("./dist-IPVFYGY2.js");
568
+ const { readAdoptionRecords, aggregateBySkill } = await import("./dist-MCTEX5QH.js");
568
569
  const records = readAdoptionRecords(cwd);
569
570
  const skillRecords = records.filter((r) => r.skill === name);
570
571
  if (skillRecords.length === 0) {
@@ -1995,10 +1996,24 @@ function createCheckHarnessStrengthCommand() {
1995
1996
  init_dist3();
1996
1997
  import { Command as Command15 } from "commander";
1997
1998
  import * as path9 from "path";
1999
+ function resolveConfiguredEntryPoints(configPath) {
2000
+ const configResult = resolveConfig(configPath);
2001
+ if (!configResult.ok) return void 0;
2002
+ const config = configResult.value;
2003
+ const fromPerformance = config.performance?.entryPoints;
2004
+ if (Array.isArray(fromPerformance) && fromPerformance.length > 0) {
2005
+ return fromPerformance.filter((e) => typeof e === "string");
2006
+ }
2007
+ const fromEntropy = config.entropy?.entryPoints;
2008
+ if (Array.isArray(fromEntropy) && fromEntropy.length > 0) return fromEntropy;
2009
+ return void 0;
2010
+ }
1998
2011
  async function runCheckPerf(cwd, options) {
1999
2012
  const runAll2 = !options.structural && !options.size && !options.coupling;
2013
+ const entryPoints = resolveConfiguredEntryPoints(options.configPath);
2000
2014
  const analyzer = new EntropyAnalyzer({
2001
2015
  rootDir: path9.resolve(cwd),
2016
+ ...entryPoints && { entryPoints },
2002
2017
  analyze: {
2003
2018
  complexity: runAll2 || !!options.structural,
2004
2019
  coupling: runAll2 || !!options.coupling,
@@ -2682,12 +2697,14 @@ async function runCleanup(options) {
2682
2697
  };
2683
2698
  const rootDir = path12.resolve(cwd, config.rootDir);
2684
2699
  const docsDir = path12.resolve(cwd, config.docsDir);
2700
+ const driftEnabled = type === "all" || type === "drift";
2701
+ const driftConfig = config.entropy?.drift;
2685
2702
  const entropyConfig = {
2686
2703
  rootDir,
2687
2704
  ...config.entropy?.entryPoints && { entryPoints: config.entropy.entryPoints },
2688
2705
  docPaths: [path12.join(docsDir, "**/*.md")],
2689
2706
  analyze: {
2690
- drift: type === "all" || type === "drift",
2707
+ drift: driftEnabled ? driftConfig ?? true : false,
2691
2708
  deadCode: type === "all" || type === "dead-code",
2692
2709
  patterns: type === "all" || type === "patterns" ? { patterns: [] } : false
2693
2710
  },
@@ -4331,8 +4348,7 @@ function promptYesNo(message) {
4331
4348
  });
4332
4349
  });
4333
4350
  }
4334
- function createDeliveriesCommand() {
4335
- const cmd = new Command32("deliveries").description("Inspect and manage webhook delivery queue");
4351
+ function registerListCommand(cmd) {
4336
4352
  cmd.command("list").description("List delivery queue entries (newest first; capped at 200 rows)").option("--status <status>", "Filter by status: pending|failed|delivered|dead").option("--subscription <id>", "Filter by subscription ID").action((opts) => {
4337
4353
  const queue = getQueue();
4338
4354
  try {
@@ -4345,6 +4361,8 @@ function createDeliveriesCommand() {
4345
4361
  queue.close();
4346
4362
  }
4347
4363
  });
4364
+ }
4365
+ function registerRetryCommand(cmd) {
4348
4366
  cmd.command("retry <id>").description("Re-enqueue a dead-lettered delivery by ID").action((id) => {
4349
4367
  const queue = getQueue();
4350
4368
  try {
@@ -4359,23 +4377,30 @@ function createDeliveriesCommand() {
4359
4377
  queue.close();
4360
4378
  }
4361
4379
  });
4380
+ }
4381
+ function buildPurgeOptions(opts) {
4382
+ const purgeOpts = {};
4383
+ if (opts.deadOnly) purgeOpts.deadOnly = true;
4384
+ if (opts.olderThan !== void 0) purgeOpts.olderThanMs = Number(opts.olderThan);
4385
+ if (opts.all) purgeOpts.all = true;
4386
+ return purgeOpts;
4387
+ }
4388
+ function ttyPurgeConfirm(count) {
4389
+ if (count === 0) {
4390
+ console.log("No matching rows to delete.");
4391
+ return false;
4392
+ }
4393
+ return promptYesNo(`Delete ${count} row(s)? [y/N] `);
4394
+ }
4395
+ function registerPurgeCommand(cmd) {
4362
4396
  cmd.command("purge").description("Delete delivery rows from the queue (requires at least one filter)").option("--dead-only", "Delete only dead-lettered rows").option("--older-than <ms>", "Delete delivered rows older than N milliseconds").option("--all", "Delete every row in the queue (use with caution)").action(async (opts) => {
4363
4397
  const queue = getQueue();
4364
4398
  try {
4365
- const purgeOpts = {};
4366
- if (opts.deadOnly) purgeOpts.deadOnly = true;
4367
- if (opts.olderThan !== void 0) purgeOpts.olderThanMs = Number(opts.olderThan);
4368
- if (opts.all) purgeOpts.all = true;
4399
+ const purgeOpts = buildPurgeOptions(opts);
4369
4400
  const isTty = Boolean(process.stdout.isTTY);
4370
4401
  const runOpts = {};
4371
4402
  if (isTty) {
4372
- runOpts.confirm = (count) => {
4373
- if (count === 0) {
4374
- console.log("No matching rows to delete.");
4375
- return false;
4376
- }
4377
- return promptYesNo(`Delete ${count} row(s)? [y/N] `);
4378
- };
4403
+ runOpts.confirm = ttyPurgeConfirm;
4379
4404
  }
4380
4405
  const result = await runDeliveriesPurge(queue, purgeOpts, runOpts);
4381
4406
  if (result === -1) {
@@ -4387,6 +4412,12 @@ function createDeliveriesCommand() {
4387
4412
  queue.close();
4388
4413
  }
4389
4414
  });
4415
+ }
4416
+ function createDeliveriesCommand() {
4417
+ const cmd = new Command32("deliveries").description("Inspect and manage webhook delivery queue");
4418
+ registerListCommand(cmd);
4419
+ registerRetryCommand(cmd);
4420
+ registerPurgeCommand(cmd);
4390
4421
  return cmd;
4391
4422
  }
4392
4423
 
@@ -4483,16 +4514,16 @@ async function readConnectorSyncStatus(graphDir) {
4483
4514
  return result;
4484
4515
  }
4485
4516
  async function runGraphStatus(projectPath) {
4486
- const { GraphStore: GraphStore2, loadGraphMetadata } = await import("./dist-OWHMNL4W.js");
4517
+ const { GraphStore: GraphStore2, loadGraphMetadata } = await import("./dist-DWBTZXR5.js");
4487
4518
  const graphDir = path18.join(projectPath, ".harness", "graph");
4488
4519
  const metaResult = await loadGraphMetadata(graphDir);
4489
4520
  if (metaResult.status === "not_found") {
4490
- return { status: "no_graph", message: "No graph found. Run `harness scan` first." };
4521
+ return { status: "no_graph", message: "No graph found. Run `harness graph scan` first." };
4491
4522
  }
4492
4523
  if (metaResult.status === "schema_mismatch") {
4493
4524
  return {
4494
4525
  status: "schema_mismatch",
4495
- message: `Graph schema version mismatch: file is v${metaResult.found}, CLI expects v${metaResult.expected}. Run \`harness scan\` to rebuild.`
4526
+ message: `Graph schema version mismatch: file is v${metaResult.found}, CLI expects v${metaResult.expected}. Run \`harness graph scan\` to rebuild.`
4496
4527
  };
4497
4528
  }
4498
4529
  const meta = metaResult.metadata;
@@ -4535,11 +4566,11 @@ async function runGraphStatus(projectPath) {
4535
4566
  // src/commands/graph/export.ts
4536
4567
  import * as path19 from "path";
4537
4568
  async function runGraphExport(projectPath, format) {
4538
- const { GraphStore: GraphStore2 } = await import("./dist-OWHMNL4W.js");
4569
+ const { GraphStore: GraphStore2 } = await import("./dist-DWBTZXR5.js");
4539
4570
  const graphDir = path19.join(projectPath, ".harness", "graph");
4540
4571
  const store = new GraphStore2();
4541
4572
  const loaded = await store.load(graphDir);
4542
- if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
4573
+ if (!loaded) throw new Error("No graph found. Run `harness graph scan` first.");
4543
4574
  if (format === "json") {
4544
4575
  const nodes = store.findNodes({});
4545
4576
  const edges = store.getEdges({});
@@ -4568,11 +4599,11 @@ async function runGraphExport(projectPath, format) {
4568
4599
  import { Command as Command35 } from "commander";
4569
4600
  import * as path20 from "path";
4570
4601
  async function runQuery(projectPath, rootNodeId, opts) {
4571
- const { GraphStore: GraphStore2, ContextQL } = await import("./dist-OWHMNL4W.js");
4602
+ const { GraphStore: GraphStore2, ContextQL } = await import("./dist-DWBTZXR5.js");
4572
4603
  const store = new GraphStore2();
4573
4604
  const graphDir = path20.join(projectPath, ".harness", "graph");
4574
4605
  const loaded = await store.load(graphDir);
4575
- if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
4606
+ if (!loaded) throw new Error("No graph found. Run `harness graph scan` first.");
4576
4607
  const params = {
4577
4608
  rootNodeIds: [rootNodeId],
4578
4609
  maxDepth: opts.depth ?? 3,
@@ -4673,7 +4704,7 @@ async function runIngest(projectPath, source, opts) {
4673
4704
  ConfluenceConnector,
4674
4705
  FigmaConnector,
4675
4706
  MiroConnector
4676
- } = await import("./dist-OWHMNL4W.js");
4707
+ } = await import("./dist-DWBTZXR5.js");
4677
4708
  const graphDir = path21.join(projectPath, ".harness", "graph");
4678
4709
  const store = new GraphStore2();
4679
4710
  await store.load(graphDir);
@@ -4689,7 +4720,7 @@ async function runIngest(projectPath, source, opts) {
4689
4720
  path21.join(projectPath, "docs", "changes")
4690
4721
  );
4691
4722
  const gitResult = await new GitIngestor(store).ingest(projectPath);
4692
- const { createExtractionRunner } = await import("./dist-OWHMNL4W.js");
4723
+ const { createExtractionRunner } = await import("./dist-DWBTZXR5.js");
4693
4724
  const extractedDir = path21.join(projectPath, ".harness", "knowledge", "extracted");
4694
4725
  const signalsResult = await createExtractionRunner().run(projectPath, store, extractedDir);
4695
4726
  const syncManager = new SyncManager(store, graphDir);
@@ -4739,7 +4770,7 @@ async function runIngest(projectPath, source, opts) {
4739
4770
  );
4740
4771
  break;
4741
4772
  case "business-signals": {
4742
- const { createExtractionRunner } = await import("./dist-OWHMNL4W.js");
4773
+ const { createExtractionRunner } = await import("./dist-DWBTZXR5.js");
4743
4774
  const extractedDir = path21.join(projectPath, ".harness", "knowledge", "extracted");
4744
4775
  result = await createExtractionRunner().run(projectPath, store, extractedDir);
4745
4776
  break;
@@ -5451,7 +5482,7 @@ async function runImpactPreview(options) {
5451
5482
  const stagedFiles = getStagedFiles(projectPath);
5452
5483
  if (stagedFiles.length === 0) return "Impact Preview: no staged changes";
5453
5484
  if (!graphExists(projectPath)) {
5454
- return "Impact Preview: skipped (no graph \u2014 run `harness scan` to enable)";
5485
+ return "Impact Preview: skipped (no graph \u2014 run `harness graph scan` to enable)";
5455
5486
  }
5456
5487
  const mode = options.detailed ? "detailed" : "summary";
5457
5488
  const acc = {
@@ -6131,7 +6162,7 @@ function createInsightsCommand() {
6131
6162
  return new Command46("insights").description("Composite project report \u2014 health, entropy, decay, attention, impact.").option("--json", "Emit JSON to stdout instead of pretty text").option("--skip <list>", `Comma-separated keys to skip (${INSIGHTS_KEYS.join(",")})`).action(async (opts) => {
6132
6163
  const cwd = process.cwd();
6133
6164
  const skip = parseSkip2(opts.skip);
6134
- const { composeInsights } = await import("./dist-IPVFYGY2.js");
6165
+ const { composeInsights } = await import("./dist-MCTEX5QH.js");
6135
6166
  const report = await composeInsights(cwd, { skip });
6136
6167
  if (opts.json) {
6137
6168
  console.log(JSON.stringify(report, null, 2));
@@ -7323,6 +7354,166 @@ ${file}`);
7323
7354
  import { Command as Command55 } from "commander";
7324
7355
  import * as path41 from "path";
7325
7356
  import chalk7 from "chalk";
7357
+ function resolveInferenceOptions(cfgKnowledge) {
7358
+ const patterns = cfgKnowledge?.domainPatterns;
7359
+ const blocklist = cfgKnowledge?.domainBlocklist;
7360
+ const hasPatterns = (patterns?.length ?? 0) > 0;
7361
+ const hasBlocklist = (blocklist?.length ?? 0) > 0;
7362
+ if (!hasPatterns && !hasBlocklist) {
7363
+ return void 0;
7364
+ }
7365
+ return {
7366
+ ...hasPatterns ? { extraPatterns: patterns } : {},
7367
+ ...hasBlocklist ? { extraBlocklist: blocklist } : {}
7368
+ };
7369
+ }
7370
+ function buildPipelineOptions(opts, projectDir, graphDir, inferenceOptions) {
7371
+ const pipelineOpts = {
7372
+ projectDir,
7373
+ fix: Boolean(opts.fix),
7374
+ ci: Boolean(opts.ci),
7375
+ ...opts.domain ? { domain: opts.domain } : {},
7376
+ graphDir,
7377
+ analyzeImages: Boolean(opts.analyzeImages),
7378
+ ...inferenceOptions ? { inferenceOptions } : {}
7379
+ };
7380
+ if (opts.imagePaths) {
7381
+ pipelineOpts.imagePaths = opts.imagePaths.split(",").map((p) => p.trim());
7382
+ }
7383
+ return pipelineOpts;
7384
+ }
7385
+ async function createAnalysisProvider() {
7386
+ try {
7387
+ const intelligence = await import("@harness-engineering/intelligence");
7388
+ const Provider = intelligence.AnthropicAnalysisProvider;
7389
+ const apiKey = process.env.ANTHROPIC_API_KEY;
7390
+ if (!apiKey) {
7391
+ logger.error("ANTHROPIC_API_KEY environment variable is required for --analyze-images");
7392
+ process.exit(1);
7393
+ }
7394
+ return new Provider({ apiKey });
7395
+ } catch {
7396
+ logger.error(
7397
+ "Image analysis requires @harness-engineering/intelligence with ANTHROPIC_API_KEY set."
7398
+ );
7399
+ process.exit(1);
7400
+ }
7401
+ }
7402
+ function printJsonResult(result) {
7403
+ console.log(
7404
+ JSON.stringify(
7405
+ {
7406
+ verdict: result.verdict,
7407
+ driftScore: result.driftScore,
7408
+ iterations: result.iterations,
7409
+ findings: result.findings,
7410
+ extraction: result.extraction,
7411
+ errors: result.errors,
7412
+ gaps: {
7413
+ domains: result.gaps.domains.length,
7414
+ totalEntries: result.gaps.totalEntries,
7415
+ totalExtracted: result.gaps.totalExtracted,
7416
+ totalGaps: result.gaps.totalGaps
7417
+ },
7418
+ remediations: result.remediations,
7419
+ contradictions: {
7420
+ count: result.contradictions.contradictions.length,
7421
+ sourcePairCounts: result.contradictions.sourcePairCounts
7422
+ },
7423
+ coverage: {
7424
+ overallScore: result.coverage.overallScore,
7425
+ overallGrade: result.coverage.overallGrade,
7426
+ domains: result.coverage.domains.length
7427
+ },
7428
+ ...result.materialization ? {
7429
+ materialization: {
7430
+ created: result.materialization.created.length,
7431
+ skipped: result.materialization.skipped.length,
7432
+ files: result.materialization.created.map((d) => d.filePath)
7433
+ }
7434
+ } : {}
7435
+ },
7436
+ null,
7437
+ 2
7438
+ )
7439
+ );
7440
+ }
7441
+ function printSummary(result) {
7442
+ const verdictColor = result.verdict === "pass" ? chalk7.green("PASS") : result.verdict === "warn" ? chalk7.yellow("WARN") : chalk7.red("FAIL");
7443
+ console.log("");
7444
+ console.log(`KNOWLEDGE PIPELINE -- Verdict: ${verdictColor}`);
7445
+ console.log("");
7446
+ console.log(` Drift Score: ${result.driftScore.toFixed(2)}`);
7447
+ console.log(
7448
+ ` Findings: ${result.findings.new} new, ${result.findings.stale} stale, ${result.findings.drifted} drifted, ${result.findings.contradicting} contradicting`
7449
+ );
7450
+ console.log(
7451
+ ` Extraction: ${result.extraction.codeSignals} code signals, ${result.extraction.diagrams} diagrams, ${result.extraction.linkerFacts} linker facts, ${result.extraction.businessKnowledge} business knowledge, ${result.extraction.decisions} decisions, ${result.extraction.images} images`
7452
+ );
7453
+ console.log(
7454
+ ` Gaps: ${result.gaps.domains.length} domains \u2014 ${result.gaps.totalEntries} documented / ${result.gaps.totalExtracted} extracted / ${result.gaps.totalGaps} undocumented`
7455
+ );
7456
+ if (result.iterations > 1) {
7457
+ console.log(` Convergence: ${result.iterations} iterations`);
7458
+ }
7459
+ if (result.remediations.length > 0) {
7460
+ console.log(` Remediations: ${result.remediations.length} applied`);
7461
+ }
7462
+ }
7463
+ function printIngestionErrors(result) {
7464
+ if (result.errors.length === 0) {
7465
+ return;
7466
+ }
7467
+ console.warn("");
7468
+ console.warn(` ${result.errors.length} ingestion warning(s):`);
7469
+ for (const err of result.errors) {
7470
+ console.warn(` - ${err}`);
7471
+ }
7472
+ }
7473
+ function printMaterialization(result) {
7474
+ if (!result.materialization) {
7475
+ return;
7476
+ }
7477
+ const mat = result.materialization;
7478
+ console.log(
7479
+ ` Materialization: ${mat.created.length} docs created, ${mat.skipped.length} skipped`
7480
+ );
7481
+ for (const doc of mat.created) {
7482
+ console.log(` ${chalk7.green("+")} ${doc.filePath}`);
7483
+ }
7484
+ }
7485
+ function printContradictions(result, opts) {
7486
+ if (!opts.checkContradictions && result.contradictions.contradictions.length === 0) {
7487
+ return;
7488
+ }
7489
+ console.log("");
7490
+ console.log(
7491
+ ` Contradictions: ${result.contradictions.contradictions.length} detected across ${result.contradictions.totalChecked} knowledge nodes`
7492
+ );
7493
+ for (const c of result.contradictions.contradictions) {
7494
+ console.log(` ${chalk7.red("!")} ${c.description} [${c.conflictType}] (${c.severity})`);
7495
+ }
7496
+ }
7497
+ function printCoverage(result, opts) {
7498
+ if (!opts.coverage && result.coverage.domains.length === 0) {
7499
+ return;
7500
+ }
7501
+ console.log("");
7502
+ console.log(` Coverage: ${result.coverage.overallGrade} (${result.coverage.overallScore}/100)`);
7503
+ for (const d of result.coverage.domains) {
7504
+ console.log(
7505
+ ` ${d.domain}: ${d.grade} (${d.score}/100) \u2014 ${d.knowledgeEntries} knowledge, ${d.linkedEntities}/${d.codeEntities} code linked`
7506
+ );
7507
+ }
7508
+ }
7509
+ function printHumanResult(result, opts) {
7510
+ printSummary(result);
7511
+ printIngestionErrors(result);
7512
+ printMaterialization(result);
7513
+ printContradictions(result, opts);
7514
+ printCoverage(result, opts);
7515
+ console.log("");
7516
+ }
7326
7517
  function createKnowledgePipelineCommand() {
7327
7518
  return new Command55("knowledge-pipeline").description("Run knowledge extraction, drift detection, and gap analysis").option("--fix", "Enable convergence-based auto-remediation (default: detect-only)").option("--ci", "Non-interactive mode \u2014 apply safe fixes only, report everything else").option("--domain <name>", "Limit pipeline to a specific knowledge domain").option("--drift-check", "Exit 1 if unresolved drift exists (CI gate mode)").option("--analyze-images", "Enable vision model analysis of image files").option("--image-paths <paths>", "Comma-separated image file paths for analysis").option("--coverage", "Display per-domain coverage report").option("--check-contradictions", "Display cross-source contradiction report").action(async (opts, cmd) => {
7328
7519
  const globalOpts = cmd.optsWithGlobals();
@@ -7331,7 +7522,7 @@ function createKnowledgePipelineCommand() {
7331
7522
  const graphDir = path41.join(projectDir, ".harness", "graph");
7332
7523
  const fs50 = await import("fs/promises");
7333
7524
  await fs50.mkdir(graphDir, { recursive: true });
7334
- const { GraphStore: GraphStore2, KnowledgePipelineRunner } = await import("./dist-OWHMNL4W.js");
7525
+ const { GraphStore: GraphStore2, KnowledgePipelineRunner } = await import("./dist-DWBTZXR5.js");
7335
7526
  const store = new GraphStore2();
7336
7527
  try {
7337
7528
  await store.load(graphDir);
@@ -7339,145 +7530,19 @@ function createKnowledgePipelineCommand() {
7339
7530
  }
7340
7531
  const cfgResult = resolveConfig();
7341
7532
  const cfgKnowledge = cfgResult.ok ? cfgResult.value.knowledge : void 0;
7342
- const inferenceOptions = cfgKnowledge && ((cfgKnowledge.domainPatterns?.length ?? 0) > 0 || (cfgKnowledge.domainBlocklist?.length ?? 0) > 0) ? {
7343
- ...(cfgKnowledge.domainPatterns?.length ?? 0) > 0 ? { extraPatterns: cfgKnowledge.domainPatterns } : {},
7344
- ...(cfgKnowledge.domainBlocklist?.length ?? 0) > 0 ? { extraBlocklist: cfgKnowledge.domainBlocklist } : {}
7345
- } : void 0;
7346
- const pipelineOpts = {
7347
- projectDir,
7348
- fix: Boolean(opts.fix),
7349
- ci: Boolean(opts.ci),
7350
- ...opts.domain ? { domain: opts.domain } : {},
7351
- graphDir,
7352
- analyzeImages: Boolean(opts.analyzeImages),
7353
- ...inferenceOptions ? { inferenceOptions } : {}
7354
- };
7355
- if (opts.imagePaths) {
7356
- pipelineOpts.imagePaths = opts.imagePaths.split(",").map((p) => p.trim());
7357
- }
7533
+ const inferenceOptions = resolveInferenceOptions(cfgKnowledge);
7534
+ const pipelineOpts = buildPipelineOptions(opts, projectDir, graphDir, inferenceOptions);
7358
7535
  if (opts.analyzeImages) {
7359
- try {
7360
- const intelligence = await import("@harness-engineering/intelligence");
7361
- const Provider = intelligence.AnthropicAnalysisProvider;
7362
- const apiKey = process.env.ANTHROPIC_API_KEY;
7363
- if (!apiKey) {
7364
- logger.error(
7365
- "ANTHROPIC_API_KEY environment variable is required for --analyze-images"
7366
- );
7367
- process.exit(1);
7368
- }
7369
- pipelineOpts.analysisProvider = new Provider({ apiKey });
7370
- } catch {
7371
- logger.error(
7372
- "Image analysis requires @harness-engineering/intelligence with ANTHROPIC_API_KEY set."
7373
- );
7374
- process.exit(1);
7375
- }
7536
+ pipelineOpts.analysisProvider = await createAnalysisProvider();
7376
7537
  }
7377
7538
  const runner = new KnowledgePipelineRunner(store);
7378
7539
  const result = await runner.run(
7379
7540
  pipelineOpts
7380
7541
  );
7381
7542
  if (globalOpts.json) {
7382
- console.log(
7383
- JSON.stringify(
7384
- {
7385
- verdict: result.verdict,
7386
- driftScore: result.driftScore,
7387
- iterations: result.iterations,
7388
- findings: result.findings,
7389
- extraction: result.extraction,
7390
- errors: result.errors,
7391
- gaps: {
7392
- domains: result.gaps.domains.length,
7393
- totalEntries: result.gaps.totalEntries,
7394
- totalExtracted: result.gaps.totalExtracted,
7395
- totalGaps: result.gaps.totalGaps
7396
- },
7397
- remediations: result.remediations,
7398
- contradictions: {
7399
- count: result.contradictions.contradictions.length,
7400
- sourcePairCounts: result.contradictions.sourcePairCounts
7401
- },
7402
- coverage: {
7403
- overallScore: result.coverage.overallScore,
7404
- overallGrade: result.coverage.overallGrade,
7405
- domains: result.coverage.domains.length
7406
- },
7407
- ...result.materialization ? {
7408
- materialization: {
7409
- created: result.materialization.created.length,
7410
- skipped: result.materialization.skipped.length,
7411
- files: result.materialization.created.map(
7412
- (d) => d.filePath
7413
- )
7414
- }
7415
- } : {}
7416
- },
7417
- null,
7418
- 2
7419
- )
7420
- );
7543
+ printJsonResult(result);
7421
7544
  } else {
7422
- const verdictColor = result.verdict === "pass" ? chalk7.green("PASS") : result.verdict === "warn" ? chalk7.yellow("WARN") : chalk7.red("FAIL");
7423
- console.log("");
7424
- console.log(`KNOWLEDGE PIPELINE -- Verdict: ${verdictColor}`);
7425
- console.log("");
7426
- console.log(` Drift Score: ${result.driftScore.toFixed(2)}`);
7427
- console.log(
7428
- ` Findings: ${result.findings.new} new, ${result.findings.stale} stale, ${result.findings.drifted} drifted, ${result.findings.contradicting} contradicting`
7429
- );
7430
- console.log(
7431
- ` Extraction: ${result.extraction.codeSignals} code signals, ${result.extraction.diagrams} diagrams, ${result.extraction.linkerFacts} linker facts, ${result.extraction.businessKnowledge} business knowledge, ${result.extraction.decisions} decisions, ${result.extraction.images} images`
7432
- );
7433
- console.log(
7434
- ` Gaps: ${result.gaps.domains.length} domains \u2014 ${result.gaps.totalEntries} documented / ${result.gaps.totalExtracted} extracted / ${result.gaps.totalGaps} undocumented`
7435
- );
7436
- if (result.iterations > 1) {
7437
- console.log(` Convergence: ${result.iterations} iterations`);
7438
- }
7439
- if (result.remediations.length > 0) {
7440
- console.log(` Remediations: ${result.remediations.length} applied`);
7441
- }
7442
- if (result.errors.length > 0) {
7443
- console.warn("");
7444
- console.warn(` ${result.errors.length} ingestion warning(s):`);
7445
- for (const err of result.errors) {
7446
- console.warn(` - ${err}`);
7447
- }
7448
- }
7449
- if (result.materialization) {
7450
- const mat = result.materialization;
7451
- console.log(
7452
- ` Materialization: ${mat.created.length} docs created, ${mat.skipped.length} skipped`
7453
- );
7454
- for (const doc of mat.created) {
7455
- console.log(` ${chalk7.green("+")} ${doc.filePath}`);
7456
- }
7457
- }
7458
- if (opts.checkContradictions || result.contradictions.contradictions.length > 0) {
7459
- console.log("");
7460
- console.log(
7461
- ` Contradictions: ${result.contradictions.contradictions.length} detected across ${result.contradictions.totalChecked} knowledge nodes`
7462
- );
7463
- for (const c of result.contradictions.contradictions) {
7464
- console.log(
7465
- ` ${chalk7.red("!")} ${c.description} [${c.conflictType}] (${c.severity})`
7466
- );
7467
- }
7468
- }
7469
- if (opts.coverage || result.coverage.domains.length > 0) {
7470
- console.log("");
7471
- console.log(
7472
- ` Coverage: ${result.coverage.overallGrade} (${result.coverage.overallScore}/100)`
7473
- );
7474
- for (const d of result.coverage.domains) {
7475
- console.log(
7476
- ` ${d.domain}: ${d.grade} (${d.score}/100) \u2014 ${d.knowledgeEntries} knowledge, ${d.linkedEntities}/${d.codeEntities} code linked`
7477
- );
7478
- }
7479
- }
7480
- console.log("");
7545
+ printHumanResult(result, opts);
7481
7546
  }
7482
7547
  const unresolvedDrift = result.findings.drifted + result.findings.stale + result.findings.contradicting;
7483
7548
  if (opts.driftCheck && unresolvedDrift > 0) {
@@ -8208,7 +8273,7 @@ function createMcpCommand() {
8208
8273
  parseBudget
8209
8274
  ).action(async (opts) => {
8210
8275
  const [{ startServer: startServer2, getToolDefinitions: getToolDefinitions2 }, { selectTier }] = await Promise.all([
8211
- import("./mcp-TCLNK7HG.js"),
8276
+ import("./mcp-5V4LPMB3.js"),
8212
8277
  import("./tool-tiers-OKK5FE57.js")
8213
8278
  ]);
8214
8279
  if (opts.tools && opts.tools.length > 0) {
@@ -9283,7 +9348,7 @@ function registerBenchCommand(perf) {
9283
9348
  perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob2, _opts, cmd) => {
9284
9349
  const globalOpts = cmd.optsWithGlobals();
9285
9350
  const cwd = process.cwd();
9286
- const { BenchmarkRunner } = await import("./dist-IPVFYGY2.js");
9351
+ const { BenchmarkRunner } = await import("./dist-MCTEX5QH.js");
9287
9352
  const runner = new BenchmarkRunner();
9288
9353
  const benchFiles = runner.discover(cwd, glob2);
9289
9354
  if (benchFiles.length === 0) {
@@ -9347,7 +9412,7 @@ async function runBaselinesShow(globalOpts) {
9347
9412
  }
9348
9413
  async function runBaselinesUpdate(globalOpts) {
9349
9414
  const cwd = process.cwd();
9350
- const { BenchmarkRunner } = await import("./dist-IPVFYGY2.js");
9415
+ const { BenchmarkRunner } = await import("./dist-MCTEX5QH.js");
9351
9416
  const runner = new BenchmarkRunner();
9352
9417
  const manager = new BaselineManager(cwd);
9353
9418
  logger.info("Running benchmarks to update baselines...");
@@ -9388,7 +9453,7 @@ function registerReportCommand(perf) {
9388
9453
  perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
9389
9454
  const globalOpts = cmd.optsWithGlobals();
9390
9455
  const cwd = process.cwd();
9391
- const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-IPVFYGY2.js");
9456
+ const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-MCTEX5QH.js");
9392
9457
  const analyzer = new EntropyAnalyzer2({
9393
9458
  rootDir: path50.resolve(cwd),
9394
9459
  analyze: { complexity: true, coupling: true }
@@ -9691,79 +9756,560 @@ function createPredictCommand() {
9691
9756
  return command;
9692
9757
  }
9693
9758
 
9694
- // src/commands/proposals.ts
9759
+ // src/commands/pre-merge-brief.ts
9760
+ init_dist2();
9761
+ import { execFileSync as execFileSync7 } from "child_process";
9762
+ import { readFileSync as readFileSync18 } from "fs";
9763
+ import { join as join40 } from "path";
9764
+ import { Command as Command77 } from "commander";
9765
+ import { gatherSignals } from "@harness-engineering/signals";
9766
+
9767
+ // src/commands/review-ci.ts
9695
9768
  init_dist3();
9696
- import { Command as Command76 } from "commander";
9697
- import { resolve as resolve34 } from "path";
9698
- function projectRoot() {
9699
- return resolve34(process.env["HARNESS_PROJECT_ROOT"] ?? process.cwd());
9700
- }
9701
- function summarizeProposal(p) {
9702
- return {
9703
- id: p.id,
9704
- kind: p.kind,
9705
- targetSkill: p.targetSkill,
9706
- name: p.content.name,
9707
- status: p.status,
9708
- proposedBy: p.proposedBy,
9709
- createdAt: p.createdAt,
9710
- gateLastRunAt: p.gate?.lastRunAt,
9711
- findings: p.gate?.findings?.length ?? 0
9712
- };
9713
- }
9714
- async function runProposalsList(status) {
9715
- const opts = {};
9716
- if (status) opts.status = status;
9717
- const proposals = await listProposals(projectRoot(), opts);
9718
- return proposals.map(summarizeProposal);
9719
- }
9720
- async function runProposalsShow(id) {
9721
- return getProposal(projectRoot(), id);
9769
+ import { execFileSync as execFileSync6 } from "child_process";
9770
+ import { writeFileSync as writeFileSync18 } from "fs";
9771
+ import { Command as Command76, Option as Option2 } from "commander";
9772
+
9773
+ // src/commands/review-ci-local-adapter.ts
9774
+ import { z } from "zod";
9775
+ import { OpenAICompatibleAnalysisProvider } from "@harness-engineering/intelligence";
9776
+ var FindingSchema = z.object({
9777
+ id: z.string(),
9778
+ file: z.string(),
9779
+ lineRange: z.tuple([z.number(), z.number()]),
9780
+ domain: z.enum(["compliance", "bug", "security", "architecture", "learnings"]),
9781
+ severity: z.enum(["critical", "important", "suggestion"]),
9782
+ title: z.string(),
9783
+ rationale: z.string(),
9784
+ suggestion: z.string().optional(),
9785
+ evidence: z.array(z.string())
9786
+ });
9787
+ var LocalVerdictSchema = z.object({
9788
+ assessment: z.enum(["approve", "comment", "request-changes"]),
9789
+ findings: z.array(FindingSchema)
9790
+ });
9791
+ var MAX_SURFACED_ERROR_LEN = 200;
9792
+ function sanitizeProviderError(err) {
9793
+ const raw = err instanceof Error ? err.message : String(err);
9794
+ const redacted = raw.replace(/https?:\/\/\S+/gi, "[endpoint]").replace(/\b(bearer|authorization|api[-_]?key|token)\b\s*[:=]?\s*\S+/gi, "[redacted]").replace(/\s+/g, " ").trim();
9795
+ const capped = redacted.length > MAX_SURFACED_ERROR_LEN ? redacted.slice(0, MAX_SURFACED_ERROR_LEN - 1) + "\u2026" : redacted;
9796
+ return `local runner provider error: ${capped}`;
9722
9797
  }
9723
- async function runProposalsReject(id, reason) {
9724
- const decision = {
9725
- decidedAt: (/* @__PURE__ */ new Date()).toISOString(),
9726
- decidedBy: process.env["USER"] ?? "cli",
9727
- action: "rejected",
9728
- reason
9798
+ function createLocalInvoke() {
9799
+ return async ({ endpoint, model, instruction, diff: diff2 }) => {
9800
+ if (!/^https?:\/\//i.test(endpoint)) {
9801
+ throw new Error(
9802
+ `HARNESS_LOCAL_ENDPOINT must be an http(s) URL (got '${endpoint}'); e.g. http://localhost:1234/v1`
9803
+ );
9804
+ }
9805
+ const provider = new OpenAICompatibleAnalysisProvider({
9806
+ apiKey: process.env.HARNESS_LOCAL_API_KEY ?? "local",
9807
+ baseUrl: endpoint,
9808
+ defaultModel: model
9809
+ });
9810
+ try {
9811
+ const { result } = await provider.analyze({
9812
+ prompt: `${instruction}
9813
+
9814
+ ---
9815
+ DIFF UNDER REVIEW:
9816
+ ${diff2}`,
9817
+ responseSchema: LocalVerdictSchema,
9818
+ model
9819
+ });
9820
+ return JSON.stringify(result);
9821
+ } catch (err) {
9822
+ throw new Error(sanitizeProviderError(err), { cause: err });
9823
+ }
9729
9824
  };
9730
- return updateProposal(projectRoot(), id, { status: "rejected", decision });
9731
- }
9732
- var ALLOWED_STATUSES = [
9733
- "open",
9734
- "gate-running",
9735
- "gate-failed",
9736
- "approved",
9737
- "rejected",
9738
- "all"
9739
- ];
9740
- function fail(message) {
9741
- console.error(message);
9742
- process.exitCode = 1;
9743
- }
9744
- async function actListCommand(opts) {
9745
- const raw = opts.status ?? "open";
9746
- if (!ALLOWED_STATUSES.includes(raw)) {
9747
- fail(`Error: unknown status "${raw}"`);
9748
- return;
9749
- }
9750
- const proposals = await runProposalsList(raw);
9751
- console.log(JSON.stringify(proposals, null, 2));
9752
9825
  }
9753
- async function actShowCommand(id) {
9754
- const proposal = await runProposalsShow(id);
9755
- if (!proposal) {
9756
- fail(`No such proposal: ${id}`);
9757
- return;
9826
+
9827
+ // src/commands/review-ci.ts
9828
+ var KNOWN_RUNNERS = Object.keys(RUNNER_PRESETS);
9829
+ var BLOCK_ON_LEVELS = [...CI_ASSESSMENTS, "none"];
9830
+ function assertKnownRunner(runner) {
9831
+ if (runner === void 0) return;
9832
+ if (!KNOWN_RUNNERS.includes(runner)) {
9833
+ throw new Error(`unknown runner '${runner}' (expected: ${KNOWN_RUNNERS.join("|")})`);
9758
9834
  }
9759
- console.log(JSON.stringify(proposal, null, 2));
9760
9835
  }
9761
- async function actRejectCommand(id, opts) {
9836
+ var defaultRunGit = (args) => execFileSync6("git", args, { encoding: "utf-8" }).toString().trim();
9837
+ function resolveDiffRange(opts) {
9838
+ if (opts.range) return opts.range;
9839
+ const runGit = opts.runGit ?? defaultRunGit;
9840
+ let base = "main";
9762
9841
  try {
9763
- const updated = await runProposalsReject(id, opts.reason);
9764
- console.log(JSON.stringify(summarizeProposal(updated), null, 2));
9765
- } catch (err) {
9766
- fail(err instanceof Error ? err.message : String(err));
9842
+ const ref = runGit(["symbolic-ref", "refs/remotes/origin/HEAD"]);
9843
+ const m = ref.match(/origin\/(.+)$/);
9844
+ if (m?.[1]) base = m[1];
9845
+ } catch {
9846
+ }
9847
+ return `origin/${base}...HEAD`;
9848
+ }
9849
+ function splitDiffByFile(rawDiff) {
9850
+ const sections = /* @__PURE__ */ new Map();
9851
+ const headerRe = /^diff --git a\/(.+?) b\/(.+?)$/;
9852
+ let currentPath = null;
9853
+ let buffer = [];
9854
+ const flush = () => {
9855
+ if (currentPath !== null) sections.set(currentPath, buffer.join("\n"));
9856
+ };
9857
+ for (const line of rawDiff.split("\n")) {
9858
+ const m = line.match(headerRe);
9859
+ if (m?.[2]) {
9860
+ flush();
9861
+ currentPath = m[2];
9862
+ buffer = [line];
9863
+ } else if (currentPath !== null) {
9864
+ buffer.push(line);
9865
+ }
9866
+ }
9867
+ flush();
9868
+ return sections;
9869
+ }
9870
+ function buildDiffInfo(rawDiff) {
9871
+ const parsed = parseDiff(rawDiff);
9872
+ if (!parsed.ok) throw new Error(`Failed to parse diff: ${parsed.error.message}`);
9873
+ const files = parsed.value.files;
9874
+ const perFile = splitDiffByFile(rawDiff);
9875
+ return {
9876
+ changedFiles: files.map((f) => f.path),
9877
+ newFiles: files.filter((f) => f.status === "added").map((f) => f.path),
9878
+ deletedFiles: files.filter((f) => f.status === "deleted").map((f) => f.path),
9879
+ totalDiffLines: rawDiff ? rawDiff.split("\n").length : 0,
9880
+ // On a path-key miss, fall back to '' (the file contributes no per-file diff)
9881
+ // rather than the ENTIRE raw diff — substituting the whole diff would duplicate
9882
+ // every file's content into one section, inflating the STDIN payload to the LLM
9883
+ // (and risking core's execMaxStdoutBytes). With splitDiffByFile aligned to core's
9884
+ // path extraction, ordinary paths never miss; this is the safe degenerate case.
9885
+ fileDiffs: new Map(files.map((f) => [f.path, perFile.get(f.path) ?? ""]))
9886
+ };
9887
+ }
9888
+ function defaultResolveRaw(range, _cwd, runGit) {
9889
+ return runGit(["diff", range]);
9890
+ }
9891
+ function buildCallOpts(opts, cwd, diff2) {
9892
+ const runner = opts.runner;
9893
+ return {
9894
+ projectRoot: cwd,
9895
+ diff: diff2,
9896
+ ...runner ? { runner } : {},
9897
+ ...opts.blockOn ? { blockOn: opts.blockOn } : {},
9898
+ ...runner === "local" ? { localInvoke: opts.localInvoke ?? createLocalInvoke() } : {}
9899
+ };
9900
+ }
9901
+ async function runReviewCi(opts) {
9902
+ assertKnownRunner(opts.runner);
9903
+ const cwd = opts.cwd ?? process.cwd();
9904
+ const runGit = opts.runGit ?? defaultRunGit;
9905
+ const range = resolveDiffRange({
9906
+ ...opts.diffRange ? { range: opts.diffRange } : {},
9907
+ cwd,
9908
+ runGit
9909
+ });
9910
+ const rawDiff = (opts.resolveRaw ?? defaultResolveRaw)(range, cwd, runGit);
9911
+ const diff2 = buildDiffInfo(rawDiff);
9912
+ const callOpts = buildCallOpts(opts, cwd, diff2);
9913
+ return (opts.runCiReviewImpl ?? runCiReview)(callOpts);
9914
+ }
9915
+ function findingLine(f) {
9916
+ const loc = f.lineRange ? `${f.file}:${f.lineRange[0]}` : f.file;
9917
+ return `- \`${f.severity}\` **${loc}** \u2014 ${f.title}`;
9918
+ }
9919
+ function buildReviewBody(verdict) {
9920
+ const findings = verdict.findings ?? [];
9921
+ const blocking = verdict.blockingFindings ?? [];
9922
+ const icon = verdict.assessment === "approve" ? "\u2705" : verdict.assessment === "request-changes" ? "\u{1F6D1}" : "\u{1F4AC}";
9923
+ const out = [
9924
+ `## ${icon} harness review-ci \u2014 ${verdict.assessment}`,
9925
+ "",
9926
+ `**Runner:** \`${verdict.runner}\` \u2022 **Findings:** ${findings.length} (blocking: ${blocking.length})`
9927
+ ];
9928
+ if (verdict.skipped) out.push("", `> \u26A0\uFE0F ${verdict.skipReason ?? "A review tier was skipped."}`);
9929
+ if (blocking.length) out.push("", "### Blocking", ...blocking.map(findingLine));
9930
+ const nonBlocking = findings.filter((f) => !blocking.some((b) => b.id === f.id));
9931
+ if (nonBlocking.length) out.push("", "### Other findings", ...nonBlocking.map(findingLine));
9932
+ if (!findings.length) out.push("", "No findings. \u{1F389}");
9933
+ out.push("", "<sub>Posted by `harness review-ci`. The CI exit code is authoritative.</sub>");
9934
+ return out.join("\n");
9935
+ }
9936
+ var defaultPostReview = (verdict) => {
9937
+ execFileSync6("gh", ["pr", "comment", "--body-file", "-"], {
9938
+ input: buildReviewBody(verdict),
9939
+ stdio: ["pipe", "pipe", "pipe"],
9940
+ encoding: "utf-8"
9941
+ });
9942
+ };
9943
+ function emitReviewCi(result, opts, writeFile2 = (p, d) => writeFileSync18(p, d), log = (m) => process.stdout.write(m + "\n"), postReview = defaultPostReview) {
9944
+ const serialized = JSON.stringify(result.verdict, null, 2);
9945
+ const jsonToStdout = opts.jsonPath === true;
9946
+ if (!jsonToStdout) log(result.terminalOutput);
9947
+ if (typeof opts.jsonPath === "string") writeFile2(opts.jsonPath, serialized);
9948
+ else if (jsonToStdout) log(serialized);
9949
+ if (opts.comment) {
9950
+ try {
9951
+ postReview(result.verdict);
9952
+ } catch (err) {
9953
+ logger.warn(
9954
+ `review-ci: failed to post PR comment (${err instanceof Error ? err.message : String(err)}). The verdict above is authoritative; the exit code still reflects the gate.`
9955
+ );
9956
+ }
9957
+ }
9958
+ }
9959
+ function createReviewCiCommand() {
9960
+ return new Command76("review-ci").description("Run the tiered code-review gate (floor + optional LLM runner) for CI").addOption(
9961
+ new Option2("--runner <runner>", `${KNOWN_RUNNERS.join(" | ")} (omit = floor-only)`).choices(
9962
+ KNOWN_RUNNERS
9963
+ )
9964
+ ).addOption(
9965
+ new Option2("--block-on <level>", BLOCK_ON_LEVELS.join(" | ")).choices(BLOCK_ON_LEVELS).default("request-changes")
9966
+ ).option("--diff <range>", "git range (default: origin/<base>...HEAD)").option("--comment", "post the verdict as a comment on the current branch's PR via gh").option(
9967
+ "--out <path>",
9968
+ "write the verdict JSON artifact to a file (use the global --json to stream it to stdout instead)"
9969
+ ).action(async (opts, cmd) => {
9970
+ const result = await runReviewCi({
9971
+ runner: opts.runner,
9972
+ blockOn: opts.blockOn,
9973
+ diffRange: opts.diff
9974
+ });
9975
+ const streamJson = cmd.optsWithGlobals().json === true;
9976
+ emitReviewCi(result, {
9977
+ jsonPath: typeof opts.out === "string" ? opts.out : streamJson ? true : void 0,
9978
+ comment: opts.comment
9979
+ });
9980
+ process.exit(result.exitCode);
9981
+ });
9982
+ }
9983
+
9984
+ // src/commands/pre-merge-brief.ts
9985
+ var BRIEF_MARKER = "<!-- harness:pre-merge-brief -->";
9986
+ var UNAVAILABLE = "> _unavailable / not configured._";
9987
+ function renderDiffSummary(diff2) {
9988
+ const out = ["## Diff summary", ""];
9989
+ if (!diff2) {
9990
+ out.push(UNAVAILABLE);
9991
+ return out;
9992
+ }
9993
+ out.push(
9994
+ `**Files changed:** ${diff2.changedFiles.length} (new: ${diff2.newFiles.length}, deleted: ${diff2.deletedFiles.length}) \u2022 **Diff lines:** ${diff2.totalDiffLines}`
9995
+ );
9996
+ return out;
9997
+ }
9998
+ function findingLine2(f) {
9999
+ const loc = f.lineRange ? `${f.file}:${f.lineRange[0]}` : f.file;
10000
+ return `- \`${f.severity}\` **${loc}** \u2014 ${f.title}`;
10001
+ }
10002
+ function renderPopulatedVerdict(verdict) {
10003
+ const findings = verdict.findings ?? [];
10004
+ const blocking = verdict.blockingFindings ?? [];
10005
+ const out = [
10006
+ `**Assessment:** \`${verdict.assessment}\` \u2022 **Runner:** \`${verdict.runner}\` \u2022 **Findings:** ${findings.length} (blocking: ${blocking.length})`
10007
+ ];
10008
+ if (verdict.skipped) {
10009
+ out.push("", `> \u26A0\uFE0F ${verdict.skipReason ?? "A review tier was skipped."}`);
10010
+ }
10011
+ if (blocking.length) out.push("", "### Blocking", ...blocking.map(findingLine2));
10012
+ const nonBlocking = findings.filter((f) => !blocking.some((b) => b.id === f.id));
10013
+ if (nonBlocking.length) out.push("", "### Other findings", ...nonBlocking.map(findingLine2));
10014
+ return out;
10015
+ }
10016
+ function renderReviewVerdict(verdict) {
10017
+ if (!verdict) return ["## Review verdict", "", UNAVAILABLE];
10018
+ return ["## Review verdict", "", ...renderPopulatedVerdict(verdict)];
10019
+ }
10020
+ function signalLine(s) {
10021
+ const value = s.value === null ? "\u2014" : `${s.value}${s.unit ?? ""}`;
10022
+ return `- \`${s.status}\` **${s.label}** \u2014 ${value}`;
10023
+ }
10024
+ function renderSignalStatus(signals) {
10025
+ const out = ["## Signal status", ""];
10026
+ if (!signals || signals.length === 0) {
10027
+ out.push(UNAVAILABLE);
10028
+ return out;
10029
+ }
10030
+ out.push(...signals.map(signalLine));
10031
+ return out;
10032
+ }
10033
+ function renderOutcomeEval(outcome) {
10034
+ const out = ["## Outcome evaluation", ""];
10035
+ if (!outcome) {
10036
+ out.push("> _not yet evaluated._");
10037
+ return out;
10038
+ }
10039
+ out.push(
10040
+ `**Verdict:** \`${outcome.verdict}\` \u2022 **Confidence:** \`${outcome.confidence}\` \u2022 **Authority:** \`${outcome.authority}\``,
10041
+ "",
10042
+ outcome.rationale
10043
+ );
10044
+ return out;
10045
+ }
10046
+ function blockingBullets(inputs) {
10047
+ return (inputs.review?.blockingFindings ?? []).map(
10048
+ (f) => `- \u{1F6D1} ${findingLine2(f).replace(/^- /, "")}`
10049
+ );
10050
+ }
10051
+ function signalBullets(inputs) {
10052
+ return (inputs.signals ?? []).filter((s) => s.status === "warn" || s.status === "alert").map((s) => `- \u{1F4CA} ${signalLine(s).replace(/^- /, "")}`);
10053
+ }
10054
+ function unmetBullets(inputs) {
10055
+ const unmet = inputs.outcome?.verdict === "NOT_SATISFIED" ? inputs.outcome.unmetCriteria ?? [] : [];
10056
+ return unmet.map((c) => `- \u{1F3AF} ${c}`);
10057
+ }
10058
+ function collectWorthYourEyesBullets(inputs) {
10059
+ return [...blockingBullets(inputs), ...signalBullets(inputs), ...unmetBullets(inputs)];
10060
+ }
10061
+ function deriveWorthYourEyes(inputs) {
10062
+ const bullets = collectWorthYourEyesBullets(inputs);
10063
+ if (bullets.length === 0) {
10064
+ return [
10065
+ "## \u{1F440} Worth your eyes",
10066
+ "",
10067
+ "_Nothing flagged \u2014 no blocking findings, no warn/alert signals, no unmet criteria._"
10068
+ ];
10069
+ }
10070
+ return ["## \u{1F440} Worth your eyes", "", ...bullets];
10071
+ }
10072
+ function buildBriefBody(inputs) {
10073
+ const lines = [
10074
+ BRIEF_MARKER,
10075
+ "# \u{1F9ED} Pre-merge brief",
10076
+ "",
10077
+ ...renderDiffSummary(inputs.diff),
10078
+ "",
10079
+ ...renderReviewVerdict(inputs.review),
10080
+ "",
10081
+ ...renderSignalStatus(inputs.signals),
10082
+ "",
10083
+ ...renderOutcomeEval(inputs.outcome),
10084
+ "",
10085
+ ...deriveWorthYourEyes(inputs)
10086
+ ];
10087
+ return lines.join("\n");
10088
+ }
10089
+ function upsertComment(comments, body, patch, post) {
10090
+ const marked = comments.find((c) => c.body.trimStart().startsWith(BRIEF_MARKER));
10091
+ if (marked) {
10092
+ patch(marked.id, body);
10093
+ } else {
10094
+ post(body);
10095
+ }
10096
+ }
10097
+ var defaultPostBrief = (body) => {
10098
+ const raw = execFileSync7("gh", ["pr", "view", "--json", "comments"], {
10099
+ encoding: "utf-8"
10100
+ }).toString();
10101
+ const parsed = JSON.parse(raw);
10102
+ const comments = (parsed.comments ?? []).filter(
10103
+ (c) => typeof c.id === "number" && typeof c.body === "string"
10104
+ ).map((c) => ({ id: c.id, body: c.body }));
10105
+ upsertComment(
10106
+ comments,
10107
+ body,
10108
+ (id, patchBody) => {
10109
+ execFileSync7(
10110
+ "gh",
10111
+ ["api", "-X", "PATCH", `/repos/{owner}/{repo}/issues/comments/${id}`, "-F", "body=@-"],
10112
+ { input: patchBody, stdio: ["pipe", "pipe", "pipe"], encoding: "utf-8" }
10113
+ );
10114
+ },
10115
+ (postBody) => {
10116
+ execFileSync7("gh", ["pr", "comment", "--body-file", "-"], {
10117
+ input: postBody,
10118
+ stdio: ["pipe", "pipe", "pipe"],
10119
+ encoding: "utf-8"
10120
+ });
10121
+ }
10122
+ );
10123
+ };
10124
+ var defaultReadFile = (path80) => readFileSync18(path80, "utf-8");
10125
+ function readReview(path80, readFile4 = defaultReadFile) {
10126
+ if (!path80) return void 0;
10127
+ try {
10128
+ const parsed = JSON.parse(readFile4(path80));
10129
+ return parsed?.verdict && typeof parsed.verdict === "object" ? parsed.verdict : void 0;
10130
+ } catch {
10131
+ return void 0;
10132
+ }
10133
+ }
10134
+ async function gatherSignalsSafe(projectPath, gather = gatherSignals) {
10135
+ try {
10136
+ const result = await gather(projectPath);
10137
+ return result.signals;
10138
+ } catch {
10139
+ return [];
10140
+ }
10141
+ }
10142
+ var GRAPH_DIR = ".harness/graph";
10143
+ async function loadOutcomeStore(projectPath) {
10144
+ try {
10145
+ const store = new GraphStore();
10146
+ const loaded = await store.load(join40(projectPath, GRAPH_DIR));
10147
+ return loaded ? store : void 0;
10148
+ } catch {
10149
+ return void 0;
10150
+ }
10151
+ }
10152
+ function findOutcomeVerdict(store, headSha) {
10153
+ if (!store || !headSha) return void 0;
10154
+ try {
10155
+ const nodes = store.findNodes({ type: "execution_outcome" });
10156
+ const match = nodes.find((n) => {
10157
+ const m2 = n.metadata ?? {};
10158
+ return m2.commit === headSha || m2.headSha === headSha;
10159
+ });
10160
+ if (!match) return void 0;
10161
+ const m = match.metadata;
10162
+ return {
10163
+ verdict: m.verdict,
10164
+ confidence: m.confidence ?? "low",
10165
+ rationale: m.rationale ?? "",
10166
+ judgedAgainst: m.judgedAgainst ?? "success-criteria",
10167
+ unmetCriteria: Array.isArray(m.unmetCriteria) ? m.unmetCriteria : [],
10168
+ authority: m.authority ?? "advisory"
10169
+ };
10170
+ } catch {
10171
+ return void 0;
10172
+ }
10173
+ }
10174
+ function defaultResolveRaw2(range, _cwd, runGit) {
10175
+ return runGit(["diff", range]);
10176
+ }
10177
+ async function runPreMergeBrief(opts) {
10178
+ const cwd = opts.cwd ?? process.cwd();
10179
+ const runGit = opts.runGit ?? ((args) => execFileSync7("git", args, { encoding: "utf-8" }).toString().trim());
10180
+ const range = resolveDiffRange({
10181
+ ...opts.diffRange ? { range: opts.diffRange } : {},
10182
+ cwd,
10183
+ runGit
10184
+ });
10185
+ let diff2;
10186
+ try {
10187
+ const rawDiff = (opts.resolveRaw ?? defaultResolveRaw2)(range, cwd, runGit);
10188
+ diff2 = rawDiff.trim() ? buildDiffInfo(rawDiff) : void 0;
10189
+ } catch {
10190
+ diff2 = void 0;
10191
+ }
10192
+ const review = readReview(opts.from, opts.readFile);
10193
+ const signals = await gatherSignalsSafe(cwd, opts.gather);
10194
+ const outcome = findOutcomeVerdict(opts.store, opts.headSha);
10195
+ const body = buildBriefBody({ diff: diff2, review, signals, outcome });
10196
+ const log = opts.log ?? ((m) => process.stdout.write(m + "\n"));
10197
+ if (opts.comment) {
10198
+ try {
10199
+ (opts.postBrief ?? defaultPostBrief)(body);
10200
+ } catch (err) {
10201
+ const reason = err instanceof Error ? err.message : String(err);
10202
+ (opts.warn ?? ((m) => process.stderr.write(m + "\n")))(
10203
+ `\u26A0\uFE0F pre-merge-brief: could not post sticky comment (${reason}); printing brief instead.`
10204
+ );
10205
+ log(body);
10206
+ }
10207
+ } else {
10208
+ log(body);
10209
+ }
10210
+ return { body };
10211
+ }
10212
+ function createPreMergeBriefCommand() {
10213
+ return new Command77("pre-merge-brief").description(
10214
+ 'Compose a senior-facing pre-merge PR brief (diff, review, signals, outcome, "worth your eyes")'
10215
+ ).option("--from <path>", "review-ci --json verdict artifact").option("--comment", "upsert the brief as a sticky comment on the current branch's PR").option("--diff <range>", "git range (default: origin/<base>...HEAD)").option("--head <sha>", "head commit sha for the outcome lookup (default: git rev-parse HEAD)").action(async (opts) => {
10216
+ const cwd = process.cwd();
10217
+ const runGit = (args) => execFileSync7("git", args, { encoding: "utf-8" }).toString().trim();
10218
+ let headSha = opts.head;
10219
+ if (!headSha) {
10220
+ try {
10221
+ headSha = runGit(["rev-parse", "HEAD"]) || void 0;
10222
+ } catch {
10223
+ headSha = void 0;
10224
+ }
10225
+ }
10226
+ const store = await loadOutcomeStore(cwd);
10227
+ await runPreMergeBrief({
10228
+ cwd,
10229
+ from: opts.from,
10230
+ comment: opts.comment,
10231
+ diffRange: opts.diff,
10232
+ headSha,
10233
+ store,
10234
+ runGit
10235
+ });
10236
+ process.exit(0);
10237
+ });
10238
+ }
10239
+
10240
+ // src/commands/proposals.ts
10241
+ init_dist3();
10242
+ import { Command as Command78 } from "commander";
10243
+ import { resolve as resolve34 } from "path";
10244
+ function projectRoot() {
10245
+ return resolve34(process.env["HARNESS_PROJECT_ROOT"] ?? process.cwd());
10246
+ }
10247
+ function summarizeProposal(p) {
10248
+ return {
10249
+ id: p.id,
10250
+ kind: p.kind,
10251
+ targetSkill: p.targetSkill,
10252
+ name: p.content.name,
10253
+ status: p.status,
10254
+ proposedBy: p.proposedBy,
10255
+ createdAt: p.createdAt,
10256
+ gateLastRunAt: p.gate?.lastRunAt,
10257
+ findings: p.gate?.findings?.length ?? 0
10258
+ };
10259
+ }
10260
+ async function runProposalsList(status) {
10261
+ const opts = {};
10262
+ if (status) opts.status = status;
10263
+ const proposals = await listProposals(projectRoot(), opts);
10264
+ return proposals.map(summarizeProposal);
10265
+ }
10266
+ async function runProposalsShow(id) {
10267
+ return getProposal(projectRoot(), id);
10268
+ }
10269
+ async function runProposalsReject(id, reason) {
10270
+ const decision = {
10271
+ decidedAt: (/* @__PURE__ */ new Date()).toISOString(),
10272
+ decidedBy: process.env["USER"] ?? "cli",
10273
+ action: "rejected",
10274
+ reason
10275
+ };
10276
+ return updateProposal(projectRoot(), id, { status: "rejected", decision });
10277
+ }
10278
+ var ALLOWED_STATUSES = [
10279
+ "open",
10280
+ "gate-running",
10281
+ "gate-failed",
10282
+ "approved",
10283
+ "rejected",
10284
+ "all"
10285
+ ];
10286
+ function fail(message) {
10287
+ console.error(message);
10288
+ process.exitCode = 1;
10289
+ }
10290
+ async function actListCommand(opts) {
10291
+ const raw = opts.status ?? "open";
10292
+ if (!ALLOWED_STATUSES.includes(raw)) {
10293
+ fail(`Error: unknown status "${raw}"`);
10294
+ return;
10295
+ }
10296
+ const proposals = await runProposalsList(raw);
10297
+ console.log(JSON.stringify(proposals, null, 2));
10298
+ }
10299
+ async function actShowCommand(id) {
10300
+ const proposal = await runProposalsShow(id);
10301
+ if (!proposal) {
10302
+ fail(`No such proposal: ${id}`);
10303
+ return;
10304
+ }
10305
+ console.log(JSON.stringify(proposal, null, 2));
10306
+ }
10307
+ async function actRejectCommand(id, opts) {
10308
+ try {
10309
+ const updated = await runProposalsReject(id, opts.reason);
10310
+ console.log(JSON.stringify(summarizeProposal(updated), null, 2));
10311
+ } catch (err) {
10312
+ fail(err instanceof Error ? err.message : String(err));
9767
10313
  }
9768
10314
  }
9769
10315
  async function actApproveCommand(id) {
@@ -9788,7 +10334,7 @@ async function actApproveCommand(id) {
9788
10334
  }
9789
10335
  }
9790
10336
  function createProposalsCommand() {
9791
- const cmd = new Command76("proposals").description("Skill-proposal review queue");
10337
+ const cmd = new Command78("proposals").description("Skill-proposal review queue");
9792
10338
  cmd.command("list").description("List skill proposals in the local queue").option(
9793
10339
  "--status <status>",
9794
10340
  `Filter by status \u2014 one of ${ALLOWED_STATUSES.join(" | ")}`,
@@ -9805,7 +10351,7 @@ function createProposalsCommand() {
9805
10351
  // src/commands/publish-analyses.ts
9806
10352
  import * as fs31 from "fs";
9807
10353
  import * as path52 from "path";
9808
- import { Command as Command77 } from "commander";
10354
+ import { Command as Command79 } from "commander";
9809
10355
  init_dist3();
9810
10356
  import {
9811
10357
  renderAnalysisComment,
@@ -9917,7 +10463,7 @@ async function runPublishAnalyses(opts) {
9917
10463
  const nameToExternalId = await buildNameToExternalIdMap(projectPath);
9918
10464
  if (!nameToExternalId) return process.exit(1);
9919
10465
  const { AnalysisArchive } = await import("@harness-engineering/orchestrator");
9920
- const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-IPVFYGY2.js");
10466
+ const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-MCTEX5QH.js");
9921
10467
  const archive = new AnalysisArchive(path52.join(projectPath, ".harness", "analyses"));
9922
10468
  const analyses = await archive.list();
9923
10469
  if (analyses.length === 0) {
@@ -9940,7 +10486,7 @@ async function runPublishAnalyses(opts) {
9940
10486
  }
9941
10487
  }
9942
10488
  function createPublishAnalysesCommand() {
9943
- const command = new Command77("publish-analyses").description(
10489
+ const command = new Command79("publish-analyses").description(
9944
10490
  "Publishes locally generated intelligence analyses to the external issue tracker (e.g., GitHub)"
9945
10491
  ).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
9946
10492
  try {
@@ -9956,18 +10502,18 @@ function createPublishAnalysesCommand() {
9956
10502
  }
9957
10503
 
9958
10504
  // src/commands/pulse/index.ts
9959
- import { Command as Command79 } from "commander";
10505
+ import { Command as Command81 } from "commander";
9960
10506
 
9961
10507
  // src/commands/pulse/run.ts
9962
10508
  init_dist3();
9963
- import { readFileSync as readFileSync18, mkdirSync as mkdirSync15, writeFileSync as writeFileSync18 } from "fs";
9964
- import { dirname as dirname18, join as join41, resolve as resolve36 } from "path";
9965
- import { Command as Command78 } from "commander";
10509
+ import { readFileSync as readFileSync19, mkdirSync as mkdirSync15, writeFileSync as writeFileSync19 } from "fs";
10510
+ import { dirname as dirname18, join as join42, resolve as resolve36 } from "path";
10511
+ import { Command as Command80 } from "commander";
9966
10512
  async function runPulseRunCommand(opts) {
9967
10513
  const startedAt = Date.now();
9968
10514
  let raw;
9969
10515
  try {
9970
- raw = JSON.parse(readFileSync18(opts.configPath, "utf-8"));
10516
+ raw = JSON.parse(readFileSync19(opts.configPath, "utf-8"));
9971
10517
  } catch (err) {
9972
10518
  return emit2(
9973
10519
  {
@@ -9993,9 +10539,9 @@ async function runPulseRunCommand(opts) {
9993
10539
  const report = assembleReport(result, productName, lookback);
9994
10540
  const now = /* @__PURE__ */ new Date();
9995
10541
  const ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}_${String(now.getHours()).padStart(2, "0")}-${String(now.getMinutes()).padStart(2, "0")}`;
9996
- const filePath = join41(opts.outputDir, `${ts}.md`);
10542
+ const filePath = join42(opts.outputDir, `${ts}.md`);
9997
10543
  mkdirSync15(dirname18(filePath), { recursive: true });
9998
- writeFileSync18(filePath, report);
10544
+ writeFileSync19(filePath, report);
9999
10545
  const headlines = extractHeadlines(report);
10000
10546
  return emit2(
10001
10547
  {
@@ -10027,7 +10573,7 @@ function emit2(status, nonInteractive) {
10027
10573
  return status;
10028
10574
  }
10029
10575
  function createRunCommand2() {
10030
- return new Command78("run").description("Run a pulse: query configured adapters, sanitize, assemble single-page report").option(
10576
+ return new Command80("run").description("Run a pulse: query configured adapters, sanitize, assemble single-page report").option(
10031
10577
  "--lookback <window>",
10032
10578
  "Lookback window (e.g. 24h, 7d). Defaults to pulse.lookbackDefault."
10033
10579
  ).option(
@@ -10051,13 +10597,13 @@ function createRunCommand2() {
10051
10597
 
10052
10598
  // src/commands/pulse/index.ts
10053
10599
  function createPulseCommand() {
10054
- const command = new Command79("pulse").description("Pulse (read-side observability) commands");
10600
+ const command = new Command81("pulse").description("Pulse (read-side observability) commands");
10055
10601
  command.addCommand(createRunCommand2());
10056
10602
  return command;
10057
10603
  }
10058
10604
 
10059
10605
  // src/commands/recommend.ts
10060
- import { Command as Command80 } from "commander";
10606
+ import { Command as Command82 } from "commander";
10061
10607
  import chalk13 from "chalk";
10062
10608
  async function resolveSnapshot(cwd, noCache) {
10063
10609
  if (!noCache) {
@@ -10084,301 +10630,84 @@ async function runRecommend(options) {
10084
10630
  const { snapshot, usedCache } = await resolveSnapshot(cwd, options.noCache);
10085
10631
  const skills = buildSkillsRecord(cwd);
10086
10632
  const result = recommend(snapshot, skills, { top });
10087
- return {
10088
- ...result,
10089
- snapshotAge: usedCache ? "cached" : "fresh"
10090
- };
10091
- }
10092
- function formatRecommendation(rec) {
10093
- const lines = [];
10094
- if (rec.urgency === "critical") {
10095
- lines.push(` ${chalk13.red("[CRITICAL]")} ${rec.sequence}. ${rec.skillName}`);
10096
- } else {
10097
- lines.push(` ${rec.sequence}. ${rec.skillName} (${rec.score.toFixed(2)})`);
10098
- }
10099
- for (const reason of rec.reasons) {
10100
- lines.push(` ${chalk13.dim("\u2192")} ${reason}`);
10101
- }
10102
- return lines.join("\n");
10103
- }
10104
- function printRecommendations(result) {
10105
- if (result.recommendations.length === 0) {
10106
- console.log("");
10107
- console.log("No recommendations. Codebase health looks good!");
10108
- console.log("");
10109
- return;
10110
- }
10111
- console.log("");
10112
- console.log(
10113
- `Recommended workflow (${result.recommendations.length} skill${result.recommendations.length === 1 ? "" : "s"}):`
10114
- );
10115
- console.log("");
10116
- for (const rec of result.recommendations) {
10117
- console.log(formatRecommendation(rec));
10118
- console.log("");
10119
- }
10120
- console.log(`Sequence reasoning: ${result.sequenceReasoning}`);
10121
- console.log("");
10122
- }
10123
- function createRecommendCommand() {
10124
- const command = new Command80("recommend").description("Recommend skills based on codebase health analysis").option("--no-cache", "Force fresh health snapshot").option("--top <n>", "Max recommendations (default 5)", "5").action(async (opts, cmd) => {
10125
- const globalOpts = cmd.optsWithGlobals();
10126
- const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
10127
- try {
10128
- const top = parseInt(opts.top, 10);
10129
- if (isNaN(top) || top < 1) {
10130
- logger.error("--top must be a positive integer");
10131
- process.exit(1);
10132
- }
10133
- if (mode === OutputMode.TEXT) {
10134
- console.log("");
10135
- console.log("Analyzing codebase health...");
10136
- }
10137
- const result = await runRecommend({
10138
- noCache: opts.cache === false,
10139
- top
10140
- });
10141
- if (mode === OutputMode.JSON) {
10142
- console.log(JSON.stringify(result, null, 2));
10143
- } else {
10144
- printRecommendations(result);
10145
- }
10146
- } catch (err) {
10147
- const message = err instanceof Error ? err.message : String(err);
10148
- if (mode === OutputMode.JSON) {
10149
- console.log(JSON.stringify({ error: message }));
10150
- } else {
10151
- logger.error(message);
10152
- }
10153
- process.exit(1);
10154
- }
10155
- });
10156
- return command;
10157
- }
10158
-
10159
- // src/commands/review-ci.ts
10160
- init_dist3();
10161
- import { execFileSync as execFileSync6 } from "child_process";
10162
- import { writeFileSync as writeFileSync19 } from "fs";
10163
- import { Command as Command81, Option as Option2 } from "commander";
10164
-
10165
- // src/commands/review-ci-local-adapter.ts
10166
- import { z } from "zod";
10167
- import { OpenAICompatibleAnalysisProvider } from "@harness-engineering/intelligence";
10168
- var FindingSchema = z.object({
10169
- id: z.string(),
10170
- file: z.string(),
10171
- lineRange: z.tuple([z.number(), z.number()]),
10172
- domain: z.enum(["compliance", "bug", "security", "architecture", "learnings"]),
10173
- severity: z.enum(["critical", "important", "suggestion"]),
10174
- title: z.string(),
10175
- rationale: z.string(),
10176
- suggestion: z.string().optional(),
10177
- evidence: z.array(z.string())
10178
- });
10179
- var LocalVerdictSchema = z.object({
10180
- assessment: z.enum(["approve", "comment", "request-changes"]),
10181
- findings: z.array(FindingSchema)
10182
- });
10183
- var MAX_SURFACED_ERROR_LEN = 200;
10184
- function sanitizeProviderError(err) {
10185
- const raw = err instanceof Error ? err.message : String(err);
10186
- const redacted = raw.replace(/https?:\/\/\S+/gi, "[endpoint]").replace(/\b(bearer|authorization|api[-_]?key|token)\b\s*[:=]?\s*\S+/gi, "[redacted]").replace(/\s+/g, " ").trim();
10187
- const capped = redacted.length > MAX_SURFACED_ERROR_LEN ? redacted.slice(0, MAX_SURFACED_ERROR_LEN - 1) + "\u2026" : redacted;
10188
- return `local runner provider error: ${capped}`;
10189
- }
10190
- function createLocalInvoke() {
10191
- return async ({ endpoint, model, instruction, diff: diff2 }) => {
10192
- if (!/^https?:\/\//i.test(endpoint)) {
10193
- throw new Error(
10194
- `HARNESS_LOCAL_ENDPOINT must be an http(s) URL (got '${endpoint}'); e.g. http://localhost:1234/v1`
10195
- );
10196
- }
10197
- const provider = new OpenAICompatibleAnalysisProvider({
10198
- apiKey: process.env.HARNESS_LOCAL_API_KEY ?? "local",
10199
- baseUrl: endpoint,
10200
- defaultModel: model
10201
- });
10202
- try {
10203
- const { result } = await provider.analyze({
10204
- prompt: `${instruction}
10205
-
10206
- ---
10207
- DIFF UNDER REVIEW:
10208
- ${diff2}`,
10209
- responseSchema: LocalVerdictSchema,
10210
- model
10211
- });
10212
- return JSON.stringify(result);
10213
- } catch (err) {
10214
- throw new Error(sanitizeProviderError(err), { cause: err });
10215
- }
10216
- };
10217
- }
10218
-
10219
- // src/commands/review-ci.ts
10220
- var KNOWN_RUNNERS = Object.keys(RUNNER_PRESETS);
10221
- var BLOCK_ON_LEVELS = [...CI_ASSESSMENTS, "none"];
10222
- function assertKnownRunner(runner) {
10223
- if (runner === void 0) return;
10224
- if (!KNOWN_RUNNERS.includes(runner)) {
10225
- throw new Error(`unknown runner '${runner}' (expected: ${KNOWN_RUNNERS.join("|")})`);
10226
- }
10227
- }
10228
- var defaultRunGit = (args) => execFileSync6("git", args, { encoding: "utf-8" }).toString().trim();
10229
- function resolveDiffRange(opts) {
10230
- if (opts.range) return opts.range;
10231
- const runGit = opts.runGit ?? defaultRunGit;
10232
- let base = "main";
10233
- try {
10234
- const ref = runGit(["symbolic-ref", "refs/remotes/origin/HEAD"]);
10235
- const m = ref.match(/origin\/(.+)$/);
10236
- if (m?.[1]) base = m[1];
10237
- } catch {
10238
- }
10239
- return `origin/${base}...HEAD`;
10240
- }
10241
- function splitDiffByFile(rawDiff) {
10242
- const sections = /* @__PURE__ */ new Map();
10243
- const headerRe = /^diff --git a\/(.+?) b\/(.+?)$/;
10244
- let currentPath = null;
10245
- let buffer = [];
10246
- const flush = () => {
10247
- if (currentPath !== null) sections.set(currentPath, buffer.join("\n"));
10248
- };
10249
- for (const line of rawDiff.split("\n")) {
10250
- const m = line.match(headerRe);
10251
- if (m?.[2]) {
10252
- flush();
10253
- currentPath = m[2];
10254
- buffer = [line];
10255
- } else if (currentPath !== null) {
10256
- buffer.push(line);
10257
- }
10258
- }
10259
- flush();
10260
- return sections;
10261
- }
10262
- function buildDiffInfo(rawDiff) {
10263
- const parsed = parseDiff(rawDiff);
10264
- if (!parsed.ok) throw new Error(`Failed to parse diff: ${parsed.error.message}`);
10265
- const files = parsed.value.files;
10266
- const perFile = splitDiffByFile(rawDiff);
10267
- return {
10268
- changedFiles: files.map((f) => f.path),
10269
- newFiles: files.filter((f) => f.status === "added").map((f) => f.path),
10270
- deletedFiles: files.filter((f) => f.status === "deleted").map((f) => f.path),
10271
- totalDiffLines: rawDiff ? rawDiff.split("\n").length : 0,
10272
- // On a path-key miss, fall back to '' (the file contributes no per-file diff)
10273
- // rather than the ENTIRE raw diff — substituting the whole diff would duplicate
10274
- // every file's content into one section, inflating the STDIN payload to the LLM
10275
- // (and risking core's execMaxStdoutBytes). With splitDiffByFile aligned to core's
10276
- // path extraction, ordinary paths never miss; this is the safe degenerate case.
10277
- fileDiffs: new Map(files.map((f) => [f.path, perFile.get(f.path) ?? ""]))
10278
- };
10279
- }
10280
- function defaultResolveRaw(range, _cwd, runGit) {
10281
- return runGit(["diff", range]);
10282
- }
10283
- function buildCallOpts(opts, cwd, diff2) {
10284
- const runner = opts.runner;
10285
- return {
10286
- projectRoot: cwd,
10287
- diff: diff2,
10288
- ...runner ? { runner } : {},
10289
- ...opts.blockOn ? { blockOn: opts.blockOn } : {},
10290
- ...runner === "local" ? { localInvoke: opts.localInvoke ?? createLocalInvoke() } : {}
10291
- };
10292
- }
10293
- async function runReviewCi(opts) {
10294
- assertKnownRunner(opts.runner);
10295
- const cwd = opts.cwd ?? process.cwd();
10296
- const runGit = opts.runGit ?? defaultRunGit;
10297
- const range = resolveDiffRange({
10298
- ...opts.diffRange ? { range: opts.diffRange } : {},
10299
- cwd,
10300
- runGit
10301
- });
10302
- const rawDiff = (opts.resolveRaw ?? defaultResolveRaw)(range, cwd, runGit);
10303
- const diff2 = buildDiffInfo(rawDiff);
10304
- const callOpts = buildCallOpts(opts, cwd, diff2);
10305
- return (opts.runCiReviewImpl ?? runCiReview)(callOpts);
10633
+ return {
10634
+ ...result,
10635
+ snapshotAge: usedCache ? "cached" : "fresh"
10636
+ };
10306
10637
  }
10307
- function findingLine(f) {
10308
- const loc = f.lineRange ? `${f.file}:${f.lineRange[0]}` : f.file;
10309
- return `- \`${f.severity}\` **${loc}** \u2014 ${f.title}`;
10638
+ function formatRecommendation(rec) {
10639
+ const lines = [];
10640
+ if (rec.urgency === "critical") {
10641
+ lines.push(` ${chalk13.red("[CRITICAL]")} ${rec.sequence}. ${rec.skillName}`);
10642
+ } else {
10643
+ lines.push(` ${rec.sequence}. ${rec.skillName} (${rec.score.toFixed(2)})`);
10644
+ }
10645
+ for (const reason of rec.reasons) {
10646
+ lines.push(` ${chalk13.dim("\u2192")} ${reason}`);
10647
+ }
10648
+ return lines.join("\n");
10310
10649
  }
10311
- function buildReviewBody(verdict) {
10312
- const findings = verdict.findings ?? [];
10313
- const blocking = verdict.blockingFindings ?? [];
10314
- const icon = verdict.assessment === "approve" ? "\u2705" : verdict.assessment === "request-changes" ? "\u{1F6D1}" : "\u{1F4AC}";
10315
- const out = [
10316
- `## ${icon} harness review-ci \u2014 ${verdict.assessment}`,
10317
- "",
10318
- `**Runner:** \`${verdict.runner}\` \u2022 **Findings:** ${findings.length} (blocking: ${blocking.length})`
10319
- ];
10320
- if (verdict.skipped) out.push("", `> \u26A0\uFE0F ${verdict.skipReason ?? "A review tier was skipped."}`);
10321
- if (blocking.length) out.push("", "### Blocking", ...blocking.map(findingLine));
10322
- const nonBlocking = findings.filter((f) => !blocking.some((b) => b.id === f.id));
10323
- if (nonBlocking.length) out.push("", "### Other findings", ...nonBlocking.map(findingLine));
10324
- if (!findings.length) out.push("", "No findings. \u{1F389}");
10325
- out.push("", "<sub>Posted by `harness review-ci`. The CI exit code is authoritative.</sub>");
10326
- return out.join("\n");
10650
+ function printRecommendations(result) {
10651
+ if (result.recommendations.length === 0) {
10652
+ console.log("");
10653
+ console.log("No recommendations. Codebase health looks good!");
10654
+ console.log("");
10655
+ return;
10656
+ }
10657
+ console.log("");
10658
+ console.log(
10659
+ `Recommended workflow (${result.recommendations.length} skill${result.recommendations.length === 1 ? "" : "s"}):`
10660
+ );
10661
+ console.log("");
10662
+ for (const rec of result.recommendations) {
10663
+ console.log(formatRecommendation(rec));
10664
+ console.log("");
10665
+ }
10666
+ console.log(`Sequence reasoning: ${result.sequenceReasoning}`);
10667
+ console.log("");
10327
10668
  }
10328
- var defaultPostReview = (verdict) => {
10329
- execFileSync6("gh", ["pr", "comment", "--body-file", "-"], {
10330
- input: buildReviewBody(verdict),
10331
- stdio: ["pipe", "pipe", "pipe"],
10332
- encoding: "utf-8"
10333
- });
10334
- };
10335
- function emitReviewCi(result, opts, writeFile2 = (p, d) => writeFileSync19(p, d), log = (m) => process.stdout.write(m + "\n"), postReview = defaultPostReview) {
10336
- const serialized = JSON.stringify(result.verdict, null, 2);
10337
- const jsonToStdout = opts.jsonPath === true;
10338
- if (!jsonToStdout) log(result.terminalOutput);
10339
- if (typeof opts.jsonPath === "string") writeFile2(opts.jsonPath, serialized);
10340
- else if (jsonToStdout) log(serialized);
10341
- if (opts.comment) {
10669
+ function createRecommendCommand() {
10670
+ const command = new Command82("recommend").description("Recommend skills based on codebase health analysis").option("--no-cache", "Force fresh health snapshot").option("--top <n>", "Max recommendations (default 5)", "5").action(async (opts, cmd) => {
10671
+ const globalOpts = cmd.optsWithGlobals();
10672
+ const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
10342
10673
  try {
10343
- postReview(result.verdict);
10674
+ const top = parseInt(opts.top, 10);
10675
+ if (isNaN(top) || top < 1) {
10676
+ logger.error("--top must be a positive integer");
10677
+ process.exit(1);
10678
+ }
10679
+ if (mode === OutputMode.TEXT) {
10680
+ console.log("");
10681
+ console.log("Analyzing codebase health...");
10682
+ }
10683
+ const result = await runRecommend({
10684
+ noCache: opts.cache === false,
10685
+ top
10686
+ });
10687
+ if (mode === OutputMode.JSON) {
10688
+ console.log(JSON.stringify(result, null, 2));
10689
+ } else {
10690
+ printRecommendations(result);
10691
+ }
10344
10692
  } catch (err) {
10345
- logger.warn(
10346
- `review-ci: failed to post PR comment (${err instanceof Error ? err.message : String(err)}). The verdict above is authoritative; the exit code still reflects the gate.`
10347
- );
10693
+ const message = err instanceof Error ? err.message : String(err);
10694
+ if (mode === OutputMode.JSON) {
10695
+ console.log(JSON.stringify({ error: message }));
10696
+ } else {
10697
+ logger.error(message);
10698
+ }
10699
+ process.exit(1);
10348
10700
  }
10349
- }
10350
- }
10351
- function createReviewCiCommand() {
10352
- return new Command81("review-ci").description("Run the tiered code-review gate (floor + optional LLM runner) for CI").addOption(
10353
- new Option2("--runner <runner>", `${KNOWN_RUNNERS.join(" | ")} (omit = floor-only)`).choices(
10354
- KNOWN_RUNNERS
10355
- )
10356
- ).addOption(
10357
- new Option2("--block-on <level>", BLOCK_ON_LEVELS.join(" | ")).choices(BLOCK_ON_LEVELS).default("request-changes")
10358
- ).option("--diff <range>", "git range (default: origin/<base>...HEAD)").option("--comment", "post the verdict as a comment on the current branch's PR via gh").option(
10359
- "--out <path>",
10360
- "write the verdict JSON artifact to a file (use the global --json to stream it to stdout instead)"
10361
- ).action(async (opts, cmd) => {
10362
- const result = await runReviewCi({
10363
- runner: opts.runner,
10364
- blockOn: opts.blockOn,
10365
- diffRange: opts.diff
10366
- });
10367
- const streamJson = cmd.optsWithGlobals().json === true;
10368
- emitReviewCi(result, {
10369
- jsonPath: typeof opts.out === "string" ? opts.out : streamJson ? true : void 0,
10370
- comment: opts.comment
10371
- });
10372
- process.exit(result.exitCode);
10373
10701
  });
10702
+ return command;
10374
10703
  }
10375
10704
 
10376
10705
  // src/commands/roadmap/index.ts
10377
- import { Command as Command87 } from "commander";
10706
+ import { Command as Command89 } from "commander";
10378
10707
 
10379
10708
  // src/commands/roadmap/migrate.ts
10380
10709
  init_dist3();
10381
- import { Command as Command82 } from "commander";
10710
+ import { Command as Command83 } from "commander";
10382
10711
  import * as fs33 from "fs";
10383
10712
  import * as path54 from "path";
10384
10713
  import chalk14 from "chalk";
@@ -10788,7 +11117,7 @@ async function runReverseMigrate(opts) {
10788
11117
  }
10789
11118
  }
10790
11119
  function createRoadmapMigrateCommand() {
10791
- return new Command82("migrate").description("Migrate the project roadmap to a different storage mode").requiredOption("--to <target>", 'Migration target: "file-less" or "file-backed"').option("--dry-run", "Print the migration plan without making any changes", false).option(
11120
+ return new Command83("migrate").description("Migrate the project roadmap to a different storage mode").requiredOption("--to <target>", 'Migration target: "file-less" or "file-backed"').option("--dry-run", "Print the migration plan without making any changes", false).option(
10792
11121
  "--format <fmt>",
10793
11122
  'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
10794
11123
  "human"
@@ -10823,7 +11152,7 @@ function createRoadmapMigrateCommand() {
10823
11152
 
10824
11153
  // src/commands/roadmap/shard.ts
10825
11154
  init_dist3();
10826
- import { Command as Command83 } from "commander";
11155
+ import { Command as Command84 } from "commander";
10827
11156
  import * as path55 from "path";
10828
11157
 
10829
11158
  // src/commands/roadmap/shard-io.ts
@@ -10922,7 +11251,7 @@ async function runRoadmapShard(opts = {}) {
10922
11251
  return Ok(report);
10923
11252
  }
10924
11253
  function createRoadmapShardCommand() {
10925
- return new Command83("shard").description("Migrate docs/roadmap.md to per-row shards under docs/roadmap.d").option("--cwd <dir>", "Project root (defaults to the current working directory)").option("--dry-run", "Report the migration plan without writing anything", false).option("--force", "Proceed even if docs/roadmap.d already exists", false).option(
11254
+ return new Command84("shard").description("Migrate docs/roadmap.md to per-row shards under docs/roadmap.d").option("--cwd <dir>", "Project root (defaults to the current working directory)").option("--dry-run", "Report the migration plan without writing anything", false).option("--force", "Proceed even if docs/roadmap.d already exists", false).option(
10926
11255
  "--format <fmt>",
10927
11256
  'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
10928
11257
  "human"
@@ -10949,7 +11278,7 @@ function createRoadmapShardCommand() {
10949
11278
 
10950
11279
  // src/commands/roadmap/unshard.ts
10951
11280
  init_dist3();
10952
- import { Command as Command84 } from "commander";
11281
+ import { Command as Command85 } from "commander";
10953
11282
  import * as path56 from "path";
10954
11283
  async function runRoadmapUnshard(opts = {}) {
10955
11284
  const cwd = opts.cwd ?? process.cwd();
@@ -10981,7 +11310,7 @@ async function runRoadmapUnshard(opts = {}) {
10981
11310
  return Ok(report);
10982
11311
  }
10983
11312
  function createRoadmapUnshardCommand() {
10984
- return new Command84("unshard").description("Reassemble the aggregate from shards and remove docs/roadmap.d").option("--cwd <dir>", "Project root (defaults to the current working directory)").option("--dry-run", "Preview the reassembly without writing or deleting the shard dir", false).option(
11313
+ return new Command85("unshard").description("Reassemble the aggregate from shards and remove docs/roadmap.d").option("--cwd <dir>", "Project root (defaults to the current working directory)").option("--dry-run", "Preview the reassembly without writing or deleting the shard dir", false).option(
10985
11314
  "--format <fmt>",
10986
11315
  'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
10987
11316
  "human"
@@ -11005,7 +11334,7 @@ function createRoadmapUnshardCommand() {
11005
11334
 
11006
11335
  // src/commands/roadmap/regen.ts
11007
11336
  init_dist3();
11008
- import { Command as Command85 } from "commander";
11337
+ import { Command as Command86 } from "commander";
11009
11338
  import * as path57 from "path";
11010
11339
  async function runRoadmapRegen(opts = {}) {
11011
11340
  const cwd = opts.cwd ?? process.cwd();
@@ -11034,7 +11363,7 @@ async function runRoadmapRegen(opts = {}) {
11034
11363
  return Ok(report);
11035
11364
  }
11036
11365
  function createRoadmapRegenCommand() {
11037
- return new Command85("regen").description("Regenerate the aggregate from the shard directory (docs/roadmap.d)").option("--cwd <dir>", "Project root (defaults to the current working directory)").option("--dry-run", "Report what would be regenerated without writing anything", false).option(
11366
+ return new Command86("regen").description("Regenerate the aggregate from the shard directory (docs/roadmap.d)").option("--cwd <dir>", "Project root (defaults to the current working directory)").option("--dry-run", "Report what would be regenerated without writing anything", false).option(
11038
11367
  "--format <fmt>",
11039
11368
  'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
11040
11369
  "human"
@@ -11058,7 +11387,7 @@ function createRoadmapRegenCommand() {
11058
11387
 
11059
11388
  // src/commands/roadmap/reconcile.ts
11060
11389
  init_dist3();
11061
- import { Command as Command86 } from "commander";
11390
+ import { Command as Command87 } from "commander";
11062
11391
  import * as fs34 from "fs";
11063
11392
  import * as path58 from "path";
11064
11393
  async function runRoadmapReconcile(opts = {}) {
@@ -11163,8 +11492,35 @@ function logSummary(result) {
11163
11492
  `Reconciled ${markedDone.length} row(s) to done: ${markedDone.join(", ")} (already-done: ${alreadyDone.length}, unmatched: ${unmatched.length}).`
11164
11493
  );
11165
11494
  }
11495
+ function parseFromRefsFlag(raw) {
11496
+ const refs = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
11497
+ if (refs.length === 0) {
11498
+ logger.error(
11499
+ `--from-refs was provided ("${raw}") but contained no valid references; expected a comma-separated list of owner/repo#number`
11500
+ );
11501
+ process.exit(ExitCode.ERROR);
11502
+ }
11503
+ return refs;
11504
+ }
11505
+ function parseFromIssuesFlag(raw) {
11506
+ const parsed = raw.split(",").map((s) => Number.parseInt(s.trim(), 10)).filter((n) => Number.isInteger(n));
11507
+ if (parsed.length === 0) {
11508
+ logger.error(
11509
+ `--from-issues was provided ("${raw}") but contained no valid issue numbers; expected a comma-separated list of integers`
11510
+ );
11511
+ process.exit(ExitCode.ERROR);
11512
+ }
11513
+ return parsed;
11514
+ }
11515
+ function buildReconcileOptions(options) {
11516
+ const opts = {};
11517
+ if (options.cwd) opts.cwd = options.cwd;
11518
+ if (options.fromRefs !== void 0) opts.fromRefs = parseFromRefsFlag(options.fromRefs);
11519
+ if (options.fromIssues !== void 0) opts.fromIssues = parseFromIssuesFlag(options.fromIssues);
11520
+ return opts;
11521
+ }
11166
11522
  function createRoadmapReconcileCommand() {
11167
- return new Command86("reconcile").description(
11523
+ return new Command87("reconcile").description(
11168
11524
  "Flip roadmap rows whose linked GitHub issue is closed to done. Offline mode flips only issues closed as 'completed' (a 'not planned'/'wontfix' close is left untouched); the PR-merge auto-done workflow remains authoritative for cross-repo correctness."
11169
11525
  ).option("--cwd <dir>", "Project root (defaults to the current working directory)").option(
11170
11526
  "--from-issues <numbers>",
@@ -11173,29 +11529,7 @@ function createRoadmapReconcileCommand() {
11173
11529
  "--from-refs <refs>",
11174
11530
  "comma-separated owner/repo#number closing-issue references (preferred; cross-repo safe; skips the network fetch)"
11175
11531
  ).action(async (options) => {
11176
- const opts = {};
11177
- if (options.cwd) opts.cwd = options.cwd;
11178
- if (options.fromRefs !== void 0) {
11179
- const refs = options.fromRefs.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
11180
- if (refs.length === 0) {
11181
- logger.error(
11182
- `--from-refs was provided ("${options.fromRefs}") but contained no valid references; expected a comma-separated list of owner/repo#number`
11183
- );
11184
- process.exit(ExitCode.ERROR);
11185
- }
11186
- opts.fromRefs = refs;
11187
- }
11188
- if (options.fromIssues !== void 0) {
11189
- const parsed = options.fromIssues.split(",").map((s) => Number.parseInt(s.trim(), 10)).filter((n) => Number.isInteger(n));
11190
- if (parsed.length === 0) {
11191
- logger.error(
11192
- `--from-issues was provided ("${options.fromIssues}") but contained no valid issue numbers; expected a comma-separated list of integers`
11193
- );
11194
- process.exit(ExitCode.ERROR);
11195
- }
11196
- opts.fromIssues = parsed;
11197
- }
11198
- const result = await runRoadmapReconcile(opts);
11532
+ const result = await runRoadmapReconcile(buildReconcileOptions(options));
11199
11533
  if (!result.ok) {
11200
11534
  logger.error(result.error.message);
11201
11535
  process.exit(result.error.exitCode);
@@ -11203,22 +11537,40 @@ function createRoadmapReconcileCommand() {
11203
11537
  });
11204
11538
  }
11205
11539
 
11540
+ // src/commands/roadmap/referenced-issues.ts
11541
+ init_dist3();
11542
+ import { Command as Command88 } from "commander";
11543
+ function runReferencedIssues(text, print) {
11544
+ for (const n of parseReferencedIssues(text)) print(String(n));
11545
+ }
11546
+ function createRoadmapReferencedIssuesCommand() {
11547
+ return new Command88("referenced-issues").description(
11548
+ "Parse issue references (#N, Closes/Fixes/Resolves #N, owner/repo#N) from stdin text (PR body + title) and print each issue number on its own line. Backstop for auto-done when a PR's closing keyword is malformed."
11549
+ ).action(async () => {
11550
+ const chunks = [];
11551
+ for await (const c of process.stdin) chunks.push(c);
11552
+ const text = Buffer.concat(chunks).toString("utf8");
11553
+ runReferencedIssues(text, (line) => process.stdout.write(line + "\n"));
11554
+ });
11555
+ }
11556
+
11206
11557
  // src/commands/roadmap/index.ts
11207
11558
  function createRoadmapCommand() {
11208
- const roadmap = new Command87("roadmap").description("Roadmap management");
11559
+ const roadmap = new Command89("roadmap").description("Roadmap management");
11209
11560
  roadmap.addCommand(createRoadmapMigrateCommand());
11210
11561
  roadmap.addCommand(createRoadmapShardCommand());
11211
11562
  roadmap.addCommand(createRoadmapUnshardCommand());
11212
11563
  roadmap.addCommand(createRoadmapRegenCommand());
11213
11564
  roadmap.addCommand(createRoadmapReconcileCommand());
11565
+ roadmap.addCommand(createRoadmapReferencedIssuesCommand());
11214
11566
  return roadmap;
11215
11567
  }
11216
11568
 
11217
11569
  // src/commands/routing/index.ts
11218
- import { Command as Command91 } from "commander";
11570
+ import { Command as Command93 } from "commander";
11219
11571
 
11220
11572
  // src/commands/routing/config.ts
11221
- import { Command as Command88 } from "commander";
11573
+ import { Command as Command90 } from "commander";
11222
11574
 
11223
11575
  // src/commands/routing/http-client.ts
11224
11576
  function orchestratorBase() {
@@ -11283,7 +11635,7 @@ function renderHuman(data) {
11283
11635
  }
11284
11636
  }
11285
11637
  function createConfigCommand() {
11286
- return new Command88("config").description("Print active routing config and resolved fallback chains").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
11638
+ return new Command90("config").description("Print active routing config and resolved fallback chains").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
11287
11639
  const r = await getJson("/api/v1/routing/config");
11288
11640
  if (!r.ok) {
11289
11641
  if (r.status === 0) {
@@ -11309,7 +11661,7 @@ function createConfigCommand() {
11309
11661
  }
11310
11662
 
11311
11663
  // src/commands/routing/trace.ts
11312
- import { Command as Command89 } from "commander";
11664
+ import { Command as Command91 } from "commander";
11313
11665
  function buildUseCase(opts) {
11314
11666
  if (opts.skill) {
11315
11667
  return opts.mode ? { kind: "skill", skillName: opts.skill, cognitiveMode: opts.mode } : { kind: "skill", skillName: opts.skill };
@@ -11330,7 +11682,7 @@ function renderHuman2(r) {
11330
11682
  }
11331
11683
  }
11332
11684
  function createTraceCommand() {
11333
- return new Command89("trace").description("Dry-run a routing decision without dispatching (Spec B F7)").option("--skill <name>", "Skill name to trace").option("--mode <m>", "Cognitive mode to trace (or attach to --skill per spec D12)").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
11685
+ return new Command91("trace").description("Dry-run a routing decision without dispatching (Spec B F7)").option("--skill <name>", "Skill name to trace").option("--mode <m>", "Cognitive mode to trace (or attach to --skill per spec D12)").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
11334
11686
  const useCase = buildUseCase(opts);
11335
11687
  if (!useCase) {
11336
11688
  logger.error("Either --skill <name> or --mode <m> is required");
@@ -11362,7 +11714,7 @@ function createTraceCommand() {
11362
11714
  }
11363
11715
 
11364
11716
  // src/commands/routing/decisions.ts
11365
- import { Command as Command90 } from "commander";
11717
+ import { Command as Command92 } from "commander";
11366
11718
  function summarizeUseCase(uc) {
11367
11719
  switch (uc.kind) {
11368
11720
  case "skill":
@@ -11410,7 +11762,7 @@ function buildQuery(opts) {
11410
11762
  return q ? `?${q}` : "";
11411
11763
  }
11412
11764
  function createDecisionsCommand() {
11413
- return new Command90("decisions").description("List recent routing decisions from the orchestrator ring buffer (Spec B F8)").option("--skill <name>", "Filter by useCase.skillName").option("--mode <m>", "Filter by useCase.cognitiveMode").option("--backend <name>", "Filter by chosen backendName").option("--last <N>", "Limit to the N most recent decisions").option("--json", "Emit JSON to stdout instead of human-readable text").action(
11765
+ return new Command92("decisions").description("List recent routing decisions from the orchestrator ring buffer (Spec B F8)").option("--skill <name>", "Filter by useCase.skillName").option("--mode <m>", "Filter by useCase.cognitiveMode").option("--backend <name>", "Filter by chosen backendName").option("--last <N>", "Limit to the N most recent decisions").option("--json", "Emit JSON to stdout instead of human-readable text").action(
11414
11766
  async (opts) => {
11415
11767
  const query = buildQuery(opts);
11416
11768
  const r = await getJson(`/api/v1/routing/decisions${query}`);
@@ -11440,7 +11792,7 @@ function createDecisionsCommand() {
11440
11792
 
11441
11793
  // src/commands/routing/index.ts
11442
11794
  function createRoutingCommand() {
11443
- const cmd = new Command91("routing").description(
11795
+ const cmd = new Command93("routing").description(
11444
11796
  "Inspect routing config, trace decisions, and read recent dispatches"
11445
11797
  );
11446
11798
  cmd.addCommand(createConfigCommand());
@@ -11451,9 +11803,9 @@ function createRoutingCommand() {
11451
11803
 
11452
11804
  // src/commands/scan-config.ts
11453
11805
  init_dist3();
11454
- import { Command as Command92 } from "commander";
11455
- import { existsSync as existsSync30, readFileSync as readFileSync21, writeFileSync as writeFileSync22 } from "fs";
11456
- import { join as join48, relative as relative3 } from "path";
11806
+ import { Command as Command94 } from "commander";
11807
+ import { existsSync as existsSync30, readFileSync as readFileSync22, writeFileSync as writeFileSync22 } from "fs";
11808
+ import { join as join49, relative as relative3 } from "path";
11457
11809
  var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
11458
11810
  function stripHighSeverityPatterns(content, injectionFindings) {
11459
11811
  const highLines = /* @__PURE__ */ new Set();
@@ -11489,7 +11841,7 @@ function scanSingleFile(filePath, targetDir, scanner, options) {
11489
11841
  if (!existsSync30(filePath)) return null;
11490
11842
  let content;
11491
11843
  try {
11492
- content = readFileSync21(filePath, "utf8");
11844
+ content = readFileSync22(filePath, "utf8");
11493
11845
  } catch {
11494
11846
  return null;
11495
11847
  }
@@ -11510,7 +11862,7 @@ async function runScanConfig(targetDir, options) {
11510
11862
  const scanner = new SecurityScanner(parseSecurityConfig({}));
11511
11863
  const results = [];
11512
11864
  for (const configFile of CONFIG_FILES) {
11513
- const result = scanSingleFile(join48(targetDir, configFile), targetDir, scanner, options);
11865
+ const result = scanSingleFile(join49(targetDir, configFile), targetDir, scanner, options);
11514
11866
  if (result) results.push(result);
11515
11867
  }
11516
11868
  return { exitCode: computeScanExitCode(results), results };
@@ -11540,7 +11892,7 @@ function formatTextOutput(result) {
11540
11892
  }
11541
11893
  }
11542
11894
  function createScanConfigCommand() {
11543
- const command = new Command92("scan-config").description(
11895
+ const command = new Command94("scan-config").description(
11544
11896
  "Scan CLAUDE.md, AGENTS.md, .gemini/settings.json, and skill.yaml for prompt injection patterns"
11545
11897
  ).option("--path <dir>", "Target directory to scan (default: cwd)").option("--fix", "Strip high-severity patterns from files in-place").action(async (opts, cmd) => {
11546
11898
  const globalOpts = cmd.optsWithGlobals();
@@ -11558,7 +11910,7 @@ function createScanConfigCommand() {
11558
11910
 
11559
11911
  // src/commands/search.ts
11560
11912
  init_dist();
11561
- import { Command as Command93 } from "commander";
11913
+ import { Command as Command95 } from "commander";
11562
11914
  function parseFileKinds(raw) {
11563
11915
  if (!raw) return void 0;
11564
11916
  const set = /* @__PURE__ */ new Set();
@@ -11579,7 +11931,7 @@ function fmtBytes(n) {
11579
11931
  return n.toFixed(0);
11580
11932
  }
11581
11933
  function createSearchCommand() {
11582
- return new Command93("search").description("Full-text search over archived + live session content.").argument(
11934
+ return new Command95("search").description("Full-text search over archived + live session content.").argument(
11583
11935
  "<query>",
11584
11936
  "FTS5 query (bare words AND-joined; quotes/AND/OR/NOT/column: for advanced syntax)"
11585
11937
  ).option("-n, --limit <n>", "Max results", "20").option("--archived-only", "Skip live sessions, only search archived ones").option("--json", "Emit JSON to stdout instead of pretty text").option(
@@ -11639,9 +11991,9 @@ function createSearchCommand() {
11639
11991
  }
11640
11992
 
11641
11993
  // src/commands/security-craft.ts
11642
- import { Command as Command94 } from "commander";
11994
+ import { Command as Command96 } from "commander";
11643
11995
  function createSecurityCraftCommand() {
11644
- return new Command94("security-craft").description(
11996
+ return new Command96("security-craft").description(
11645
11997
  "LLM-judgment critique of security posture (TS/JS source). Sixth non-design craft-pipeline ceiling skill (the final sub-project). AST-driven signal detection fires only on files with security-relevant constructs; conservative confidence defaults manage the FP risk inherent in judgment-based security."
11646
11998
  ).option("-f, --files <files...>", "Optional file scope (overrides discovery)").option("-p, --packages <names...>", "Restrict to specific packages under packages/").option("--max-files <n>", "Cap source-file count (default: 100)").option("--max-signals-per-file <n>", "Cap per-file signal critique (default: 10)").action(async (opts, cmd) => {
11647
11999
  const globalOpts = cmd.optsWithGlobals();
@@ -11707,7 +12059,7 @@ ${file}`);
11707
12059
  }
11708
12060
 
11709
12061
  // src/commands/setup.ts
11710
- import { Command as Command95 } from "commander";
12062
+ import { Command as Command97 } from "commander";
11711
12063
  import * as fs37 from "fs";
11712
12064
  import * as os9 from "os";
11713
12065
  import * as path61 from "path";
@@ -12013,7 +12365,7 @@ async function detectLegacyLayout(cwd) {
12013
12365
  }
12014
12366
  async function runInitialGraphScan(cwd) {
12015
12367
  try {
12016
- const { runScan: runScan2 } = await import("./scan-P7YFKB77.js");
12368
+ const { runScan: runScan2 } = await import("./scan-IYSVRPD2.js");
12017
12369
  const result = await runScan2(cwd);
12018
12370
  return {
12019
12371
  status: "pass",
@@ -12052,7 +12404,7 @@ async function runSetup(cwd) {
12052
12404
  return { steps, success };
12053
12405
  }
12054
12406
  function createSetupCommand() {
12055
- return new Command95("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
12407
+ return new Command97("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
12056
12408
  const cwd = process.cwd();
12057
12409
  console.log("");
12058
12410
  console.log(` ${chalk16.bold("harness setup")}`);
@@ -12075,7 +12427,7 @@ function createSetupCommand() {
12075
12427
 
12076
12428
  // src/commands/share.ts
12077
12429
  init_dist3();
12078
- import { Command as Command96 } from "commander";
12430
+ import { Command as Command98 } from "commander";
12079
12431
  import * as fs38 from "fs";
12080
12432
  import * as path62 from "path";
12081
12433
  import { parse as parseYaml3 } from "yaml";
@@ -12134,16 +12486,16 @@ Create a constraints.yaml in your project root to define what to share.`
12134
12486
  logger.success(`Bundle written to ${outputPath}`);
12135
12487
  }
12136
12488
  function createShareCommand() {
12137
- return new Command96("share").description("Extract and publish a constraints bundle from constraints.yaml").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory for the bundle", ".").action(async (projectPath, options) => {
12489
+ return new Command98("share").description("Extract and publish a constraints bundle from constraints.yaml").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory for the bundle", ".").action(async (projectPath, options) => {
12138
12490
  await runShareAction(projectPath, options);
12139
12491
  });
12140
12492
  }
12141
12493
 
12142
12494
  // src/commands/skill/index.ts
12143
- import { Command as Command104 } from "commander";
12495
+ import { Command as Command106 } from "commander";
12144
12496
 
12145
12497
  // src/commands/skill/list.ts
12146
- import { Command as Command97 } from "commander";
12498
+ import { Command as Command99 } from "commander";
12147
12499
  import * as fs39 from "fs";
12148
12500
  import * as path63 from "path";
12149
12501
  import { parse } from "yaml";
@@ -12246,7 +12598,7 @@ function printSkillsVerbose(skills) {
12246
12598
  for (const s of skills) printSkillEntry(s);
12247
12599
  }
12248
12600
  function createListCommand3() {
12249
- return new Command97("list").description("List available skills").option("--installed", "Show only community-installed skills").option("--local", "Show only project-local skills").option("--all", "Show all skills (default)").action(async (opts, cmd) => {
12601
+ return new Command99("list").description("List available skills").option("--installed", "Show only community-installed skills").option("--local", "Show only project-local skills").option("--all", "Show all skills (default)").action(async (opts, cmd) => {
12250
12602
  const globalOpts = cmd.optsWithGlobals();
12251
12603
  const skills = collectSkills({ filter: resolveFilter(opts) });
12252
12604
  if (globalOpts.json) {
@@ -12261,13 +12613,13 @@ function createListCommand3() {
12261
12613
  }
12262
12614
 
12263
12615
  // src/commands/skill/run.ts
12264
- import { Command as Command98 } from "commander";
12616
+ import { Command as Command100 } from "commander";
12265
12617
  import * as fs40 from "fs";
12266
12618
  import * as path64 from "path";
12267
12619
  import { parse as parse2 } from "yaml";
12268
12620
 
12269
12621
  // src/skill/complexity.ts
12270
- import { execFileSync as execFileSync7 } from "child_process";
12622
+ import { execFileSync as execFileSync8 } from "child_process";
12271
12623
  function evaluateSignals(signals) {
12272
12624
  if (signals.fileCount >= 3) return "thorough";
12273
12625
  if (signals.newDir) return "thorough";
@@ -12279,17 +12631,17 @@ function evaluateSignals(signals) {
12279
12631
  }
12280
12632
  function detectComplexity(projectPath) {
12281
12633
  try {
12282
- const base = execFileSync7("git", ["merge-base", "HEAD", "main"], {
12634
+ const base = execFileSync8("git", ["merge-base", "HEAD", "main"], {
12283
12635
  cwd: projectPath,
12284
12636
  encoding: "utf-8",
12285
12637
  stdio: ["pipe", "pipe", "pipe"]
12286
12638
  }).trim();
12287
- const diffFiles = execFileSync7("git", ["diff", "--name-only", base], {
12639
+ const diffFiles = execFileSync8("git", ["diff", "--name-only", base], {
12288
12640
  cwd: projectPath,
12289
12641
  encoding: "utf-8",
12290
12642
  stdio: ["pipe", "pipe", "pipe"]
12291
12643
  }).trim().split("\n").filter(Boolean);
12292
- const diffStat = execFileSync7("git", ["diff", "--stat", base], {
12644
+ const diffStat = execFileSync8("git", ["diff", "--stat", base], {
12293
12645
  cwd: projectPath,
12294
12646
  encoding: "utf-8",
12295
12647
  stdio: ["pipe", "pipe", "pipe"]
@@ -12409,7 +12761,7 @@ function resolvePhaseState(metadata, projectPath, phase) {
12409
12761
  }
12410
12762
  async function appendProjectState(content, metadata, projectPath, hasPathOpt) {
12411
12763
  if (!metadata?.state.persistent || !hasPathOpt) return content;
12412
- const { readHarnessState: readHarnessState2, isEmptyHarnessState } = await import("./state-events-F44CUUZG.js");
12764
+ const { readHarnessState: readHarnessState2, isEmptyHarnessState } = await import("./state-events-YY5KBZTC.js");
12413
12765
  const stateResult = await readHarnessState2(projectPath);
12414
12766
  if (!stateResult.ok || isEmptyHarnessState(stateResult.value)) return content;
12415
12767
  const stateContent = JSON.stringify(stateResult.value, null, 2);
@@ -12475,14 +12827,14 @@ async function runSkill(name, opts) {
12475
12827
  process.exit(ExitCode.SUCCESS);
12476
12828
  }
12477
12829
  function createRunCommand3() {
12478
- return new Command98("run").description("Run a skill (outputs SKILL.md content with context preamble)").argument("<name>", "Skill name (e.g., harness-tdd)").option("--path <path>", "Project root path for context injection").option("--complexity <level>", "Rigor level: fast, standard, thorough", "standard").option("--phase <name>", "Start at a specific phase (for re-entry)").option("--party", "Enable multi-perspective evaluation").option(
12830
+ return new Command100("run").description("Run a skill (outputs SKILL.md content with context preamble)").argument("<name>", "Skill name (e.g., harness-tdd)").option("--path <path>", "Project root path for context injection").option("--complexity <level>", "Rigor level: fast, standard, thorough", "standard").option("--phase <name>", "Start at a specific phase (for re-entry)").option("--party", "Enable multi-perspective evaluation").option(
12479
12831
  "--backend <name>",
12480
12832
  "Spec B: one-shot routing override forwarded to the orchestrator as HARNESS_BACKEND_OVERRIDE"
12481
12833
  ).action(async (name, opts) => runSkill(name, opts));
12482
12834
  }
12483
12835
 
12484
12836
  // src/commands/skill/validate.ts
12485
- import { Command as Command99 } from "commander";
12837
+ import { Command as Command101 } from "commander";
12486
12838
  import * as fs41 from "fs";
12487
12839
  import * as path65 from "path";
12488
12840
  import { parse as parse3 } from "yaml";
@@ -12546,7 +12898,7 @@ function validateSkillEntry(name, skillsDir, errors) {
12546
12898
  }
12547
12899
  }
12548
12900
  function createValidateCommand2() {
12549
- return new Command99("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
12901
+ return new Command101("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
12550
12902
  const globalOpts = cmd.optsWithGlobals();
12551
12903
  const skillsDir = resolveSkillsDir();
12552
12904
  if (!fs41.existsSync(skillsDir)) {
@@ -12576,7 +12928,7 @@ function createValidateCommand2() {
12576
12928
  }
12577
12929
 
12578
12930
  // src/commands/skill/info.ts
12579
- import { Command as Command100 } from "commander";
12931
+ import { Command as Command102 } from "commander";
12580
12932
  import * as fs42 from "fs";
12581
12933
  import * as path66 from "path";
12582
12934
  import { parse as parse4 } from "yaml";
@@ -12621,7 +12973,7 @@ function printSkillInfo(skill) {
12621
12973
  console.log(`Persistent: ${skill.state.persistent}`);
12622
12974
  }
12623
12975
  function createInfoCommand() {
12624
- return new Command100("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
12976
+ return new Command102("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
12625
12977
  const globalOpts = cmd.optsWithGlobals();
12626
12978
  const loaded = loadSkillMetadata2(name);
12627
12979
  if (!loaded.ok) {
@@ -12638,7 +12990,7 @@ function createInfoCommand() {
12638
12990
  }
12639
12991
 
12640
12992
  // src/commands/skill/search.ts
12641
- import { Command as Command101 } from "commander";
12993
+ import { Command as Command103 } from "commander";
12642
12994
  async function runSearch(query, opts) {
12643
12995
  const results = await searchNpmRegistry(query, opts.registry);
12644
12996
  return results.filter((r) => {
@@ -12683,13 +13035,13 @@ async function runSearchAction(query, opts, globalOpts) {
12683
13035
  }
12684
13036
  }
12685
13037
  function createSearchCommand2() {
12686
- return new Command101("search").description("Search for community skills on the @harness-skills registry").argument("<query>", "Search query").option("--platform <platform>", "Filter by platform (e.g., claude-code)").option("--trigger <trigger>", "Filter by trigger type (e.g., manual, automatic)").option("--registry <url>", "Use a custom npm registry URL").action(async (query, opts, cmd) => {
13038
+ return new Command103("search").description("Search for community skills on the @harness-skills registry").argument("<query>", "Search query").option("--platform <platform>", "Filter by platform (e.g., claude-code)").option("--trigger <trigger>", "Filter by trigger type (e.g., manual, automatic)").option("--registry <url>", "Use a custom npm registry URL").action(async (query, opts, cmd) => {
12687
13039
  await runSearchAction(query, opts, cmd.optsWithGlobals());
12688
13040
  });
12689
13041
  }
12690
13042
 
12691
13043
  // src/commands/skill/create.ts
12692
- import { Command as Command102 } from "commander";
13044
+ import { Command as Command104 } from "commander";
12693
13045
  import * as path67 from "path";
12694
13046
  import * as fs43 from "fs";
12695
13047
  import YAML from "yaml";
@@ -12809,7 +13161,7 @@ Next steps:`);
12809
13161
  logger.info(` 3. Run: harness skills publish`);
12810
13162
  }
12811
13163
  function createCreateCommand() {
12812
- return new Command102("create").description("Scaffold a new community skill").argument("<name>", "Skill name (kebab-case)").option("--description <desc>", "Skill description").option("--type <type>", "Skill type: rigid or flexible", "flexible").option("--platforms <platforms>", "Comma-separated platforms (default: claude-code)").option("--triggers <triggers>", "Comma-separated triggers (default: manual)").option("--output-dir <dir>", "Output directory (default: agents/skills/claude-code/)").action(async (name, opts, cmd) => {
13164
+ return new Command104("create").description("Scaffold a new community skill").argument("<name>", "Skill name (kebab-case)").option("--description <desc>", "Skill description").option("--type <type>", "Skill type: rigid or flexible", "flexible").option("--platforms <platforms>", "Comma-separated platforms (default: claude-code)").option("--triggers <triggers>", "Comma-separated triggers (default: manual)").option("--output-dir <dir>", "Output directory (default: agents/skills/claude-code/)").action(async (name, opts, cmd) => {
12813
13165
  const globalOpts = cmd.optsWithGlobals();
12814
13166
  try {
12815
13167
  const result = runCreate(name, {
@@ -12832,10 +13184,10 @@ function createCreateCommand() {
12832
13184
  }
12833
13185
 
12834
13186
  // src/commands/skill/publish.ts
12835
- import { Command as Command103 } from "commander";
13187
+ import { Command as Command105 } from "commander";
12836
13188
  import * as fs45 from "fs";
12837
13189
  import * as path69 from "path";
12838
- import { execFileSync as execFileSync8 } from "child_process";
13190
+ import { execFileSync as execFileSync9 } from "child_process";
12839
13191
 
12840
13192
  // src/registry/validator.ts
12841
13193
  import * as fs44 from "fs";
@@ -12989,7 +13341,7 @@ ${skillMdContent}`;
12989
13341
  if (opts.registry) {
12990
13342
  publishArgs.push("--registry", opts.registry);
12991
13343
  }
12992
- execFileSync8("npm", publishArgs, {
13344
+ execFileSync9("npm", publishArgs, {
12993
13345
  cwd: skillDir,
12994
13346
  stdio: "pipe",
12995
13347
  timeout: 6e4
@@ -13001,7 +13353,7 @@ ${skillMdContent}`;
13001
13353
  };
13002
13354
  }
13003
13355
  function createPublishCommand() {
13004
- return new Command103("publish").description("Validate and publish a skill to @harness-skills on npm").option("--dry-run", "Run validation and generate package.json without publishing").option("--dir <dir>", "Skill directory (default: current directory)").option("--registry <url>", "Use a custom npm registry URL").action(async (opts, cmd) => {
13356
+ return new Command105("publish").description("Validate and publish a skill to @harness-skills on npm").option("--dry-run", "Run validation and generate package.json without publishing").option("--dir <dir>", "Skill directory (default: current directory)").option("--registry <url>", "Use a custom npm registry URL").action(async (opts, cmd) => {
13005
13357
  const globalOpts = cmd.optsWithGlobals();
13006
13358
  const skillDir = opts.dir || process.cwd();
13007
13359
  try {
@@ -13026,7 +13378,7 @@ function createPublishCommand() {
13026
13378
 
13027
13379
  // src/commands/skill/index.ts
13028
13380
  function createSkillCommand() {
13029
- const command = new Command104("skill").description("Skill management commands");
13381
+ const command = new Command106("skill").description("Skill management commands");
13030
13382
  command.addCommand(createListCommand3());
13031
13383
  command.addCommand(createRunCommand3());
13032
13384
  command.addCommand(createValidateCommand2());
@@ -13039,7 +13391,7 @@ function createSkillCommand() {
13039
13391
 
13040
13392
  // src/commands/snapshot.ts
13041
13393
  init_dist3();
13042
- import { Command as Command105 } from "commander";
13394
+ import { Command as Command107 } from "commander";
13043
13395
  import { execSync as execSync5 } from "child_process";
13044
13396
  import chalk17 from "chalk";
13045
13397
  function getCommitHash3(cwd) {
@@ -13208,7 +13560,7 @@ function registerTrendsCommand(parent) {
13208
13560
  }
13209
13561
  });
13210
13562
  }
13211
- function registerListCommand(parent) {
13563
+ function registerListCommand2(parent) {
13212
13564
  parent.command("list").description("List all captured architecture snapshots").action(async (_opts, cmd) => {
13213
13565
  const globalOpts = cmd.optsWithGlobals();
13214
13566
  const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
@@ -13221,17 +13573,17 @@ function registerListCommand(parent) {
13221
13573
  });
13222
13574
  }
13223
13575
  function createSnapshotCommand() {
13224
- const command = new Command105("snapshot").description("Architecture timeline snapshot commands");
13576
+ const command = new Command107("snapshot").description("Architecture timeline snapshot commands");
13225
13577
  registerCaptureCommand(command);
13226
13578
  registerTrendsCommand(command);
13227
- registerListCommand(command);
13579
+ registerListCommand2(command);
13228
13580
  return command;
13229
13581
  }
13230
13582
 
13231
13583
  // src/commands/spec-craft.ts
13232
- import { Command as Command106 } from "commander";
13584
+ import { Command as Command108 } from "commander";
13233
13585
  function createSpecCraftCommand() {
13234
- return new Command106("spec-craft").description(
13586
+ return new Command108("spec-craft").description(
13235
13587
  "LLM-judgment critique of spec quality (proposals + ADRs). Second craft-pipeline ceiling skill; 7 seed rubrics from the spec-quality canon. Per-section critique."
13236
13588
  ).option("-f, --files <files...>", "Optional spec file/glob scope").option("-k, --kinds <kinds...>", "Restrict to proposal / adr (default: both)").option("-s, --sections <names...>", "Restrict to specific canonical section names").option("--max-files <n>", "Cap doc count (default: 50)").option("--max-sections-per-file <n>", "Cap per-doc section critique (default: 10)").action(async (opts, cmd) => {
13237
13589
  const globalOpts = cmd.optsWithGlobals();
@@ -13299,7 +13651,7 @@ ${file}`);
13299
13651
 
13300
13652
  // src/commands/stale-constraints.ts
13301
13653
  init_dist3();
13302
- import { Command as Command107 } from "commander";
13654
+ import { Command as Command109 } from "commander";
13303
13655
  import chalk18 from "chalk";
13304
13656
  var CATEGORIES = [
13305
13657
  "circular-deps",
@@ -13386,7 +13738,7 @@ async function runStaleConstraintsCommand(options) {
13386
13738
  );
13387
13739
  }
13388
13740
  function createStaleConstraintsCommand() {
13389
- return new Command107("stale-constraints").description(
13741
+ return new Command109("stale-constraints").description(
13390
13742
  "Detect architectural constraints not violated within a window (candidates for removal)"
13391
13743
  ).option(
13392
13744
  "--window <days>",
@@ -13404,10 +13756,10 @@ function createStaleConstraintsCommand() {
13404
13756
  }
13405
13757
 
13406
13758
  // src/commands/state/index.ts
13407
- import { Command as Command112 } from "commander";
13759
+ import { Command as Command114 } from "commander";
13408
13760
 
13409
13761
  // src/commands/state/show.ts
13410
- import { Command as Command108 } from "commander";
13762
+ import { Command as Command110 } from "commander";
13411
13763
  import * as path70 from "path";
13412
13764
  function printStateText(state, stream) {
13413
13765
  if (stream) console.log(`Stream: ${stream}`);
@@ -13432,7 +13784,7 @@ function printStateProgress(progress) {
13432
13784
  }
13433
13785
  }
13434
13786
  function createShowCommand() {
13435
- return new Command108("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
13787
+ return new Command110("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
13436
13788
  const globalOpts = cmd.optsWithGlobals();
13437
13789
  const result = await readHarnessState(path70.resolve(opts.path), { stream: opts.stream });
13438
13790
  if (!result.ok) {
@@ -13450,7 +13802,7 @@ function createShowCommand() {
13450
13802
 
13451
13803
  // src/commands/state/reset.ts
13452
13804
  init_dist3();
13453
- import { Command as Command109 } from "commander";
13805
+ import { Command as Command111 } from "commander";
13454
13806
  import * as path71 from "path";
13455
13807
  import * as readline3 from "readline";
13456
13808
  async function confirmReset() {
@@ -13476,15 +13828,15 @@ async function runReset(opts) {
13476
13828
  process.exit(ExitCode.SUCCESS);
13477
13829
  }
13478
13830
  function createResetCommand() {
13479
- return new Command109("reset").description("Reset project state (truncates the event log to a fresh default)").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").option("--yes", "Skip confirmation prompt").action(async (opts) => runReset(opts));
13831
+ return new Command111("reset").description("Reset project state (truncates the event log to a fresh default)").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").option("--yes", "Skip confirmation prompt").action(async (opts) => runReset(opts));
13480
13832
  }
13481
13833
 
13482
13834
  // src/commands/state/learn.ts
13483
13835
  init_dist3();
13484
- import { Command as Command110 } from "commander";
13836
+ import { Command as Command112 } from "commander";
13485
13837
  import * as path72 from "path";
13486
13838
  function createLearnCommand() {
13487
- return new Command110("learn").description("Append a learning to .harness/learnings.md").argument("<message>", "The learning to record").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (message, opts, _cmd) => {
13839
+ return new Command112("learn").description("Append a learning to .harness/learnings.md").argument("<message>", "The learning to record").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (message, opts, _cmd) => {
13488
13840
  const projectPath = path72.resolve(opts.path);
13489
13841
  const result = await appendLearning(projectPath, message, void 0, void 0, opts.stream);
13490
13842
  if (!result.ok) {
@@ -13499,7 +13851,7 @@ function createLearnCommand() {
13499
13851
 
13500
13852
  // src/commands/state/streams.ts
13501
13853
  init_dist3();
13502
- import { Command as Command111 } from "commander";
13854
+ import { Command as Command113 } from "commander";
13503
13855
  import * as path73 from "path";
13504
13856
  async function runListStreams(opts, globalOpts) {
13505
13857
  const projectPath = path73.resolve(opts.path);
@@ -13550,7 +13902,7 @@ async function runActivateStream(name, opts) {
13550
13902
  process.exit(ExitCode.SUCCESS);
13551
13903
  }
13552
13904
  function createStreamsCommand() {
13553
- const command = new Command111("streams").description("Manage state streams");
13905
+ const command = new Command113("streams").description("Manage state streams");
13554
13906
  command.command("list").description("List all known streams").option("--path <path>", "Project root path", ".").action(async (opts, cmd) => runListStreams(opts, cmd.optsWithGlobals()));
13555
13907
  command.command("create <name>").description("Create a new stream").option("--path <path>", "Project root path", ".").option("--branch <branch>", "Associate with a git branch").action(async (name, opts) => runCreateStream(name, opts));
13556
13908
  command.command("archive <name>").description("Archive a stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => runArchiveStream(name, opts));
@@ -13560,7 +13912,7 @@ function createStreamsCommand() {
13560
13912
 
13561
13913
  // src/commands/state/index.ts
13562
13914
  function createStateCommand() {
13563
- const command = new Command112("state").description("Project state management commands");
13915
+ const command = new Command114("state").description("Project state management commands");
13564
13916
  command.addCommand(createShowCommand());
13565
13917
  command.addCommand(createResetCommand());
13566
13918
  command.addCommand(createLearnCommand());
@@ -13571,7 +13923,7 @@ function createStateCommand() {
13571
13923
  // src/commands/sync-analyses.ts
13572
13924
  import * as fs46 from "fs";
13573
13925
  import * as path74 from "path";
13574
- import { Command as Command113 } from "commander";
13926
+ import { Command as Command115 } from "commander";
13575
13927
  init_dist3();
13576
13928
  function isValidRecord(record) {
13577
13929
  return typeof record.issueId === "string" && !!record.issueId && typeof record.identifier === "string" && !!record.identifier && typeof record.analyzedAt === "string" && !/[/\\]/.test(record.issueId);
@@ -13696,7 +14048,7 @@ async function runSyncAnalyses(opts) {
13696
14048
  return;
13697
14049
  }
13698
14050
  const { AnalysisArchive, loadPublishedIndex: loadPublishedIndex2, savePublishedIndex: savePublishedIndex2 } = await import("@harness-engineering/orchestrator");
13699
- const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-IPVFYGY2.js");
14051
+ const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-MCTEX5QH.js");
13700
14052
  const adapter = new GitHubIssuesSyncAdapter2({ token, config: trackerConfig });
13701
14053
  const archive = new AnalysisArchive(path74.join(projectPath, ".harness", "analyses"));
13702
14054
  const publishedIndex = loadPublishedIndex2(projectPath);
@@ -13718,7 +14070,7 @@ async function runSyncAnalyses(opts) {
13718
14070
  }
13719
14071
  }
13720
14072
  function createSyncAnalysesCommand() {
13721
- const command = new Command113("sync-analyses").description(
14073
+ const command = new Command115("sync-analyses").description(
13722
14074
  "Pull published intelligence analyses from the external issue tracker into the local .harness/analyses/ directory"
13723
14075
  ).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
13724
14076
  try {
@@ -13732,7 +14084,7 @@ function createSyncAnalysesCommand() {
13732
14084
  }
13733
14085
 
13734
14086
  // src/commands/sync-main.ts
13735
- import { Command as Command114 } from "commander";
14087
+ import { Command as Command116 } from "commander";
13736
14088
  import * as path75 from "path";
13737
14089
  import {
13738
14090
  syncMain as defaultSyncMain
@@ -13763,7 +14115,7 @@ function formatHuman2(r) {
13763
14115
  }
13764
14116
  }
13765
14117
  function createSyncMainCommand() {
13766
- return new Command114("sync-main").description("Fast-forward the local default branch from origin (no-op on conflict)").option("--json", "Emit a SyncMainResult JSON object", false).option("--path <path>", "Project root path", ".").action(async (opts) => {
14118
+ return new Command116("sync-main").description("Fast-forward the local default branch from origin (no-op on conflict)").option("--json", "Emit a SyncMainResult JSON object", false).option("--path <path>", "Project root path", ".").action(async (opts) => {
13767
14119
  const cwd = path75.resolve(opts.path ?? ".");
13768
14120
  const exitCode = await runSyncMain({ cwd, json: Boolean(opts.json) });
13769
14121
  process.exit(exitCode);
@@ -13772,7 +14124,7 @@ function createSyncMainCommand() {
13772
14124
 
13773
14125
  // src/commands/taint.ts
13774
14126
  init_dist3();
13775
- import { Command as Command115 } from "commander";
14127
+ import { Command as Command117 } from "commander";
13776
14128
  function getProjectRoot() {
13777
14129
  return process.cwd();
13778
14130
  }
@@ -13844,18 +14196,18 @@ function registerStatusCommand(taint) {
13844
14196
  });
13845
14197
  }
13846
14198
  function createTaintCommand() {
13847
- const taint = new Command115("taint").description("Manage sentinel session taint state");
14199
+ const taint = new Command117("taint").description("Manage sentinel session taint state");
13848
14200
  registerClearCommand(taint);
13849
14201
  registerStatusCommand(taint);
13850
14202
  return taint;
13851
14203
  }
13852
14204
 
13853
14205
  // src/commands/telemetry/index.ts
13854
- import { Command as Command119 } from "commander";
14206
+ import { Command as Command121 } from "commander";
13855
14207
 
13856
14208
  // src/commands/telemetry/identify.ts
13857
14209
  init_dist3();
13858
- import { Command as Command116 } from "commander";
14210
+ import { Command as Command118 } from "commander";
13859
14211
  import * as fs47 from "fs";
13860
14212
  import * as path76 from "path";
13861
14213
  function telemetryFilePath(cwd) {
@@ -13879,7 +14231,7 @@ function printIdentity(identity) {
13879
14231
  }
13880
14232
  }
13881
14233
  function createIdentifyCommand() {
13882
- const cmd = new Command116("identify").description("Set or clear telemetry identity fields in .harness/telemetry.json").option("--project <name>", "Project name").option("--team <name>", "Team name").option("--alias <name>", "User alias").option("--clear", "Remove all identity fields").action((opts) => {
14234
+ const cmd = new Command118("identify").description("Set or clear telemetry identity fields in .harness/telemetry.json").option("--project <name>", "Project name").option("--team <name>", "Team name").option("--alias <name>", "User alias").option("--clear", "Remove all identity fields").action((opts) => {
13883
14235
  const cwd = process.cwd();
13884
14236
  if (opts.clear) {
13885
14237
  writeTelemetryFile(cwd, { identity: {} });
@@ -13904,7 +14256,7 @@ function createIdentifyCommand() {
13904
14256
 
13905
14257
  // src/commands/telemetry/status.ts
13906
14258
  init_dist3();
13907
- import { Command as Command117 } from "commander";
14259
+ import { Command as Command119 } from "commander";
13908
14260
  function gatherEnvOverrides() {
13909
14261
  const overrides = {};
13910
14262
  if (process.env.DO_NOT_TRACK) overrides.DO_NOT_TRACK = process.env.DO_NOT_TRACK;
@@ -13946,7 +14298,7 @@ function printHumanStatus(result) {
13946
14298
  printEnvOverrides(result.envOverrides);
13947
14299
  }
13948
14300
  function createStatusCommand() {
13949
- const cmd = new Command117("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
14301
+ const cmd = new Command119("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
13950
14302
  const cwd = process.cwd();
13951
14303
  const envOverrides = gatherEnvOverrides();
13952
14304
  const consent = resolveConsent(cwd, void 0);
@@ -13979,11 +14331,11 @@ function createStatusCommand() {
13979
14331
 
13980
14332
  // src/commands/telemetry/test.ts
13981
14333
  init_dist3();
13982
- import { Command as Command118 } from "commander";
14334
+ import { Command as Command120 } from "commander";
13983
14335
 
13984
14336
  // src/bin/command-telemetry.ts
13985
- import { existsSync as existsSync43, readFileSync as readFileSync31, mkdirSync as mkdirSync22, appendFileSync, writeFileSync as writeFileSync28 } from "fs";
13986
- import { join as join62, parse as parsePath, resolve as resolve45 } from "path";
14337
+ import { existsSync as existsSync43, readFileSync as readFileSync32, mkdirSync as mkdirSync22, appendFileSync, writeFileSync as writeFileSync28 } from "fs";
14338
+ import { join as join63, parse as parsePath, resolve as resolve45 } from "path";
13987
14339
  import { spawn as spawn2 } from "child_process";
13988
14340
  var POSTHOG_API_KEY = "phc_wNTdCMcfJXZPgdNeDociZW6vwoGGo4nb7vqEfWThFfsG";
13989
14341
  var EXCLUDED_COMMANDS = /* @__PURE__ */ new Set(["help", "completion"]);
@@ -13991,7 +14343,7 @@ function findProjectRoot(cwd) {
13991
14343
  let dir = resolve45(cwd);
13992
14344
  const { root } = parsePath(dir);
13993
14345
  while (dir !== root) {
13994
- if (existsSync43(join62(dir, "harness.config.json"))) return dir;
14346
+ if (existsSync43(join63(dir, "harness.config.json"))) return dir;
13995
14347
  dir = resolve45(dir, "..");
13996
14348
  }
13997
14349
  return cwd;
@@ -14029,7 +14381,7 @@ function resolveCommandName(cmd) {
14029
14381
  }
14030
14382
  function writeCommandRecordSync(cwd, command, duration, outcome) {
14031
14383
  try {
14032
- const metricsDir = join62(cwd, ".harness", "metrics");
14384
+ const metricsDir = join63(cwd, ".harness", "metrics");
14033
14385
  mkdirSync22(metricsDir, { recursive: true });
14034
14386
  const record = {
14035
14387
  skill: command,
@@ -14039,16 +14391,16 @@ function writeCommandRecordSync(cwd, command, duration, outcome) {
14039
14391
  outcome,
14040
14392
  phasesReached: []
14041
14393
  };
14042
- const adoptionFile = join62(metricsDir, "adoption.jsonl");
14394
+ const adoptionFile = join63(metricsDir, "adoption.jsonl");
14043
14395
  appendFileSync(adoptionFile, JSON.stringify(record) + "\n");
14044
14396
  } catch {
14045
14397
  }
14046
14398
  }
14047
14399
  function isTelemetryDisabledByConfig(cwd) {
14048
- const configPath = join62(cwd, "harness.config.json");
14400
+ const configPath = join63(cwd, "harness.config.json");
14049
14401
  if (!existsSync43(configPath)) return false;
14050
14402
  try {
14051
- const config = JSON.parse(readFileSync31(configPath, "utf-8"));
14403
+ const config = JSON.parse(readFileSync32(configPath, "utf-8"));
14052
14404
  return config?.telemetry?.enabled === false;
14053
14405
  } catch {
14054
14406
  return false;
@@ -14060,10 +14412,10 @@ function isTelemetryOptedOut(cwd) {
14060
14412
  }
14061
14413
  function flushTelemetryBackground(cwd) {
14062
14414
  try {
14063
- const adoptionFile = join62(cwd, ".harness", "metrics", "adoption.jsonl");
14415
+ const adoptionFile = join63(cwd, ".harness", "metrics", "adoption.jsonl");
14064
14416
  if (!existsSync43(adoptionFile)) return;
14065
14417
  if (isTelemetryOptedOut(cwd)) return;
14066
- const reporterPath = join62(cwd, ".harness", "hooks", "telemetry-reporter.js");
14418
+ const reporterPath = join63(cwd, ".harness", "hooks", "telemetry-reporter.js");
14067
14419
  if (!existsSync43(reporterPath)) return;
14068
14420
  const child = spawn2(process.execPath, [reporterPath], {
14069
14421
  cwd,
@@ -14101,7 +14453,7 @@ function reportTestSuccess(status, distinctId, identity) {
14101
14453
  if (identity.team) logger.info(` team: ${identity.team}`);
14102
14454
  }
14103
14455
  function createTestCommand() {
14104
- return new Command118("test").description("Send a test event to PostHog and verify connectivity").action(async () => {
14456
+ return new Command120("test").description("Send a test event to PostHog and verify connectivity").action(async () => {
14105
14457
  const cwd = process.cwd();
14106
14458
  const consent = resolveConsent(cwd, void 0);
14107
14459
  if (!consent.allowed) {
@@ -14138,7 +14490,7 @@ function createTestCommand() {
14138
14490
 
14139
14491
  // src/commands/telemetry/index.ts
14140
14492
  function createTelemetryCommand() {
14141
- const command = new Command119("telemetry").description("Telemetry identity and status management");
14493
+ const command = new Command121("telemetry").description("Telemetry identity and status management");
14142
14494
  command.addCommand(createIdentifyCommand());
14143
14495
  command.addCommand(createStatusCommand());
14144
14496
  command.addCommand(createTestCommand());
@@ -14146,9 +14498,9 @@ function createTelemetryCommand() {
14146
14498
  }
14147
14499
 
14148
14500
  // src/commands/test-craft.ts
14149
- import { Command as Command120 } from "commander";
14501
+ import { Command as Command122 } from "commander";
14150
14502
  function createTestCraftCommand() {
14151
- return new Command120("test-craft").description(
14503
+ return new Command122("test-craft").description(
14152
14504
  "LLM-judgment critique of test quality across vitest/jest/mocha/playwright. Fourth craft-pipeline ceiling skill. Per-test critique with best-effort source pairing."
14153
14505
  ).option("-f, --files <files...>", "Optional test file/glob scope").option("--frameworks <names...>", "Restrict to: vitest / jest / mocha / playwright").option("--max-files <n>", "Cap test file count (default: 100)").option("--max-tests-per-file <n>", "Cap per-file test critique (default: 20)").option("--no-source-pair", "Skip source-pairing resolution").action(async (opts, cmd) => {
14154
14506
  const globalOpts = cmd.optsWithGlobals();
@@ -14218,7 +14570,7 @@ ${file}`);
14218
14570
  }
14219
14571
 
14220
14572
  // src/commands/traceability.ts
14221
- import { Command as Command121 } from "commander";
14573
+ import { Command as Command123 } from "commander";
14222
14574
  import chalk19 from "chalk";
14223
14575
  function confidenceLabel(maxConfidence) {
14224
14576
  if (maxConfidence >= 0.8) return "explicit";
@@ -14260,9 +14612,11 @@ function buildFilterOptions(options) {
14260
14612
  }
14261
14613
  function handleNoStore2(mode) {
14262
14614
  if (mode === OutputMode.JSON) {
14263
- console.log(JSON.stringify({ error: "No knowledge graph found. Run `harness scan` first." }));
14615
+ console.log(
14616
+ JSON.stringify({ error: "No knowledge graph found. Run `harness graph scan` first." })
14617
+ );
14264
14618
  } else {
14265
- logger.error("No knowledge graph found. Run `harness scan` first.");
14619
+ logger.error("No knowledge graph found. Run `harness graph scan` first.");
14266
14620
  }
14267
14621
  process.exit(ExitCode.ERROR);
14268
14622
  }
@@ -14271,11 +14625,13 @@ function handleEmptyResults(mode) {
14271
14625
  console.log(
14272
14626
  JSON.stringify({
14273
14627
  results: [],
14274
- message: "No requirements found in graph. Run `harness scan` to ingest spec requirements."
14628
+ message: "No requirements found in graph. Run `harness graph scan` to ingest spec requirements."
14275
14629
  })
14276
14630
  );
14277
14631
  } else if (mode !== OutputMode.QUIET) {
14278
- logger.info("No requirements found in graph. Run `harness scan` to ingest spec requirements.");
14632
+ logger.info(
14633
+ "No requirements found in graph. Run `harness graph scan` to ingest spec requirements."
14634
+ );
14279
14635
  }
14280
14636
  process.exit(ExitCode.SUCCESS);
14281
14637
  }
@@ -14339,7 +14695,7 @@ async function runTraceability(options) {
14339
14695
  const projectPath = process.cwd();
14340
14696
  const store = await loadGraphStore(projectPath);
14341
14697
  if (!store) handleNoStore2(mode);
14342
- const graphModule = await import("./dist-OWHMNL4W.js");
14698
+ const graphModule = await import("./dist-DWBTZXR5.js");
14343
14699
  const filterOptions = buildFilterOptions(options);
14344
14700
  const results = graphModule.queryTraceability(store, filterOptions);
14345
14701
  if (results.length === 0) handleEmptyResults(mode);
@@ -14354,7 +14710,7 @@ async function runTraceability(options) {
14354
14710
  process.exit(ExitCode.SUCCESS);
14355
14711
  }
14356
14712
  function createTraceabilityCommand() {
14357
- return new Command121("traceability").description("Show spec-to-implementation traceability from the knowledge graph").option("--spec <path>", "Filter by spec file path").option("--feature <name>", "Filter by feature name").action(async (opts, cmd) => {
14713
+ return new Command123("traceability").description("Show spec-to-implementation traceability from the knowledge graph").option("--spec <path>", "Filter by spec file path").option("--feature <name>", "Filter by feature name").action(async (opts, cmd) => {
14358
14714
  const globalOpts = cmd.optsWithGlobals();
14359
14715
  await runTraceability({
14360
14716
  spec: opts.spec,
@@ -14368,7 +14724,7 @@ function createTraceabilityCommand() {
14368
14724
 
14369
14725
  // src/commands/uninstall.ts
14370
14726
  import * as path77 from "path";
14371
- import { Command as Command122 } from "commander";
14727
+ import { Command as Command124 } from "commander";
14372
14728
  async function runUninstall(skillName, options) {
14373
14729
  const packageName = resolvePackageName(skillName);
14374
14730
  const shortName = extractSkillName(packageName);
@@ -14405,7 +14761,7 @@ async function runUninstall(skillName, options) {
14405
14761
  return result;
14406
14762
  }
14407
14763
  function createUninstallCommand() {
14408
- const cmd = new Command122("uninstall");
14764
+ const cmd = new Command124("uninstall");
14409
14765
  cmd.description("Uninstall a community skill").argument("<skill>", "Skill name or @harness-skills/scoped package name").option("--force", "Remove even if other skills depend on this one").action(async (skill, opts) => {
14410
14766
  try {
14411
14767
  const result = await runUninstall(skill, opts);
@@ -14427,7 +14783,7 @@ function createUninstallCommand() {
14427
14783
  init_dist3();
14428
14784
  import * as fs48 from "fs/promises";
14429
14785
  import * as path78 from "path";
14430
- import { Command as Command123 } from "commander";
14786
+ import { Command as Command125 } from "commander";
14431
14787
  async function runUninstallConstraints(options) {
14432
14788
  const { packageName, configPath, lockfilePath } = options;
14433
14789
  const lockfileResult = await readLockfile(lockfilePath);
@@ -14484,7 +14840,7 @@ async function runUninstallConstraints(options) {
14484
14840
  };
14485
14841
  }
14486
14842
  function createUninstallConstraintsCommand() {
14487
- const cmd = new Command123("uninstall-constraints");
14843
+ const cmd = new Command125("uninstall-constraints");
14488
14844
  cmd.description("Remove a previously installed constraints package").argument("<name>", "Name of the constraint package to uninstall").option("-c, --config <path>", "Path to harness.config.json").action(async (name, opts) => {
14489
14845
  let configPath;
14490
14846
  if (opts.config) {
@@ -14524,10 +14880,10 @@ function createUninstallConstraintsCommand() {
14524
14880
 
14525
14881
  // src/commands/update.ts
14526
14882
  init_dist3();
14527
- import { Command as Command124 } from "commander";
14528
- import { execFile as execFile2, execFileSync as execFileSync9 } from "child_process";
14529
- import { realpathSync, existsSync as existsSync44, readFileSync as readFileSync32 } from "fs";
14530
- import { dirname as dirname24, join as join65 } from "path";
14883
+ import { Command as Command126 } from "commander";
14884
+ import { execFile as execFile2, execFileSync as execFileSync10 } from "child_process";
14885
+ import { realpathSync, existsSync as existsSync44, readFileSync as readFileSync33 } from "fs";
14886
+ import { dirname as dirname24, join as join66 } from "path";
14531
14887
  import { promisify as promisify2 } from "util";
14532
14888
  import readline4 from "readline";
14533
14889
  import chalk20 from "chalk";
@@ -14567,7 +14923,7 @@ async function getLatestVersionAsync(pkg) {
14567
14923
  function getInstalledVersions(pm, packages) {
14568
14924
  const versions = {};
14569
14925
  try {
14570
- const output = execFileSync9(pm, ["list", "-g", "--json"], {
14926
+ const output = execFileSync10(pm, ["list", "-g", "--json"], {
14571
14927
  encoding: "utf-8",
14572
14928
  timeout: 15e3
14573
14929
  });
@@ -14588,7 +14944,7 @@ function getInstalledVersions(pm, packages) {
14588
14944
  }
14589
14945
  function getInstalledPackages(pm) {
14590
14946
  try {
14591
- const output = execFileSync9(pm, ["list", "-g", "--json"], {
14947
+ const output = execFileSync10(pm, ["list", "-g", "--json"], {
14592
14948
  encoding: "utf-8",
14593
14949
  timeout: 15e3
14594
14950
  });
@@ -14618,9 +14974,9 @@ function prompt3(question) {
14618
14974
  function findPackageDir(resolvedBin) {
14619
14975
  let dir = dirname24(resolvedBin);
14620
14976
  for (let i = 0; i < 6; i++) {
14621
- if (existsSync44(join65(dir, "package.json"))) {
14977
+ if (existsSync44(join66(dir, "package.json"))) {
14622
14978
  try {
14623
- const pkg = JSON.parse(readFileSync32(join65(dir, "package.json"), "utf-8"));
14979
+ const pkg = JSON.parse(readFileSync33(join66(dir, "package.json"), "utf-8"));
14624
14980
  if (pkg?.name === CLI_PACKAGE) return dir;
14625
14981
  } catch {
14626
14982
  }
@@ -14643,7 +14999,7 @@ function findAllInstalls() {
14643
14999
  const args = isWindows ? ["harness"] : ["-a", "harness"];
14644
15000
  let output;
14645
15001
  try {
14646
- const raw = execFileSync9(cmd, args, { encoding: "utf-8", timeout: 5e3 });
15002
+ const raw = execFileSync10(cmd, args, { encoding: "utf-8", timeout: 5e3 });
14647
15003
  if (typeof raw !== "string") return [];
14648
15004
  output = raw;
14649
15005
  } catch {
@@ -14665,7 +15021,7 @@ function findAllInstalls() {
14665
15021
  if (!packageDir) continue;
14666
15022
  let version = null;
14667
15023
  try {
14668
- const pkg = JSON.parse(readFileSync32(join65(packageDir, "package.json"), "utf-8"));
15024
+ const pkg = JSON.parse(readFileSync33(join66(packageDir, "package.json"), "utf-8"));
14669
15025
  if (typeof pkg?.version === "string") version = pkg.version;
14670
15026
  } catch {
14671
15027
  }
@@ -14720,7 +15076,7 @@ async function offerCleanupOfOtherInstalls(activeDir) {
14720
15076
  }
14721
15077
  try {
14722
15078
  logger.info(`Uninstalling: ${cmd.display}`);
14723
- execFileSync9(cmd.bin, cmd.args, { stdio: "inherit", timeout: 12e4 });
15079
+ execFileSync10(cmd.bin, cmd.args, { stdio: "inherit", timeout: 12e4 });
14724
15080
  } catch {
14725
15081
  logger.warn(`Uninstall failed for ${cmd.install.binPath}.`);
14726
15082
  console.log(` Run manually: ${chalk20.cyan(cmd.display)}`);
@@ -14758,12 +15114,12 @@ async function ensureTelemetryIfNeeded() {
14758
15114
  }
14759
15115
  function refreshHooks() {
14760
15116
  const cwd = process.cwd();
14761
- const configPath = join65(cwd, "harness.config.json");
15117
+ const configPath = join66(cwd, "harness.config.json");
14762
15118
  if (!existsSync44(configPath)) return;
14763
15119
  let profile = "standard";
14764
- const profilePath = join65(cwd, ".harness", "hooks", "profile.json");
15120
+ const profilePath = join66(cwd, ".harness", "hooks", "profile.json");
14765
15121
  try {
14766
- const data = JSON.parse(readFileSync32(profilePath, "utf-8"));
15122
+ const data = JSON.parse(readFileSync33(profilePath, "utf-8"));
14767
15123
  if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
14768
15124
  profile = data.profile;
14769
15125
  }
@@ -14780,7 +15136,7 @@ function refreshHooks() {
14780
15136
  function runLocalGraphScan() {
14781
15137
  try {
14782
15138
  logger.info("Scanning codebase to rebuild knowledge graph...");
14783
- execFileSync9("harness", ["graph", "scan", "."], { stdio: "inherit" });
15139
+ execFileSync10("harness", ["graph", "scan", "."], { stdio: "inherit" });
14784
15140
  } catch {
14785
15141
  logger.warn("Graph scan failed. Run manually:");
14786
15142
  console.log(` ${chalk20.cyan("harness graph scan .")}`);
@@ -14795,7 +15151,7 @@ async function offerRegeneration() {
14795
15151
  const scopeAnswer = await prompt3("Generate for (G)lobal or (l)ocal project? (G/l) ");
14796
15152
  const isGlobal = scopeAnswer !== "l" && scopeAnswer !== "local";
14797
15153
  try {
14798
- execFileSync9("harness", ["generate", ...isGlobal ? ["--global"] : []], {
15154
+ execFileSync10("harness", ["generate", ...isGlobal ? ["--global"] : []], {
14799
15155
  stdio: "inherit"
14800
15156
  });
14801
15157
  } catch {
@@ -14875,7 +15231,7 @@ async function runUpdateAction(opts, globalOpts) {
14875
15231
  }
14876
15232
  try {
14877
15233
  logger.info("Updating packages...");
14878
- execFileSync9(pm, ["install", "-g", ...installPkgs], { stdio: "inherit", timeout: 12e4 });
15234
+ execFileSync10(pm, ["install", "-g", ...installPkgs], { stdio: "inherit", timeout: 12e4 });
14879
15235
  console.log("");
14880
15236
  logger.success("Update complete");
14881
15237
  invalidateCheckState();
@@ -14892,7 +15248,7 @@ async function runUpdateAction(opts, globalOpts) {
14892
15248
  process.exit(ExitCode.SUCCESS);
14893
15249
  }
14894
15250
  function createUpdateCommand() {
14895
- return new Command124("update").description("Update all @harness-engineering packages to the latest version").option("--version <semver>", "Pin @harness-engineering/cli to a specific version").option("--force", "Force update even if versions match").option(
15251
+ return new Command126("update").description("Update all @harness-engineering packages to the latest version").option("--version <semver>", "Pin @harness-engineering/cli to a specific version").option("--force", "Force update even if versions match").option(
14896
15252
  "--regenerate",
14897
15253
  "Only regenerate slash commands and agent definitions (skip package updates)"
14898
15254
  ).action(async (opts, cmd) => {
@@ -14902,9 +15258,9 @@ function createUpdateCommand() {
14902
15258
  }
14903
15259
 
14904
15260
  // src/commands/usage.ts
14905
- import { Command as Command125 } from "commander";
15261
+ import { Command as Command127 } from "commander";
14906
15262
  async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
14907
- const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-IPVFYGY2.js");
15263
+ const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-MCTEX5QH.js");
14908
15264
  const records = readCostRecords(cwd);
14909
15265
  if (includeClaudeSessions) {
14910
15266
  const ccRecords = parseCCRecords();
@@ -14997,7 +15353,7 @@ function registerDailyCommand(usage) {
14997
15353
  else logger.info("No usage data found. Run some harness sessions first.");
14998
15354
  return;
14999
15355
  }
15000
- const { aggregateByDay } = await import("./dist-IPVFYGY2.js");
15356
+ const { aggregateByDay } = await import("./dist-MCTEX5QH.js");
15001
15357
  const limited = aggregateByDay(records).slice(0, days);
15002
15358
  if (globalOpts.json) {
15003
15359
  console.log(
@@ -15026,7 +15382,7 @@ function registerSessionsCommand(usage) {
15026
15382
  }
15027
15383
  return;
15028
15384
  }
15029
- const { aggregateBySession } = await import("./dist-IPVFYGY2.js");
15385
+ const { aggregateBySession } = await import("./dist-MCTEX5QH.js");
15030
15386
  const sessionData = aggregateBySession(records);
15031
15387
  const limited = sessionData.slice(0, limit);
15032
15388
  if (globalOpts.json) {
@@ -15106,7 +15462,7 @@ function registerSessionCommand(usage) {
15106
15462
  cwd,
15107
15463
  globalOpts.includeClaudeSessions
15108
15464
  );
15109
- const { aggregateBySession } = await import("./dist-IPVFYGY2.js");
15465
+ const { aggregateBySession } = await import("./dist-MCTEX5QH.js");
15110
15466
  const sessionData = aggregateBySession(records);
15111
15467
  const match = sessionData.find((s) => s.sessionId === id);
15112
15468
  if (!match) {
@@ -15141,7 +15497,7 @@ function registerLatestCommand(usage) {
15141
15497
  }
15142
15498
  return;
15143
15499
  }
15144
- const { aggregateBySession } = await import("./dist-IPVFYGY2.js");
15500
+ const { aggregateBySession } = await import("./dist-MCTEX5QH.js");
15145
15501
  const sessionData = aggregateBySession(records);
15146
15502
  const latest = sessionData[0];
15147
15503
  if (!latest) {
@@ -15167,7 +15523,7 @@ function registerLatestCommand(usage) {
15167
15523
  });
15168
15524
  }
15169
15525
  function createUsageCommand() {
15170
- const usage = new Command125("usage").description("Token usage and cost tracking");
15526
+ const usage = new Command127("usage").description("Token usage and cost tracking");
15171
15527
  usage.option(
15172
15528
  "--include-claude-sessions",
15173
15529
  "Include Claude Code session data from ~/.claude/projects/"
@@ -15182,10 +15538,10 @@ function createUsageCommand() {
15182
15538
  // src/commands/validate.ts
15183
15539
  init_dist3();
15184
15540
  init_dist3();
15185
- import { Command as Command126 } from "commander";
15541
+ import { Command as Command128 } from "commander";
15186
15542
  import * as fs49 from "fs";
15187
15543
  import * as path79 from "path";
15188
- import { execFileSync as execFileSync10 } from "child_process";
15544
+ import { execFileSync as execFileSync11 } from "child_process";
15189
15545
  async function runValidate(options) {
15190
15546
  const configResult = resolveConfig(options.configPath);
15191
15547
  if (!configResult.ok) {
@@ -15304,7 +15660,7 @@ async function runValidate(options) {
15304
15660
  const gitattributesContent = fs49.readFileSync(gitattributesPath, "utf-8");
15305
15661
  let driverConfigured = false;
15306
15662
  try {
15307
- const out = execFileSync10("git", ["config", "--get", "merge.ours.driver"], {
15663
+ const out = execFileSync11("git", ["config", "--get", "merge.ours.driver"], {
15308
15664
  cwd,
15309
15665
  encoding: "utf-8",
15310
15666
  stdio: ["ignore", "pipe", "ignore"]
@@ -15490,7 +15846,7 @@ function resolveValidateMode(globalOpts) {
15490
15846
  return OutputMode.TEXT;
15491
15847
  }
15492
15848
  async function printCrossCheckWarnings(mode) {
15493
- const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-M2ZM6RFY.js");
15849
+ const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-OYKEDCST.js");
15494
15850
  const cwd = process.cwd();
15495
15851
  const crossResult = await runCrossCheck2({
15496
15852
  specsDir: path79.join(cwd, "docs", "specs"),
@@ -15506,7 +15862,7 @@ async function printCrossCheckWarnings(mode) {
15506
15862
  ${crossResult.value.warnings} warnings`);
15507
15863
  }
15508
15864
  function createValidateCommand3() {
15509
- const command = new Command126("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
15865
+ const command = new Command128("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
15510
15866
  "--agent-configs",
15511
15867
  "Validate agent configs (CLAUDE.md, hooks, skills) via agnix or built-in fallback rules"
15512
15868
  ).option("--strict", "Treat warnings as errors (applies to --agent-configs)").option("--agnix-bin <path>", "Override the agnix binary path discovered on PATH").action(async (opts, cmd) => runValidateAction(opts, cmd.optsWithGlobals()));
@@ -15555,7 +15911,7 @@ Agent configs checked via ${engineLabel}${note}`);
15555
15911
 
15556
15912
  // src/commands/verify.ts
15557
15913
  init_dist3();
15558
- import { Command as Command127 } from "commander";
15914
+ import { Command as Command129 } from "commander";
15559
15915
  import { execSync as execSync6 } from "child_process";
15560
15916
  function loadBranchingConfig(configPath) {
15561
15917
  const shouldLoad = configPath !== void 0 || findConfigFile().ok;
@@ -15618,7 +15974,7 @@ async function runVerify(options) {
15618
15974
  process.exit(ExitCode.VALIDATION_FAILED);
15619
15975
  }
15620
15976
  function createVerifyCommand() {
15621
- return new Command127("verify").description(
15977
+ return new Command129("verify").description(
15622
15978
  "Verify project conventions (currently: branch naming). Works with or without a harness.config.json."
15623
15979
  ).option(
15624
15980
  "--branch <name>",
@@ -15669,7 +16025,6 @@ var commandCreators = [
15669
16025
  createGraphCommand,
15670
16026
  createHooksCommand,
15671
16027
  createImpactPreviewCommand,
15672
- createIngestCommand,
15673
16028
  createInitCommand3,
15674
16029
  createInsightsCommand,
15675
16030
  createInstallCommand,
@@ -15690,15 +16045,14 @@ var commandCreators = [
15690
16045
  createPerfCommand,
15691
16046
  createPersonaCommand,
15692
16047
  createPredictCommand,
16048
+ createPreMergeBriefCommand,
15693
16049
  createProposalsCommand,
15694
16050
  createPublishAnalysesCommand,
15695
16051
  createPulseCommand,
15696
- createQueryCommand,
15697
16052
  createRecommendCommand,
15698
16053
  createReviewCiCommand,
15699
16054
  createRoadmapCommand,
15700
16055
  createRoutingCommand,
15701
- createScanCommand,
15702
16056
  createScanConfigCommand,
15703
16057
  createSearchCommand,
15704
16058
  createSecurityCraftCommand,
@@ -15724,13 +16078,35 @@ var commandCreators = [
15724
16078
  createVerifyCommand
15725
16079
  ];
15726
16080
 
16081
+ // src/commands/graph/deprecated-aliases.ts
16082
+ var DEPRECATED_GRAPH_ALIASES = [
16083
+ { factory: createScanCommand, canonical: "harness graph scan" },
16084
+ { factory: createQueryCommand, canonical: "harness graph query" },
16085
+ { factory: createIngestCommand, canonical: "harness graph ingest" }
16086
+ ];
16087
+ function registerDeprecatedGraphAliases(program) {
16088
+ for (const { factory, canonical } of DEPRECATED_GRAPH_ALIASES) {
16089
+ const alias = factory();
16090
+ alias.hook("preAction", (thisCommand) => {
16091
+ const globalOpts = thisCommand.optsWithGlobals();
16092
+ if (globalOpts.quiet) return;
16093
+ process.stderr.write(
16094
+ `\u26A0 "harness ${alias.name()}" is deprecated and will be removed in the next major release. Use "${canonical}" instead.
16095
+ `
16096
+ );
16097
+ });
16098
+ program.addCommand(alias, { hidden: true });
16099
+ }
16100
+ }
16101
+
15727
16102
  // src/index.ts
15728
16103
  function createProgram() {
15729
- const program = new Command128();
16104
+ const program = new Command130();
15730
16105
  program.name("harness").description("CLI for Harness Engineering toolkit").version(CLI_VERSION).option("-c, --config <path>", "Path to config file").option("--json", "Output as JSON").option("--verbose", "Verbose output").option("--quiet", "Minimal output");
15731
16106
  for (const creator of commandCreators) {
15732
16107
  program.addCommand(creator());
15733
16108
  }
16109
+ registerDeprecatedGraphAliases(program);
15734
16110
  return program;
15735
16111
  }
15736
16112