@harness-engineering/cli 1.24.3 → 1.25.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 (106) hide show
  1. package/dist/agents/skills/claude-code/harness-architecture-advisor/SKILL.md +10 -6
  2. package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +40 -5
  3. package/dist/agents/skills/claude-code/harness-git-workflow/SKILL.md +32 -11
  4. package/dist/agents/skills/claude-code/harness-planning/SKILL.md +19 -0
  5. package/dist/agents/skills/claude-code/harness-skill-authoring/SKILL.md +42 -7
  6. package/dist/agents/skills/claude-code/harness-verification/SKILL.md +25 -0
  7. package/dist/agents/skills/codex/harness-architecture-advisor/SKILL.md +10 -6
  8. package/dist/agents/skills/codex/harness-code-review/SKILL.md +40 -5
  9. package/dist/agents/skills/codex/harness-git-workflow/SKILL.md +32 -11
  10. package/dist/agents/skills/codex/harness-planning/SKILL.md +19 -0
  11. package/dist/agents/skills/codex/harness-skill-authoring/SKILL.md +42 -7
  12. package/dist/agents/skills/codex/harness-verification/SKILL.md +25 -0
  13. package/dist/agents/skills/cursor/harness-architecture-advisor/SKILL.md +10 -6
  14. package/dist/agents/skills/cursor/harness-code-review/SKILL.md +40 -5
  15. package/dist/agents/skills/cursor/harness-git-workflow/SKILL.md +32 -11
  16. package/dist/agents/skills/cursor/harness-planning/SKILL.md +19 -0
  17. package/dist/agents/skills/cursor/harness-skill-authoring/SKILL.md +42 -7
  18. package/dist/agents/skills/cursor/harness-verification/SKILL.md +25 -0
  19. package/dist/agents/skills/gemini-cli/harness-architecture-advisor/SKILL.md +10 -6
  20. package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +40 -5
  21. package/dist/agents/skills/gemini-cli/harness-git-workflow/SKILL.md +32 -11
  22. package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +19 -0
  23. package/dist/agents/skills/gemini-cli/harness-skill-authoring/SKILL.md +42 -7
  24. package/dist/agents/skills/gemini-cli/harness-verification/SKILL.md +25 -0
  25. package/dist/agents-md-MCUM4SIZ.js +10 -0
  26. package/dist/{architecture-FBSLURIB.js → architecture-HNIO6AUX.js} +6 -5
  27. package/dist/{assess-project-74UVWPMB.js → assess-project-6MV5TNY3.js} +2 -1
  28. package/dist/bin/harness-mcp.js +18 -17
  29. package/dist/bin/harness.js +47 -31
  30. package/dist/{check-phase-gate-WY6UICCL.js → check-phase-gate-VCBQHQAC.js} +6 -5
  31. package/dist/{chunk-Q3XYV5UC.js → chunk-47N6R2F4.js} +5 -1
  32. package/dist/{chunk-3XAPHB2Z.js → chunk-4NK7Z3BP.js} +1 -1
  33. package/dist/{chunk-I4QR3HNH.js → chunk-5BQ5BOJL.js} +5 -1
  34. package/dist/{chunk-LM5Z2WCA.js → chunk-6VZQJ5CX.js} +5 -1
  35. package/dist/{chunk-NV4FPO7J.js → chunk-AT74HEQM.js} +1 -1
  36. package/dist/{chunk-ZAMT24QN.js → chunk-AZT567I6.js} +1525 -735
  37. package/dist/{chunk-TDLOFNNQ.js → chunk-BOQRTARD.js} +1 -1
  38. package/dist/{chunk-A737JDL4.js → chunk-CXJTVICF.js} +4 -4
  39. package/dist/{chunk-LOUH2LIC.js → chunk-EHRZMOQ2.js} +5 -1
  40. package/dist/{chunk-L5UONZ53.js → chunk-F23H3U5U.js} +6 -2
  41. package/dist/{chunk-YPKKEP3O.js → chunk-FES2YEQU.js} +9 -9
  42. package/dist/{chunk-SPTKLCKC.js → chunk-FIQL2HND.js} +6 -2
  43. package/dist/{chunk-FP53DDB5.js → chunk-FSNPBT74.js} +5 -1
  44. package/dist/{chunk-TB427QOK.js → chunk-GEEYCQDS.js} +13 -9
  45. package/dist/{chunk-ZOVATVQC.js → chunk-HIK6OEUF.js} +6 -1
  46. package/dist/chunk-K2SON7TI.js +5382 -0
  47. package/dist/chunk-KFQGP6VL.js +33 -0
  48. package/dist/{chunk-V2FGX2KD.js → chunk-M55DGGF3.js} +9 -5
  49. package/dist/{chunk-H4U2QNY2.js → chunk-MI6MA6OP.js} +16888 -13143
  50. package/dist/{chunk-YDRB55Q4.js → chunk-P7PANON5.js} +5 -1
  51. package/dist/chunk-RL4VMEXL.js +53 -0
  52. package/dist/{chunk-XNEMDKV5.js → chunk-RRHUCDRD.js} +1 -1
  53. package/dist/{chunk-O6UF33QH.js → chunk-RX7TUMBR.js} +320 -136
  54. package/dist/{chunk-3VYWO6QN.js → chunk-TYV4EUAD.js} +12 -8
  55. package/dist/{chunk-FJYP32IV.js → chunk-UQZBZINS.js} +6 -6
  56. package/dist/{chunk-UFQQBGC3.js → chunk-UV3BZMGT.js} +64 -3
  57. package/dist/{chunk-5PMRARB5.js → chunk-WIQA4BSH.js} +12 -5
  58. package/dist/{chunk-UQEUYRBP.js → chunk-WWACIIBA.js} +1 -1
  59. package/dist/{chunk-LVYPPKZI.js → chunk-XTITAVUR.js} +5 -1
  60. package/dist/{chunk-WEN5Z7CL.js → chunk-YTP2UDPV.js} +3 -3
  61. package/dist/ci-workflow-RTM7VVTD.js +10 -0
  62. package/dist/{constants-5JGUXPEK.js → constants-P4M3C2T3.js} +1 -0
  63. package/dist/{create-skill-QCXINA5Q.js → create-skill-6QWJHQYS.js} +3 -2
  64. package/dist/{dist-666AAZQ6.js → dist-3EWNRFFQ.js} +6 -1
  65. package/dist/{dist-RRMRZRV7.js → dist-ABTKRYZH.js} +1 -0
  66. package/dist/{dist-QW5G3GX3.js → dist-RADHOOXG.js} +4 -1
  67. package/dist/{dist-7EBSGAHX.js → dist-WCSJHQPK.js} +106 -3
  68. package/dist/{docs-H34GBVRS.js → docs-UBOGGHTY.js} +6 -5
  69. package/dist/engine-MJJAP5CH.js +10 -0
  70. package/dist/{entropy-ZAY73R6A.js → entropy-EMSXF2PX.js} +5 -4
  71. package/dist/{feedback-TMEGYMWU.js → feedback-ZLUX72HD.js} +2 -1
  72. package/dist/{generate-agent-definitions-PQPG6SX5.js → generate-agent-definitions-AWLPJ27C.js} +6 -5
  73. package/dist/{glob-helper-SRXMZPKM.js → glob-helper-VCQXK5XY.js} +2 -0
  74. package/dist/{graph-loader-M6FXJAKK.js → graph-loader-JHQVQRUS.js} +2 -1
  75. package/dist/index.d.ts +13 -7
  76. package/dist/index.js +30 -29
  77. package/dist/loader-JVSJZSWZ.js +12 -0
  78. package/dist/mcp-2553PNUC.js +38 -0
  79. package/dist/{performance-N67YJJDG.js → performance-7AGWJUY4.js} +6 -5
  80. package/dist/review-pipeline-ZWVQJTJX.js +13 -0
  81. package/dist/{runner-TY7DJGQV.js → runner-AAEF2TXY.js} +1 -0
  82. package/dist/runtime-D6YUQPP2.js +11 -0
  83. package/dist/{scan-U67OKDRS.js → scan-MPJ6JHUY.js} +2 -1
  84. package/dist/security-JLZUAQYT.js +14 -0
  85. package/dist/skill-executor-MOCUIAYS.js +9 -0
  86. package/dist/templates/base/.agnix.toml +16 -0
  87. package/dist/templates/orchestrator/WORKFLOW.md +55 -7
  88. package/dist/templates/orchestrator/template.json +1 -0
  89. package/dist/tool-tiers-7QGZ3FKY.js +98 -0
  90. package/dist/validate-TIIHRPMA.js +14 -0
  91. package/dist/validate-cross-check-ZOWFA3DB.js +10 -0
  92. package/dist/{version-KFFPOQAX.js → version-CUI434OP.js} +1 -0
  93. package/package.json +4 -4
  94. package/dist/agents-md-PBKKTSQY.js +0 -9
  95. package/dist/chunk-5LMZA5LZ.js +0 -38
  96. package/dist/chunk-OZIHPMA7.js +0 -5171
  97. package/dist/ci-workflow-QZRHAIO2.js +0 -9
  98. package/dist/engine-VUQEAJFZ.js +0 -9
  99. package/dist/loader-Y6A42WBD.js +0 -11
  100. package/dist/mcp-LCHC4NZ5.js +0 -37
  101. package/dist/review-pipeline-YXF5ITL2.js +0 -12
  102. package/dist/runtime-XNJUJCSG.js +0 -10
  103. package/dist/security-L2YN3CTI.js +0 -9
  104. package/dist/skill-executor-GA7BDX3F.js +0 -8
  105. package/dist/validate-MNE25KLZ.js +0 -13
  106. package/dist/validate-cross-check-Y4PDR63C.js +0 -9
@@ -1,25 +1,25 @@
1
1
  import {
2
2
  generateAgentsMd
3
- } from "./chunk-I4QR3HNH.js";
3
+ } from "./chunk-5BQ5BOJL.js";
4
4
  import {
5
5
  generateCIWorkflow
6
- } from "./chunk-LOUH2LIC.js";
6
+ } from "./chunk-EHRZMOQ2.js";
7
7
  import {
8
8
  TemplateEngine
9
- } from "./chunk-FP53DDB5.js";
9
+ } from "./chunk-FSNPBT74.js";
10
10
  import {
11
11
  generate,
12
12
  validate
13
13
  } from "./chunk-CQ553GZO.js";
14
14
  import {
15
15
  generateRuntime
16
- } from "./chunk-LM5Z2WCA.js";
16
+ } from "./chunk-6VZQJ5CX.js";
17
17
  import {
18
18
  runPersona
19
19
  } from "./chunk-GISMXMVL.js";
20
20
  import {
21
21
  executeSkill
22
- } from "./chunk-UQEUYRBP.js";
22
+ } from "./chunk-WWACIIBA.js";
23
23
  import {
24
24
  ALLOWED_PERSONA_COMMANDS
25
25
  } from "./chunk-TEFCFC4H.js";
@@ -28,21 +28,21 @@ import {
28
28
  OutputMode,
29
29
  createCheckPhaseGateCommand,
30
30
  findFiles
31
- } from "./chunk-SPTKLCKC.js";
31
+ } from "./chunk-FIQL2HND.js";
32
32
  import {
33
33
  createGenerateAgentDefinitionsCommand,
34
34
  generateAgentDefinitions
35
- } from "./chunk-NV4FPO7J.js";
35
+ } from "./chunk-AT74HEQM.js";
36
36
  import {
37
37
  toKebabCase
38
38
  } from "./chunk-KET4QQZB.js";
39
39
  import {
40
40
  listPersonas,
41
41
  loadPersona
42
- } from "./chunk-YDRB55Q4.js";
42
+ } from "./chunk-P7PANON5.js";
43
43
  import {
44
44
  createScanCommand
45
- } from "./chunk-3XAPHB2Z.js";
45
+ } from "./chunk-4NK7Z3BP.js";
46
46
  import {
47
47
  appendFrameworkAgents,
48
48
  captureHealthSnapshot,
@@ -56,11 +56,11 @@ import {
56
56
  loadOrRebuildIndex,
57
57
  persistToolingConfig,
58
58
  recommend
59
- } from "./chunk-O6UF33QH.js";
59
+ } from "./chunk-RX7TUMBR.js";
60
60
  import {
61
61
  findConfigFile,
62
62
  resolveConfig
63
- } from "./chunk-5PMRARB5.js";
63
+ } from "./chunk-WIQA4BSH.js";
64
64
  import {
65
65
  VALID_PLATFORMS
66
66
  } from "./chunk-3ISINLYT.js";
@@ -74,7 +74,7 @@ import {
74
74
  } from "./chunk-6B6UN6SG.js";
75
75
  import {
76
76
  loadGraphStore
77
- } from "./chunk-TDLOFNNQ.js";
77
+ } from "./chunk-BOQRTARD.js";
78
78
  import {
79
79
  CLI_VERSION
80
80
  } from "./chunk-BM3PWGXQ.js";
@@ -84,11 +84,14 @@ import {
84
84
  BaselineManager,
85
85
  BlueprintGenerator,
86
86
  BundleSchema,
87
+ CINotifier,
87
88
  CriticalPathResolver,
88
89
  EntropyAnalyzer,
90
+ GitHubIssuesSyncAdapter,
89
91
  PredictionEngine,
90
92
  ProjectScanner,
91
93
  SecurityScanner,
94
+ SecurityTimelineManager,
92
95
  SpecImpactEstimator,
93
96
  TimelineManager,
94
97
  TypeScriptParser,
@@ -110,16 +113,20 @@ import {
110
113
  detectDeadCode,
111
114
  detectDocDrift,
112
115
  diff,
116
+ dist_exports,
113
117
  extractBundle,
114
118
  generateSuggestions,
115
119
  getOrCreateInstallId,
120
+ init_dist,
116
121
  listStreams,
117
122
  listTaintedSessions,
118
123
  loadState,
119
124
  loadStreamIndex,
125
+ loadTrackerSyncConfig,
120
126
  mapInjectionFindings,
121
127
  mapSecurityFindings,
122
128
  parseDiff,
129
+ parseFileRegions,
123
130
  parseManifest,
124
131
  parseSecurityConfig,
125
132
  pruneLearnings,
@@ -135,35 +142,41 @@ import {
135
142
  runReviewPipeline,
136
143
  scanForInjection,
137
144
  setActiveStream,
145
+ validateAgentConfigs,
138
146
  validateAgentsMap,
139
147
  validateDependencies,
140
148
  validateKnowledgeMap,
141
149
  writeConfig,
142
150
  writeLockfile
143
- } from "./chunk-H4U2QNY2.js";
151
+ } from "./chunk-MI6MA6OP.js";
144
152
  import {
145
153
  Err,
146
154
  Ok
147
- } from "./chunk-5LMZA5LZ.js";
155
+ } from "./chunk-RL4VMEXL.js";
148
156
  import {
149
157
  createCreateSkillCommand
150
- } from "./chunk-XNEMDKV5.js";
158
+ } from "./chunk-RRHUCDRD.js";
151
159
  import {
152
160
  logger
153
161
  } from "./chunk-EBJQ6N4M.js";
154
162
  import {
155
163
  SkillMetadataSchema
156
- } from "./chunk-ZOVATVQC.js";
164
+ } from "./chunk-HIK6OEUF.js";
157
165
  import {
158
166
  CLIError,
159
167
  ExitCode,
160
168
  handleError
161
169
  } from "./chunk-3WGJMBKH.js";
170
+ import {
171
+ __require,
172
+ __toCommonJS
173
+ } from "./chunk-KFQGP6VL.js";
162
174
 
163
175
  // src/index.ts
164
- import { Command as Command79 } from "commander";
176
+ import { Command as Command83 } from "commander";
165
177
 
166
178
  // src/commands/add.ts
179
+ init_dist();
167
180
  import { Command } from "commander";
168
181
  import * as fs from "fs";
169
182
  import * as path from "path";
@@ -251,7 +264,7 @@ function addDoc(name, cwd, configResult, created) {
251
264
  return Ok(void 0);
252
265
  }
253
266
  async function addSkill(name, cwd, created) {
254
- const { generateSkillFiles: generateSkillFiles2 } = await import("./create-skill-QCXINA5Q.js");
267
+ const { generateSkillFiles: generateSkillFiles2 } = await import("./create-skill-6QWJHQYS.js");
255
268
  generateSkillFiles2({
256
269
  name,
257
270
  description: `${name} skill`,
@@ -349,7 +362,7 @@ function registerSkillsCommand(adoption) {
349
362
  const globalOpts = cmd.optsWithGlobals();
350
363
  const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
351
364
  const cwd = process.cwd();
352
- const { readAdoptionRecords, aggregateBySkill } = await import("./dist-7EBSGAHX.js");
365
+ const { readAdoptionRecords, aggregateBySkill } = await import("./dist-WCSJHQPK.js");
353
366
  const records = readAdoptionRecords(cwd);
354
367
  if (records.length === 0) {
355
368
  if (globalOpts.json) {
@@ -385,7 +398,7 @@ function registerRecentCommand(adoption) {
385
398
  const globalOpts = cmd.optsWithGlobals();
386
399
  const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
387
400
  const cwd = process.cwd();
388
- const { readAdoptionRecords } = await import("./dist-7EBSGAHX.js");
401
+ const { readAdoptionRecords } = await import("./dist-WCSJHQPK.js");
389
402
  const records = readAdoptionRecords(cwd);
390
403
  if (records.length === 0) {
391
404
  if (globalOpts.json) {
@@ -422,7 +435,7 @@ function registerSkillCommand(adoption) {
422
435
  adoption.command("skill <name>").description("Show detail for a specific skill").action(async (name, _opts, cmd) => {
423
436
  const globalOpts = cmd.optsWithGlobals();
424
437
  const cwd = process.cwd();
425
- const { readAdoptionRecords, aggregateBySkill } = await import("./dist-7EBSGAHX.js");
438
+ const { readAdoptionRecords, aggregateBySkill } = await import("./dist-WCSJHQPK.js");
426
439
  const records = readAdoptionRecords(cwd);
427
440
  const skillRecords = records.filter((r) => r.skill === name);
428
441
  if (skillRecords.length === 0) {
@@ -488,6 +501,8 @@ function createAdoptionCommand() {
488
501
  import { Command as Command5 } from "commander";
489
502
 
490
503
  // src/commands/agent/run.ts
504
+ init_dist();
505
+ init_dist();
491
506
  import { Command as Command3 } from "commander";
492
507
  import * as path2 from "path";
493
508
  import * as childProcess from "child_process";
@@ -609,6 +624,7 @@ function createRunCommand() {
609
624
  }
610
625
 
611
626
  // src/commands/agent/review.ts
627
+ init_dist();
612
628
  import { Command as Command4 } from "commander";
613
629
  import { execSync } from "child_process";
614
630
  async function runAgentReview(options) {
@@ -657,7 +673,9 @@ async function runAgentReview(options) {
657
673
  comment: options.comment ?? false,
658
674
  ci: options.ci ?? false,
659
675
  deep: options.deep ?? false,
660
- noMechanical: options.noMechanical ?? false
676
+ noMechanical: options.noMechanical ?? false,
677
+ ...options.thorough ? { thorough: true } : {},
678
+ ...options.isolated ? { isolated: true } : {}
661
679
  },
662
680
  config
663
681
  });
@@ -703,7 +721,10 @@ function printReviewResult(result, mode) {
703
721
  }
704
722
  }
705
723
  function createReviewCommand() {
706
- return new Command4("review").description("Run unified code review pipeline on current changes").option("--comment", "Post inline comments to GitHub PR").option("--ci", "Enable eligibility gate, non-interactive output").option("--deep", "Add threat modeling pass to security agent").option("--no-mechanical", "Skip mechanical checks").action(async (opts, cmd) => {
724
+ return new Command4("review").description("Run unified code review pipeline on current changes").option("--comment", "Post inline comments to GitHub PR").option("--ci", "Enable eligibility gate, non-interactive output").option("--deep", "Add threat modeling pass to security agent").option("--no-mechanical", "Skip mechanical checks").option("--thorough", "Generate task-specific rubric before reading implementation").option(
725
+ "--isolated",
726
+ "Two-stage review: spec-compliance then code-quality with disjoint context"
727
+ ).action(async (opts, cmd) => {
707
728
  const globalOpts = cmd.optsWithGlobals();
708
729
  const mode = resolveReviewMode(globalOpts);
709
730
  const result = await runAgentReview({
@@ -714,7 +735,9 @@ function createReviewCommand() {
714
735
  comment: opts.comment,
715
736
  ci: opts.ci,
716
737
  deep: opts.deep,
717
- noMechanical: opts.mechanical === false
738
+ noMechanical: opts.mechanical === false,
739
+ thorough: opts.thorough,
740
+ isolated: opts.isolated
718
741
  });
719
742
  if (!result.ok) {
720
743
  if (mode === OutputMode.JSON) console.log(JSON.stringify({ error: result.error.message }));
@@ -737,21 +760,130 @@ function createAgentCommand() {
737
760
  return command;
738
761
  }
739
762
 
740
- // src/commands/blueprint.ts
763
+ // src/commands/audit-protected.ts
764
+ init_dist();
741
765
  import { Command as Command6 } from "commander";
742
766
  import * as path3 from "path";
767
+ import * as fs2 from "fs";
768
+
769
+ // src/utils/output.ts
770
+ function resolveOutputMode(globalOpts) {
771
+ if (globalOpts.json) return OutputMode.JSON;
772
+ if (globalOpts.quiet) return OutputMode.QUIET;
773
+ if (globalOpts.verbose) return OutputMode.VERBOSE;
774
+ return OutputMode.TEXT;
775
+ }
776
+
777
+ // src/commands/audit-protected.ts
778
+ import { glob } from "glob";
779
+ async function runAuditProtected(options) {
780
+ const cwd = options.cwd ?? process.cwd();
781
+ const configResult = resolveConfig(options.configPath);
782
+ if (!configResult.ok) {
783
+ return Err(configResult.error);
784
+ }
785
+ const config = configResult.value;
786
+ const rootDir = path3.resolve(cwd, config.rootDir);
787
+ const excludePatterns = config.entropy?.excludePatterns ?? ["**/node_modules/**", "**/*.test.ts"];
788
+ let files;
789
+ try {
790
+ files = await glob("**/*.{ts,tsx,js,jsx,py,sh}", {
791
+ cwd: rootDir,
792
+ ignore: excludePatterns
793
+ });
794
+ } catch (e) {
795
+ return Err(new CLIError(`Failed to scan files: ${e.message}`, ExitCode.ERROR));
796
+ }
797
+ const allRegions = [];
798
+ const allIssues = [];
799
+ for (const relativePath of files) {
800
+ const absolutePath = path3.resolve(rootDir, relativePath);
801
+ let content;
802
+ try {
803
+ content = fs2.readFileSync(absolutePath, "utf-8");
804
+ } catch {
805
+ continue;
806
+ }
807
+ const { regions, issues } = parseFileRegions(relativePath, content);
808
+ allRegions.push(...regions);
809
+ allIssues.push(...issues);
810
+ }
811
+ return Ok({
812
+ regions: allRegions,
813
+ issues: allIssues,
814
+ fileCount: files.length
815
+ });
816
+ }
817
+ function formatRegion(region) {
818
+ const lineRange = region.startLine === region.endLine ? `${region.startLine}` : `${region.startLine}-${region.endLine}`;
819
+ const scopes = region.scopes.join(",");
820
+ const reason = region.reason ? ` ${region.reason}` : "";
821
+ return ` ${region.file}:${lineRange} [${scopes}]${reason}`;
822
+ }
823
+ function printAuditResult(result, formatter) {
824
+ const regionCount = result.regions.length;
825
+ const fileSet = new Set(result.regions.map((r) => r.file));
826
+ console.log(
827
+ formatter.formatSummary("Protected regions", `${regionCount} in ${fileSet.size} file(s)`, true)
828
+ );
829
+ if (regionCount > 0) {
830
+ console.log(`
831
+ Found ${regionCount} protected region(s) in ${fileSet.size} file(s):
832
+ `);
833
+ for (const region of result.regions) {
834
+ console.log(formatRegion(region));
835
+ }
836
+ }
837
+ if (result.issues.length > 0) {
838
+ console.log(`
839
+ Issues (${result.issues.length}):`);
840
+ for (const issue of result.issues) {
841
+ console.log(` ${issue.file}:${issue.line} \u2014 ${issue.message}`);
842
+ }
843
+ }
844
+ }
845
+ function createAuditProtectedCommand() {
846
+ const command = new Command6("audit-protected").description("Report all harness-ignore protected code regions").action(async (_opts, cmd) => {
847
+ const globalOpts = cmd.optsWithGlobals();
848
+ const mode = resolveOutputMode(globalOpts);
849
+ const formatter = new OutputFormatter(mode);
850
+ const result = await runAuditProtected({
851
+ configPath: globalOpts.config
852
+ });
853
+ if (!result.ok) {
854
+ if (mode === OutputMode.JSON) {
855
+ console.log(JSON.stringify({ error: result.error.message }));
856
+ } else {
857
+ logger.error(result.error.message);
858
+ }
859
+ process.exit(result.error.exitCode);
860
+ }
861
+ if (mode === OutputMode.JSON) {
862
+ console.log(JSON.stringify(result.value, null, 2));
863
+ } else if (mode !== OutputMode.QUIET || result.value.regions.length > 0) {
864
+ printAuditResult(result.value, formatter);
865
+ }
866
+ process.exit(result.value.issues.length > 0 ? ExitCode.VALIDATION_FAILED : ExitCode.SUCCESS);
867
+ });
868
+ return command;
869
+ }
870
+
871
+ // src/commands/blueprint.ts
872
+ init_dist();
873
+ import { Command as Command7 } from "commander";
874
+ import * as path4 from "path";
743
875
  function createBlueprintCommand() {
744
- return new Command6("blueprint").description("Generate a self-contained, interactive blueprint of the codebase").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory", "docs/blueprint").action(async (projectPath, options) => {
876
+ return new Command7("blueprint").description("Generate a self-contained, interactive blueprint of the codebase").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory", "docs/blueprint").action(async (projectPath, options) => {
745
877
  try {
746
- const rootDir = path3.resolve(projectPath);
747
- const outputDir = path3.resolve(options.output);
878
+ const rootDir = path4.resolve(projectPath);
879
+ const outputDir = path4.resolve(options.output);
748
880
  logger.info(`Scanning project at ${rootDir}...`);
749
881
  const scanner = new ProjectScanner(rootDir);
750
882
  const data = await scanner.scan();
751
883
  logger.info(`Generating blueprint to ${outputDir}...`);
752
884
  const generator = new BlueprintGenerator();
753
885
  await generator.generate(data, { outputDir });
754
- logger.success(`Blueprint generated successfully at ${path3.join(outputDir, "index.html")}`);
886
+ logger.success(`Blueprint generated successfully at ${path4.join(outputDir, "index.html")}`);
755
887
  } catch (error) {
756
888
  logger.error(
757
889
  `Failed to generate blueprint: ${error instanceof Error ? error.message : String(error)}`
@@ -762,7 +894,8 @@ function createBlueprintCommand() {
762
894
  }
763
895
 
764
896
  // src/commands/check-arch.ts
765
- import { Command as Command7 } from "commander";
897
+ init_dist();
898
+ import { Command as Command8 } from "commander";
766
899
  import { execSync as execSync2 } from "child_process";
767
900
  function getCommitHash(cwd) {
768
901
  try {
@@ -856,7 +989,7 @@ async function runCheckArch(options) {
856
989
  thresholdViolations
857
990
  });
858
991
  }
859
- function resolveOutputMode(globalOpts) {
992
+ function resolveOutputMode2(globalOpts) {
860
993
  if (globalOpts.json) return OutputMode.JSON;
861
994
  if (globalOpts.quiet) return OutputMode.QUIET;
862
995
  if (globalOpts.verbose) return OutputMode.VERBOSE;
@@ -892,9 +1025,9 @@ function printArchResult(value, mode, formatter) {
892
1025
  if (output) console.log(output);
893
1026
  }
894
1027
  function createCheckArchCommand() {
895
- const command = new Command7("check-arch").description("Check architecture assertions against baseline and thresholds").option("--update-baseline", "Capture current state as new baseline").option("--module <path>", "Check a single module").action(async (opts, cmd) => {
1028
+ const command = new Command8("check-arch").description("Check architecture assertions against baseline and thresholds").option("--update-baseline", "Capture current state as new baseline").option("--module <path>", "Check a single module").action(async (opts, cmd) => {
896
1029
  const globalOpts = cmd.optsWithGlobals();
897
- const mode = resolveOutputMode(globalOpts);
1030
+ const mode = resolveOutputMode2(globalOpts);
898
1031
  const formatter = new OutputFormatter(mode);
899
1032
  const result = await runCheckArch({
900
1033
  configPath: globalOpts.config,
@@ -922,8 +1055,10 @@ function createCheckArchCommand() {
922
1055
  }
923
1056
 
924
1057
  // src/commands/check-deps.ts
925
- import { Command as Command8 } from "commander";
926
- import * as path4 from "path";
1058
+ init_dist();
1059
+ init_dist();
1060
+ import { Command as Command9 } from "commander";
1061
+ import * as path5 from "path";
927
1062
  async function runCheckDeps(options) {
928
1063
  const cwd = options.cwd ?? process.cwd();
929
1064
  const configResult = resolveConfig(options.configPath);
@@ -939,7 +1074,7 @@ async function runCheckDeps(options) {
939
1074
  if (!config.layers || config.layers.length === 0) {
940
1075
  return Ok(result);
941
1076
  }
942
- const rootDir = path4.resolve(cwd, config.rootDir);
1077
+ const rootDir = path5.resolve(cwd, config.rootDir);
943
1078
  const parser = new TypeScriptParser();
944
1079
  const layers = config.layers.map((l) => defineLayer(l.name, [l.pattern], l.allowedDependencies));
945
1080
  const layerConfig = {
@@ -1014,25 +1149,17 @@ async function runCheckDepsAction(globalOpts) {
1014
1149
  process.exit(result.value.valid ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
1015
1150
  }
1016
1151
  function createCheckDepsCommand() {
1017
- const command = new Command8("check-deps").description("Validate dependency layers and detect circular dependencies").action(async (_opts, cmd) => {
1152
+ const command = new Command9("check-deps").description("Validate dependency layers and detect circular dependencies").action(async (_opts, cmd) => {
1018
1153
  await runCheckDepsAction(cmd.optsWithGlobals());
1019
1154
  });
1020
1155
  return command;
1021
1156
  }
1022
1157
 
1023
1158
  // src/commands/check-docs.ts
1024
- import { Command as Command9 } from "commander";
1025
- import * as path5 from "path";
1026
-
1027
- // src/utils/output.ts
1028
- function resolveOutputMode2(globalOpts) {
1029
- if (globalOpts.json) return OutputMode.JSON;
1030
- if (globalOpts.quiet) return OutputMode.QUIET;
1031
- if (globalOpts.verbose) return OutputMode.VERBOSE;
1032
- return OutputMode.TEXT;
1033
- }
1034
-
1035
- // src/commands/check-docs.ts
1159
+ init_dist();
1160
+ init_dist();
1161
+ import { Command as Command10 } from "commander";
1162
+ import * as path6 from "path";
1036
1163
  async function runCheckDocs(options) {
1037
1164
  const cwd = options.cwd ?? process.cwd();
1038
1165
  const minCoverage = options.minCoverage ?? 80;
@@ -1041,8 +1168,8 @@ async function runCheckDocs(options) {
1041
1168
  return configResult;
1042
1169
  }
1043
1170
  const config = configResult.value;
1044
- const docsDir = path5.resolve(cwd, config.docsDir);
1045
- const sourceDir = path5.resolve(cwd, config.rootDir);
1171
+ const docsDir = path6.resolve(cwd, config.docsDir);
1172
+ const sourceDir = path6.resolve(cwd, config.rootDir);
1046
1173
  const coverageResult = await checkDocCoverage("project", {
1047
1174
  docsDir,
1048
1175
  sourceDir,
@@ -1109,9 +1236,9 @@ function printCheckDocsResult(value, mode, formatter) {
1109
1236
  }
1110
1237
  }
1111
1238
  function createCheckDocsCommand() {
1112
- const command = new Command9("check-docs").description("Check documentation coverage").option("--min-coverage <percent>", "Minimum coverage percentage", "80").action(async (opts, cmd) => {
1239
+ const command = new Command10("check-docs").description("Check documentation coverage").option("--min-coverage <percent>", "Minimum coverage percentage", "80").action(async (opts, cmd) => {
1113
1240
  const globalOpts = cmd.optsWithGlobals();
1114
- const mode = resolveOutputMode2(globalOpts);
1241
+ const mode = resolveOutputMode(globalOpts);
1115
1242
  const formatter = new OutputFormatter(mode);
1116
1243
  const result = await runCheckDocs({
1117
1244
  configPath: globalOpts.config,
@@ -1139,12 +1266,13 @@ function createCheckDocsCommand() {
1139
1266
  }
1140
1267
 
1141
1268
  // src/commands/check-perf.ts
1142
- import { Command as Command10 } from "commander";
1143
- import * as path6 from "path";
1269
+ init_dist();
1270
+ import { Command as Command11 } from "commander";
1271
+ import * as path7 from "path";
1144
1272
  async function runCheckPerf(cwd, options) {
1145
1273
  const runAll2 = !options.structural && !options.size && !options.coupling;
1146
1274
  const analyzer = new EntropyAnalyzer({
1147
- rootDir: path6.resolve(cwd),
1275
+ rootDir: path7.resolve(cwd),
1148
1276
  analyze: {
1149
1277
  complexity: runAll2 || !!options.structural,
1150
1278
  coupling: runAll2 || !!options.coupling,
@@ -1256,15 +1384,16 @@ async function runCheckPerfAction(opts, globalOpts) {
1256
1384
  process.exit(result.value.valid ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
1257
1385
  }
1258
1386
  function createCheckPerfCommand() {
1259
- const command = new Command10("check-perf").description("Run performance checks: structural complexity, coupling, and size budgets").option("--structural", "Run structural complexity checks only").option("--coupling", "Run coupling metric checks only").option("--size", "Run size budget checks only").action(async (opts, cmd) => {
1387
+ const command = new Command11("check-perf").description("Run performance checks: structural complexity, coupling, and size budgets").option("--structural", "Run structural complexity checks only").option("--coupling", "Run coupling metric checks only").option("--size", "Run size budget checks only").action(async (opts, cmd) => {
1260
1388
  await runCheckPerfAction(opts, cmd.optsWithGlobals());
1261
1389
  });
1262
1390
  return command;
1263
1391
  }
1264
1392
 
1265
1393
  // src/commands/check-security.ts
1266
- import { Command as Command11 } from "commander";
1267
- import * as path7 from "path";
1394
+ init_dist();
1395
+ import { Command as Command12 } from "commander";
1396
+ import * as path8 from "path";
1268
1397
  import { execSync as execSync3 } from "child_process";
1269
1398
  var SEVERITY_RANK = {
1270
1399
  error: 3,
@@ -1277,19 +1406,19 @@ function getChangedFiles(cwd) {
1277
1406
  cwd,
1278
1407
  encoding: "utf-8"
1279
1408
  });
1280
- return output.trim().split("\n").filter((f) => f.length > 0).map((f) => path7.resolve(cwd, f));
1409
+ return output.trim().split("\n").filter((f) => f.length > 0).map((f) => path8.resolve(cwd, f));
1281
1410
  } catch {
1282
1411
  return [];
1283
1412
  }
1284
1413
  }
1285
1414
  async function runCheckSecurity(cwd, options) {
1286
- const projectRoot = path7.resolve(cwd);
1415
+ const projectRoot = path8.resolve(cwd);
1287
1416
  let configData = {};
1288
1417
  try {
1289
- const fs36 = await import("fs");
1290
- const configPath = path7.join(projectRoot, "harness.config.json");
1291
- if (fs36.existsSync(configPath)) {
1292
- const raw = fs36.readFileSync(configPath, "utf-8");
1418
+ const fs41 = await import("fs");
1419
+ const configPath = path8.join(projectRoot, "harness.config.json");
1420
+ if (fs41.existsSync(configPath)) {
1421
+ const raw = fs41.readFileSync(configPath, "utf-8");
1293
1422
  const parsed = JSON.parse(raw);
1294
1423
  configData = parsed.security ?? {};
1295
1424
  }
@@ -1302,7 +1431,7 @@ async function runCheckSecurity(cwd, options) {
1302
1431
  if (options.changedOnly) {
1303
1432
  filesToScan = getChangedFiles(projectRoot);
1304
1433
  } else {
1305
- const { glob } = await import("glob");
1434
+ const { glob: glob2 } = await import("glob");
1306
1435
  const pattern = "**/*.{ts,tsx,js,jsx,go,py,java,rb}";
1307
1436
  const ignore = securityConfig.exclude ?? [
1308
1437
  "**/node_modules/**",
@@ -1310,9 +1439,19 @@ async function runCheckSecurity(cwd, options) {
1310
1439
  "**/*.test.ts",
1311
1440
  "**/fixtures/**"
1312
1441
  ];
1313
- filesToScan = await glob(pattern, { cwd: projectRoot, absolute: true, ignore });
1442
+ filesToScan = await glob2(pattern, { cwd: projectRoot, absolute: true, ignore });
1314
1443
  }
1315
1444
  const result = await scanner.scanFiles(filesToScan);
1445
+ try {
1446
+ const commitHash = execSync3("git rev-parse HEAD", {
1447
+ cwd: projectRoot,
1448
+ encoding: "utf-8"
1449
+ }).trim();
1450
+ const timelineManager = new SecurityTimelineManager(projectRoot);
1451
+ timelineManager.capture(result, commitHash);
1452
+ timelineManager.updateLifecycles(result.findings, commitHash);
1453
+ } catch {
1454
+ }
1316
1455
  const threshold = options.severity ?? "warning";
1317
1456
  const thresholdRank = SEVERITY_RANK[threshold];
1318
1457
  const filtered = result.findings.filter((f) => SEVERITY_RANK[f.severity] >= thresholdRank);
@@ -1358,7 +1497,7 @@ async function runCheckSecurityAction(opts, globalOpts) {
1358
1497
  process.exit(result.value.valid ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
1359
1498
  }
1360
1499
  function createCheckSecurityCommand() {
1361
- const command = new Command11("check-security").description("Run lightweight security scan: secrets, injection, XSS, weak crypto").option("--severity <level>", "Minimum severity threshold", "warning").hook("preAction", (thisCommand) => {
1500
+ const command = new Command12("check-security").description("Run lightweight security scan: secrets, injection, XSS, weak crypto").option("--severity <level>", "Minimum severity threshold", "warning").hook("preAction", (thisCommand) => {
1362
1501
  const severity = thisCommand.opts().severity;
1363
1502
  if (!["error", "warning", "info"].includes(severity)) {
1364
1503
  logger.error(`Invalid severity: "${severity}". Must be one of: error, warning, info`);
@@ -1371,10 +1510,11 @@ function createCheckSecurityCommand() {
1371
1510
  }
1372
1511
 
1373
1512
  // src/commands/ci/index.ts
1374
- import { Command as Command14 } from "commander";
1513
+ import { Command as Command16 } from "commander";
1375
1514
 
1376
1515
  // src/commands/ci/check.ts
1377
- import { Command as Command12 } from "commander";
1516
+ init_dist();
1517
+ import { Command as Command13 } from "commander";
1378
1518
  var VALID_CHECKS = [
1379
1519
  "validate",
1380
1520
  "deps",
@@ -1438,7 +1578,7 @@ function printCheckReport(report) {
1438
1578
  }
1439
1579
  }
1440
1580
  async function runCheckAction(opts, globalOpts) {
1441
- const mode = resolveOutputMode2(globalOpts);
1581
+ const mode = resolveOutputMode(globalOpts);
1442
1582
  const skip = parseSkip(opts.skip);
1443
1583
  const failOn = parseFailOn(opts.failOn);
1444
1584
  const opts2 = {
@@ -1464,15 +1604,16 @@ async function runCheckAction(opts, globalOpts) {
1464
1604
  process.exit(report.exitCode);
1465
1605
  }
1466
1606
  function createCheckCommand() {
1467
- return new Command12("check").description("Run all harness checks for CI (validate, deps, docs, entropy, phase-gate, arch)").option("--skip <checks>", "Comma-separated checks to skip (e.g., entropy,docs)").option("--fail-on <severity>", "Fail on severity level: error (default) or warning", "error").action(async (opts, cmd) => {
1607
+ return new Command13("check").description("Run all harness checks for CI (validate, deps, docs, entropy, phase-gate, arch)").option("--skip <checks>", "Comma-separated checks to skip (e.g., entropy,docs)").option("--fail-on <severity>", "Fail on severity level: error (default) or warning", "error").action(async (opts, cmd) => {
1468
1608
  await runCheckAction(opts, cmd.optsWithGlobals());
1469
1609
  });
1470
1610
  }
1471
1611
 
1472
1612
  // src/commands/ci/init.ts
1473
- import { Command as Command13 } from "commander";
1474
- import * as fs2 from "fs";
1475
- import * as path8 from "path";
1613
+ init_dist();
1614
+ import { Command as Command14 } from "commander";
1615
+ import * as fs3 from "fs";
1616
+ import * as path9 from "path";
1476
1617
  var ALL_CHECKS = [
1477
1618
  "validate",
1478
1619
  "deps",
@@ -1574,17 +1715,17 @@ function generateCIConfig(options) {
1574
1715
  });
1575
1716
  }
1576
1717
  function detectPlatform() {
1577
- if (fs2.existsSync(".github")) return "github";
1578
- if (fs2.existsSync(".gitlab-ci.yml")) return "gitlab";
1718
+ if (fs3.existsSync(".github")) return "github";
1719
+ if (fs3.existsSync(".gitlab-ci.yml")) return "gitlab";
1579
1720
  return null;
1580
1721
  }
1581
1722
  function writeGeneratedConfig(filename, content, platform) {
1582
- const targetPath = path8.resolve(filename);
1583
- const dir = path8.dirname(targetPath);
1584
- fs2.mkdirSync(dir, { recursive: true });
1585
- fs2.writeFileSync(targetPath, content);
1723
+ const targetPath = path9.resolve(filename);
1724
+ const dir = path9.dirname(targetPath);
1725
+ fs3.mkdirSync(dir, { recursive: true });
1726
+ fs3.writeFileSync(targetPath, content);
1586
1727
  if (platform === "generic" && process.platform !== "win32") {
1587
- fs2.chmodSync(targetPath, "755");
1728
+ fs3.chmodSync(targetPath, "755");
1588
1729
  }
1589
1730
  }
1590
1731
  async function runInitAction(opts, globalOpts) {
@@ -1607,22 +1748,128 @@ async function runInitAction(opts, globalOpts) {
1607
1748
  }
1608
1749
  }
1609
1750
  function createInitCommand() {
1610
- return new Command13("init").description("Generate CI configuration for harness checks").option("--platform <platform>", "CI platform: github, gitlab, or generic").option("--checks <list>", "Comma-separated list of checks to include").action(async (opts, cmd) => {
1751
+ return new Command14("init").description("Generate CI configuration for harness checks").option("--platform <platform>", "CI platform: github, gitlab, or generic").option("--checks <list>", "Comma-separated list of checks to include").action(async (opts, cmd) => {
1611
1752
  await runInitAction(opts, cmd.optsWithGlobals());
1612
1753
  });
1613
1754
  }
1614
1755
 
1756
+ // src/commands/ci/notify.ts
1757
+ init_dist();
1758
+ import { Command as Command15 } from "commander";
1759
+ import * as fs4 from "fs";
1760
+ function loadReport(reportPath) {
1761
+ try {
1762
+ const raw = fs4.readFileSync(reportPath, "utf-8");
1763
+ return JSON.parse(raw);
1764
+ } catch {
1765
+ return null;
1766
+ }
1767
+ }
1768
+ function resolveToken() {
1769
+ return process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN ?? null;
1770
+ }
1771
+ function resolveTrackerConfig(config) {
1772
+ const roadmap = config.roadmap;
1773
+ const tracker = roadmap?.tracker;
1774
+ if (!tracker || tracker.kind !== "github") return null;
1775
+ return tracker;
1776
+ }
1777
+ async function runNotifyAction(reportPath, opts, globalOpts) {
1778
+ const mode = resolveOutputMode(globalOpts);
1779
+ const report = loadReport(reportPath);
1780
+ if (!report) {
1781
+ logger.error(`Failed to read or parse report: ${reportPath}`);
1782
+ process.exit(ExitCode.ERROR);
1783
+ }
1784
+ const configResult = resolveConfig(
1785
+ typeof globalOpts.config === "string" ? globalOpts.config : void 0
1786
+ );
1787
+ if (!configResult.ok) {
1788
+ logger.error(configResult.error.message);
1789
+ process.exit(ExitCode.ERROR);
1790
+ }
1791
+ const config = configResult.value;
1792
+ const trackerConfig = resolveTrackerConfig(config);
1793
+ if (!trackerConfig || !trackerConfig.repo) {
1794
+ logger.error(
1795
+ 'No GitHub tracker configured. Set roadmap.tracker in harness.config.json with kind: "github" and repo: "owner/repo".'
1796
+ );
1797
+ process.exit(ExitCode.ERROR);
1798
+ }
1799
+ const token = resolveToken();
1800
+ if (!token) {
1801
+ logger.error("No GitHub token found. Set GITHUB_TOKEN or GH_TOKEN environment variable.");
1802
+ process.exit(ExitCode.ERROR);
1803
+ }
1804
+ const adapter = new GitHubIssuesSyncAdapter({ token, config: trackerConfig });
1805
+ const notifier = new CINotifier(adapter, trackerConfig.repo);
1806
+ const target = opts.target;
1807
+ if (target === "pr-comment") {
1808
+ if (!opts.pr) {
1809
+ logger.error("--pr <number> is required when target is pr-comment");
1810
+ process.exit(ExitCode.ERROR);
1811
+ }
1812
+ const prNumber = parseInt(opts.pr, 10);
1813
+ if (isNaN(prNumber)) {
1814
+ logger.error(`Invalid PR number: ${opts.pr}`);
1815
+ process.exit(ExitCode.ERROR);
1816
+ }
1817
+ const result = await notifier.notifyPR(report, prNumber);
1818
+ if (!result.ok) {
1819
+ logger.error(`Failed to post PR comment: ${result.error.message}`);
1820
+ process.exit(ExitCode.ERROR);
1821
+ }
1822
+ if (mode === OutputMode.JSON) {
1823
+ console.log(JSON.stringify({ target, pr: prNumber, status: "posted" }));
1824
+ } else if (mode !== OutputMode.QUIET) {
1825
+ logger.success(`Posted CI report as comment on PR #${prNumber}`);
1826
+ }
1827
+ } else if (target === "issue") {
1828
+ if (report.exitCode === 0) {
1829
+ if (mode === OutputMode.JSON) {
1830
+ console.log(JSON.stringify({ target, status: "skipped", reason: "no failures" }));
1831
+ } else if (mode !== OutputMode.QUIET) {
1832
+ logger.dim("No failures \u2014 skipping issue creation");
1833
+ }
1834
+ return;
1835
+ }
1836
+ const issueOpts = {};
1837
+ if (opts.title) issueOpts.issueTitle = opts.title;
1838
+ if (opts.labels) issueOpts.labels = opts.labels.split(",").map((l) => l.trim());
1839
+ const result = await notifier.notifyIssue(report, issueOpts);
1840
+ if (!result.ok) {
1841
+ logger.error(`Failed to create issue: ${result.error.message}`);
1842
+ process.exit(ExitCode.ERROR);
1843
+ }
1844
+ if (mode === OutputMode.JSON) {
1845
+ console.log(JSON.stringify({ target, ...result.value, status: "created" }));
1846
+ } else if (mode !== OutputMode.QUIET) {
1847
+ logger.success(`Created issue: ${result.value.url}`);
1848
+ }
1849
+ } else {
1850
+ logger.error(`Unknown target: ${target}. Use "pr-comment" or "issue".`);
1851
+ process.exit(ExitCode.ERROR);
1852
+ }
1853
+ }
1854
+ function createNotifyCommand() {
1855
+ return new Command15("notify").description("Post CI check results to GitHub (PR comment or issue)").argument("<report>", "Path to CI check report JSON file (from harness ci check --json)").requiredOption("--target <target>", "Notification target: pr-comment or issue").option("--pr <number>", "PR number (required for pr-comment target)").option("--title <title>", "Custom issue title (for issue target)").option("--labels <labels>", "Comma-separated labels for created issues").action(async (reportPath, opts, cmd) => {
1856
+ await runNotifyAction(reportPath, opts, cmd.optsWithGlobals());
1857
+ });
1858
+ }
1859
+
1615
1860
  // src/commands/ci/index.ts
1616
1861
  function createCICommand() {
1617
- const command = new Command14("ci").description("CI/CD integration commands");
1862
+ const command = new Command16("ci").description("CI/CD integration commands");
1618
1863
  command.addCommand(createCheckCommand());
1619
1864
  command.addCommand(createInitCommand());
1865
+ command.addCommand(createNotifyCommand());
1620
1866
  return command;
1621
1867
  }
1622
1868
 
1623
1869
  // src/commands/cleanup.ts
1624
- import { Command as Command15 } from "commander";
1625
- import * as path9 from "path";
1870
+ init_dist();
1871
+ import { Command as Command17 } from "commander";
1872
+ import * as path10 from "path";
1626
1873
  async function runCleanup(options) {
1627
1874
  const cwd = options.cwd ?? process.cwd();
1628
1875
  const type = options.type ?? "all";
@@ -1637,11 +1884,11 @@ async function runCleanup(options) {
1637
1884
  patternViolations: [],
1638
1885
  totalIssues: 0
1639
1886
  };
1640
- const rootDir = path9.resolve(cwd, config.rootDir);
1641
- const docsDir = path9.resolve(cwd, config.docsDir);
1887
+ const rootDir = path10.resolve(cwd, config.rootDir);
1888
+ const docsDir = path10.resolve(cwd, config.docsDir);
1642
1889
  const entropyConfig = {
1643
1890
  rootDir,
1644
- entryPoints: [path9.join(rootDir, "src/index.ts")],
1891
+ ...config.entropy?.entryPoints && { entryPoints: config.entropy.entryPoints },
1645
1892
  docPaths: [docsDir],
1646
1893
  analyze: {
1647
1894
  drift: type === "all" || type === "drift",
@@ -1710,9 +1957,9 @@ function printCleanupResult(value, formatter) {
1710
1957
  }
1711
1958
  }
1712
1959
  function createCleanupCommand() {
1713
- const command = new Command15("cleanup").description("Detect entropy issues (doc drift, dead code, patterns)").option("-t, --type <type>", "Issue type: drift, dead-code, patterns, all", "all").action(async (opts, cmd) => {
1960
+ const command = new Command17("cleanup").description("Detect entropy issues (doc drift, dead code, patterns)").option("-t, --type <type>", "Issue type: drift, dead-code, patterns, all", "all").action(async (opts, cmd) => {
1714
1961
  const globalOpts = cmd.optsWithGlobals();
1715
- const mode = resolveOutputMode2(globalOpts);
1962
+ const mode = resolveOutputMode(globalOpts);
1716
1963
  const formatter = new OutputFormatter(mode);
1717
1964
  const result = await runCleanup({
1718
1965
  configPath: globalOpts.config,
@@ -1740,20 +1987,21 @@ function createCleanupCommand() {
1740
1987
  }
1741
1988
 
1742
1989
  // src/commands/cleanup-sessions.ts
1743
- import { Command as Command16 } from "commander";
1744
- import * as fs3 from "fs";
1745
- import * as path10 from "path";
1990
+ init_dist();
1991
+ import { Command as Command18 } from "commander";
1992
+ import * as fs5 from "fs";
1993
+ import * as path11 from "path";
1746
1994
  var STALE_TTL_MS = 24 * 60 * 60 * 1e3;
1747
1995
  function getMostRecentMtime(dirPath) {
1748
1996
  let latest = 0;
1749
1997
  try {
1750
- const entries = fs3.readdirSync(dirPath, { withFileTypes: true });
1998
+ const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
1751
1999
  for (const entry of entries) {
1752
- const fullPath = path10.join(dirPath, entry.name);
1753
- const stat = fs3.statSync(fullPath);
2000
+ const fullPath = path11.join(dirPath, entry.name);
2001
+ const stat = fs5.statSync(fullPath);
1754
2002
  if (stat.mtimeMs > latest) latest = stat.mtimeMs;
1755
2003
  }
1756
- const dirStat = fs3.statSync(dirPath);
2004
+ const dirStat = fs5.statSync(dirPath);
1757
2005
  if (dirStat.mtimeMs > latest) latest = dirStat.mtimeMs;
1758
2006
  } catch {
1759
2007
  }
@@ -1762,14 +2010,14 @@ function getMostRecentMtime(dirPath) {
1762
2010
  async function runCleanupSessions(options) {
1763
2011
  const cwd = options.cwd ?? process.cwd();
1764
2012
  const dryRun = options.dryRun ?? false;
1765
- const sessionsDir = path10.join(cwd, ".harness", "sessions");
2013
+ const sessionsDir = path11.join(cwd, ".harness", "sessions");
1766
2014
  const result = { removed: [], kept: [] };
1767
- if (!fs3.existsSync(sessionsDir)) {
2015
+ if (!fs5.existsSync(sessionsDir)) {
1768
2016
  return Ok(result);
1769
2017
  }
1770
2018
  let entries;
1771
2019
  try {
1772
- entries = fs3.readdirSync(sessionsDir, { withFileTypes: true });
2020
+ entries = fs5.readdirSync(sessionsDir, { withFileTypes: true });
1773
2021
  } catch (err) {
1774
2022
  return Err(
1775
2023
  new CLIError(
@@ -1781,14 +2029,14 @@ async function runCleanupSessions(options) {
1781
2029
  const now = Date.now();
1782
2030
  for (const entry of entries) {
1783
2031
  if (!entry.isDirectory()) continue;
1784
- const sessionPath = path10.join(sessionsDir, entry.name);
2032
+ const sessionPath = path11.join(sessionsDir, entry.name);
1785
2033
  const mostRecent = getMostRecentMtime(sessionPath);
1786
2034
  const ageMs = now - mostRecent;
1787
2035
  if (ageMs > STALE_TTL_MS) {
1788
2036
  result.removed.push(entry.name);
1789
2037
  if (!dryRun) {
1790
2038
  try {
1791
- fs3.rmSync(sessionPath, { recursive: true, force: true });
2039
+ fs5.rmSync(sessionPath, { recursive: true, force: true });
1792
2040
  } catch (err) {
1793
2041
  return Err(
1794
2042
  new CLIError(
@@ -1831,9 +2079,9 @@ Cleaned up ${removed.length} stale session(s).`);
1831
2079
  }
1832
2080
  }
1833
2081
  function createCleanupSessionsCommand() {
1834
- const command = new Command16("cleanup-sessions").description("Remove stale session directories from .harness/sessions/ (no write in 24h)").option("--dry-run", "List stale sessions without deleting them", false).option("--path <path>", "Project root path", ".").action(async (opts, cmd) => {
2082
+ const command = new Command18("cleanup-sessions").description("Remove stale session directories from .harness/sessions/ (no write in 24h)").option("--dry-run", "List stale sessions without deleting them", false).option("--path <path>", "Project root path", ".").action(async (opts, cmd) => {
1835
2083
  const globalOpts = cmd.optsWithGlobals();
1836
- const cwd = path10.resolve(opts.path);
2084
+ const cwd = path11.resolve(opts.path);
1837
2085
  const result = await runCleanupSessions({ cwd, dryRun: opts.dryRun });
1838
2086
  if (!result.ok) {
1839
2087
  logger.error(result.error.message);
@@ -1847,11 +2095,11 @@ function createCleanupSessionsCommand() {
1847
2095
  }
1848
2096
 
1849
2097
  // src/commands/dashboard.ts
1850
- import { Command as Command17 } from "commander";
2098
+ import { Command as Command19 } from "commander";
1851
2099
  import { spawn } from "child_process";
1852
2100
  import { existsSync as existsSync4 } from "fs";
1853
2101
  import { createRequire } from "module";
1854
- import { dirname as dirname2, join as join7, resolve as resolve10 } from "path";
2102
+ import { dirname as dirname2, join as join6, resolve as resolve11 } from "path";
1855
2103
  import { setTimeout } from "timers";
1856
2104
  import { fileURLToPath } from "url";
1857
2105
  var __filename = fileURLToPath(import.meta.url);
@@ -1867,20 +2115,20 @@ function resolveServerScript() {
1867
2115
  try {
1868
2116
  const pkgPath = require2.resolve("@harness-engineering/dashboard/package.json");
1869
2117
  const pkgDir = dirname2(pkgPath);
1870
- const built2 = join7(pkgDir, "dist", "server", "serve.js");
2118
+ const built2 = join6(pkgDir, "dist", "server", "serve.js");
1871
2119
  if (existsSync4(built2)) return { script: built2, dev: false };
1872
- const dev2 = join7(pkgDir, "src", "server", "serve.ts");
2120
+ const dev2 = join6(pkgDir, "src", "server", "serve.ts");
1873
2121
  if (existsSync4(dev2)) return { script: dev2, dev: true };
1874
2122
  } catch {
1875
2123
  }
1876
2124
  const built = [
1877
- join7(__dirname, "..", "..", "..", "dashboard", "dist", "server", "serve.js"),
1878
- join7(__dirname, "..", "..", "..", "..", "packages", "dashboard", "dist", "server", "serve.js")
2125
+ join6(__dirname, "..", "..", "..", "dashboard", "dist", "server", "serve.js"),
2126
+ join6(__dirname, "..", "..", "..", "..", "packages", "dashboard", "dist", "server", "serve.js")
1879
2127
  ].find((p) => existsSync4(p));
1880
2128
  if (built) return { script: built, dev: false };
1881
2129
  const dev = [
1882
- join7(__dirname, "..", "..", "..", "dashboard", "src", "server", "serve.ts"),
1883
- join7(__dirname, "..", "..", "..", "..", "packages", "dashboard", "src", "server", "serve.ts")
2130
+ join6(__dirname, "..", "..", "..", "dashboard", "src", "server", "serve.ts"),
2131
+ join6(__dirname, "..", "..", "..", "..", "packages", "dashboard", "src", "server", "serve.ts")
1884
2132
  ].find((p) => existsSync4(p));
1885
2133
  return dev ? { script: dev, dev: true } : null;
1886
2134
  }
@@ -1901,7 +2149,7 @@ function spawnDashboardServer(server, env) {
1901
2149
  function runDashboard(opts) {
1902
2150
  const clientPort = Number(opts.port ?? DEFAULT_CLIENT_PORT);
1903
2151
  const apiPort = Number(opts.apiPort ?? DEFAULT_API_PORT);
1904
- const projectPath = resolve10(opts.cwd ?? process.cwd());
2152
+ const projectPath = resolve11(opts.cwd ?? process.cwd());
1905
2153
  const url = `http://localhost:${apiPort}`;
1906
2154
  const server = resolveServerScript();
1907
2155
  if (!server) {
@@ -1922,14 +2170,14 @@ function runDashboard(opts) {
1922
2170
  }
1923
2171
  }
1924
2172
  function createDashboardCommand() {
1925
- return new Command17("dashboard").description("Start the Harness local web dashboard").option("--port <port>", "Client dev server port", String(DEFAULT_CLIENT_PORT)).option("--api-port <port>", "API server port", String(DEFAULT_API_PORT)).option("--no-open", "Do not automatically open browser").option("--cwd <path>", "Project directory (defaults to cwd)").action((opts) => runDashboard(opts));
2173
+ return new Command19("dashboard").description("Start the Harness local web dashboard").option("--port <port>", "Client dev server port", String(DEFAULT_CLIENT_PORT)).option("--api-port <port>", "API server port", String(DEFAULT_API_PORT)).option("--no-open", "Do not automatically open browser").option("--cwd <path>", "Project directory (defaults to cwd)").action((opts) => runDashboard(opts));
1926
2174
  }
1927
2175
 
1928
2176
  // src/commands/doctor.ts
1929
- import { Command as Command18 } from "commander";
1930
- import * as fs5 from "fs";
2177
+ import { Command as Command20 } from "commander";
2178
+ import * as fs7 from "fs";
1931
2179
  import * as os from "os";
1932
- import * as path12 from "path";
2180
+ import * as path13 from "path";
1933
2181
  import chalk from "chalk";
1934
2182
 
1935
2183
  // src/utils/node-version.ts
@@ -2012,24 +2260,24 @@ var INTEGRATION_REGISTRY = [
2012
2260
  ];
2013
2261
 
2014
2262
  // src/integrations/config.ts
2015
- import * as fs4 from "fs";
2016
- import * as path11 from "path";
2263
+ import * as fs6 from "fs";
2264
+ import * as path12 from "path";
2017
2265
  function readJsonSafe(filePath) {
2018
- if (!fs4.existsSync(filePath)) return null;
2266
+ if (!fs6.existsSync(filePath)) return null;
2019
2267
  try {
2020
- return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
2268
+ return JSON.parse(fs6.readFileSync(filePath, "utf-8"));
2021
2269
  } catch {
2022
2270
  return null;
2023
2271
  }
2024
2272
  }
2025
2273
  function writeJson(filePath, data) {
2026
- const dir = path11.dirname(filePath);
2027
- if (!fs4.existsSync(dir)) {
2028
- fs4.mkdirSync(dir, { recursive: true });
2274
+ const dir = path12.dirname(filePath);
2275
+ if (!fs6.existsSync(dir)) {
2276
+ fs6.mkdirSync(dir, { recursive: true });
2029
2277
  }
2030
2278
  const tmp = filePath + ".tmp";
2031
- fs4.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n");
2032
- fs4.renameSync(tmp, filePath);
2279
+ fs6.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n");
2280
+ fs6.renameSync(tmp, filePath);
2033
2281
  }
2034
2282
  function readMcpConfig(filePath) {
2035
2283
  const config = readJsonSafe(filePath);
@@ -2043,7 +2291,7 @@ function writeMcpEntry(filePath, name, entry) {
2043
2291
  writeJson(filePath, config);
2044
2292
  }
2045
2293
  function removeMcpEntry(filePath, name) {
2046
- if (!fs4.existsSync(filePath)) return;
2294
+ if (!fs6.existsSync(filePath)) return;
2047
2295
  const config = readMcpConfig(filePath);
2048
2296
  delete config.mcpServers[name];
2049
2297
  writeJson(filePath, config);
@@ -2082,7 +2330,7 @@ function checkNodeVersion2() {
2082
2330
  }
2083
2331
  function countCommandFiles(dir, ext) {
2084
2332
  try {
2085
- return fs5.readdirSync(dir).filter((f) => f.endsWith(ext)).length;
2333
+ return fs7.readdirSync(dir).filter((f) => f.endsWith(ext)).length;
2086
2334
  } catch {
2087
2335
  return 0;
2088
2336
  }
@@ -2091,13 +2339,13 @@ function checkSlashCommands() {
2091
2339
  const platforms = [
2092
2340
  {
2093
2341
  name: "Claude Code",
2094
- dir: path12.join(os.homedir(), ".claude", "commands", "harness"),
2342
+ dir: path13.join(os.homedir(), ".claude", "commands", "harness"),
2095
2343
  ext: ".md",
2096
2344
  client: "claude-code"
2097
2345
  },
2098
2346
  {
2099
2347
  name: "Gemini CLI",
2100
- dir: path12.join(os.homedir(), ".gemini", "commands", "harness"),
2348
+ dir: path13.join(os.homedir(), ".gemini", "commands", "harness"),
2101
2349
  ext: ".toml",
2102
2350
  client: "gemini-cli"
2103
2351
  }
@@ -2121,7 +2369,7 @@ function checkSlashCommands() {
2121
2369
  }
2122
2370
  function checkMcpConfig(cwd) {
2123
2371
  const results = [];
2124
- const claudeConfig = readMcpConfig(path12.join(cwd, ".mcp.json"));
2372
+ const claudeConfig = readMcpConfig(path13.join(cwd, ".mcp.json"));
2125
2373
  if (claudeConfig.mcpServers?.["harness"]) {
2126
2374
  results.push({
2127
2375
  name: "mcp-claude",
@@ -2136,9 +2384,9 @@ function checkMcpConfig(cwd) {
2136
2384
  fix: "Run: harness setup-mcp --client claude"
2137
2385
  });
2138
2386
  }
2139
- const geminiDir = path12.join(cwd, ".gemini");
2140
- if (fs5.existsSync(geminiDir)) {
2141
- const geminiConfig = readMcpConfig(path12.join(geminiDir, "settings.json"));
2387
+ const geminiDir = path13.join(cwd, ".gemini");
2388
+ if (fs7.existsSync(geminiDir)) {
2389
+ const geminiConfig = readMcpConfig(path13.join(geminiDir, "settings.json"));
2142
2390
  if (geminiConfig.mcpServers?.["harness"]) {
2143
2391
  results.push({
2144
2392
  name: "mcp-gemini",
@@ -2157,12 +2405,12 @@ function checkMcpConfig(cwd) {
2157
2405
  return results;
2158
2406
  }
2159
2407
  function loadMcpPresence(cwd) {
2160
- const mcpPath = path12.join(cwd, ".mcp.json");
2161
- const geminiDir = path12.join(cwd, ".gemini");
2162
- const hasGemini = fs5.existsSync(geminiDir);
2408
+ const mcpPath = path13.join(cwd, ".mcp.json");
2409
+ const geminiDir = path13.join(cwd, ".gemini");
2410
+ const hasGemini = fs7.existsSync(geminiDir);
2163
2411
  return {
2164
2412
  mcpConfig: readMcpConfig(mcpPath),
2165
- geminiConfig: hasGemini ? readMcpConfig(path12.join(geminiDir, "settings.json")) : null,
2413
+ geminiConfig: hasGemini ? readMcpConfig(path13.join(geminiDir, "settings.json")) : null,
2166
2414
  hasGemini
2167
2415
  };
2168
2416
  }
@@ -2194,7 +2442,7 @@ function checkTier0Presence(def, presence) {
2194
2442
  function checkIntegrations(cwd) {
2195
2443
  const results = [];
2196
2444
  const presence = loadMcpPresence(cwd);
2197
- const configPath = path12.join(cwd, "harness.config.json");
2445
+ const configPath = path13.join(cwd, "harness.config.json");
2198
2446
  const integrationsConfig = readIntegrationsConfig(configPath);
2199
2447
  for (const def of INTEGRATION_REGISTRY.filter((d) => d.tier === 0)) {
2200
2448
  results.push(checkTier0Presence(def, presence));
@@ -2244,7 +2492,7 @@ function formatCheck(check) {
2244
2492
  return line;
2245
2493
  }
2246
2494
  function createDoctorCommand() {
2247
- return new Command18("doctor").description("Check environment health: Node version, slash commands, MCP configuration").action((_opts, cmd) => {
2495
+ return new Command20("doctor").description("Check environment health: Node version, slash commands, MCP configuration").action((_opts, cmd) => {
2248
2496
  const globalOpts = cmd.optsWithGlobals();
2249
2497
  const cwd = process.cwd();
2250
2498
  const useJson = globalOpts.json;
@@ -2269,8 +2517,9 @@ function createDoctorCommand() {
2269
2517
  }
2270
2518
 
2271
2519
  // src/commands/fix-drift.ts
2272
- import { Command as Command19 } from "commander";
2273
- import * as path13 from "path";
2520
+ init_dist();
2521
+ import { Command as Command21 } from "commander";
2522
+ import * as path14 from "path";
2274
2523
  async function runFixDrift(options) {
2275
2524
  const cwd = options.cwd ?? process.cwd();
2276
2525
  const dryRun = options.dryRun !== false;
@@ -2279,11 +2528,11 @@ async function runFixDrift(options) {
2279
2528
  return Err(configResult.error);
2280
2529
  }
2281
2530
  const config = configResult.value;
2282
- const rootDir = path13.resolve(cwd, config.rootDir);
2283
- const docsDir = path13.resolve(cwd, config.docsDir);
2531
+ const rootDir = path14.resolve(cwd, config.rootDir);
2532
+ const docsDir = path14.resolve(cwd, config.docsDir);
2284
2533
  const entropyConfig = {
2285
2534
  rootDir,
2286
- entryPoints: [path13.join(rootDir, "src/index.ts")],
2535
+ ...config.entropy?.entryPoints && { entryPoints: config.entropy.entryPoints },
2287
2536
  docPaths: [docsDir],
2288
2537
  analyze: {
2289
2538
  drift: true,
@@ -2402,9 +2651,9 @@ function printFixDriftResult(value, mode, formatter) {
2402
2651
  }
2403
2652
  }
2404
2653
  function createFixDriftCommand() {
2405
- const command = new Command19("fix-drift").description("Auto-fix entropy issues (doc drift, dead code)").option("--no-dry-run", "Actually apply fixes (default is dry-run mode)").action(async (opts, cmd) => {
2654
+ const command = new Command21("fix-drift").description("Auto-fix entropy issues (doc drift, dead code)").option("--no-dry-run", "Actually apply fixes (default is dry-run mode)").action(async (opts, cmd) => {
2406
2655
  const globalOpts = cmd.optsWithGlobals();
2407
- const mode = resolveOutputMode2(globalOpts);
2656
+ const mode = resolveOutputMode(globalOpts);
2408
2657
  const formatter = new OutputFormatter(mode);
2409
2658
  const result = await runFixDrift({
2410
2659
  configPath: globalOpts.config,
@@ -2432,7 +2681,7 @@ function createFixDriftCommand() {
2432
2681
  }
2433
2682
 
2434
2683
  // src/commands/generate.ts
2435
- import { Command as Command20 } from "commander";
2684
+ import { Command as Command22 } from "commander";
2436
2685
  function validatePlatforms(platforms) {
2437
2686
  for (const p of platforms) {
2438
2687
  if (!VALID_PLATFORMS.includes(p)) {
@@ -2492,27 +2741,27 @@ async function runGenerateAction(opts, globalOpts) {
2492
2741
  }
2493
2742
  }
2494
2743
  function createGenerateCommand() {
2495
- return new Command20("generate").description("Generate all platform integrations (slash commands + agent definitions)").option("--platforms <list>", "Target platforms (comma-separated)", "claude-code,gemini-cli").option("--global", "Write to global directories", false).option("--include-global", "Include built-in global skills", false).option("--output <dir>", "Custom output directory").option("--dry-run", "Show what would change without writing", false).option("--yes", "Skip deletion confirmation prompts", false).action(async (opts, cmd) => {
2744
+ return new Command22("generate").description("Generate all platform integrations (slash commands + agent definitions)").option("--platforms <list>", "Target platforms (comma-separated)", "claude-code,gemini-cli").option("--global", "Write to global directories", false).option("--include-global", "Include built-in global skills", false).option("--output <dir>", "Custom output directory").option("--dry-run", "Show what would change without writing", false).option("--yes", "Skip deletion confirmation prompts", false).action(async (opts, cmd) => {
2496
2745
  await runGenerateAction(opts, cmd.optsWithGlobals());
2497
2746
  });
2498
2747
  }
2499
2748
 
2500
2749
  // src/commands/graph/index.ts
2501
- import { Command as Command23 } from "commander";
2750
+ import { Command as Command25 } from "commander";
2502
2751
 
2503
2752
  // src/commands/graph/status.ts
2504
- import * as path14 from "path";
2753
+ import * as path15 from "path";
2505
2754
  async function runGraphStatus(projectPath) {
2506
- const { GraphStore } = await import("./dist-QW5G3GX3.js");
2507
- const graphDir = path14.join(projectPath, ".harness", "graph");
2755
+ const { GraphStore } = await import("./dist-RADHOOXG.js");
2756
+ const graphDir = path15.join(projectPath, ".harness", "graph");
2508
2757
  const store = new GraphStore();
2509
2758
  const loaded = await store.load(graphDir);
2510
2759
  if (!loaded) return { status: "no_graph", message: "No graph found. Run `harness scan` first." };
2511
- const fs36 = await import("fs/promises");
2512
- const metaPath = path14.join(graphDir, "metadata.json");
2760
+ const fs41 = await import("fs/promises");
2761
+ const metaPath = path15.join(graphDir, "metadata.json");
2513
2762
  let lastScan = "unknown";
2514
2763
  try {
2515
- const meta = JSON.parse(await fs36.readFile(metaPath, "utf-8"));
2764
+ const meta = JSON.parse(await fs41.readFile(metaPath, "utf-8"));
2516
2765
  lastScan = meta.lastScanTimestamp;
2517
2766
  } catch {
2518
2767
  }
@@ -2523,8 +2772,8 @@ async function runGraphStatus(projectPath) {
2523
2772
  }
2524
2773
  let connectorSyncStatus = {};
2525
2774
  try {
2526
- const syncMetaPath = path14.join(graphDir, "sync-metadata.json");
2527
- const syncMeta = JSON.parse(await fs36.readFile(syncMetaPath, "utf-8"));
2775
+ const syncMetaPath = path15.join(graphDir, "sync-metadata.json");
2776
+ const syncMeta = JSON.parse(await fs41.readFile(syncMetaPath, "utf-8"));
2528
2777
  for (const [name, data] of Object.entries(syncMeta.connectors ?? {})) {
2529
2778
  connectorSyncStatus[name] = data.lastSyncTimestamp;
2530
2779
  }
@@ -2541,10 +2790,10 @@ async function runGraphStatus(projectPath) {
2541
2790
  }
2542
2791
 
2543
2792
  // src/commands/graph/export.ts
2544
- import * as path15 from "path";
2793
+ import * as path16 from "path";
2545
2794
  async function runGraphExport(projectPath, format) {
2546
- const { GraphStore } = await import("./dist-QW5G3GX3.js");
2547
- const graphDir = path15.join(projectPath, ".harness", "graph");
2795
+ const { GraphStore } = await import("./dist-RADHOOXG.js");
2796
+ const graphDir = path16.join(projectPath, ".harness", "graph");
2548
2797
  const store = new GraphStore();
2549
2798
  const loaded = await store.load(graphDir);
2550
2799
  if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
@@ -2573,15 +2822,15 @@ async function runGraphExport(projectPath, format) {
2573
2822
  }
2574
2823
 
2575
2824
  // src/commands/graph/index.ts
2576
- import * as path18 from "path";
2825
+ import * as path19 from "path";
2577
2826
 
2578
2827
  // src/commands/graph/query.ts
2579
- import { Command as Command21 } from "commander";
2580
- import * as path16 from "path";
2828
+ import { Command as Command23 } from "commander";
2829
+ import * as path17 from "path";
2581
2830
  async function runQuery(projectPath, rootNodeId, opts) {
2582
- const { GraphStore, ContextQL } = await import("./dist-QW5G3GX3.js");
2831
+ const { GraphStore, ContextQL } = await import("./dist-RADHOOXG.js");
2583
2832
  const store = new GraphStore();
2584
- const graphDir = path16.join(projectPath, ".harness", "graph");
2833
+ const graphDir = path17.join(projectPath, ".harness", "graph");
2585
2834
  const loaded = await store.load(graphDir);
2586
2835
  if (!loaded) throw new Error("No graph found. Run `harness scan` first.");
2587
2836
  const params = {
@@ -2603,7 +2852,7 @@ function printQueryResult(result) {
2603
2852
  }
2604
2853
  }
2605
2854
  async function runQueryAction(rootNodeId, opts, globalOpts) {
2606
- const projectPath = path16.resolve(globalOpts.config ? path16.dirname(globalOpts.config) : ".");
2855
+ const projectPath = path17.resolve(globalOpts.config ? path17.dirname(globalOpts.config) : ".");
2607
2856
  try {
2608
2857
  const result = await runQuery(projectPath, rootNodeId, {
2609
2858
  depth: parseInt(opts.depth),
@@ -2622,19 +2871,19 @@ async function runQueryAction(rootNodeId, opts, globalOpts) {
2622
2871
  }
2623
2872
  }
2624
2873
  function createQueryCommand() {
2625
- return new Command21("query").description("Query the knowledge graph").argument("<rootNodeId>", "Starting node ID").option("--depth <n>", "Max traversal depth", "3").option("--types <types>", "Comma-separated node types to include").option("--edges <edges>", "Comma-separated edge types to include").option("--bidirectional", "Traverse both directions").action(async (rootNodeId, opts, cmd) => {
2874
+ return new Command23("query").description("Query the knowledge graph").argument("<rootNodeId>", "Starting node ID").option("--depth <n>", "Max traversal depth", "3").option("--types <types>", "Comma-separated node types to include").option("--edges <edges>", "Comma-separated edge types to include").option("--bidirectional", "Traverse both directions").action(async (rootNodeId, opts, cmd) => {
2626
2875
  await runQueryAction(rootNodeId, opts, cmd.optsWithGlobals());
2627
2876
  });
2628
2877
  }
2629
2878
 
2630
2879
  // src/commands/graph/ingest.ts
2631
- import { Command as Command22 } from "commander";
2632
- import * as path17 from "path";
2880
+ import { Command as Command24 } from "commander";
2881
+ import * as path18 from "path";
2633
2882
  async function loadConnectorConfig(projectPath, source) {
2634
2883
  try {
2635
- const fs36 = await import("fs/promises");
2636
- const configPath = path17.join(projectPath, "harness.config.json");
2637
- const config = JSON.parse(await fs36.readFile(configPath, "utf-8"));
2884
+ const fs41 = await import("fs/promises");
2885
+ const configPath = path18.join(projectPath, "harness.config.json");
2886
+ const config = JSON.parse(await fs41.readFile(configPath, "utf-8"));
2638
2887
  const connector = config.graph?.connectors?.[source];
2639
2888
  return connector ?? {};
2640
2889
  } catch {
@@ -2673,8 +2922,8 @@ async function runIngest(projectPath, source, opts) {
2673
2922
  SlackConnector,
2674
2923
  CIConnector,
2675
2924
  ConfluenceConnector
2676
- } = await import("./dist-QW5G3GX3.js");
2677
- const graphDir = path17.join(projectPath, ".harness", "graph");
2925
+ } = await import("./dist-RADHOOXG.js");
2926
+ const graphDir = path18.join(projectPath, ".harness", "graph");
2678
2927
  const store = new GraphStore();
2679
2928
  await store.load(graphDir);
2680
2929
  if (opts?.all) {
@@ -2741,7 +2990,7 @@ async function runIngest(projectPath, source, opts) {
2741
2990
  return result;
2742
2991
  }
2743
2992
  function createIngestCommand() {
2744
- return new Command22("ingest").description("Ingest data into the knowledge graph").option(
2993
+ return new Command24("ingest").description("Ingest data into the knowledge graph").option(
2745
2994
  "--source <name>",
2746
2995
  "Source to ingest (code, knowledge, git, jira, slack, ci, confluence)"
2747
2996
  ).option("--all", "Run all sources (code, knowledge, git, and configured connectors)").option("--full", "Force full re-ingestion").action(async (opts, cmd) => {
@@ -2750,7 +2999,7 @@ function createIngestCommand() {
2750
2999
  process.exit(1);
2751
3000
  }
2752
3001
  const globalOpts = cmd.optsWithGlobals();
2753
- const projectPath = path17.resolve(globalOpts.config ? path17.dirname(globalOpts.config) : ".");
3002
+ const projectPath = path18.resolve(globalOpts.config ? path18.dirname(globalOpts.config) : ".");
2754
3003
  try {
2755
3004
  const result = await runIngest(projectPath, opts.source ?? "", {
2756
3005
  full: opts.full,
@@ -2773,7 +3022,7 @@ function createIngestCommand() {
2773
3022
 
2774
3023
  // src/commands/graph/index.ts
2775
3024
  function resolveProjectPath(globalOpts) {
2776
- return path18.resolve(globalOpts.config ? path18.dirname(globalOpts.config) : ".");
3025
+ return path19.resolve(globalOpts.config ? path19.dirname(globalOpts.config) : ".");
2777
3026
  }
2778
3027
  function printGraphStatus(result) {
2779
3028
  if (result.status === "no_graph") {
@@ -2817,19 +3066,19 @@ async function runExportAction(opts, cmd) {
2817
3066
  }
2818
3067
  }
2819
3068
  function createGraphCommand() {
2820
- const graph = new Command23("graph").description("Knowledge graph management");
3069
+ const graph = new Command25("graph").description("Knowledge graph management");
2821
3070
  graph.command("status").description("Show graph statistics").action(runStatusAction);
2822
3071
  graph.command("export").description("Export graph").requiredOption("--format <format>", "Output format (json, mermaid)").action(runExportAction);
2823
3072
  return graph;
2824
3073
  }
2825
3074
 
2826
3075
  // src/commands/hooks/index.ts
2827
- import { Command as Command28 } from "commander";
3076
+ import { Command as Command30 } from "commander";
2828
3077
 
2829
3078
  // src/commands/hooks/init.ts
2830
- import { Command as Command24 } from "commander";
2831
- import * as fs6 from "fs";
2832
- import * as path19 from "path";
3079
+ import { Command as Command26 } from "commander";
3080
+ import * as fs8 from "fs";
3081
+ import * as path20 from "path";
2833
3082
  import { fileURLToPath as fileURLToPath2 } from "url";
2834
3083
 
2835
3084
  // src/hooks/profiles.ts
@@ -2859,11 +3108,11 @@ var PROFILES = {
2859
3108
 
2860
3109
  // src/commands/hooks/init.ts
2861
3110
  var __filename2 = fileURLToPath2(import.meta.url);
2862
- var __dirname2 = path19.dirname(__filename2);
3111
+ var __dirname2 = path20.dirname(__filename2);
2863
3112
  var VALID_PROFILES = ["minimal", "standard", "strict"];
2864
3113
  function resolveHookSourceDir() {
2865
- const candidate = path19.resolve(__dirname2, "..", "..", "hooks");
2866
- if (fs6.existsSync(candidate)) {
3114
+ const candidate = path20.resolve(__dirname2, "..", "..", "hooks");
3115
+ if (fs8.existsSync(candidate)) {
2867
3116
  return candidate;
2868
3117
  }
2869
3118
  throw new Error(`Cannot locate hook scripts directory. Expected at: ${candidate}`);
@@ -2891,12 +3140,12 @@ function mergeSettings(existing, hooksConfig) {
2891
3140
  }
2892
3141
  function initHooks(options) {
2893
3142
  const { profile, projectDir } = options;
2894
- const hooksDestDir = path19.join(projectDir, ".harness", "hooks");
2895
- fs6.mkdirSync(hooksDestDir, { recursive: true });
2896
- if (fs6.existsSync(hooksDestDir)) {
2897
- for (const entry of fs6.readdirSync(hooksDestDir)) {
3143
+ const hooksDestDir = path20.join(projectDir, ".harness", "hooks");
3144
+ fs8.mkdirSync(hooksDestDir, { recursive: true });
3145
+ if (fs8.existsSync(hooksDestDir)) {
3146
+ for (const entry of fs8.readdirSync(hooksDestDir)) {
2898
3147
  if (entry.endsWith(".js")) {
2899
- fs6.unlinkSync(path19.join(hooksDestDir, entry));
3148
+ fs8.unlinkSync(path20.join(hooksDestDir, entry));
2900
3149
  }
2901
3150
  }
2902
3151
  }
@@ -2905,22 +3154,22 @@ function initHooks(options) {
2905
3154
  const activeNames = PROFILES[profile];
2906
3155
  const activeScripts = HOOK_SCRIPTS.filter((h) => activeNames.includes(h.name));
2907
3156
  for (const script of activeScripts) {
2908
- const srcFile = path19.join(sourceDir, `${script.name}.js`);
2909
- const destFile = path19.join(hooksDestDir, `${script.name}.js`);
2910
- if (fs6.existsSync(srcFile)) {
2911
- fs6.copyFileSync(srcFile, destFile);
3157
+ const srcFile = path20.join(sourceDir, `${script.name}.js`);
3158
+ const destFile = path20.join(hooksDestDir, `${script.name}.js`);
3159
+ if (fs8.existsSync(srcFile)) {
3160
+ fs8.copyFileSync(srcFile, destFile);
2912
3161
  copiedScripts.push(script.name);
2913
3162
  }
2914
3163
  }
2915
- const profilePath = path19.join(hooksDestDir, "profile.json");
2916
- fs6.writeFileSync(profilePath, JSON.stringify({ profile }, null, 2) + "\n");
2917
- const claudeDir = path19.join(projectDir, ".claude");
2918
- fs6.mkdirSync(claudeDir, { recursive: true });
2919
- const settingsPath = path19.join(claudeDir, "settings.json");
3164
+ const profilePath = path20.join(hooksDestDir, "profile.json");
3165
+ fs8.writeFileSync(profilePath, JSON.stringify({ profile }, null, 2) + "\n");
3166
+ const claudeDir = path20.join(projectDir, ".claude");
3167
+ fs8.mkdirSync(claudeDir, { recursive: true });
3168
+ const settingsPath = path20.join(claudeDir, "settings.json");
2920
3169
  let existing = {};
2921
- if (fs6.existsSync(settingsPath)) {
3170
+ if (fs8.existsSync(settingsPath)) {
2922
3171
  try {
2923
- existing = JSON.parse(fs6.readFileSync(settingsPath, "utf-8"));
3172
+ existing = JSON.parse(fs8.readFileSync(settingsPath, "utf-8"));
2924
3173
  } catch (e) {
2925
3174
  throw new Error(
2926
3175
  `Malformed .claude/settings.json \u2014 fix the JSON syntax before running hooks init. Parse error: ${e instanceof Error ? e.message : String(e)}`,
@@ -2930,11 +3179,11 @@ function initHooks(options) {
2930
3179
  }
2931
3180
  const hooksConfig = buildSettingsHooks(profile);
2932
3181
  const merged = mergeSettings(existing, hooksConfig);
2933
- fs6.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n");
3182
+ fs8.writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n");
2934
3183
  return { copiedScripts, settingsPath, profilePath };
2935
3184
  }
2936
3185
  function createInitCommand2() {
2937
- return new Command24("init").description("Install Claude Code hook configurations into the current project").option("--profile <profile>", "Hook profile: minimal, standard, or strict", "standard").action(async (opts, cmd) => {
3186
+ return new Command26("init").description("Install Claude Code hook configurations into the current project").option("--profile <profile>", "Hook profile: minimal, standard, or strict", "standard").action(async (opts, cmd) => {
2938
3187
  const globalOpts = cmd.optsWithGlobals();
2939
3188
  const profile = opts.profile;
2940
3189
  if (!VALID_PROFILES.includes(profile)) {
@@ -2958,7 +3207,9 @@ function createInitCommand2() {
2958
3207
  `Installed ${result.copiedScripts.length} hook scripts to .harness/hooks/`
2959
3208
  );
2960
3209
  logger.info(`Profile: ${profile}`);
2961
- logger.info(`Settings: ${path19.relative(projectDir, result.settingsPath)}`);
3210
+ logger.info(
3211
+ `Settings: ${path20.relative(projectDir, result.settingsPath).replaceAll("\\", "/")}`
3212
+ );
2962
3213
  logger.dim("Run 'harness hooks list' to see installed hooks");
2963
3214
  }
2964
3215
  } catch (err) {
@@ -2970,19 +3221,19 @@ function createInitCommand2() {
2970
3221
  }
2971
3222
 
2972
3223
  // src/commands/hooks/list.ts
2973
- import { Command as Command25 } from "commander";
2974
- import * as fs7 from "fs";
2975
- import * as path20 from "path";
3224
+ import { Command as Command27 } from "commander";
3225
+ import * as fs9 from "fs";
3226
+ import * as path21 from "path";
2976
3227
  function listHooks(projectDir) {
2977
- const hooksDir = path20.join(projectDir, ".harness", "hooks");
2978
- const profilePath = path20.join(hooksDir, "profile.json");
2979
- if (!fs7.existsSync(profilePath)) {
3228
+ const hooksDir = path21.join(projectDir, ".harness", "hooks");
3229
+ const profilePath = path21.join(hooksDir, "profile.json");
3230
+ if (!fs9.existsSync(profilePath)) {
2980
3231
  return { installed: false, profile: null, hooks: [] };
2981
3232
  }
2982
3233
  let profile = "standard";
2983
3234
  let warning;
2984
3235
  try {
2985
- const data = JSON.parse(fs7.readFileSync(profilePath, "utf-8"));
3236
+ const data = JSON.parse(fs9.readFileSync(profilePath, "utf-8"));
2986
3237
  if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
2987
3238
  profile = data.profile;
2988
3239
  }
@@ -2994,7 +3245,7 @@ function listHooks(projectDir) {
2994
3245
  name: h.name,
2995
3246
  event: h.event,
2996
3247
  matcher: h.matcher,
2997
- scriptPath: path20.join(".harness", "hooks", `${h.name}.js`)
3248
+ scriptPath: path21.join(".harness", "hooks", `${h.name}.js`)
2998
3249
  }));
2999
3250
  const result = { installed: true, profile, hooks };
3000
3251
  if (warning) {
@@ -3003,7 +3254,7 @@ function listHooks(projectDir) {
3003
3254
  return result;
3004
3255
  }
3005
3256
  function createListCommand() {
3006
- return new Command25("list").description("Show installed hooks and active profile").action(async (_opts, cmd) => {
3257
+ return new Command27("list").description("Show installed hooks and active profile").action(async (_opts, cmd) => {
3007
3258
  const globalOpts = cmd.optsWithGlobals();
3008
3259
  const projectDir = process.cwd();
3009
3260
  const result = listHooks(projectDir);
@@ -3024,28 +3275,28 @@ function createListCommand() {
3024
3275
  }
3025
3276
 
3026
3277
  // src/commands/hooks/remove.ts
3027
- import { Command as Command26 } from "commander";
3028
- import * as fs8 from "fs";
3029
- import * as path21 from "path";
3278
+ import { Command as Command28 } from "commander";
3279
+ import * as fs10 from "fs";
3280
+ import * as path22 from "path";
3030
3281
  function removeHooks(projectDir) {
3031
- const hooksDir = path21.join(projectDir, ".harness", "hooks");
3032
- const settingsPath = path21.join(projectDir, ".claude", "settings.json");
3282
+ const hooksDir = path22.join(projectDir, ".harness", "hooks");
3283
+ const settingsPath = path22.join(projectDir, ".claude", "settings.json");
3033
3284
  let removed = false;
3034
3285
  let settingsCleaned = false;
3035
- if (fs8.existsSync(hooksDir)) {
3036
- fs8.rmSync(hooksDir, { recursive: true, force: true });
3286
+ if (fs10.existsSync(hooksDir)) {
3287
+ fs10.rmSync(hooksDir, { recursive: true, force: true });
3037
3288
  removed = true;
3038
3289
  }
3039
- if (fs8.existsSync(settingsPath)) {
3290
+ if (fs10.existsSync(settingsPath)) {
3040
3291
  try {
3041
- const settings = JSON.parse(fs8.readFileSync(settingsPath, "utf-8"));
3292
+ const settings = JSON.parse(fs10.readFileSync(settingsPath, "utf-8"));
3042
3293
  if (settings.hooks !== void 0) {
3043
3294
  delete settings.hooks;
3044
3295
  settingsCleaned = true;
3045
3296
  if (Object.keys(settings).length === 0) {
3046
- fs8.unlinkSync(settingsPath);
3297
+ fs10.unlinkSync(settingsPath);
3047
3298
  } else {
3048
- fs8.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
3299
+ fs10.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
3049
3300
  }
3050
3301
  }
3051
3302
  } catch {
@@ -3054,7 +3305,7 @@ function removeHooks(projectDir) {
3054
3305
  return { removed, hooksDir, settingsCleaned };
3055
3306
  }
3056
3307
  function createRemoveCommand() {
3057
- return new Command26("remove").description("Remove harness-managed hooks from the current project").action(async (_opts, cmd) => {
3308
+ return new Command28("remove").description("Remove harness-managed hooks from the current project").action(async (_opts, cmd) => {
3058
3309
  const globalOpts = cmd.optsWithGlobals();
3059
3310
  const projectDir = process.cwd();
3060
3311
  const result = removeHooks(projectDir);
@@ -3076,21 +3327,21 @@ function createRemoveCommand() {
3076
3327
  }
3077
3328
 
3078
3329
  // src/commands/hooks/add.ts
3079
- import { Command as Command27 } from "commander";
3080
- import * as fs9 from "fs";
3081
- import * as path22 from "path";
3330
+ import { Command as Command29 } from "commander";
3331
+ import * as fs11 from "fs";
3332
+ import * as path23 from "path";
3082
3333
  import { fileURLToPath as fileURLToPath3 } from "url";
3083
- var __dirname3 = path22.dirname(fileURLToPath3(import.meta.url));
3334
+ var __dirname3 = path23.dirname(fileURLToPath3(import.meta.url));
3084
3335
  var ALIASES = {
3085
3336
  sentinel: ["sentinel-pre", "sentinel-post"]
3086
3337
  };
3087
3338
  function hookSourceDir() {
3088
- const d = path22.resolve(__dirname3, "..", "..", "hooks");
3089
- if (fs9.existsSync(d)) return d;
3339
+ const d = path23.resolve(__dirname3, "..", "..", "hooks");
3340
+ if (fs11.existsSync(d)) return d;
3090
3341
  throw new Error(`Hook scripts not found: ${d}`);
3091
3342
  }
3092
3343
  function readJson(p) {
3093
- return fs9.existsSync(p) ? JSON.parse(fs9.readFileSync(p, "utf-8")) : {};
3344
+ return fs11.existsSync(p) ? JSON.parse(fs11.readFileSync(p, "utf-8")) : {};
3094
3345
  }
3095
3346
  function registerHook(s, ev, matcher, name) {
3096
3347
  if (!s.hooks[ev]) s.hooks[ev] = [];
@@ -3103,11 +3354,11 @@ function addHooks(hookName, projectDir) {
3103
3354
  const names = ALIASES[hookName] ?? [hookName];
3104
3355
  const result = { added: [], alreadyInstalled: [], notFound: [] };
3105
3356
  const srcDir = hookSourceDir();
3106
- const destDir = path22.join(projectDir, ".harness", "hooks");
3107
- fs9.mkdirSync(destDir, { recursive: true });
3108
- const claudeDir = path22.join(projectDir, ".claude");
3109
- fs9.mkdirSync(claudeDir, { recursive: true });
3110
- const settingsPath = path22.join(claudeDir, "settings.json");
3357
+ const destDir = path23.join(projectDir, ".harness", "hooks");
3358
+ fs11.mkdirSync(destDir, { recursive: true });
3359
+ const claudeDir = path23.join(projectDir, ".claude");
3360
+ fs11.mkdirSync(claudeDir, { recursive: true });
3361
+ const settingsPath = path23.join(claudeDir, "settings.json");
3111
3362
  const settings = readJson(settingsPath);
3112
3363
  if (!settings.hooks) settings.hooks = {};
3113
3364
  for (const name of names) {
@@ -3116,24 +3367,24 @@ function addHooks(hookName, projectDir) {
3116
3367
  result.notFound.push(name);
3117
3368
  continue;
3118
3369
  }
3119
- const src = path22.join(srcDir, `${name}.js`);
3120
- const dest = path22.join(destDir, `${name}.js`);
3121
- if (fs9.existsSync(dest)) {
3370
+ const src = path23.join(srcDir, `${name}.js`);
3371
+ const dest = path23.join(destDir, `${name}.js`);
3372
+ if (fs11.existsSync(dest)) {
3122
3373
  result.alreadyInstalled.push(name);
3123
- } else if (!fs9.existsSync(src)) {
3374
+ } else if (!fs11.existsSync(src)) {
3124
3375
  result.notFound.push(name);
3125
3376
  continue;
3126
3377
  } else {
3127
- fs9.copyFileSync(src, dest);
3378
+ fs11.copyFileSync(src, dest);
3128
3379
  result.added.push(name);
3129
3380
  }
3130
3381
  registerHook(settings, def.event, def.matcher, name);
3131
3382
  }
3132
- fs9.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
3383
+ fs11.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
3133
3384
  return result;
3134
3385
  }
3135
3386
  function createAddCommand2() {
3136
- return new Command27("add").argument("<hook-name>", "Hook name or alias (e.g., sentinel)").description("Add a hook without changing the profile").action(async (hookName, _opts, cmd) => {
3387
+ return new Command29("add").argument("<hook-name>", "Hook name or alias (e.g., sentinel)").description("Add a hook without changing the profile").action(async (hookName, _opts, cmd) => {
3137
3388
  const projectDir = process.cwd();
3138
3389
  try {
3139
3390
  const res = addHooks(hookName, projectDir);
@@ -3158,7 +3409,7 @@ function createAddCommand2() {
3158
3409
 
3159
3410
  // src/commands/hooks/index.ts
3160
3411
  function createHooksCommand() {
3161
- const command = new Command28("hooks").description("Manage Claude Code hook configurations");
3412
+ const command = new Command30("hooks").description("Manage Claude Code hook configurations");
3162
3413
  command.addCommand(createInitCommand2());
3163
3414
  command.addCommand(createListCommand());
3164
3415
  command.addCommand(createRemoveCommand());
@@ -3167,10 +3418,10 @@ function createHooksCommand() {
3167
3418
  }
3168
3419
 
3169
3420
  // src/commands/impact-preview.ts
3170
- import { Command as Command29 } from "commander";
3421
+ import { Command as Command31 } from "commander";
3171
3422
  import { execSync as execSync4 } from "child_process";
3172
- import * as path23 from "path";
3173
- import * as fs10 from "fs";
3423
+ import * as path24 from "path";
3424
+ import * as fs12 from "fs";
3174
3425
  function getStagedFiles(cwd) {
3175
3426
  try {
3176
3427
  const output = execSync4("git diff --cached --name-only", {
@@ -3184,7 +3435,7 @@ function getStagedFiles(cwd) {
3184
3435
  }
3185
3436
  function graphExists(projectPath) {
3186
3437
  try {
3187
- return fs10.existsSync(path23.join(projectPath, ".harness", "graph", "graph.json"));
3438
+ return fs12.existsSync(path24.join(projectPath, ".harness", "graph", "graph.json"));
3188
3439
  } catch {
3189
3440
  return false;
3190
3441
  }
@@ -3193,7 +3444,7 @@ function extractNodeName(id) {
3193
3444
  const parts = id.split(":");
3194
3445
  if (parts.length > 1) {
3195
3446
  const fullPath = parts.slice(1).join(":");
3196
- return path23.basename(fullPath);
3447
+ return path24.basename(fullPath);
3197
3448
  }
3198
3449
  return id;
3199
3450
  }
@@ -3348,7 +3599,7 @@ function formatImpactOutput(stagedFiles, acc, options) {
3348
3599
  return options.detailed ? formatDetailed(stagedFiles.length, merged, acc.aggregateCounts) : formatCompact(stagedFiles.length, merged, acc.aggregateCounts);
3349
3600
  }
3350
3601
  async function runImpactPreview(options) {
3351
- const projectPath = path23.resolve(options.path ?? process.cwd());
3602
+ const projectPath = path24.resolve(options.path ?? process.cwd());
3352
3603
  const stagedFiles = getStagedFiles(projectPath);
3353
3604
  if (stagedFiles.length === 0) return "Impact Preview: no staged changes";
3354
3605
  if (!graphExists(projectPath)) {
@@ -3366,7 +3617,7 @@ async function runImpactPreview(options) {
3366
3617
  return formatImpactOutput(stagedFiles, acc, options);
3367
3618
  }
3368
3619
  function createImpactPreviewCommand() {
3369
- const command = new Command29("impact-preview").description("Show blast radius of staged changes using the knowledge graph").option("--detailed", "Show all affected files instead of top items").option("--per-file", "Show impact per staged file instead of aggregate").option("--path <dir>", "Project root (default: cwd)").action(async (opts) => {
3620
+ const command = new Command31("impact-preview").description("Show blast radius of staged changes using the knowledge graph").option("--detailed", "Show all affected files instead of top items").option("--per-file", "Show impact per staged file instead of aggregate").option("--path <dir>", "Project root (default: cwd)").action(async (opts) => {
3370
3621
  const output = await runImpactPreview({
3371
3622
  detailed: opts.detailed,
3372
3623
  perFile: opts.perFile,
@@ -3379,28 +3630,29 @@ function createImpactPreviewCommand() {
3379
3630
  }
3380
3631
 
3381
3632
  // src/commands/init.ts
3382
- import { Command as Command31 } from "commander";
3633
+ init_dist();
3634
+ import { Command as Command33 } from "commander";
3383
3635
  import chalk3 from "chalk";
3384
- import * as fs13 from "fs";
3385
- import * as path26 from "path";
3636
+ import * as fs15 from "fs";
3637
+ import * as path27 from "path";
3386
3638
 
3387
3639
  // src/commands/setup-mcp.ts
3388
- import { Command as Command30 } from "commander";
3389
- import * as fs12 from "fs";
3390
- import * as path25 from "path";
3640
+ import { Command as Command32 } from "commander";
3641
+ import * as fs14 from "fs";
3642
+ import * as path26 from "path";
3391
3643
  import * as os2 from "os";
3392
3644
  import chalk2 from "chalk";
3393
3645
  import * as clack from "@clack/prompts";
3394
3646
 
3395
3647
  // src/integrations/toml.ts
3396
- import * as fs11 from "fs";
3397
- import * as path24 from "path";
3648
+ import * as fs13 from "fs";
3649
+ import * as path25 from "path";
3398
3650
  function writeTomlMcpEntry(filePath, name, entry) {
3399
- const dir = path24.dirname(filePath);
3400
- if (!fs11.existsSync(dir)) {
3401
- fs11.mkdirSync(dir, { recursive: true });
3651
+ const dir = path25.dirname(filePath);
3652
+ if (!fs13.existsSync(dir)) {
3653
+ fs13.mkdirSync(dir, { recursive: true });
3402
3654
  }
3403
- const existing = fs11.existsSync(filePath) ? fs11.readFileSync(filePath, "utf-8") : "";
3655
+ const existing = fs13.existsSync(filePath) ? fs13.readFileSync(filePath, "utf-8") : "";
3404
3656
  const blockHeader = `[mcp_servers.${name}]`;
3405
3657
  const newBlock = serializeTomlMcpBlock(name, entry);
3406
3658
  let updated;
@@ -3411,8 +3663,8 @@ function writeTomlMcpEntry(filePath, name, entry) {
3411
3663
  updated = existing + separator + newBlock;
3412
3664
  }
3413
3665
  const tmp = filePath + ".tmp";
3414
- fs11.writeFileSync(tmp, updated);
3415
- fs11.renameSync(tmp, filePath);
3666
+ fs13.writeFileSync(tmp, updated);
3667
+ fs13.renameSync(tmp, filePath);
3416
3668
  }
3417
3669
  function serializeTomlMcpBlock(name, entry) {
3418
3670
  const lines = [`[mcp_servers.${name}]`];
@@ -3470,6 +3722,7 @@ var CURSOR_CURATED_TOOLS = [
3470
3722
  "get_impact",
3471
3723
  "detect_entropy",
3472
3724
  "run_security_scan",
3725
+ "get_security_trends",
3473
3726
  "assess_project",
3474
3727
  "manage_state",
3475
3728
  "create_self_review",
@@ -3514,6 +3767,7 @@ var ALL_MCP_TOOLS = [
3514
3767
  "ingest_source",
3515
3768
  "generate_agent_definitions",
3516
3769
  "run_security_scan",
3770
+ "get_security_trends",
3517
3771
  "check_performance",
3518
3772
  "get_perf_baselines",
3519
3773
  "update_perf_baselines",
@@ -3540,7 +3794,8 @@ var ALL_MCP_TOOLS = [
3540
3794
  "recommend_skills",
3541
3795
  "compute_blast_radius",
3542
3796
  "dispatch_skills",
3543
- "compact"
3797
+ "compact",
3798
+ "detect_constraint_emergence"
3544
3799
  ];
3545
3800
  async function runCursorToolPicker() {
3546
3801
  try {
@@ -3568,20 +3823,20 @@ function writeCursorMcpEntryWithTools(configPath, tools) {
3568
3823
  });
3569
3824
  }
3570
3825
  function readJsonFile(filePath) {
3571
- if (!fs12.existsSync(filePath)) return null;
3826
+ if (!fs14.existsSync(filePath)) return null;
3572
3827
  try {
3573
- return JSON.parse(fs12.readFileSync(filePath, "utf-8"));
3828
+ return JSON.parse(fs14.readFileSync(filePath, "utf-8"));
3574
3829
  } catch {
3575
- fs12.copyFileSync(filePath, filePath + ".bak");
3830
+ fs14.copyFileSync(filePath, filePath + ".bak");
3576
3831
  return null;
3577
3832
  }
3578
3833
  }
3579
3834
  function writeJsonFile(filePath, data) {
3580
- const dir = path25.dirname(filePath);
3581
- if (!fs12.existsSync(dir)) {
3582
- fs12.mkdirSync(dir, { recursive: true });
3835
+ const dir = path26.dirname(filePath);
3836
+ if (!fs14.existsSync(dir)) {
3837
+ fs14.mkdirSync(dir, { recursive: true });
3583
3838
  }
3584
- fs12.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
3839
+ fs14.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
3585
3840
  }
3586
3841
  function configureMcpServer(configPath) {
3587
3842
  const config = readJsonFile(configPath) ?? {};
@@ -3596,7 +3851,7 @@ function configureMcpServer(configPath) {
3596
3851
  return true;
3597
3852
  }
3598
3853
  function addGeminiTrustedFolder(cwd) {
3599
- const trustedPath = path25.join(os2.homedir(), ".gemini", "trustedFolders.json");
3854
+ const trustedPath = path26.join(os2.homedir(), ".gemini", "trustedFolders.json");
3600
3855
  const folders = readJsonFile(trustedPath) ?? {};
3601
3856
  if (folders[cwd] === "TRUST_FOLDER") {
3602
3857
  return false;
@@ -3610,7 +3865,7 @@ function setupMcp(cwd, client) {
3610
3865
  const skipped = [];
3611
3866
  let trustedFolder = false;
3612
3867
  if (client === "all" || client === "claude") {
3613
- const configPath = path25.join(cwd, ".mcp.json");
3868
+ const configPath = path26.join(cwd, ".mcp.json");
3614
3869
  if (configureMcpServer(configPath)) {
3615
3870
  configured.push("Claude Code");
3616
3871
  } else {
@@ -3618,7 +3873,7 @@ function setupMcp(cwd, client) {
3618
3873
  }
3619
3874
  }
3620
3875
  if (client === "all" || client === "gemini") {
3621
- const configPath = path25.join(cwd, ".gemini", "settings.json");
3876
+ const configPath = path26.join(cwd, ".gemini", "settings.json");
3622
3877
  if (configureMcpServer(configPath)) {
3623
3878
  configured.push("Gemini CLI");
3624
3879
  } else {
@@ -3627,10 +3882,10 @@ function setupMcp(cwd, client) {
3627
3882
  trustedFolder = addGeminiTrustedFolder(cwd);
3628
3883
  }
3629
3884
  if (client === "all" || client === "codex") {
3630
- const configPath = path25.join(cwd, ".codex", "config.toml");
3885
+ const configPath = path26.join(cwd, ".codex", "config.toml");
3631
3886
  const alreadyConfigured = (() => {
3632
- if (!fs12.existsSync(configPath)) return false;
3633
- const content = fs12.readFileSync(configPath, "utf-8");
3887
+ if (!fs14.existsSync(configPath)) return false;
3888
+ const content = fs14.readFileSync(configPath, "utf-8");
3634
3889
  return content.includes("[mcp_servers.harness]");
3635
3890
  })();
3636
3891
  if (alreadyConfigured) {
@@ -3645,7 +3900,7 @@ function setupMcp(cwd, client) {
3645
3900
  }
3646
3901
  }
3647
3902
  if (client === "all" || client === "cursor") {
3648
- const configPath = path25.join(cwd, ".cursor", "mcp.json");
3903
+ const configPath = path26.join(cwd, ".cursor", "mcp.json");
3649
3904
  const existing = readJsonFile(configPath);
3650
3905
  if (existing?.mcpServers?.["harness"]) {
3651
3906
  skipped.push("Cursor");
@@ -3659,7 +3914,7 @@ function setupMcp(cwd, client) {
3659
3914
  async function resolveCursorWithPicker(cwd, pick) {
3660
3915
  const configured = [];
3661
3916
  const skipped = [];
3662
- const cursorConfigPath = path25.join(cwd, ".cursor", "mcp.json");
3917
+ const cursorConfigPath = path26.join(cwd, ".cursor", "mcp.json");
3663
3918
  const existing = readJsonFile(cursorConfigPath);
3664
3919
  if (existing?.mcpServers?.["harness"] && !pick) {
3665
3920
  skipped.push("Cursor");
@@ -3703,7 +3958,7 @@ function printMcpResult(configured, skipped, trustedFolder) {
3703
3958
  console.log("");
3704
3959
  }
3705
3960
  function createSetupMcpCommand() {
3706
- return new Command30("setup-mcp").description("Configure MCP server for AI agent integration").option("--client <client>", "Client to configure (claude, gemini, codex, cursor, all)", "all").option("--pick", "Launch interactive tool picker (Cursor only)").option("--yes", "Bypass interactive picker and use curated 25-tool set (Cursor only)").action(async (opts, cmd) => {
3961
+ return new Command32("setup-mcp").description("Configure MCP server for AI agent integration").option("--client <client>", "Client to configure (claude, gemini, codex, cursor, all)", "all").option("--pick", "Launch interactive tool picker (Cursor only)").option("--yes", "Bypass interactive picker and use curated 25-tool set (Cursor only)").action(async (opts, cmd) => {
3707
3962
  const globalOpts = cmd.optsWithGlobals();
3708
3963
  const cwd = process.cwd();
3709
3964
  let configured;
@@ -3730,12 +3985,12 @@ function loadEngineAndTemplates(_options) {
3730
3985
  }
3731
3986
  function resolveInitDefaults(options) {
3732
3987
  const cwd = options.cwd ?? process.cwd();
3733
- return { cwd, name: options.name ?? path26.basename(cwd), force: options.force ?? false };
3988
+ return { cwd, name: options.name ?? path27.basename(cwd), force: options.force ?? false };
3734
3989
  }
3735
3990
  async function runInit(options) {
3736
3991
  const { cwd, name, force } = resolveInitDefaults(options);
3737
- const configPath = path26.join(cwd, "harness.config.json");
3738
- if (!force && fs13.existsSync(configPath)) {
3992
+ const configPath = path27.join(cwd, "harness.config.json");
3993
+ if (!force && fs15.existsSync(configPath)) {
3739
3994
  return Err(
3740
3995
  new CLIError("Project already initialized. Use --force to overwrite.", ExitCode.ERROR)
3741
3996
  );
@@ -3843,11 +4098,11 @@ async function runInitAction2(opts) {
3843
4098
  process.exit(ExitCode.SUCCESS);
3844
4099
  }
3845
4100
  function createInitCommand3() {
3846
- const command = new Command31("init").description("Initialize a new harness-engineering project").option("-n, --name <name>", "Project name").option("-l, --level <level>", "Adoption level (basic, intermediate, advanced)", "basic").option("--framework <framework>", "Framework overlay (nextjs)").option("--language <language>", "Target language (typescript, python, go, rust, java)").option("-f, --force", "Overwrite existing files").option("-y, --yes", "Use defaults without prompting").action(async (opts, cmd) => {
4101
+ const command = new Command33("init").description("Initialize a new harness-engineering project").option("-n, --name <name>", "Project name").option("-l, --level <level>", "Adoption level (basic, intermediate, advanced)", "basic").option("-t, --template <template>", "Specific template name (e.g. orchestrator)").option("--framework <framework>", "Framework overlay (nextjs)").option("--language <language>", "Target language (typescript, python, go, rust, java)").option("-f, --force", "Overwrite existing files").option("-y, --yes", "Use defaults without prompting").action(async (opts, cmd) => {
3847
4102
  const globalOpts = cmd.optsWithGlobals();
3848
4103
  await runInitAction2({
3849
4104
  name: opts.name,
3850
- level: opts.level,
4105
+ level: opts.template ?? opts.level,
3851
4106
  framework: opts.framework,
3852
4107
  language: opts.language,
3853
4108
  force: opts.force,
@@ -3858,16 +4113,16 @@ function createInitCommand3() {
3858
4113
  }
3859
4114
 
3860
4115
  // src/commands/install.ts
3861
- import * as fs18 from "fs";
4116
+ import * as fs20 from "fs";
3862
4117
  import * as os5 from "os";
3863
- import * as path31 from "path";
4118
+ import * as path32 from "path";
3864
4119
  import { execFileSync as execFileSync3 } from "child_process";
3865
- import { Command as Command32 } from "commander";
4120
+ import { Command as Command34 } from "commander";
3866
4121
  import { parse as yamlParse } from "yaml";
3867
4122
 
3868
4123
  // src/registry/npm-client.ts
3869
- import * as fs14 from "fs";
3870
- import * as path27 from "path";
4124
+ import * as fs16 from "fs";
4125
+ import * as path28 from "path";
3871
4126
  import * as os3 from "os";
3872
4127
  var NPM_REGISTRY = "https://registry.npmjs.org";
3873
4128
  var FETCH_TIMEOUT_MS = 3e4;
@@ -3890,10 +4145,10 @@ function extractSkillName(packageName) {
3890
4145
  function readNpmrcToken(registryUrl) {
3891
4146
  const { hostname, pathname } = new URL(registryUrl);
3892
4147
  const registryPath = `//${hostname}${pathname.replace(/\/$/, "")}/:_authToken=`;
3893
- const candidates = [path27.join(process.cwd(), ".npmrc"), path27.join(os3.homedir(), ".npmrc")];
4148
+ const candidates = [path28.join(process.cwd(), ".npmrc"), path28.join(os3.homedir(), ".npmrc")];
3894
4149
  for (const npmrcPath of candidates) {
3895
4150
  try {
3896
- const content = fs14.readFileSync(npmrcPath, "utf-8");
4151
+ const content = fs16.readFileSync(npmrcPath, "utf-8");
3897
4152
  for (const line of content.split("\n")) {
3898
4153
  const trimmed = line.trim();
3899
4154
  if (trimmed.startsWith(registryPath)) {
@@ -3988,19 +4243,19 @@ async function searchNpmRegistry(query, registryUrl) {
3988
4243
  }
3989
4244
 
3990
4245
  // src/registry/tarball.ts
3991
- import * as fs15 from "fs";
3992
- import * as path28 from "path";
4246
+ import * as fs17 from "fs";
4247
+ import * as path29 from "path";
3993
4248
  import * as os4 from "os";
3994
4249
  import { execFileSync as execFileSync2 } from "child_process";
3995
4250
  function extractTarball(tarballBuffer) {
3996
- const tmpDir = fs15.mkdtempSync(path28.join(os4.tmpdir(), "harness-skill-install-"));
3997
- const tarballPath = path28.join(tmpDir, "package.tgz");
4251
+ const tmpDir = fs17.mkdtempSync(path29.join(os4.tmpdir(), "harness-skill-install-"));
4252
+ const tarballPath = path29.join(tmpDir, "package.tgz");
3998
4253
  try {
3999
- fs15.writeFileSync(tarballPath, tarballBuffer);
4254
+ fs17.writeFileSync(tarballPath, tarballBuffer);
4000
4255
  execFileSync2("tar", ["-xzf", tarballPath, "-C", tmpDir], {
4001
4256
  timeout: 3e4
4002
4257
  });
4003
- fs15.unlinkSync(tarballPath);
4258
+ fs17.unlinkSync(tarballPath);
4004
4259
  } catch (err) {
4005
4260
  cleanupTempDir(tmpDir);
4006
4261
  throw new Error(
@@ -4011,37 +4266,37 @@ function extractTarball(tarballBuffer) {
4011
4266
  return tmpDir;
4012
4267
  }
4013
4268
  function placeSkillContent(extractedPkgDir, communityBaseDir, skillName, platforms) {
4014
- const files = fs15.readdirSync(extractedPkgDir);
4269
+ const files = fs17.readdirSync(extractedPkgDir);
4015
4270
  for (const platform of platforms) {
4016
- const targetDir = path28.join(communityBaseDir, platform, skillName);
4017
- if (fs15.existsSync(targetDir)) {
4018
- fs15.rmSync(targetDir, { recursive: true, force: true });
4271
+ const targetDir = path29.join(communityBaseDir, platform, skillName);
4272
+ if (fs17.existsSync(targetDir)) {
4273
+ fs17.rmSync(targetDir, { recursive: true, force: true });
4019
4274
  }
4020
- fs15.mkdirSync(targetDir, { recursive: true });
4275
+ fs17.mkdirSync(targetDir, { recursive: true });
4021
4276
  for (const file of files) {
4022
4277
  if (file === "package.json" || file === "node_modules") continue;
4023
- const srcPath = path28.join(extractedPkgDir, file);
4024
- const destPath = path28.join(targetDir, file);
4025
- const stat = fs15.statSync(srcPath);
4278
+ const srcPath = path29.join(extractedPkgDir, file);
4279
+ const destPath = path29.join(targetDir, file);
4280
+ const stat = fs17.statSync(srcPath);
4026
4281
  if (stat.isDirectory()) {
4027
- fs15.cpSync(srcPath, destPath, { recursive: true });
4282
+ fs17.cpSync(srcPath, destPath, { recursive: true });
4028
4283
  } else {
4029
- fs15.copyFileSync(srcPath, destPath);
4284
+ fs17.copyFileSync(srcPath, destPath);
4030
4285
  }
4031
4286
  }
4032
4287
  }
4033
4288
  }
4034
4289
  function removeSkillContent(communityBaseDir, skillName, platforms) {
4035
4290
  for (const platform of platforms) {
4036
- const targetDir = path28.join(communityBaseDir, platform, skillName);
4037
- if (fs15.existsSync(targetDir)) {
4038
- fs15.rmSync(targetDir, { recursive: true, force: true });
4291
+ const targetDir = path29.join(communityBaseDir, platform, skillName);
4292
+ if (fs17.existsSync(targetDir)) {
4293
+ fs17.rmSync(targetDir, { recursive: true, force: true });
4039
4294
  }
4040
4295
  }
4041
4296
  }
4042
4297
  function cleanupTempDir(dirPath) {
4043
4298
  try {
4044
- fs15.rmSync(dirPath, { recursive: true, force: true });
4299
+ fs17.rmSync(dirPath, { recursive: true, force: true });
4045
4300
  } catch {
4046
4301
  }
4047
4302
  }
@@ -4083,8 +4338,8 @@ function findDependentsOf(lockfile, targetPackageName) {
4083
4338
  }
4084
4339
 
4085
4340
  // src/registry/lockfile.ts
4086
- import * as fs16 from "fs";
4087
- import * as path29 from "path";
4341
+ import * as fs18 from "fs";
4342
+ import * as path30 from "path";
4088
4343
  function createEmptyLockfile() {
4089
4344
  return { version: 1, skills: {} };
4090
4345
  }
@@ -4104,10 +4359,10 @@ function sortedStringify(obj) {
4104
4359
  );
4105
4360
  }
4106
4361
  function readLockfile2(filePath) {
4107
- if (!fs16.existsSync(filePath)) {
4362
+ if (!fs18.existsSync(filePath)) {
4108
4363
  return createEmptyLockfile();
4109
4364
  }
4110
- const raw = fs16.readFileSync(filePath, "utf-8");
4365
+ const raw = fs18.readFileSync(filePath, "utf-8");
4111
4366
  let parsed;
4112
4367
  try {
4113
4368
  parsed = JSON.parse(raw);
@@ -4124,9 +4379,9 @@ function readLockfile2(filePath) {
4124
4379
  return parsed;
4125
4380
  }
4126
4381
  function writeLockfile2(filePath, lockfile) {
4127
- const dir = path29.dirname(filePath);
4128
- fs16.mkdirSync(dir, { recursive: true });
4129
- fs16.writeFileSync(filePath, sortedStringify(lockfile) + "\n", "utf-8");
4382
+ const dir = path30.dirname(filePath);
4383
+ fs18.mkdirSync(dir, { recursive: true });
4384
+ fs18.writeFileSync(filePath, sortedStringify(lockfile) + "\n", "utf-8");
4130
4385
  }
4131
4386
  function updateLockfileEntry(lockfile, name, entry) {
4132
4387
  return {
@@ -4149,17 +4404,17 @@ function removeLockfileEntry(lockfile, name) {
4149
4404
  }
4150
4405
 
4151
4406
  // src/registry/bundled-skills.ts
4152
- import * as fs17 from "fs";
4153
- import * as path30 from "path";
4407
+ import * as fs19 from "fs";
4408
+ import * as path31 from "path";
4154
4409
  function getBundledSkillNames(bundledSkillsDir) {
4155
- if (!fs17.existsSync(bundledSkillsDir)) {
4410
+ if (!fs19.existsSync(bundledSkillsDir)) {
4156
4411
  return /* @__PURE__ */ new Set();
4157
4412
  }
4158
- const entries = fs17.readdirSync(bundledSkillsDir);
4413
+ const entries = fs19.readdirSync(bundledSkillsDir);
4159
4414
  const names = /* @__PURE__ */ new Set();
4160
4415
  for (const entry of entries) {
4161
4416
  try {
4162
- const stat = fs17.statSync(path30.join(bundledSkillsDir, String(entry)));
4417
+ const stat = fs19.statSync(path31.join(bundledSkillsDir, String(entry)));
4163
4418
  if (stat.isDirectory()) {
4164
4419
  names.add(String(entry));
4165
4420
  }
@@ -4186,12 +4441,12 @@ function validateSkillYaml(parsed) {
4186
4441
  function resolveCommunityBase(global) {
4187
4442
  if (global) {
4188
4443
  const communityBase2 = resolveGlobalCommunityBaseDir();
4189
- return { communityBase: communityBase2, lockfilePath: path31.join(communityBase2, "skills-lock.json") };
4444
+ return { communityBase: communityBase2, lockfilePath: path32.join(communityBase2, "skills-lock.json") };
4190
4445
  }
4191
4446
  const globalDir = resolveGlobalSkillsDir();
4192
- const skillsDir = path31.dirname(globalDir);
4193
- const communityBase = path31.join(skillsDir, "community");
4194
- return { communityBase, lockfilePath: path31.join(communityBase, "skills-lock.json") };
4447
+ const skillsDir = path32.dirname(globalDir);
4448
+ const communityBase = path32.join(skillsDir, "community");
4449
+ return { communityBase, lockfilePath: path32.join(communityBase, "skills-lock.json") };
4195
4450
  }
4196
4451
  function parseGitHubRef(from) {
4197
4452
  const ghPrefix = from.match(/^github:([^/]+)\/([^#]+?)(?:#(.+))?$/);
@@ -4207,7 +4462,7 @@ function parseGitHubRef(from) {
4207
4462
  return null;
4208
4463
  }
4209
4464
  function cloneGitHubRepo(owner, repo, ref) {
4210
- const tmpDir = fs18.mkdtempSync(path31.join(os5.tmpdir(), "harness-gh-install-"));
4465
+ const tmpDir = fs20.mkdtempSync(path32.join(os5.tmpdir(), "harness-gh-install-"));
4211
4466
  const url = `https://github.com/${owner}/${repo}.git`;
4212
4467
  try {
4213
4468
  const cloneArgs = ["clone", "--depth", "1"];
@@ -4228,43 +4483,43 @@ function discoverSkillDirs(rootDir) {
4228
4483
  const skillDirs = [];
4229
4484
  function scan(dir, depth) {
4230
4485
  if (depth > 3) return;
4231
- if (!fs18.existsSync(dir)) return;
4232
- if (fs18.existsSync(path31.join(dir, "skill.yaml"))) {
4486
+ if (!fs20.existsSync(dir)) return;
4487
+ if (fs20.existsSync(path32.join(dir, "skill.yaml"))) {
4233
4488
  skillDirs.push(dir);
4234
4489
  return;
4235
4490
  }
4236
- const entries = fs18.readdirSync(dir, { withFileTypes: true });
4491
+ const entries = fs20.readdirSync(dir, { withFileTypes: true });
4237
4492
  for (const entry of entries) {
4238
4493
  if (!entry.isDirectory()) continue;
4239
4494
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
4240
- scan(path31.join(dir, entry.name), depth + 1);
4495
+ scan(path32.join(dir, entry.name), depth + 1);
4241
4496
  }
4242
4497
  }
4243
4498
  scan(rootDir, 0);
4244
4499
  return skillDirs;
4245
4500
  }
4246
4501
  function resolveLocalPkgDir(fromPath) {
4247
- const resolvedPath = path31.resolve(fromPath);
4248
- if (!fs18.existsSync(resolvedPath)) {
4502
+ const resolvedPath = path32.resolve(fromPath);
4503
+ if (!fs20.existsSync(resolvedPath)) {
4249
4504
  throw new Error(`--from path does not exist: ${resolvedPath}`);
4250
4505
  }
4251
- const stat = fs18.statSync(resolvedPath);
4506
+ const stat = fs20.statSync(resolvedPath);
4252
4507
  if (stat.isDirectory()) {
4253
4508
  return { pkgDir: resolvedPath, extractDir: null };
4254
4509
  }
4255
4510
  if (resolvedPath.endsWith(".tgz") || resolvedPath.endsWith(".tar.gz")) {
4256
- const tarballBuffer = fs18.readFileSync(resolvedPath);
4511
+ const tarballBuffer = fs20.readFileSync(resolvedPath);
4257
4512
  const extractDir = extractTarball(tarballBuffer);
4258
- return { pkgDir: path31.join(extractDir, "package"), extractDir };
4513
+ return { pkgDir: path32.join(extractDir, "package"), extractDir };
4259
4514
  }
4260
4515
  throw new Error(`--from path must be a directory or .tgz file. Got: ${resolvedPath}`);
4261
4516
  }
4262
4517
  function installSkillDir(pkgDir, resolvedPath, options) {
4263
- const skillYamlPath = path31.join(pkgDir, "skill.yaml");
4264
- if (!fs18.existsSync(skillYamlPath)) {
4518
+ const skillYamlPath = path32.join(pkgDir, "skill.yaml");
4519
+ if (!fs20.existsSync(skillYamlPath)) {
4265
4520
  throw new Error(`No skill.yaml found at ${skillYamlPath}`);
4266
4521
  }
4267
- const skillYaml = validateSkillYaml(yamlParse(fs18.readFileSync(skillYamlPath, "utf-8")));
4522
+ const skillYaml = validateSkillYaml(yamlParse(fs20.readFileSync(skillYamlPath, "utf-8")));
4268
4523
  const shortName = skillYaml.name;
4269
4524
  const { communityBase, lockfilePath } = resolveCommunityBase(options.global ?? false);
4270
4525
  if (!options.global) {
@@ -4292,7 +4547,7 @@ function installSkillDir(pkgDir, resolvedPath, options) {
4292
4547
  async function runLocalInstall(fromPath, options) {
4293
4548
  const { pkgDir, extractDir } = resolveLocalPkgDir(fromPath);
4294
4549
  try {
4295
- return installSkillDir(pkgDir, path31.resolve(fromPath), options);
4550
+ return installSkillDir(pkgDir, path32.resolve(fromPath), options);
4296
4551
  } finally {
4297
4552
  if (extractDir) cleanupTempDir(extractDir);
4298
4553
  }
@@ -4335,8 +4590,8 @@ async function runInstall(skillName, options) {
4335
4590
  version: installed.map((r) => r.version).join(", ")
4336
4591
  };
4337
4592
  }
4338
- const resolvedFrom = path31.resolve(options.from);
4339
- if (fs18.existsSync(resolvedFrom) && fs18.statSync(resolvedFrom).isDirectory() && !fs18.existsSync(path31.join(resolvedFrom, "skill.yaml"))) {
4593
+ const resolvedFrom = path32.resolve(options.from);
4594
+ if (fs20.existsSync(resolvedFrom) && fs20.statSync(resolvedFrom).isDirectory() && !fs20.existsSync(path32.join(resolvedFrom, "skill.yaml"))) {
4340
4595
  const results = await runBulkInstall(resolvedFrom, options);
4341
4596
  const installed = results.filter((r) => r.installed);
4342
4597
  return {
@@ -4377,12 +4632,12 @@ async function runInstall(skillName, options) {
4377
4632
  const extractDir = extractTarball(tarballBuffer);
4378
4633
  let skillYaml;
4379
4634
  try {
4380
- const extractedPkgDir = path31.join(extractDir, "package");
4381
- const skillYamlPath = path31.join(extractedPkgDir, "skill.yaml");
4382
- if (!fs18.existsSync(skillYamlPath)) {
4635
+ const extractedPkgDir = path32.join(extractDir, "package");
4636
+ const skillYamlPath = path32.join(extractedPkgDir, "skill.yaml");
4637
+ if (!fs20.existsSync(skillYamlPath)) {
4383
4638
  throw new Error(`contains invalid skill.yaml: file not found in package`);
4384
4639
  }
4385
- const rawYaml = fs18.readFileSync(skillYamlPath, "utf-8");
4640
+ const rawYaml = fs20.readFileSync(skillYamlPath, "utf-8");
4386
4641
  const parsed = yamlParse(rawYaml);
4387
4642
  skillYaml = validateSkillYaml(parsed);
4388
4643
  placeSkillContent(extractedPkgDir, communityBase, shortName, skillYaml.platforms);
@@ -4422,7 +4677,7 @@ async function runInstall(skillName, options) {
4422
4677
  return result;
4423
4678
  }
4424
4679
  function createInstallCommand() {
4425
- const cmd = new Command32("install");
4680
+ const cmd = new Command34("install");
4426
4681
  cmd.description("Install skills from npm registry, local directory, or GitHub repository").argument("<skill>", 'Skill name, @harness-skills/scoped package, or "." for bulk install').option("--version <range>", "Semver range or exact version to install").option("--force", "Force reinstall even if same version is already installed").option(
4427
4682
  "--from <source>",
4428
4683
  "Install from local path, directory, or GitHub (github:owner/repo, https://github.com/owner/repo)"
@@ -4455,15 +4710,16 @@ function createInstallCommand() {
4455
4710
  }
4456
4711
 
4457
4712
  // src/commands/install-constraints.ts
4458
- import * as fs19 from "fs/promises";
4459
- import * as path32 from "path";
4460
- import { Command as Command33 } from "commander";
4713
+ init_dist();
4714
+ import * as fs21 from "fs/promises";
4715
+ import * as path33 from "path";
4716
+ import { Command as Command35 } from "commander";
4461
4717
  import semver3 from "semver";
4462
4718
  async function runInstallConstraints(options) {
4463
4719
  const { source, configPath, lockfilePath } = options;
4464
4720
  let rawBundle;
4465
4721
  try {
4466
- rawBundle = await fs19.readFile(source, "utf-8");
4722
+ rawBundle = await fs21.readFile(source, "utf-8");
4467
4723
  } catch (err) {
4468
4724
  if (isNodeError(err) && err.code === "ENOENT") {
4469
4725
  return { ok: false, error: `Bundle file not found: ${source}` };
@@ -4506,7 +4762,7 @@ async function runInstallConstraints(options) {
4506
4762
  }
4507
4763
  let localConfig;
4508
4764
  try {
4509
- const raw = await fs19.readFile(configPath, "utf-8");
4765
+ const raw = await fs21.readFile(configPath, "utf-8");
4510
4766
  localConfig = JSON.parse(raw);
4511
4767
  } catch (err) {
4512
4768
  return {
@@ -4654,7 +4910,7 @@ function isNodeError(err) {
4654
4910
  return err instanceof Error && "code" in err;
4655
4911
  }
4656
4912
  function resolveConfigPath(opts) {
4657
- if (opts.config) return path32.resolve(opts.config);
4913
+ if (opts.config) return path33.resolve(opts.config);
4658
4914
  const found = findConfigFile();
4659
4915
  if (!found.ok) {
4660
4916
  logger.error(found.error.message);
@@ -4689,9 +4945,9 @@ function logInstallResult(val, opts) {
4689
4945
  }
4690
4946
  async function handleInstallConstraints(source, opts) {
4691
4947
  const configPath = resolveConfigPath(opts);
4692
- const projectRoot = path32.dirname(configPath);
4693
- const lockfilePath = path32.join(projectRoot, ".harness", "constraints.lock.json");
4694
- const resolvedSource = path32.resolve(source);
4948
+ const projectRoot = path33.dirname(configPath);
4949
+ const lockfilePath = path33.join(projectRoot, ".harness", "constraints.lock.json");
4950
+ const resolvedSource = path33.resolve(source);
4695
4951
  if (opts.forceLocal && opts.forcePackage) {
4696
4952
  logger.error("Cannot use both --force-local and --force-package.");
4697
4953
  process.exit(1);
@@ -4711,18 +4967,19 @@ async function handleInstallConstraints(source, opts) {
4711
4967
  logInstallResult(result.value, opts);
4712
4968
  }
4713
4969
  function createInstallConstraintsCommand() {
4714
- const cmd = new Command33("install-constraints");
4970
+ const cmd = new Command35("install-constraints");
4715
4971
  cmd.description("Install a constraints bundle into the local harness config").argument("<source>", "Path to a .harness-constraints.json bundle file").option("--force-local", "Resolve all conflicts by keeping local values").option("--force-package", "Resolve all conflicts by using package values").option("--dry-run", "Show what would change without writing files").option("-c, --config <path>", "Path to harness.config.json").action(handleInstallConstraints);
4716
4972
  return cmd;
4717
4973
  }
4718
4974
 
4719
4975
  // src/commands/integrations/index.ts
4720
- import { Command as Command38 } from "commander";
4976
+ import { Command as Command40 } from "commander";
4721
4977
 
4722
4978
  // src/commands/integrations/add.ts
4723
- import { Command as Command34 } from "commander";
4724
- import * as fs20 from "fs";
4725
- import * as path33 from "path";
4979
+ init_dist();
4980
+ import { Command as Command36 } from "commander";
4981
+ import * as fs22 from "fs";
4982
+ import * as path34 from "path";
4726
4983
  import chalk4 from "chalk";
4727
4984
  function buildMcpEntry(def) {
4728
4985
  const entry = { command: def.mcpConfig.command };
@@ -4731,14 +4988,14 @@ function buildMcpEntry(def) {
4731
4988
  return entry;
4732
4989
  }
4733
4990
  function writeMcpEntries(cwd, defName, mcpEntry) {
4734
- writeMcpEntry(path33.join(cwd, ".mcp.json"), defName, mcpEntry);
4735
- const geminiDir = path33.join(cwd, ".gemini");
4736
- if (fs20.existsSync(geminiDir)) {
4737
- writeMcpEntry(path33.join(geminiDir, "settings.json"), defName, mcpEntry);
4991
+ writeMcpEntry(path34.join(cwd, ".mcp.json"), defName, mcpEntry);
4992
+ const geminiDir = path34.join(cwd, ".gemini");
4993
+ if (fs22.existsSync(geminiDir)) {
4994
+ writeMcpEntry(path34.join(geminiDir, "settings.json"), defName, mcpEntry);
4738
4995
  }
4739
4996
  }
4740
4997
  function updateIntegrationsConfig(cwd, defName) {
4741
- const configPath = path33.join(cwd, "harness.config.json");
4998
+ const configPath = path34.join(cwd, "harness.config.json");
4742
4999
  const integConfig = readIntegrationsConfig(configPath);
4743
5000
  if (!integConfig.enabled.includes(defName)) integConfig.enabled.push(defName);
4744
5001
  integConfig.dismissed = integConfig.dismissed.filter((d) => d !== defName);
@@ -4784,7 +5041,7 @@ function printAddSuccess(value) {
4784
5041
  }
4785
5042
  }
4786
5043
  function createAddIntegrationCommand() {
4787
- return new Command34("add").description("Enable an MCP integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
5044
+ return new Command36("add").description("Enable an MCP integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
4788
5045
  const globalOpts = cmd.optsWithGlobals();
4789
5046
  const result = addIntegration(process.cwd(), name);
4790
5047
  if (!result.ok) {
@@ -4798,8 +5055,8 @@ function createAddIntegrationCommand() {
4798
5055
  }
4799
5056
 
4800
5057
  // src/commands/integrations/list.ts
4801
- import { Command as Command35 } from "commander";
4802
- import * as path34 from "path";
5058
+ import { Command as Command37 } from "commander";
5059
+ import * as path35 from "path";
4803
5060
  import chalk5 from "chalk";
4804
5061
  function printTier0Integrations(tier0, mcpServers) {
4805
5062
  console.log(" Tier 0 (zero-config):");
@@ -4823,8 +5080,8 @@ function printTier1Integrations(tier1, mcpServers, dismissed) {
4823
5080
  }
4824
5081
  async function runListIntegrations(globalOpts) {
4825
5082
  const cwd = process.cwd();
4826
- const mcpConfig = readMcpConfig(path34.join(cwd, ".mcp.json"));
4827
- const integConfig = readIntegrationsConfig(path34.join(cwd, "harness.config.json"));
5083
+ const mcpConfig = readMcpConfig(path35.join(cwd, ".mcp.json"));
5084
+ const integConfig = readIntegrationsConfig(path35.join(cwd, "harness.config.json"));
4828
5085
  const mcpServers = mcpConfig.mcpServers ?? {};
4829
5086
  if (globalOpts.json) {
4830
5087
  const entries = INTEGRATION_REGISTRY.map((i) => ({
@@ -4855,13 +5112,14 @@ async function runListIntegrations(globalOpts) {
4855
5112
  process.exit(ExitCode.SUCCESS);
4856
5113
  }
4857
5114
  function createListIntegrationsCommand() {
4858
- return new Command35("list").description("Show all MCP integrations with status").action(async (_opts, cmd) => runListIntegrations(cmd.optsWithGlobals()));
5115
+ return new Command37("list").description("Show all MCP integrations with status").action(async (_opts, cmd) => runListIntegrations(cmd.optsWithGlobals()));
4859
5116
  }
4860
5117
 
4861
5118
  // src/commands/integrations/remove.ts
4862
- import { Command as Command36 } from "commander";
4863
- import * as fs21 from "fs";
4864
- import * as path35 from "path";
5119
+ init_dist();
5120
+ import { Command as Command38 } from "commander";
5121
+ import * as fs23 from "fs";
5122
+ import * as path36 from "path";
4865
5123
  function removeIntegration(cwd, name) {
4866
5124
  const def = INTEGRATION_REGISTRY.find((i) => i.name === name);
4867
5125
  if (!def) {
@@ -4872,21 +5130,21 @@ function removeIntegration(cwd, name) {
4872
5130
  )
4873
5131
  );
4874
5132
  }
4875
- const mcpPath = path35.join(cwd, ".mcp.json");
5133
+ const mcpPath = path36.join(cwd, ".mcp.json");
4876
5134
  removeMcpEntry(mcpPath, def.name);
4877
- const geminiDir = path35.join(cwd, ".gemini");
4878
- if (fs21.existsSync(geminiDir)) {
4879
- const geminiPath = path35.join(geminiDir, "settings.json");
5135
+ const geminiDir = path36.join(cwd, ".gemini");
5136
+ if (fs23.existsSync(geminiDir)) {
5137
+ const geminiPath = path36.join(geminiDir, "settings.json");
4880
5138
  removeMcpEntry(geminiPath, def.name);
4881
5139
  }
4882
- const configPath = path35.join(cwd, "harness.config.json");
5140
+ const configPath = path36.join(cwd, "harness.config.json");
4883
5141
  const integConfig = readIntegrationsConfig(configPath);
4884
5142
  integConfig.enabled = integConfig.enabled.filter((e) => e !== def.name);
4885
5143
  writeIntegrationsConfig(configPath, integConfig);
4886
5144
  return Ok(def.displayName);
4887
5145
  }
4888
5146
  function createRemoveIntegrationCommand() {
4889
- return new Command36("remove").description("Remove an MCP integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
5147
+ return new Command38("remove").description("Remove an MCP integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
4890
5148
  const globalOpts = cmd.optsWithGlobals();
4891
5149
  const cwd = process.cwd();
4892
5150
  const result = removeIntegration(cwd, name);
@@ -4907,8 +5165,9 @@ function createRemoveIntegrationCommand() {
4907
5165
  }
4908
5166
 
4909
5167
  // src/commands/integrations/dismiss.ts
4910
- import { Command as Command37 } from "commander";
4911
- import * as path36 from "path";
5168
+ init_dist();
5169
+ import { Command as Command39 } from "commander";
5170
+ import * as path37 from "path";
4912
5171
  function dismissIntegration(cwd, name) {
4913
5172
  const def = INTEGRATION_REGISTRY.find((i) => i.name === name);
4914
5173
  if (!def) {
@@ -4919,7 +5178,7 @@ function dismissIntegration(cwd, name) {
4919
5178
  )
4920
5179
  );
4921
5180
  }
4922
- const configPath = path36.join(cwd, "harness.config.json");
5181
+ const configPath = path37.join(cwd, "harness.config.json");
4923
5182
  const integConfig = readIntegrationsConfig(configPath);
4924
5183
  if (!integConfig.dismissed.includes(def.name)) {
4925
5184
  integConfig.dismissed.push(def.name);
@@ -4929,7 +5188,7 @@ function dismissIntegration(cwd, name) {
4929
5188
  return Ok(def.displayName);
4930
5189
  }
4931
5190
  function createDismissIntegrationCommand() {
4932
- return new Command37("dismiss").description("Suppress doctor recommendations for an integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
5191
+ return new Command39("dismiss").description("Suppress doctor recommendations for an integration").argument("<name>", "Integration name (e.g. perplexity, augment-code)").action(async (name, _opts, cmd) => {
4933
5192
  const globalOpts = cmd.optsWithGlobals();
4934
5193
  const cwd = process.cwd();
4935
5194
  const result = dismissIntegration(cwd, name);
@@ -4953,7 +5212,7 @@ function createDismissIntegrationCommand() {
4953
5212
 
4954
5213
  // src/commands/integrations/index.ts
4955
5214
  function createIntegrationsCommand() {
4956
- const command = new Command38("integrations").description(
5215
+ const command = new Command40("integrations").description(
4957
5216
  "Manage MCP peer integrations (add, list, remove, dismiss)"
4958
5217
  );
4959
5218
  command.addCommand(createListIntegrationsCommand());
@@ -4964,13 +5223,14 @@ function createIntegrationsCommand() {
4964
5223
  }
4965
5224
 
4966
5225
  // src/commands/learnings/index.ts
4967
- import { Command as Command40 } from "commander";
5226
+ import { Command as Command42 } from "commander";
4968
5227
 
4969
5228
  // src/commands/learnings/prune.ts
4970
- import { Command as Command39 } from "commander";
4971
- import * as path37 from "path";
5229
+ init_dist();
5230
+ import { Command as Command41 } from "commander";
5231
+ import * as path38 from "path";
4972
5232
  async function handlePrune(opts) {
4973
- const projectPath = path37.resolve(opts.path);
5233
+ const projectPath = path38.resolve(opts.path);
4974
5234
  const result = await pruneLearnings(projectPath, opts.stream);
4975
5235
  if (!result.ok) {
4976
5236
  logger.error(result.error.message);
@@ -5009,23 +5269,23 @@ function printPatternProposals(patterns) {
5009
5269
  );
5010
5270
  }
5011
5271
  function createPruneCommand() {
5012
- return new Command39("prune").description(
5272
+ return new Command41("prune").description(
5013
5273
  "Analyze global learnings for patterns, present improvement proposals, and archive old entries"
5014
5274
  ).option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(handlePrune);
5015
5275
  }
5016
5276
 
5017
5277
  // src/commands/learnings/index.ts
5018
5278
  function createLearningsCommand() {
5019
- const command = new Command40("learnings").description("Learnings management commands");
5279
+ const command = new Command42("learnings").description("Learnings management commands");
5020
5280
  command.addCommand(createPruneCommand());
5021
5281
  return command;
5022
5282
  }
5023
5283
 
5024
5284
  // src/commands/linter/index.ts
5025
- import { Command as Command43 } from "commander";
5285
+ import { Command as Command45 } from "commander";
5026
5286
 
5027
5287
  // src/commands/linter/generate.ts
5028
- import { Command as Command41 } from "commander";
5288
+ import { Command as Command43 } from "commander";
5029
5289
  function formatGenerateError(e) {
5030
5290
  switch (e.type) {
5031
5291
  case "parse":
@@ -5069,7 +5329,7 @@ function handleSuccess(result, useJson) {
5069
5329
  Generated ${result.rulesGenerated.length} rules to ${result.outputDir}`);
5070
5330
  }
5071
5331
  function createGenerateCommand2() {
5072
- return new Command41("generate").description("Generate ESLint rules from harness-linter.yml").option("-c, --config <path>", "Path to harness-linter.yml", "./harness-linter.yml").option("-o, --output <dir>", "Override output directory").option("--clean", "Remove existing files before generating").option("--dry-run", "Preview without writing files").option("--json", "Output as JSON").option("--verbose", "Show detailed output").action(async (options) => {
5332
+ return new Command43("generate").description("Generate ESLint rules from harness-linter.yml").option("-c, --config <path>", "Path to harness-linter.yml", "./harness-linter.yml").option("-o, --output <dir>", "Override output directory").option("--clean", "Remove existing files before generating").option("--dry-run", "Preview without writing files").option("--json", "Output as JSON").option("--verbose", "Show detailed output").action(async (options) => {
5073
5333
  try {
5074
5334
  if (options.verbose) logger.info(`Parsing config: ${options.config}`);
5075
5335
  const result = await generate({
@@ -5091,9 +5351,9 @@ function createGenerateCommand2() {
5091
5351
  }
5092
5352
 
5093
5353
  // src/commands/linter/validate.ts
5094
- import { Command as Command42 } from "commander";
5354
+ import { Command as Command44 } from "commander";
5095
5355
  function createValidateCommand() {
5096
- return new Command42("validate").description("Validate harness-linter.yml config").option("-c, --config <path>", "Path to harness-linter.yml", "./harness-linter.yml").option("--json", "Output as JSON").action(async (options) => {
5356
+ return new Command44("validate").description("Validate harness-linter.yml config").option("-c, --config <path>", "Path to harness-linter.yml", "./harness-linter.yml").option("--json", "Output as JSON").action(async (options) => {
5097
5357
  try {
5098
5358
  const result = await validate({ configPath: options.config });
5099
5359
  if (options.json) {
@@ -5112,7 +5372,7 @@ function createValidateCommand() {
5112
5372
 
5113
5373
  // src/commands/linter/index.ts
5114
5374
  function createLinterCommand() {
5115
- const linter = new Command43("linter").description(
5375
+ const linter = new Command45("linter").description(
5116
5376
  "Generate and validate ESLint rules from YAML config"
5117
5377
  );
5118
5378
  linter.addCommand(createGenerateCommand2());
@@ -5121,22 +5381,61 @@ function createLinterCommand() {
5121
5381
  }
5122
5382
 
5123
5383
  // src/commands/mcp.ts
5124
- import { Command as Command44 } from "commander";
5384
+ import { Command as Command46 } from "commander";
5385
+ var VALID_TIERS = /* @__PURE__ */ new Set(["core", "standard", "full"]);
5386
+ function parseTier(value) {
5387
+ const lower = value.toLowerCase();
5388
+ if (!VALID_TIERS.has(lower)) {
5389
+ throw new Error(`Invalid tier "${value}". Expected one of: core, standard, full.`);
5390
+ }
5391
+ return lower;
5392
+ }
5393
+ function parseBudget(value) {
5394
+ const n = Number.parseInt(value, 10);
5395
+ if (!Number.isFinite(n) || n < 0) {
5396
+ throw new Error(`Invalid --budget-tokens "${value}". Expected a non-negative integer.`);
5397
+ }
5398
+ return n;
5399
+ }
5125
5400
  function createMcpCommand() {
5126
- return new Command44("mcp").description("Start the MCP (Model Context Protocol) server on stdio").option("--tools <tools...>", "Only register the specified tools (used by Cursor integration)").action(async (opts) => {
5127
- const { startServer: startServer2 } = await import("./mcp-LCHC4NZ5.js");
5128
- await startServer2(opts.tools);
5401
+ return new Command46("mcp").description("Start the MCP (Model Context Protocol) server on stdio").option("--tools <tools...>", "Only register the specified tools (used by Cursor integration)").option(
5402
+ "--tier <core|standard|full>",
5403
+ "Load a preset tool tier instead of all tools",
5404
+ parseTier
5405
+ ).option(
5406
+ "--budget-tokens <n>",
5407
+ "Auto-select tier to fit this baseline token budget",
5408
+ parseBudget
5409
+ ).action(async (opts) => {
5410
+ const [{ startServer: startServer2, getToolDefinitions: getToolDefinitions2 }, { selectTier }] = await Promise.all([
5411
+ import("./mcp-2553PNUC.js"),
5412
+ import("./tool-tiers-7QGZ3FKY.js")
5413
+ ]);
5414
+ if (opts.tools && opts.tools.length > 0) {
5415
+ await startServer2(opts.tools);
5416
+ return;
5417
+ }
5418
+ if (opts.tier || opts.budgetTokens !== void 0) {
5419
+ const definitions = getToolDefinitions2();
5420
+ const selection = selectTier(definitions, {
5421
+ ...opts.tier ? { overrideTier: opts.tier } : {},
5422
+ ...opts.budgetTokens !== void 0 ? { tokenBudget: opts.budgetTokens } : {}
5423
+ });
5424
+ await startServer2(selection.filter);
5425
+ return;
5426
+ }
5427
+ await startServer2();
5129
5428
  });
5130
5429
  }
5131
5430
 
5132
5431
  // src/commands/orchestrator.ts
5133
- import { Command as Command45 } from "commander";
5134
- import * as path38 from "path";
5432
+ import { Command as Command47 } from "commander";
5433
+ import * as path39 from "path";
5135
5434
  import { Orchestrator, WorkflowLoader, launchTUI } from "@harness-engineering/orchestrator";
5136
5435
  function createOrchestratorCommand() {
5137
- const orchestrator = new Command45("orchestrator");
5138
- orchestrator.command("run").description("Run the orchestrator daemon").option("-w, --workflow <path>", "Path to WORKFLOW.md", "WORKFLOW.md").action(async (opts) => {
5139
- const workflowPath = path38.resolve(process.cwd(), opts.workflow);
5436
+ const orchestrator = new Command47("orchestrator");
5437
+ orchestrator.command("run").description("Run the orchestrator daemon").option("-w, --workflow <path>", "Path to WORKFLOW.md", "WORKFLOW.md").option("--headless", "Run without TUI (server-only mode for use with web dashboard)").action(async (opts) => {
5438
+ const workflowPath = path39.resolve(process.cwd(), opts.workflow);
5140
5439
  const loader = new WorkflowLoader();
5141
5440
  const result = await loader.loadWorkflow(workflowPath);
5142
5441
  if (!result.ok) {
@@ -5152,23 +5451,32 @@ function createOrchestratorCommand() {
5152
5451
  process.on("SIGINT", shutdown);
5153
5452
  process.on("SIGTERM", shutdown);
5154
5453
  daemon.start();
5155
- const { waitUntilExit } = launchTUI(daemon);
5156
- await waitUntilExit();
5454
+ if (opts.headless) {
5455
+ logger.info(
5456
+ "Orchestrator running in headless mode (no TUI). Use the web dashboard or Ctrl+C to stop."
5457
+ );
5458
+ await new Promise(() => {
5459
+ });
5460
+ } else {
5461
+ const { waitUntilExit } = launchTUI(daemon);
5462
+ await waitUntilExit();
5463
+ }
5157
5464
  process.exit(ExitCode.SUCCESS);
5158
5465
  });
5159
5466
  return orchestrator;
5160
5467
  }
5161
5468
 
5162
5469
  // src/commands/perf.ts
5163
- import { Command as Command46 } from "commander";
5164
- import * as path39 from "path";
5470
+ init_dist();
5471
+ import { Command as Command48 } from "commander";
5472
+ import * as path40 from "path";
5165
5473
  function registerBenchCommand(perf) {
5166
- perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob, _opts, cmd) => {
5474
+ perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob2, _opts, cmd) => {
5167
5475
  const globalOpts = cmd.optsWithGlobals();
5168
5476
  const cwd = process.cwd();
5169
- const { BenchmarkRunner } = await import("./dist-7EBSGAHX.js");
5477
+ const { BenchmarkRunner } = await import("./dist-WCSJHQPK.js");
5170
5478
  const runner = new BenchmarkRunner();
5171
- const benchFiles = runner.discover(cwd, glob);
5479
+ const benchFiles = runner.discover(cwd, glob2);
5172
5480
  if (benchFiles.length === 0) {
5173
5481
  if (globalOpts.json) {
5174
5482
  console.log(JSON.stringify({ benchFiles: [], message: "No .bench.ts files found" }));
@@ -5178,7 +5486,7 @@ function registerBenchCommand(perf) {
5178
5486
  return;
5179
5487
  }
5180
5488
  logBenchDiscovery(globalOpts.json, benchFiles);
5181
- const result = await runner.run(glob ? { cwd, glob } : { cwd });
5489
+ const result = await runner.run(glob2 ? { cwd, glob: glob2 } : { cwd });
5182
5490
  outputBenchResults(globalOpts.json, result);
5183
5491
  });
5184
5492
  }
@@ -5230,7 +5538,7 @@ async function runBaselinesShow(globalOpts) {
5230
5538
  }
5231
5539
  async function runBaselinesUpdate(globalOpts) {
5232
5540
  const cwd = process.cwd();
5233
- const { BenchmarkRunner } = await import("./dist-7EBSGAHX.js");
5541
+ const { BenchmarkRunner } = await import("./dist-WCSJHQPK.js");
5234
5542
  const runner = new BenchmarkRunner();
5235
5543
  const manager = new BaselineManager(cwd);
5236
5544
  logger.info("Running benchmarks to update baselines...");
@@ -5271,9 +5579,9 @@ function registerReportCommand(perf) {
5271
5579
  perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
5272
5580
  const globalOpts = cmd.optsWithGlobals();
5273
5581
  const cwd = process.cwd();
5274
- const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-7EBSGAHX.js");
5582
+ const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-WCSJHQPK.js");
5275
5583
  const analyzer = new EntropyAnalyzer2({
5276
- rootDir: path39.resolve(cwd),
5584
+ rootDir: path40.resolve(cwd),
5277
5585
  analyze: { complexity: true, coupling: true }
5278
5586
  });
5279
5587
  const result = await analyzer.analyze();
@@ -5332,7 +5640,7 @@ function registerCriticalPathsCommand(perf) {
5332
5640
  });
5333
5641
  }
5334
5642
  function createPerfCommand() {
5335
- const perf = new Command46("perf").description("Performance benchmark and baseline management");
5643
+ const perf = new Command48("perf").description("Performance benchmark and baseline management");
5336
5644
  registerBenchCommand(perf);
5337
5645
  registerBaselinesCommands(perf);
5338
5646
  registerReportCommand(perf);
@@ -5341,10 +5649,10 @@ function createPerfCommand() {
5341
5649
  }
5342
5650
 
5343
5651
  // src/commands/persona/index.ts
5344
- import { Command as Command49 } from "commander";
5652
+ import { Command as Command51 } from "commander";
5345
5653
 
5346
5654
  // src/commands/persona/list.ts
5347
- import { Command as Command47 } from "commander";
5655
+ import { Command as Command49 } from "commander";
5348
5656
  function printPersonaList(personas) {
5349
5657
  if (personas.length === 0) {
5350
5658
  logger.info("No personas found.");
@@ -5358,7 +5666,7 @@ function printPersonaList(personas) {
5358
5666
  }
5359
5667
  }
5360
5668
  function createListCommand2() {
5361
- return new Command47("list").description("List available agent personas").action(async (_opts, cmd) => {
5669
+ return new Command49("list").description("List available agent personas").action(async (_opts, cmd) => {
5362
5670
  const globalOpts = cmd.optsWithGlobals();
5363
5671
  const personasDir = resolvePersonasDir();
5364
5672
  const result = listPersonas(personasDir);
@@ -5378,51 +5686,51 @@ function createListCommand2() {
5378
5686
  }
5379
5687
 
5380
5688
  // src/commands/persona/generate.ts
5381
- import { Command as Command48 } from "commander";
5382
- import * as fs22 from "fs";
5383
- import * as path40 from "path";
5689
+ import { Command as Command50 } from "commander";
5690
+ import * as fs24 from "fs";
5691
+ import * as path41 from "path";
5384
5692
  function generatePersonaArtifacts(persona, outputDir, only) {
5385
5693
  const slug = toKebabCase(persona.name);
5386
5694
  const generated = [];
5387
5695
  if (!only || only === "runtime") {
5388
5696
  const result = generateRuntime(persona);
5389
5697
  if (result.ok) {
5390
- const outPath = path40.join(outputDir, `${slug}.runtime.json`);
5391
- fs22.mkdirSync(path40.dirname(outPath), { recursive: true });
5392
- fs22.writeFileSync(outPath, result.value);
5698
+ const outPath = path41.join(outputDir, `${slug}.runtime.json`);
5699
+ fs24.mkdirSync(path41.dirname(outPath), { recursive: true });
5700
+ fs24.writeFileSync(outPath, result.value);
5393
5701
  generated.push(outPath);
5394
5702
  }
5395
5703
  }
5396
5704
  if (!only || only === "agents-md") {
5397
5705
  const result = generateAgentsMd(persona);
5398
5706
  if (result.ok) {
5399
- const outPath = path40.join(outputDir, `${slug}.agents.md`);
5400
- fs22.writeFileSync(outPath, result.value);
5707
+ const outPath = path41.join(outputDir, `${slug}.agents.md`);
5708
+ fs24.writeFileSync(outPath, result.value);
5401
5709
  generated.push(outPath);
5402
5710
  }
5403
5711
  }
5404
5712
  if (!only || only === "ci") {
5405
5713
  const result = generateCIWorkflow(persona, "github");
5406
5714
  if (result.ok) {
5407
- const outPath = path40.join(outputDir, ".github", "workflows", `${slug}.yml`);
5408
- fs22.mkdirSync(path40.dirname(outPath), { recursive: true });
5409
- fs22.writeFileSync(outPath, result.value);
5715
+ const outPath = path41.join(outputDir, ".github", "workflows", `${slug}.yml`);
5716
+ fs24.mkdirSync(path41.dirname(outPath), { recursive: true });
5717
+ fs24.writeFileSync(outPath, result.value);
5410
5718
  generated.push(outPath);
5411
5719
  }
5412
5720
  }
5413
5721
  return generated;
5414
5722
  }
5415
5723
  function createGenerateCommand3() {
5416
- return new Command48("generate").description("Generate artifacts from a persona config").argument("<name>", "Persona name (e.g., architecture-enforcer)").option("--output-dir <dir>", "Output directory", ".").option("--only <type>", "Generate only: ci, agents-md, runtime").action(async (name, opts, cmd) => {
5724
+ return new Command50("generate").description("Generate artifacts from a persona config").argument("<name>", "Persona name (e.g., architecture-enforcer)").option("--output-dir <dir>", "Output directory", ".").option("--only <type>", "Generate only: ci, agents-md, runtime").action(async (name, opts, cmd) => {
5417
5725
  const globalOpts = cmd.optsWithGlobals();
5418
- const personaResult = loadPersona(path40.join(resolvePersonasDir(), `${name}.yaml`));
5726
+ const personaResult = loadPersona(path41.join(resolvePersonasDir(), `${name}.yaml`));
5419
5727
  if (!personaResult.ok) {
5420
5728
  logger.error(personaResult.error.message);
5421
5729
  process.exit(ExitCode.ERROR);
5422
5730
  }
5423
5731
  const generated = generatePersonaArtifacts(
5424
5732
  personaResult.value,
5425
- path40.resolve(opts.outputDir),
5733
+ path41.resolve(opts.outputDir),
5426
5734
  opts.only
5427
5735
  );
5428
5736
  if (!globalOpts.quiet) {
@@ -5435,14 +5743,15 @@ function createGenerateCommand3() {
5435
5743
 
5436
5744
  // src/commands/persona/index.ts
5437
5745
  function createPersonaCommand() {
5438
- const command = new Command49("persona").description("Agent persona management commands");
5746
+ const command = new Command51("persona").description("Agent persona management commands");
5439
5747
  command.addCommand(createListCommand2());
5440
5748
  command.addCommand(createGenerateCommand3());
5441
5749
  return command;
5442
5750
  }
5443
5751
 
5444
5752
  // src/commands/predict.ts
5445
- import { Command as Command50 } from "commander";
5753
+ init_dist();
5754
+ import { Command as Command52 } from "commander";
5446
5755
  import chalk6 from "chalk";
5447
5756
  var CATEGORY_ORDER = [
5448
5757
  "circular-deps",
@@ -5548,7 +5857,7 @@ function handlePredictError(err, mode) {
5548
5857
  process.exit(ExitCode.ERROR);
5549
5858
  }
5550
5859
  function createPredictCommand() {
5551
- const command = new Command50("predict").description("Predict which architectural constraints will break and when").option("--category <name>", "Filter to a single metric category").option("--no-roadmap", "Baseline only \u2014 skip roadmap spec impact").option("--horizon <weeks>", "Forecast horizon in weeks (default: 12)", "12").action(async (opts, cmd) => {
5860
+ const command = new Command52("predict").description("Predict which architectural constraints will break and when").option("--category <name>", "Filter to a single metric category").option("--no-roadmap", "Baseline only \u2014 skip roadmap spec impact").option("--horizon <weeks>", "Forecast horizon in weeks (default: 12)", "12").action(async (opts, cmd) => {
5552
5861
  const globalOpts = cmd.optsWithGlobals();
5553
5862
  const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
5554
5863
  try {
@@ -5570,8 +5879,137 @@ function createPredictCommand() {
5570
5879
  return command;
5571
5880
  }
5572
5881
 
5882
+ // src/commands/publish-analyses.ts
5883
+ import * as fs25 from "fs";
5884
+ import * as path42 from "path";
5885
+ import { Command as Command53 } from "commander";
5886
+ init_dist();
5887
+ import {
5888
+ renderAnalysisComment,
5889
+ loadPublishedIndex,
5890
+ savePublishedIndex
5891
+ } from "@harness-engineering/orchestrator";
5892
+ function bootstrapTrackerCommand(opts, verb) {
5893
+ const projectPath = path42.resolve(opts.dir);
5894
+ const trackerConfig = loadTrackerSyncConfig(projectPath);
5895
+ if (!trackerConfig) {
5896
+ logger.error(`No tracker config found in harness.config.json. Cannot ${verb}.`);
5897
+ return null;
5898
+ }
5899
+ if (trackerConfig.kind !== "github") {
5900
+ logger.error(
5901
+ `${verb} currently only supports 'github' tracker kind. Found: ${String(trackerConfig.kind)}`
5902
+ );
5903
+ return null;
5904
+ }
5905
+ const projectEnvPath = path42.join(projectPath, ".env");
5906
+ if (fs25.existsSync(projectEnvPath) && !process.env.GITHUB_TOKEN) {
5907
+ __require("dotenv").config({ path: projectEnvPath });
5908
+ }
5909
+ const token = process.env.GITHUB_TOKEN;
5910
+ if (!token) {
5911
+ logger.error("No GITHUB_TOKEN environment variable found.");
5912
+ return null;
5913
+ }
5914
+ return { token, projectPath, trackerConfig };
5915
+ }
5916
+ function buildNameToExternalIdMap(projectPath) {
5917
+ const roadmapFile = path42.join(projectPath, "docs", "roadmap.md");
5918
+ if (!fs25.existsSync(roadmapFile)) {
5919
+ logger.error("No docs/roadmap.md found. Cannot map issue hashes to external IDs.");
5920
+ return null;
5921
+ }
5922
+ const { parseRoadmap } = (init_dist(), __toCommonJS(dist_exports));
5923
+ const roadmapParsed = parseRoadmap(fs25.readFileSync(roadmapFile, "utf-8"));
5924
+ if (!roadmapParsed.ok) {
5925
+ logger.error("Failed to parse docs/roadmap.md");
5926
+ return null;
5927
+ }
5928
+ const map = /* @__PURE__ */ new Map();
5929
+ for (const milestone of roadmapParsed.value.milestones) {
5930
+ for (const feature of milestone.features) {
5931
+ if (feature.externalId) {
5932
+ map.set(feature.name.toLowerCase(), feature.externalId);
5933
+ }
5934
+ }
5935
+ }
5936
+ return map;
5937
+ }
5938
+ function resolveExternalId(record, nameToExternalId) {
5939
+ if (record.externalId) return record.externalId;
5940
+ for (const [featName, extId] of nameToExternalId) {
5941
+ const prefix = featName.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 20);
5942
+ if (record.identifier.startsWith(prefix)) return extId;
5943
+ }
5944
+ return null;
5945
+ }
5946
+ async function publishUnpublishedAnalyses(analyses, adapter, nameToExternalId, publishedIndex) {
5947
+ let publishedCount = 0;
5948
+ for (const record of analyses) {
5949
+ if (publishedIndex[record.issueId]) continue;
5950
+ const externalId = resolveExternalId(record, nameToExternalId);
5951
+ if (!externalId) {
5952
+ logger.dim(`Skipping ${record.identifier}: could not resolve externalId from roadmap`);
5953
+ continue;
5954
+ }
5955
+ logger.info(`Publishing analysis for ${record.identifier} to ${externalId}...`);
5956
+ const result = await adapter.addComment(externalId, renderAnalysisComment(record));
5957
+ if (result.ok) {
5958
+ publishedIndex[record.issueId] = (/* @__PURE__ */ new Date()).toISOString();
5959
+ publishedCount++;
5960
+ } else {
5961
+ logger.error(`Failed to publish ${record.identifier}: ${result.error.message}`);
5962
+ }
5963
+ }
5964
+ return publishedCount;
5965
+ }
5966
+ async function runPublishAnalyses(opts) {
5967
+ const bootstrap = bootstrapTrackerCommand(opts, "publish");
5968
+ if (!bootstrap) return process.exit(1);
5969
+ const { token, projectPath, trackerConfig } = bootstrap;
5970
+ const nameToExternalId = buildNameToExternalIdMap(projectPath);
5971
+ if (!nameToExternalId) return process.exit(1);
5972
+ const { AnalysisArchive } = await import("@harness-engineering/orchestrator");
5973
+ const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-WCSJHQPK.js");
5974
+ const archive = new AnalysisArchive(path42.join(projectPath, ".harness", "analyses"));
5975
+ const analyses = await archive.list();
5976
+ if (analyses.length === 0) {
5977
+ logger.info("No analyses found to publish.");
5978
+ return;
5979
+ }
5980
+ const publishedIndex = loadPublishedIndex(projectPath);
5981
+ const adapter = new GitHubIssuesSyncAdapter2({ token, config: trackerConfig });
5982
+ const publishedCount = await publishUnpublishedAnalyses(
5983
+ analyses,
5984
+ adapter,
5985
+ nameToExternalId,
5986
+ publishedIndex
5987
+ );
5988
+ if (publishedCount > 0) {
5989
+ savePublishedIndex(projectPath, publishedIndex);
5990
+ logger.success(`Successfully published ${publishedCount} analyses.`);
5991
+ } else {
5992
+ logger.info("All analyses are already up to date on external tracker.");
5993
+ }
5994
+ }
5995
+ function createPublishAnalysesCommand() {
5996
+ const command = new Command53("publish-analyses").description(
5997
+ "Publishes locally generated intelligence analyses to the external issue tracker (e.g., GitHub)"
5998
+ ).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
5999
+ try {
6000
+ await runPublishAnalyses(opts);
6001
+ } catch (err) {
6002
+ logger.error(
6003
+ `Error publishing analyses: ${err instanceof Error ? err.message : String(err)}`
6004
+ );
6005
+ process.exit(1);
6006
+ }
6007
+ });
6008
+ return command;
6009
+ }
6010
+
5573
6011
  // src/commands/recommend.ts
5574
- import { Command as Command51 } from "commander";
6012
+ import { Command as Command54 } from "commander";
5575
6013
  import chalk7 from "chalk";
5576
6014
  async function resolveSnapshot(cwd, noCache) {
5577
6015
  if (!noCache) {
@@ -5635,7 +6073,7 @@ function printRecommendations(result) {
5635
6073
  console.log("");
5636
6074
  }
5637
6075
  function createRecommendCommand() {
5638
- const command = new Command51("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) => {
6076
+ const command = new Command54("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) => {
5639
6077
  const globalOpts = cmd.optsWithGlobals();
5640
6078
  const mode = globalOpts.json ? OutputMode.JSON : OutputMode.TEXT;
5641
6079
  try {
@@ -5671,9 +6109,10 @@ function createRecommendCommand() {
5671
6109
  }
5672
6110
 
5673
6111
  // src/commands/scan-config.ts
5674
- import { Command as Command52 } from "commander";
5675
- import { existsSync as existsSync21, readFileSync as readFileSync11, writeFileSync as writeFileSync12 } from "fs";
5676
- import { join as join31, relative as relative2 } from "path";
6112
+ init_dist();
6113
+ import { Command as Command55 } from "commander";
6114
+ import { existsSync as existsSync22, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
6115
+ import { join as join30, relative as relative2 } from "path";
5677
6116
  var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
5678
6117
  function stripHighSeverityPatterns(content, injectionFindings) {
5679
6118
  const highLines = /* @__PURE__ */ new Set();
@@ -5706,10 +6145,10 @@ function applyFix(filePath, targetDir, content, injectionFindings) {
5706
6145
  }
5707
6146
  }
5708
6147
  function scanSingleFile(filePath, targetDir, scanner, options) {
5709
- if (!existsSync21(filePath)) return null;
6148
+ if (!existsSync22(filePath)) return null;
5710
6149
  let content;
5711
6150
  try {
5712
- content = readFileSync11(filePath, "utf8");
6151
+ content = readFileSync14(filePath, "utf8");
5713
6152
  } catch {
5714
6153
  return null;
5715
6154
  }
@@ -5730,7 +6169,7 @@ async function runScanConfig(targetDir, options) {
5730
6169
  const scanner = new SecurityScanner(parseSecurityConfig({}));
5731
6170
  const results = [];
5732
6171
  for (const configFile of CONFIG_FILES) {
5733
- const result = scanSingleFile(join31(targetDir, configFile), targetDir, scanner, options);
6172
+ const result = scanSingleFile(join30(targetDir, configFile), targetDir, scanner, options);
5734
6173
  if (result) results.push(result);
5735
6174
  }
5736
6175
  return { exitCode: computeScanExitCode(results), results };
@@ -5760,7 +6199,7 @@ function formatTextOutput(result) {
5760
6199
  }
5761
6200
  }
5762
6201
  function createScanConfigCommand() {
5763
- const command = new Command52("scan-config").description(
6202
+ const command = new Command55("scan-config").description(
5764
6203
  "Scan CLAUDE.md, AGENTS.md, .gemini/settings.json, and skill.yaml for prompt injection patterns"
5765
6204
  ).option("--path <dir>", "Target directory to scan (default: cwd)").option("--fix", "Strip high-severity patterns from files in-place").action(async (opts, cmd) => {
5766
6205
  const globalOpts = cmd.optsWithGlobals();
@@ -5777,24 +6216,24 @@ function createScanConfigCommand() {
5777
6216
  }
5778
6217
 
5779
6218
  // src/commands/setup.ts
5780
- import { Command as Command53 } from "commander";
5781
- import * as fs24 from "fs";
6219
+ import { Command as Command56 } from "commander";
6220
+ import * as fs28 from "fs";
5782
6221
  import * as os7 from "os";
5783
- import * as path42 from "path";
5784
- import chalk8 from "chalk";
6222
+ import * as path45 from "path";
6223
+ import chalk9 from "chalk";
5785
6224
 
5786
6225
  // src/utils/first-run.ts
5787
- import * as fs23 from "fs";
6226
+ import * as fs26 from "fs";
5788
6227
  import * as os6 from "os";
5789
- import * as path41 from "path";
5790
- var HARNESS_DIR = path41.join(os6.homedir(), ".harness");
5791
- var MARKER_FILE = path41.join(HARNESS_DIR, ".setup-complete");
6228
+ import * as path43 from "path";
6229
+ var HARNESS_DIR = path43.join(os6.homedir(), ".harness");
6230
+ var MARKER_FILE = path43.join(HARNESS_DIR, ".setup-complete");
5792
6231
  function isFirstRun() {
5793
- return !fs23.existsSync(MARKER_FILE);
6232
+ return !fs26.existsSync(MARKER_FILE);
5794
6233
  }
5795
6234
  function markSetupComplete() {
5796
- fs23.mkdirSync(HARNESS_DIR, { recursive: true });
5797
- fs23.writeFileSync(MARKER_FILE, "", "utf-8");
6235
+ fs26.mkdirSync(HARNESS_DIR, { recursive: true });
6236
+ fs26.writeFileSync(MARKER_FILE, "", "utf-8");
5798
6237
  }
5799
6238
  function printFirstRunWelcome() {
5800
6239
  try {
@@ -5806,6 +6245,119 @@ function printFirstRunWelcome() {
5806
6245
  }
5807
6246
  }
5808
6247
 
6248
+ // src/commands/telemetry-wizard.ts
6249
+ import * as fs27 from "fs";
6250
+ import * as path44 from "path";
6251
+ import readline from "readline";
6252
+ import chalk8 from "chalk";
6253
+ function prompt(question) {
6254
+ const rl = readline.createInterface({
6255
+ input: process.stdin,
6256
+ output: process.stdout
6257
+ });
6258
+ return new Promise((resolve35) => {
6259
+ rl.question(question, (answer) => {
6260
+ rl.close();
6261
+ resolve35(answer.trim().toLowerCase());
6262
+ });
6263
+ });
6264
+ }
6265
+ function isNo(answer) {
6266
+ return answer === "n" || answer === "no";
6267
+ }
6268
+ function isTelemetryConfigured(cwd) {
6269
+ const configPath = path44.join(cwd, "harness.config.json");
6270
+ try {
6271
+ const raw = JSON.parse(fs27.readFileSync(configPath, "utf-8"));
6272
+ return raw.telemetry !== void 0 && raw.adoption !== void 0;
6273
+ } catch {
6274
+ return false;
6275
+ }
6276
+ }
6277
+ function writeTelemetryConfig(cwd, result) {
6278
+ const configPath = path44.join(cwd, "harness.config.json");
6279
+ try {
6280
+ const raw = JSON.parse(fs27.readFileSync(configPath, "utf-8"));
6281
+ raw.telemetry = { enabled: result.telemetryEnabled };
6282
+ raw.adoption = { enabled: result.adoptionEnabled };
6283
+ fs27.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
6284
+ } catch (err) {
6285
+ console.warn(
6286
+ `\u26A0 Could not update ${configPath}: ${err instanceof Error ? err.message : String(err)}`
6287
+ );
6288
+ }
6289
+ const hasIdentity = result.identity.project || result.identity.team || result.identity.alias;
6290
+ if (hasIdentity) {
6291
+ const harnessDir = path44.join(cwd, ".harness");
6292
+ fs27.mkdirSync(harnessDir, { recursive: true });
6293
+ const telemetryFile = path44.join(harnessDir, "telemetry.json");
6294
+ fs27.writeFileSync(telemetryFile, JSON.stringify({ identity: result.identity }, null, 2) + "\n");
6295
+ }
6296
+ }
6297
+ async function promptIdentity() {
6298
+ console.log(
6299
+ ` ${chalk8.cyan("Identity")} (optional) \u2014 tag telemetry with project/team/alias for filtering.`
6300
+ );
6301
+ console.log(" Leave blank to keep anonymous.");
6302
+ const answer = await prompt(" Set identity fields? (y/N) ");
6303
+ const identity = {};
6304
+ if (answer === "y" || answer === "yes") {
6305
+ const projectName = await prompt(" Project name: ");
6306
+ if (projectName) identity.project = projectName;
6307
+ const teamName = await prompt(" Team name: ");
6308
+ if (teamName) identity.team = teamName;
6309
+ const alias = await prompt(" Alias: ");
6310
+ if (alias) identity.alias = alias;
6311
+ }
6312
+ return identity;
6313
+ }
6314
+ async function runTelemetryWizard() {
6315
+ if (!process.stdin.isTTY) return null;
6316
+ console.log("");
6317
+ console.log(` ${chalk8.bold("Telemetry Configuration")}`);
6318
+ console.log("");
6319
+ console.log(" Harness can collect anonymous usage data to help improve the tool.");
6320
+ console.log(" You can change these settings anytime in harness.config.json.");
6321
+ console.log("");
6322
+ console.log(
6323
+ ` ${chalk8.cyan("Anonymous telemetry")} \u2014 error rates, command usage, performance metrics.`
6324
+ );
6325
+ console.log(" No code, file contents, or personally identifiable info is sent.");
6326
+ const telemetryAnswer = await prompt(" Enable anonymous telemetry? (Y/n) ");
6327
+ const telemetryEnabled = !isNo(telemetryAnswer);
6328
+ console.log("");
6329
+ console.log(
6330
+ ` ${chalk8.cyan("Adoption tracking")} \u2014 which skills are used, how often, and success rates.`
6331
+ );
6332
+ console.log(" Stored locally in .harness/adoption/. Never sent externally.");
6333
+ const adoptionAnswer = await prompt(" Enable local adoption tracking? (Y/n) ");
6334
+ const adoptionEnabled = !isNo(adoptionAnswer);
6335
+ console.log("");
6336
+ const identity = await promptIdentity();
6337
+ return { telemetryEnabled, adoptionEnabled, identity };
6338
+ }
6339
+ async function ensureTelemetryConfigured(cwd) {
6340
+ const configPath = path44.join(cwd, "harness.config.json");
6341
+ if (!fs27.existsSync(configPath)) {
6342
+ return { status: "warn", message: "Not a harness project \u2014 skipped telemetry configuration" };
6343
+ }
6344
+ if (isTelemetryConfigured(cwd)) {
6345
+ return { status: "pass", message: "Telemetry already configured" };
6346
+ }
6347
+ const result = await runTelemetryWizard();
6348
+ if (!result) {
6349
+ return { status: "warn", message: "Non-interactive mode \u2014 skipped telemetry configuration" };
6350
+ }
6351
+ writeTelemetryConfig(cwd, result);
6352
+ const parts = [];
6353
+ parts.push(`telemetry ${result.telemetryEnabled ? "enabled" : "disabled"}`);
6354
+ parts.push(`adoption ${result.adoptionEnabled ? "enabled" : "disabled"}`);
6355
+ if (result.identity.project || result.identity.team || result.identity.alias) {
6356
+ parts.push("identity set");
6357
+ }
6358
+ return { status: "pass", message: `Telemetry configured: ${parts.join(", ")}` };
6359
+ }
6360
+
5809
6361
  // src/commands/setup.ts
5810
6362
  function checkNodeVersion3() {
5811
6363
  const result = checkNodeVersion();
@@ -5832,7 +6384,7 @@ function runSlashCommandGeneration() {
5832
6384
  }
5833
6385
  }
5834
6386
  function detectClient(dirName) {
5835
- return fs24.existsSync(path42.join(os7.homedir(), dirName));
6387
+ return fs28.existsSync(path45.join(os7.homedir(), dirName));
5836
6388
  }
5837
6389
  async function runMcpSetup(cwd) {
5838
6390
  const results = [];
@@ -5869,12 +6421,12 @@ async function runMcpSetup(cwd) {
5869
6421
  return results;
5870
6422
  }
5871
6423
  function formatStep(result) {
5872
- const icon = result.status === "pass" ? chalk8.green("\u2713") : result.status === "warn" ? chalk8.yellow("\u26A0") : chalk8.red("\u2717");
6424
+ const icon = result.status === "pass" ? chalk9.green("\u2713") : result.status === "warn" ? chalk9.yellow("\u26A0") : chalk9.red("\u2717");
5873
6425
  return ` ${icon} ${result.message}`;
5874
6426
  }
5875
6427
  function configureTier0Integrations(cwd) {
5876
6428
  try {
5877
- const mcpPath = path42.join(cwd, ".mcp.json");
6429
+ const mcpPath = path45.join(cwd, ".mcp.json");
5878
6430
  const config = readMcpConfig(mcpPath);
5879
6431
  const tier0 = INTEGRATION_REGISTRY.filter((i) => i.tier === 0);
5880
6432
  const added = [];
@@ -5883,9 +6435,9 @@ function configureTier0Integrations(cwd) {
5883
6435
  writeMcpEntry(mcpPath, integration.name, integration.mcpConfig);
5884
6436
  added.push(integration.displayName);
5885
6437
  }
5886
- const geminiDir = path42.join(cwd, ".gemini");
5887
- if (fs24.existsSync(geminiDir)) {
5888
- const geminiPath = path42.join(geminiDir, "settings.json");
6438
+ const geminiDir = path45.join(cwd, ".gemini");
6439
+ if (fs28.existsSync(geminiDir)) {
6440
+ const geminiPath = path45.join(geminiDir, "settings.json");
5889
6441
  const geminiConfig = readMcpConfig(geminiPath);
5890
6442
  for (const integration of tier0) {
5891
6443
  if (!geminiConfig.mcpServers[integration.name]) {
@@ -5906,14 +6458,14 @@ function configureTier0Integrations(cwd) {
5906
6458
  }
5907
6459
  }
5908
6460
  function ensureHooks(cwd) {
5909
- const configPath = path42.join(cwd, "harness.config.json");
5910
- if (!fs24.existsSync(configPath)) {
6461
+ const configPath = path45.join(cwd, "harness.config.json");
6462
+ if (!fs28.existsSync(configPath)) {
5911
6463
  return { status: "warn", message: "Not a harness project \u2014 skipped hook installation" };
5912
6464
  }
5913
6465
  let profile = "standard";
5914
- const profilePath = path42.join(cwd, ".harness", "hooks", "profile.json");
6466
+ const profilePath = path45.join(cwd, ".harness", "hooks", "profile.json");
5915
6467
  try {
5916
- const data = JSON.parse(fs24.readFileSync(profilePath, "utf-8"));
6468
+ const data = JSON.parse(fs28.readFileSync(profilePath, "utf-8"));
5917
6469
  if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
5918
6470
  profile = data.profile;
5919
6471
  }
@@ -5932,7 +6484,7 @@ function ensureHooks(cwd) {
5932
6484
  }
5933
6485
  async function runInitialGraphScan(cwd) {
5934
6486
  try {
5935
- const { runScan: runScan2 } = await import("./scan-U67OKDRS.js");
6487
+ const { runScan: runScan2 } = await import("./scan-MPJ6JHUY.js");
5936
6488
  const result = await runScan2(cwd);
5937
6489
  return {
5938
6490
  status: "pass",
@@ -5958,6 +6510,8 @@ async function runSetup(cwd) {
5958
6510
  steps.push(tier0Result);
5959
6511
  const hooksResult = ensureHooks(cwd);
5960
6512
  steps.push(hooksResult);
6513
+ const telemetryResult = await ensureTelemetryConfigured(cwd);
6514
+ steps.push(telemetryResult);
5961
6515
  const graphResult = await runInitialGraphScan(cwd);
5962
6516
  steps.push(graphResult);
5963
6517
  const success = steps.every((s) => s.status !== "fail");
@@ -5967,10 +6521,10 @@ async function runSetup(cwd) {
5967
6521
  return { steps, success };
5968
6522
  }
5969
6523
  function createSetupCommand() {
5970
- return new Command53("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
6524
+ return new Command56("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
5971
6525
  const cwd = process.cwd();
5972
6526
  console.log("");
5973
- console.log(` ${chalk8.bold("harness setup")}`);
6527
+ console.log(` ${chalk9.bold("harness setup")}`);
5974
6528
  console.log("");
5975
6529
  const { steps, success } = await runSetup(cwd);
5976
6530
  for (const step of steps) {
@@ -5989,15 +6543,16 @@ function createSetupCommand() {
5989
6543
  }
5990
6544
 
5991
6545
  // src/commands/share.ts
5992
- import { Command as Command54 } from "commander";
5993
- import * as fs25 from "fs";
5994
- import * as path43 from "path";
6546
+ init_dist();
6547
+ import { Command as Command57 } from "commander";
6548
+ import * as fs29 from "fs";
6549
+ import * as path46 from "path";
5995
6550
  import { parse as parseYaml } from "yaml";
5996
6551
  var MANIFEST_FILENAME = "constraints.yaml";
5997
6552
  async function runShareAction(projectPath, options) {
5998
- const rootDir = path43.resolve(projectPath);
5999
- const manifestPath = path43.join(rootDir, MANIFEST_FILENAME);
6000
- if (!fs25.existsSync(manifestPath)) {
6553
+ const rootDir = path46.resolve(projectPath);
6554
+ const manifestPath = path46.join(rootDir, MANIFEST_FILENAME);
6555
+ if (!fs29.existsSync(manifestPath)) {
6001
6556
  logger.error(
6002
6557
  `No ${MANIFEST_FILENAME} found at ${manifestPath}.
6003
6558
  Create a constraints.yaml in your project root to define what to share.`
@@ -6006,7 +6561,7 @@ Create a constraints.yaml in your project root to define what to share.`
6006
6561
  }
6007
6562
  let parsed;
6008
6563
  try {
6009
- const raw = fs25.readFileSync(manifestPath, "utf-8");
6564
+ const raw = fs29.readFileSync(manifestPath, "utf-8");
6010
6565
  parsed = parseYaml(raw);
6011
6566
  } catch (err) {
6012
6567
  logger.error(
@@ -6020,7 +6575,7 @@ Create a constraints.yaml in your project root to define what to share.`
6020
6575
  process.exit(1);
6021
6576
  }
6022
6577
  const manifest = manifestResult.value;
6023
- const configResult = resolveConfig(path43.join(rootDir, "harness.config.json"));
6578
+ const configResult = resolveConfig(path46.join(rootDir, "harness.config.json"));
6024
6579
  if (!configResult.ok) {
6025
6580
  logger.error(configResult.error.message);
6026
6581
  process.exit(1);
@@ -6038,8 +6593,8 @@ Create a constraints.yaml in your project root to define what to share.`
6038
6593
  );
6039
6594
  process.exit(1);
6040
6595
  }
6041
- const outputDir = path43.resolve(options.output);
6042
- const outputPath = path43.join(outputDir, `${manifest.name}.harness-constraints.json`);
6596
+ const outputDir = path46.resolve(options.output);
6597
+ const outputPath = path46.join(outputDir, `${manifest.name}.harness-constraints.json`);
6043
6598
  const writeResult = await writeConfig(outputPath, bundle);
6044
6599
  if (!writeResult.ok) {
6045
6600
  logger.error(`Failed to write bundle: ${writeResult.error.message}`);
@@ -6048,28 +6603,28 @@ Create a constraints.yaml in your project root to define what to share.`
6048
6603
  logger.success(`Bundle written to ${outputPath}`);
6049
6604
  }
6050
6605
  function createShareCommand() {
6051
- return new Command54("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) => {
6606
+ return new Command57("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) => {
6052
6607
  await runShareAction(projectPath, options);
6053
6608
  });
6054
6609
  }
6055
6610
 
6056
6611
  // src/commands/skill/index.ts
6057
- import { Command as Command62 } from "commander";
6612
+ import { Command as Command65 } from "commander";
6058
6613
 
6059
6614
  // src/commands/skill/list.ts
6060
- import { Command as Command55 } from "commander";
6061
- import * as fs26 from "fs";
6062
- import * as path44 from "path";
6615
+ import { Command as Command58 } from "commander";
6616
+ import * as fs30 from "fs";
6617
+ import * as path47 from "path";
6063
6618
  import { parse } from "yaml";
6064
6619
  function scanDirectory(dirPath, source) {
6065
- if (!fs26.existsSync(dirPath)) return [];
6066
- const entries = fs26.readdirSync(dirPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
6620
+ if (!fs30.existsSync(dirPath)) return [];
6621
+ const entries = fs30.readdirSync(dirPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
6067
6622
  const skills = [];
6068
6623
  for (const name of entries) {
6069
- const yamlPath = path44.join(dirPath, name, "skill.yaml");
6070
- if (!fs26.existsSync(yamlPath)) continue;
6624
+ const yamlPath = path47.join(dirPath, name, "skill.yaml");
6625
+ if (!fs30.existsSync(yamlPath)) continue;
6071
6626
  try {
6072
- const raw = fs26.readFileSync(yamlPath, "utf-8");
6627
+ const raw = fs30.readFileSync(yamlPath, "utf-8");
6073
6628
  const parsed = parse(raw);
6074
6629
  const result = SkillMetadataSchema.safeParse(parsed);
6075
6630
  if (result.success) {
@@ -6087,10 +6642,10 @@ function scanDirectory(dirPath, source) {
6087
6642
  }
6088
6643
  function collectCommunitySkills(seen, allSkills) {
6089
6644
  const globalDir = resolveGlobalSkillsDir();
6090
- const skillsDir = path44.dirname(globalDir);
6091
- const communityBase = path44.join(skillsDir, "community");
6092
- const communityPlatformDir = path44.join(communityBase, "claude-code");
6093
- const lockfilePath = path44.join(communityBase, "skills-lock.json");
6645
+ const skillsDir = path47.dirname(globalDir);
6646
+ const communityBase = path47.join(skillsDir, "community");
6647
+ const communityPlatformDir = path47.join(communityBase, "claude-code");
6648
+ const lockfilePath = path47.join(communityBase, "skills-lock.json");
6094
6649
  const lockfile = readLockfile2(lockfilePath);
6095
6650
  const communitySkills = scanDirectory(communityPlatformDir, "community");
6096
6651
  for (const skill of communitySkills) {
@@ -6160,7 +6715,7 @@ function printSkillsVerbose(skills) {
6160
6715
  for (const s of skills) printSkillEntry(s);
6161
6716
  }
6162
6717
  function createListCommand3() {
6163
- return new Command55("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) => {
6718
+ return new Command58("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) => {
6164
6719
  const globalOpts = cmd.optsWithGlobals();
6165
6720
  const skills = collectSkills({ filter: resolveFilter(opts) });
6166
6721
  if (globalOpts.json) {
@@ -6175,9 +6730,9 @@ function createListCommand3() {
6175
6730
  }
6176
6731
 
6177
6732
  // src/commands/skill/run.ts
6178
- import { Command as Command56 } from "commander";
6179
- import * as fs27 from "fs";
6180
- import * as path45 from "path";
6733
+ import { Command as Command59 } from "commander";
6734
+ import * as fs31 from "fs";
6735
+ import * as path48 from "path";
6181
6736
  import { parse as parse2 } from "yaml";
6182
6737
 
6183
6738
  // src/skill/complexity.ts
@@ -6273,10 +6828,10 @@ ${options.principles}`);
6273
6828
 
6274
6829
  // src/commands/skill/run.ts
6275
6830
  function loadSkillMetadata(skillDir) {
6276
- const yamlPath = path45.join(skillDir, "skill.yaml");
6277
- if (!fs27.existsSync(yamlPath)) return null;
6831
+ const yamlPath = path48.join(skillDir, "skill.yaml");
6832
+ if (!fs31.existsSync(yamlPath)) return null;
6278
6833
  try {
6279
- const result = SkillMetadataSchema.safeParse(parse2(fs27.readFileSync(yamlPath, "utf-8")));
6834
+ const result = SkillMetadataSchema.safeParse(parse2(fs31.readFileSync(yamlPath, "utf-8")));
6280
6835
  return result.success ? result.data : null;
6281
6836
  } catch {
6282
6837
  return null;
@@ -6288,22 +6843,22 @@ function resolveComplexity(metadata, requested, projectPath) {
6288
6843
  return requested;
6289
6844
  }
6290
6845
  function loadPrinciples(projectPath) {
6291
- const principlesPath = path45.join(projectPath, "docs", "principles.md");
6292
- return fs27.existsSync(principlesPath) ? fs27.readFileSync(principlesPath, "utf-8") : void 0;
6846
+ const principlesPath = path48.join(projectPath, "docs", "principles.md");
6847
+ return fs31.existsSync(principlesPath) ? fs31.readFileSync(principlesPath, "utf-8") : void 0;
6293
6848
  }
6294
6849
  function readMostRecentFileInDir(dirPath) {
6295
- const files = fs27.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs27.statSync(path45.join(dirPath, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
6296
- if (files.length > 0) return fs27.readFileSync(path45.join(dirPath, files[0].name), "utf-8");
6850
+ const files = fs31.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs31.statSync(path48.join(dirPath, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
6851
+ if (files.length > 0) return fs31.readFileSync(path48.join(dirPath, files[0].name), "utf-8");
6297
6852
  return void 0;
6298
6853
  }
6299
6854
  function loadPriorState(metadata, projectPath) {
6300
6855
  if (!metadata?.state.persistent || metadata.state.files.length === 0) return void 0;
6301
6856
  for (const stateFilePath of metadata.state.files) {
6302
- const fullPath = path45.join(projectPath, stateFilePath);
6303
- if (!fs27.existsSync(fullPath)) continue;
6304
- const stat = fs27.statSync(fullPath);
6857
+ const fullPath = path48.join(projectPath, stateFilePath);
6858
+ if (!fs31.existsSync(fullPath)) continue;
6859
+ const stat = fs31.statSync(fullPath);
6305
6860
  if (stat.isDirectory()) return readMostRecentFileInDir(fullPath);
6306
- return fs27.readFileSync(fullPath, "utf-8");
6861
+ return fs31.readFileSync(fullPath, "utf-8");
6307
6862
  }
6308
6863
  return void 0;
6309
6864
  }
@@ -6323,9 +6878,9 @@ function resolvePhaseState(metadata, projectPath, phase) {
6323
6878
  }
6324
6879
  function appendProjectState(content, metadata, projectPath, hasPathOpt) {
6325
6880
  if (!metadata?.state.persistent || !hasPathOpt) return content;
6326
- const stateFile = path45.join(projectPath, ".harness", "state.json");
6327
- if (!fs27.existsSync(stateFile)) return content;
6328
- const stateContent = fs27.readFileSync(stateFile, "utf-8");
6881
+ const stateFile = path48.join(projectPath, ".harness", "state.json");
6882
+ if (!fs31.existsSync(stateFile)) return content;
6883
+ const stateContent = fs31.readFileSync(stateFile, "utf-8");
6329
6884
  return content + `
6330
6885
 
6331
6886
  ---
@@ -6337,14 +6892,14 @@ ${stateContent}
6337
6892
  }
6338
6893
  async function runSkill(name, opts) {
6339
6894
  const skillsDir = resolveSkillsDir();
6340
- const skillDir = path45.join(skillsDir, name);
6341
- if (!fs27.existsSync(skillDir)) {
6895
+ const skillDir = path48.join(skillsDir, name);
6896
+ if (!fs31.existsSync(skillDir)) {
6342
6897
  logger.error(`Skill not found: ${name}`);
6343
6898
  process.exit(ExitCode.ERROR);
6344
6899
  return;
6345
6900
  }
6346
6901
  const metadata = loadSkillMetadata(skillDir);
6347
- const projectPath = opts.path ? path45.resolve(opts.path) : process.cwd();
6902
+ const projectPath = opts.path ? path48.resolve(opts.path) : process.cwd();
6348
6903
  const complexity = resolveComplexity(
6349
6904
  metadata,
6350
6905
  opts.complexity ?? "standard",
@@ -6371,14 +6926,14 @@ async function runSkill(name, opts) {
6371
6926
  ...stateWarning !== void 0 && { stateWarning },
6372
6927
  ...opts.party !== void 0 && { party: opts.party }
6373
6928
  });
6374
- const skillMdPath = path45.join(skillDir, "SKILL.md");
6375
- if (!fs27.existsSync(skillMdPath)) {
6929
+ const skillMdPath = path48.join(skillDir, "SKILL.md");
6930
+ if (!fs31.existsSync(skillMdPath)) {
6376
6931
  logger.error(`SKILL.md not found for skill: ${name}`);
6377
6932
  process.exit(ExitCode.ERROR);
6378
6933
  return;
6379
6934
  }
6380
6935
  const content = appendProjectState(
6381
- fs27.readFileSync(skillMdPath, "utf-8"),
6936
+ fs31.readFileSync(skillMdPath, "utf-8"),
6382
6937
  metadata,
6383
6938
  projectPath,
6384
6939
  !!opts.path
@@ -6387,13 +6942,13 @@ async function runSkill(name, opts) {
6387
6942
  process.exit(ExitCode.SUCCESS);
6388
6943
  }
6389
6944
  function createRunCommand2() {
6390
- return new Command56("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").action(async (name, opts) => runSkill(name, opts));
6945
+ return new Command59("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").action(async (name, opts) => runSkill(name, opts));
6391
6946
  }
6392
6947
 
6393
6948
  // src/commands/skill/validate.ts
6394
- import { Command as Command57 } from "commander";
6395
- import * as fs28 from "fs";
6396
- import * as path46 from "path";
6949
+ import { Command as Command60 } from "commander";
6950
+ import * as fs32 from "fs";
6951
+ import * as path49 from "path";
6397
6952
  import { parse as parse3 } from "yaml";
6398
6953
  var BEHAVIORAL_REQUIRED_SECTIONS = [
6399
6954
  "## When to Use",
@@ -6405,11 +6960,11 @@ var BEHAVIORAL_REQUIRED_SECTIONS = [
6405
6960
  ];
6406
6961
  var KNOWLEDGE_REQUIRED_SECTIONS = ["## Instructions"];
6407
6962
  function validateSkillMd(name, skillMdPath, skillType, errors) {
6408
- if (!fs28.existsSync(skillMdPath)) {
6963
+ if (!fs32.existsSync(skillMdPath)) {
6409
6964
  errors.push(`${name}: missing SKILL.md`);
6410
6965
  return;
6411
6966
  }
6412
- const mdContent = fs28.readFileSync(skillMdPath, "utf-8");
6967
+ const mdContent = fs32.readFileSync(skillMdPath, "utf-8");
6413
6968
  if (!mdContent.trim().startsWith("# ")) {
6414
6969
  errors.push(`${name}/SKILL.md: must start with an h1 heading`);
6415
6970
  }
@@ -6434,20 +6989,20 @@ function validateSkillMd(name, skillMdPath, skillType, errors) {
6434
6989
  }
6435
6990
  }
6436
6991
  function validateSkillEntry(name, skillsDir, errors) {
6437
- const skillDir = path46.join(skillsDir, name);
6438
- const yamlPath = path46.join(skillDir, "skill.yaml");
6439
- if (!fs28.existsSync(yamlPath)) {
6992
+ const skillDir = path49.join(skillsDir, name);
6993
+ const yamlPath = path49.join(skillDir, "skill.yaml");
6994
+ if (!fs32.existsSync(yamlPath)) {
6440
6995
  errors.push(`${name}: missing skill.yaml`);
6441
6996
  return false;
6442
6997
  }
6443
6998
  try {
6444
- const raw = fs28.readFileSync(yamlPath, "utf-8");
6999
+ const raw = fs32.readFileSync(yamlPath, "utf-8");
6445
7000
  const result = SkillMetadataSchema.safeParse(parse3(raw));
6446
7001
  if (!result.success) {
6447
7002
  errors.push(`${name}/skill.yaml: ${result.error.message}`);
6448
7003
  return false;
6449
7004
  }
6450
- validateSkillMd(name, path46.join(skillDir, "SKILL.md"), result.data.type, errors);
7005
+ validateSkillMd(name, path49.join(skillDir, "SKILL.md"), result.data.type, errors);
6451
7006
  return true;
6452
7007
  } catch (e) {
6453
7008
  errors.push(`${name}: parse error \u2014 ${e instanceof Error ? e.message : String(e)}`);
@@ -6455,15 +7010,15 @@ function validateSkillEntry(name, skillsDir, errors) {
6455
7010
  }
6456
7011
  }
6457
7012
  function createValidateCommand2() {
6458
- return new Command57("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
7013
+ return new Command60("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
6459
7014
  const globalOpts = cmd.optsWithGlobals();
6460
7015
  const skillsDir = resolveSkillsDir();
6461
- if (!fs28.existsSync(skillsDir)) {
7016
+ if (!fs32.existsSync(skillsDir)) {
6462
7017
  logger.info("No skills directory found.");
6463
7018
  process.exit(ExitCode.SUCCESS);
6464
7019
  return;
6465
7020
  }
6466
- const entries = fs28.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
7021
+ const entries = fs32.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
6467
7022
  const errors = [];
6468
7023
  let validated = 0;
6469
7024
  for (const name of entries) {
@@ -6485,24 +7040,24 @@ function createValidateCommand2() {
6485
7040
  }
6486
7041
 
6487
7042
  // src/commands/skill/info.ts
6488
- import { Command as Command58 } from "commander";
6489
- import * as fs29 from "fs";
6490
- import * as path47 from "path";
7043
+ import { Command as Command61 } from "commander";
7044
+ import * as fs33 from "fs";
7045
+ import * as path50 from "path";
6491
7046
  import { parse as parse4 } from "yaml";
6492
7047
  function loadSkillMetadata2(name) {
6493
7048
  const skillsDir = resolveSkillsDir();
6494
- const skillDir = path47.join(skillsDir, name);
6495
- if (!fs29.existsSync(skillDir)) {
7049
+ const skillDir = path50.join(skillsDir, name);
7050
+ if (!fs33.existsSync(skillDir)) {
6496
7051
  logger.error(`Skill not found: ${name}`);
6497
7052
  return { ok: false, exitCode: ExitCode.ERROR };
6498
7053
  }
6499
- const yamlPath = path47.join(skillDir, "skill.yaml");
6500
- if (!fs29.existsSync(yamlPath)) {
7054
+ const yamlPath = path50.join(skillDir, "skill.yaml");
7055
+ if (!fs33.existsSync(yamlPath)) {
6501
7056
  logger.error(`skill.yaml not found for skill: ${name}`);
6502
7057
  return { ok: false, exitCode: ExitCode.ERROR };
6503
7058
  }
6504
7059
  try {
6505
- const raw = fs29.readFileSync(yamlPath, "utf-8");
7060
+ const raw = fs33.readFileSync(yamlPath, "utf-8");
6506
7061
  const parsed = parse4(raw);
6507
7062
  const result = SkillMetadataSchema.safeParse(parsed);
6508
7063
  if (!result.success) {
@@ -6531,7 +7086,7 @@ function printSkillInfo(skill) {
6531
7086
  console.log(`Persistent: ${skill.state.persistent}`);
6532
7087
  }
6533
7088
  function createInfoCommand() {
6534
- return new Command58("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
7089
+ return new Command61("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
6535
7090
  const globalOpts = cmd.optsWithGlobals();
6536
7091
  const loaded = loadSkillMetadata2(name);
6537
7092
  if (!loaded.ok) {
@@ -6548,7 +7103,7 @@ function createInfoCommand() {
6548
7103
  }
6549
7104
 
6550
7105
  // src/commands/skill/search.ts
6551
- import { Command as Command59 } from "commander";
7106
+ import { Command as Command62 } from "commander";
6552
7107
  async function runSearch(query, opts) {
6553
7108
  const results = await searchNpmRegistry(query, opts.registry);
6554
7109
  return results.filter((r) => {
@@ -6593,15 +7148,15 @@ async function runSearchAction(query, opts, globalOpts) {
6593
7148
  }
6594
7149
  }
6595
7150
  function createSearchCommand() {
6596
- return new Command59("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) => {
7151
+ return new Command62("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) => {
6597
7152
  await runSearchAction(query, opts, cmd.optsWithGlobals());
6598
7153
  });
6599
7154
  }
6600
7155
 
6601
7156
  // src/commands/skill/create.ts
6602
- import { Command as Command60 } from "commander";
6603
- import * as path48 from "path";
6604
- import * as fs30 from "fs";
7157
+ import { Command as Command63 } from "commander";
7158
+ import * as path51 from "path";
7159
+ import * as fs34 from "fs";
6605
7160
  import YAML from "yaml";
6606
7161
  var KEBAB_CASE_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
6607
7162
  function buildReadme(name, description) {
@@ -6685,22 +7240,22 @@ function runCreate(name, opts) {
6685
7240
  if (!KEBAB_CASE_RE.test(name)) {
6686
7241
  throw new Error(`Invalid skill name "${name}". Must be kebab-case (e.g., my-skill).`);
6687
7242
  }
6688
- const baseDir = opts.outputDir ?? path48.join(process.cwd(), "agents", "skills", "claude-code");
6689
- const skillDir = path48.join(baseDir, name);
6690
- if (fs30.existsSync(skillDir)) {
7243
+ const baseDir = opts.outputDir ?? path51.join(process.cwd(), "agents", "skills", "claude-code");
7244
+ const skillDir = path51.join(baseDir, name);
7245
+ if (fs34.existsSync(skillDir)) {
6691
7246
  throw new Error(`Skill directory already exists: ${skillDir}`);
6692
7247
  }
6693
- fs30.mkdirSync(skillDir, { recursive: true });
7248
+ fs34.mkdirSync(skillDir, { recursive: true });
6694
7249
  const description = opts.description || `A community skill: ${name}`;
6695
7250
  const skillYaml = buildSkillYaml(name, opts);
6696
- const skillYamlPath = path48.join(skillDir, "skill.yaml");
6697
- fs30.writeFileSync(skillYamlPath, YAML.stringify(skillYaml));
7251
+ const skillYamlPath = path51.join(skillDir, "skill.yaml");
7252
+ fs34.writeFileSync(skillYamlPath, YAML.stringify(skillYaml));
6698
7253
  const skillMd = buildSkillMd(name, description);
6699
- const skillMdPath = path48.join(skillDir, "SKILL.md");
6700
- fs30.writeFileSync(skillMdPath, skillMd);
7254
+ const skillMdPath = path51.join(skillDir, "SKILL.md");
7255
+ fs34.writeFileSync(skillMdPath, skillMd);
6701
7256
  const readme = buildReadme(name, description);
6702
- const readmePath = path48.join(skillDir, "README.md");
6703
- fs30.writeFileSync(readmePath, readme);
7257
+ const readmePath = path51.join(skillDir, "README.md");
7258
+ fs34.writeFileSync(readmePath, readme);
6704
7259
  return {
6705
7260
  name,
6706
7261
  directory: skillDir,
@@ -6714,12 +7269,12 @@ function printCreateResult(name, result) {
6714
7269
  }
6715
7270
  logger.info(`
6716
7271
  Next steps:`);
6717
- logger.info(` 1. Edit ${path48.join(result.directory, "SKILL.md")} with your skill content`);
7272
+ logger.info(` 1. Edit ${path51.join(result.directory, "SKILL.md")} with your skill content`);
6718
7273
  logger.info(` 2. Run: harness skill validate ${name}`);
6719
7274
  logger.info(` 3. Run: harness skills publish`);
6720
7275
  }
6721
7276
  function createCreateCommand() {
6722
- return new Command60("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) => {
7277
+ return new Command63("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) => {
6723
7278
  const globalOpts = cmd.optsWithGlobals();
6724
7279
  try {
6725
7280
  const result = runCreate(name, {
@@ -6742,26 +7297,26 @@ function createCreateCommand() {
6742
7297
  }
6743
7298
 
6744
7299
  // src/commands/skill/publish.ts
6745
- import { Command as Command61 } from "commander";
6746
- import * as fs32 from "fs";
6747
- import * as path50 from "path";
7300
+ import { Command as Command64 } from "commander";
7301
+ import * as fs36 from "fs";
7302
+ import * as path53 from "path";
6748
7303
  import { execFileSync as execFileSync5 } from "child_process";
6749
7304
 
6750
7305
  // src/registry/validator.ts
6751
- import * as fs31 from "fs";
6752
- import * as path49 from "path";
7306
+ import * as fs35 from "fs";
7307
+ import * as path52 from "path";
6753
7308
  import { parse as parse5 } from "yaml";
6754
7309
  import semver4 from "semver";
6755
7310
  async function validateForPublish(skillDir, registryUrl) {
6756
7311
  const errors = [];
6757
- const skillYamlPath = path49.join(skillDir, "skill.yaml");
6758
- if (!fs31.existsSync(skillYamlPath)) {
7312
+ const skillYamlPath = path52.join(skillDir, "skill.yaml");
7313
+ if (!fs35.existsSync(skillYamlPath)) {
6759
7314
  errors.push("skill.yaml not found. Create one with: harness skill create <name>");
6760
7315
  return { valid: false, errors };
6761
7316
  }
6762
7317
  let skillMeta;
6763
7318
  try {
6764
- const raw = fs31.readFileSync(skillYamlPath, "utf-8");
7319
+ const raw = fs35.readFileSync(skillYamlPath, "utf-8");
6765
7320
  const parsed = parse5(raw);
6766
7321
  const result = SkillMetadataSchema.safeParse(parsed);
6767
7322
  if (!result.success) {
@@ -6783,11 +7338,11 @@ async function validateForPublish(skillDir, registryUrl) {
6783
7338
  if (!skillMeta.triggers || skillMeta.triggers.length === 0) {
6784
7339
  errors.push("At least one trigger is required. Add triggers to skill.yaml.");
6785
7340
  }
6786
- const skillMdPath = path49.join(skillDir, "SKILL.md");
6787
- if (!fs31.existsSync(skillMdPath)) {
7341
+ const skillMdPath = path52.join(skillDir, "SKILL.md");
7342
+ if (!fs35.existsSync(skillMdPath)) {
6788
7343
  errors.push("SKILL.md not found. Create it with content describing your skill.");
6789
7344
  } else {
6790
- const content = fs31.readFileSync(skillMdPath, "utf-8");
7345
+ const content = fs35.readFileSync(skillMdPath, "utf-8");
6791
7346
  if (!content.includes("## When to Use")) {
6792
7347
  errors.push('SKILL.md must contain a "## When to Use" section.');
6793
7348
  }
@@ -6867,11 +7422,11 @@ ${errorList}`);
6867
7422
  }
6868
7423
  const meta = validation.skillMeta;
6869
7424
  const pkg = derivePackageJson(meta);
6870
- const pkgPath = path50.join(skillDir, "package.json");
6871
- fs32.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
6872
- const readmePath = path50.join(skillDir, "README.md");
6873
- if (!fs32.existsSync(readmePath)) {
6874
- const skillMdContent = fs32.readFileSync(path50.join(skillDir, "SKILL.md"), "utf-8");
7425
+ const pkgPath = path53.join(skillDir, "package.json");
7426
+ fs36.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
7427
+ const readmePath = path53.join(skillDir, "README.md");
7428
+ if (!fs36.existsSync(readmePath)) {
7429
+ const skillMdContent = fs36.readFileSync(path53.join(skillDir, "SKILL.md"), "utf-8");
6875
7430
  const readme = `# ${pkg.name}
6876
7431
 
6877
7432
  ${meta.description}
@@ -6885,7 +7440,7 @@ harness install ${meta.name}
6885
7440
  ---
6886
7441
 
6887
7442
  ${skillMdContent}`;
6888
- fs32.writeFileSync(readmePath, readme);
7443
+ fs36.writeFileSync(readmePath, readme);
6889
7444
  }
6890
7445
  if (opts.dryRun) {
6891
7446
  return {
@@ -6911,7 +7466,7 @@ ${skillMdContent}`;
6911
7466
  };
6912
7467
  }
6913
7468
  function createPublishCommand() {
6914
- return new Command61("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) => {
7469
+ return new Command64("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) => {
6915
7470
  const globalOpts = cmd.optsWithGlobals();
6916
7471
  const skillDir = opts.dir || process.cwd();
6917
7472
  try {
@@ -6936,7 +7491,7 @@ function createPublishCommand() {
6936
7491
 
6937
7492
  // src/commands/skill/index.ts
6938
7493
  function createSkillCommand() {
6939
- const command = new Command62("skill").description("Skill management commands");
7494
+ const command = new Command65("skill").description("Skill management commands");
6940
7495
  command.addCommand(createListCommand3());
6941
7496
  command.addCommand(createRunCommand2());
6942
7497
  command.addCommand(createValidateCommand2());
@@ -6948,9 +7503,10 @@ function createSkillCommand() {
6948
7503
  }
6949
7504
 
6950
7505
  // src/commands/snapshot.ts
6951
- import { Command as Command63 } from "commander";
7506
+ init_dist();
7507
+ import { Command as Command66 } from "commander";
6952
7508
  import { execSync as execSync5 } from "child_process";
6953
- import chalk9 from "chalk";
7509
+ import chalk10 from "chalk";
6954
7510
  function getCommitHash3(cwd) {
6955
7511
  try {
6956
7512
  return execSync5("git rev-parse --short HEAD", { cwd, encoding: "utf-8" }).toString().trim();
@@ -6975,9 +7531,9 @@ function formatDelta(delta) {
6975
7531
  function directionSymbol(direction) {
6976
7532
  switch (direction) {
6977
7533
  case "improving":
6978
- return chalk9.green("improving");
7534
+ return chalk10.green("improving");
6979
7535
  case "declining":
6980
- return chalk9.red("declining");
7536
+ return chalk10.red("declining");
6981
7537
  case "stable":
6982
7538
  return "=";
6983
7539
  }
@@ -7130,7 +7686,7 @@ function registerListCommand(parent) {
7130
7686
  });
7131
7687
  }
7132
7688
  function createSnapshotCommand() {
7133
- const command = new Command63("snapshot").description("Architecture timeline snapshot commands");
7689
+ const command = new Command66("snapshot").description("Architecture timeline snapshot commands");
7134
7690
  registerCaptureCommand(command);
7135
7691
  registerTrendsCommand(command);
7136
7692
  registerListCommand(command);
@@ -7138,11 +7694,12 @@ function createSnapshotCommand() {
7138
7694
  }
7139
7695
 
7140
7696
  // src/commands/state/index.ts
7141
- import { Command as Command68 } from "commander";
7697
+ import { Command as Command71 } from "commander";
7142
7698
 
7143
7699
  // src/commands/state/show.ts
7144
- import { Command as Command64 } from "commander";
7145
- import * as path51 from "path";
7700
+ init_dist();
7701
+ import { Command as Command67 } from "commander";
7702
+ import * as path54 from "path";
7146
7703
  function printStateText(state, stream) {
7147
7704
  if (stream) console.log(`Stream: ${stream}`);
7148
7705
  console.log(`Schema Version: ${state.schemaVersion}`);
@@ -7166,9 +7723,9 @@ function printStateProgress(progress) {
7166
7723
  }
7167
7724
  }
7168
7725
  function createShowCommand() {
7169
- return new Command64("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
7726
+ return new Command67("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
7170
7727
  const globalOpts = cmd.optsWithGlobals();
7171
- const result = await loadState(path51.resolve(opts.path), opts.stream);
7728
+ const result = await loadState(path54.resolve(opts.path), opts.stream);
7172
7729
  if (!result.ok) {
7173
7730
  logger.error(result.error.message);
7174
7731
  process.exit(ExitCode.ERROR);
@@ -7183,10 +7740,11 @@ function createShowCommand() {
7183
7740
  }
7184
7741
 
7185
7742
  // src/commands/state/reset.ts
7186
- import { Command as Command65 } from "commander";
7187
- import * as fs33 from "fs";
7188
- import * as path52 from "path";
7189
- import * as readline from "readline";
7743
+ init_dist();
7744
+ import { Command as Command68 } from "commander";
7745
+ import * as fs37 from "fs";
7746
+ import * as path55 from "path";
7747
+ import * as readline2 from "readline";
7190
7748
  async function resolveStatePath(projectPath, stream) {
7191
7749
  if (stream) {
7192
7750
  const streamResult = await resolveStreamPath(projectPath, { stream });
@@ -7194,22 +7752,22 @@ async function resolveStatePath(projectPath, stream) {
7194
7752
  logger.error(streamResult.error.message);
7195
7753
  process.exit(ExitCode.ERROR);
7196
7754
  }
7197
- return path52.join(streamResult.value, "state.json");
7755
+ return path55.join(streamResult.value, "state.json");
7198
7756
  }
7199
- return path52.join(projectPath, ".harness", "state.json");
7757
+ return path55.join(projectPath, ".harness", "state.json");
7200
7758
  }
7201
7759
  async function confirmReset() {
7202
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
7203
- const answer = await new Promise((resolve32) => {
7204
- rl.question("Reset project state? This cannot be undone. [y/N] ", resolve32);
7760
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
7761
+ const answer = await new Promise((resolve35) => {
7762
+ rl.question("Reset project state? This cannot be undone. [y/N] ", resolve35);
7205
7763
  });
7206
7764
  rl.close();
7207
7765
  return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
7208
7766
  }
7209
7767
  async function runReset(opts) {
7210
- const projectPath = path52.resolve(opts.path);
7768
+ const projectPath = path55.resolve(opts.path);
7211
7769
  const statePath = await resolveStatePath(projectPath, opts.stream);
7212
- if (!fs33.existsSync(statePath)) {
7770
+ if (!fs37.existsSync(statePath)) {
7213
7771
  logger.info("No state file found. Nothing to reset.");
7214
7772
  process.exit(ExitCode.SUCCESS);
7215
7773
  }
@@ -7218,7 +7776,7 @@ async function runReset(opts) {
7218
7776
  process.exit(ExitCode.SUCCESS);
7219
7777
  }
7220
7778
  try {
7221
- fs33.unlinkSync(statePath);
7779
+ fs37.unlinkSync(statePath);
7222
7780
  logger.success("Project state reset.");
7223
7781
  } catch (e) {
7224
7782
  logger.error(`Failed to reset state: ${e instanceof Error ? e.message : String(e)}`);
@@ -7227,15 +7785,16 @@ async function runReset(opts) {
7227
7785
  process.exit(ExitCode.SUCCESS);
7228
7786
  }
7229
7787
  function createResetCommand() {
7230
- return new Command65("reset").description("Reset project state (deletes .harness/state.json)").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").option("--yes", "Skip confirmation prompt").action(async (opts) => runReset(opts));
7788
+ return new Command68("reset").description("Reset project state (deletes .harness/state.json)").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").option("--yes", "Skip confirmation prompt").action(async (opts) => runReset(opts));
7231
7789
  }
7232
7790
 
7233
7791
  // src/commands/state/learn.ts
7234
- import { Command as Command66 } from "commander";
7235
- import * as path53 from "path";
7792
+ init_dist();
7793
+ import { Command as Command69 } from "commander";
7794
+ import * as path56 from "path";
7236
7795
  function createLearnCommand() {
7237
- return new Command66("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) => {
7238
- const projectPath = path53.resolve(opts.path);
7796
+ return new Command69("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) => {
7797
+ const projectPath = path56.resolve(opts.path);
7239
7798
  const result = await appendLearning(projectPath, message, void 0, void 0, opts.stream);
7240
7799
  if (!result.ok) {
7241
7800
  logger.error(result.error.message);
@@ -7248,10 +7807,11 @@ function createLearnCommand() {
7248
7807
  }
7249
7808
 
7250
7809
  // src/commands/state/streams.ts
7251
- import { Command as Command67 } from "commander";
7252
- import * as path54 from "path";
7810
+ init_dist();
7811
+ import { Command as Command70 } from "commander";
7812
+ import * as path57 from "path";
7253
7813
  async function runListStreams(opts, globalOpts) {
7254
- const projectPath = path54.resolve(opts.path);
7814
+ const projectPath = path57.resolve(opts.path);
7255
7815
  const indexResult = await loadStreamIndex(projectPath);
7256
7816
  const result = await listStreams(projectPath);
7257
7817
  if (!result.ok) {
@@ -7272,7 +7832,7 @@ async function runListStreams(opts, globalOpts) {
7272
7832
  process.exit(ExitCode.SUCCESS);
7273
7833
  }
7274
7834
  async function runCreateStream(name, opts) {
7275
- const result = await createStream(path54.resolve(opts.path), name, opts.branch);
7835
+ const result = await createStream(path57.resolve(opts.path), name, opts.branch);
7276
7836
  if (!result.ok) {
7277
7837
  logger.error(result.error.message);
7278
7838
  process.exit(ExitCode.ERROR);
@@ -7281,7 +7841,7 @@ async function runCreateStream(name, opts) {
7281
7841
  process.exit(ExitCode.SUCCESS);
7282
7842
  }
7283
7843
  async function runArchiveStream(name, opts) {
7284
- const result = await archiveStream(path54.resolve(opts.path), name);
7844
+ const result = await archiveStream(path57.resolve(opts.path), name);
7285
7845
  if (!result.ok) {
7286
7846
  logger.error(result.error.message);
7287
7847
  process.exit(ExitCode.ERROR);
@@ -7290,7 +7850,7 @@ async function runArchiveStream(name, opts) {
7290
7850
  process.exit(ExitCode.SUCCESS);
7291
7851
  }
7292
7852
  async function runActivateStream(name, opts) {
7293
- const result = await setActiveStream(path54.resolve(opts.path), name);
7853
+ const result = await setActiveStream(path57.resolve(opts.path), name);
7294
7854
  if (!result.ok) {
7295
7855
  logger.error(result.error.message);
7296
7856
  process.exit(ExitCode.ERROR);
@@ -7299,7 +7859,7 @@ async function runActivateStream(name, opts) {
7299
7859
  process.exit(ExitCode.SUCCESS);
7300
7860
  }
7301
7861
  function createStreamsCommand() {
7302
- const command = new Command67("streams").description("Manage state streams");
7862
+ const command = new Command70("streams").description("Manage state streams");
7303
7863
  command.command("list").description("List all known streams").option("--path <path>", "Project root path", ".").action(async (opts, cmd) => runListStreams(opts, cmd.optsWithGlobals()));
7304
7864
  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));
7305
7865
  command.command("archive <name>").description("Archive a stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => runArchiveStream(name, opts));
@@ -7309,7 +7869,7 @@ function createStreamsCommand() {
7309
7869
 
7310
7870
  // src/commands/state/index.ts
7311
7871
  function createStateCommand() {
7312
- const command = new Command68("state").description("Project state management commands");
7872
+ const command = new Command71("state").description("Project state management commands");
7313
7873
  command.addCommand(createShowCommand());
7314
7874
  command.addCommand(createResetCommand());
7315
7875
  command.addCommand(createLearnCommand());
@@ -7317,8 +7877,154 @@ function createStateCommand() {
7317
7877
  return command;
7318
7878
  }
7319
7879
 
7880
+ // src/commands/sync-analyses.ts
7881
+ import * as fs38 from "fs";
7882
+ import * as path58 from "path";
7883
+ import { Command as Command72 } from "commander";
7884
+ init_dist();
7885
+ function isValidRecord(record) {
7886
+ return typeof record.issueId === "string" && !!record.issueId && typeof record.identifier === "string" && !!record.identifier && typeof record.analyzedAt === "string" && !/[/\\]/.test(record.issueId);
7887
+ }
7888
+ function extractAnalysisFromComments(comments) {
7889
+ const sorted = [...comments].sort(
7890
+ (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
7891
+ );
7892
+ for (const comment of sorted) {
7893
+ const fenceRegex = /```json\s*\r?\n([\s\S]*?)\r?\n```/g;
7894
+ let match;
7895
+ while ((match = fenceRegex.exec(comment.body)) !== null) {
7896
+ try {
7897
+ const parsed = JSON.parse(match[1]);
7898
+ if (parsed._harness_analysis !== true) continue;
7899
+ const { _harness_analysis, _version, ...record } = parsed;
7900
+ if (isValidRecord(record)) return record;
7901
+ } catch {
7902
+ continue;
7903
+ }
7904
+ }
7905
+ }
7906
+ return null;
7907
+ }
7908
+ function bootstrapTrackerCommand2(opts, verb) {
7909
+ const projectPath = path58.resolve(opts.dir);
7910
+ const trackerConfig = loadTrackerSyncConfig(projectPath);
7911
+ if (!trackerConfig) {
7912
+ logger.error(`No tracker config found in harness.config.json. Cannot ${verb}.`);
7913
+ return null;
7914
+ }
7915
+ if (trackerConfig.kind !== "github") {
7916
+ logger.error(
7917
+ `${verb} currently only supports 'github' tracker kind. Found: ${String(trackerConfig.kind)}`
7918
+ );
7919
+ return null;
7920
+ }
7921
+ const projectEnvPath = path58.join(projectPath, ".env");
7922
+ if (fs38.existsSync(projectEnvPath) && !process.env.GITHUB_TOKEN) {
7923
+ __require("dotenv").config({ path: projectEnvPath });
7924
+ }
7925
+ const token = process.env.GITHUB_TOKEN;
7926
+ if (!token) {
7927
+ logger.error("No GITHUB_TOKEN environment variable found.");
7928
+ return null;
7929
+ }
7930
+ return { token, projectPath, trackerConfig };
7931
+ }
7932
+ function loadRoadmapFeatures(projectPath) {
7933
+ const roadmapFile = path58.join(projectPath, "docs", "roadmap.md");
7934
+ if (!fs38.existsSync(roadmapFile)) {
7935
+ logger.error("No docs/roadmap.md found. Cannot discover features with externalIds.");
7936
+ return null;
7937
+ }
7938
+ const { parseRoadmap } = (init_dist(), __toCommonJS(dist_exports));
7939
+ const roadmapParsed = parseRoadmap(fs38.readFileSync(roadmapFile, "utf-8"));
7940
+ if (!roadmapParsed.ok) {
7941
+ logger.error("Failed to parse docs/roadmap.md");
7942
+ return null;
7943
+ }
7944
+ const features = [];
7945
+ for (const milestone of roadmapParsed.value.milestones) {
7946
+ for (const feature of milestone.features) {
7947
+ if (feature.externalId) {
7948
+ features.push({ name: feature.name, externalId: feature.externalId });
7949
+ }
7950
+ }
7951
+ }
7952
+ return features;
7953
+ }
7954
+ async function syncFeatureAnalyses(features, adapter, archive, publishedIndex) {
7955
+ let syncedCount = 0;
7956
+ let skippedCount = 0;
7957
+ let warnCount = 0;
7958
+ for (const { name, externalId } of features) {
7959
+ const commentsResult = await adapter.fetchComments(externalId);
7960
+ if (!commentsResult.ok) {
7961
+ logger.warn(
7962
+ `Failed to fetch comments for "${name}" (${externalId}): ${commentsResult.error.message}`
7963
+ );
7964
+ warnCount++;
7965
+ continue;
7966
+ }
7967
+ const record = extractAnalysisFromComments(commentsResult.value);
7968
+ if (!record) {
7969
+ skippedCount++;
7970
+ continue;
7971
+ }
7972
+ await archive.save(record);
7973
+ publishedIndex[record.issueId] = record.analyzedAt;
7974
+ syncedCount++;
7975
+ logger.info(`Synced analysis for "${name}" (${record.identifier})`);
7976
+ }
7977
+ return { syncedCount, skippedCount, warnCount };
7978
+ }
7979
+ async function runSyncAnalyses(opts) {
7980
+ const bootstrap = bootstrapTrackerCommand2(opts, "sync");
7981
+ if (!bootstrap) return process.exit(1);
7982
+ const { token, projectPath, trackerConfig } = bootstrap;
7983
+ const features = loadRoadmapFeatures(projectPath);
7984
+ if (!features) return process.exit(1);
7985
+ if (features.length === 0) {
7986
+ logger.info("No roadmap features have externalIds. Nothing to sync.");
7987
+ return;
7988
+ }
7989
+ const { AnalysisArchive, loadPublishedIndex: loadPublishedIndex2, savePublishedIndex: savePublishedIndex2 } = await import("@harness-engineering/orchestrator");
7990
+ const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-WCSJHQPK.js");
7991
+ const adapter = new GitHubIssuesSyncAdapter2({ token, config: trackerConfig });
7992
+ const archive = new AnalysisArchive(path58.join(projectPath, ".harness", "analyses"));
7993
+ const publishedIndex = loadPublishedIndex2(projectPath);
7994
+ const { syncedCount, skippedCount, warnCount } = await syncFeatureAnalyses(
7995
+ features,
7996
+ adapter,
7997
+ archive,
7998
+ publishedIndex
7999
+ );
8000
+ if (syncedCount > 0) {
8001
+ savePublishedIndex2(projectPath, publishedIndex);
8002
+ logger.success(
8003
+ `Synced ${syncedCount} analysis record(s). Skipped ${skippedCount} (no analysis). Warnings: ${warnCount}.`
8004
+ );
8005
+ } else {
8006
+ logger.info(
8007
+ `No new analyses found on tracker. Skipped ${skippedCount} feature(s) with no analysis comments.`
8008
+ );
8009
+ }
8010
+ }
8011
+ function createSyncAnalysesCommand() {
8012
+ const command = new Command72("sync-analyses").description(
8013
+ "Pull published intelligence analyses from the external issue tracker into the local .harness/analyses/ directory"
8014
+ ).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
8015
+ try {
8016
+ await runSyncAnalyses(opts);
8017
+ } catch (err) {
8018
+ logger.error(`Error syncing analyses: ${err instanceof Error ? err.message : String(err)}`);
8019
+ process.exit(1);
8020
+ }
8021
+ });
8022
+ return command;
8023
+ }
8024
+
7320
8025
  // src/commands/taint.ts
7321
- import { Command as Command69 } from "commander";
8026
+ init_dist();
8027
+ import { Command as Command73 } from "commander";
7322
8028
  function getProjectRoot() {
7323
8029
  return process.cwd();
7324
8030
  }
@@ -7390,27 +8096,28 @@ function registerStatusCommand(taint) {
7390
8096
  });
7391
8097
  }
7392
8098
  function createTaintCommand() {
7393
- const taint = new Command69("taint").description("Manage sentinel session taint state");
8099
+ const taint = new Command73("taint").description("Manage sentinel session taint state");
7394
8100
  registerClearCommand(taint);
7395
8101
  registerStatusCommand(taint);
7396
8102
  return taint;
7397
8103
  }
7398
8104
 
7399
8105
  // src/commands/telemetry/index.ts
7400
- import { Command as Command72 } from "commander";
8106
+ import { Command as Command76 } from "commander";
7401
8107
 
7402
8108
  // src/commands/telemetry/identify.ts
7403
- import { Command as Command70 } from "commander";
7404
- import * as fs34 from "fs";
7405
- import * as path55 from "path";
8109
+ init_dist();
8110
+ import { Command as Command74 } from "commander";
8111
+ import * as fs39 from "fs";
8112
+ import * as path59 from "path";
7406
8113
  function telemetryFilePath(cwd) {
7407
- return path55.join(cwd, ".harness", "telemetry.json");
8114
+ return path59.join(cwd, ".harness", "telemetry.json");
7408
8115
  }
7409
8116
  function writeTelemetryFile(cwd, data) {
7410
8117
  const filePath = telemetryFilePath(cwd);
7411
- const dir = path55.dirname(filePath);
7412
- fs34.mkdirSync(dir, { recursive: true });
7413
- fs34.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
8118
+ const dir = path59.dirname(filePath);
8119
+ fs39.mkdirSync(dir, { recursive: true });
8120
+ fs39.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
7414
8121
  }
7415
8122
  var IDENTITY_FIELDS = ["project", "team", "alias"];
7416
8123
  function applyIdentityFields(opts, identity) {
@@ -7424,7 +8131,7 @@ function printIdentity(identity) {
7424
8131
  }
7425
8132
  }
7426
8133
  function createIdentifyCommand() {
7427
- const cmd = new Command70("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) => {
8134
+ const cmd = new Command74("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) => {
7428
8135
  const cwd = process.cwd();
7429
8136
  if (opts.clear) {
7430
8137
  writeTelemetryFile(cwd, { identity: {} });
@@ -7448,7 +8155,8 @@ function createIdentifyCommand() {
7448
8155
  }
7449
8156
 
7450
8157
  // src/commands/telemetry/status.ts
7451
- import { Command as Command71 } from "commander";
8158
+ init_dist();
8159
+ import { Command as Command75 } from "commander";
7452
8160
  function gatherEnvOverrides() {
7453
8161
  const overrides = {};
7454
8162
  if (process.env.DO_NOT_TRACK) overrides.DO_NOT_TRACK = process.env.DO_NOT_TRACK;
@@ -7486,7 +8194,7 @@ function printHumanStatus(result) {
7486
8194
  }
7487
8195
  }
7488
8196
  function createStatusCommand() {
7489
- const cmd = new Command71("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
8197
+ const cmd = new Command75("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
7490
8198
  const cwd = process.cwd();
7491
8199
  const envOverrides = gatherEnvOverrides();
7492
8200
  const consent = resolveConsent(cwd, void 0);
@@ -7519,15 +8227,15 @@ function createStatusCommand() {
7519
8227
 
7520
8228
  // src/commands/telemetry/index.ts
7521
8229
  function createTelemetryCommand() {
7522
- const command = new Command72("telemetry").description("Telemetry identity and status management");
8230
+ const command = new Command76("telemetry").description("Telemetry identity and status management");
7523
8231
  command.addCommand(createIdentifyCommand());
7524
8232
  command.addCommand(createStatusCommand());
7525
8233
  return command;
7526
8234
  }
7527
8235
 
7528
8236
  // src/commands/traceability.ts
7529
- import { Command as Command73 } from "commander";
7530
- import chalk10 from "chalk";
8237
+ import { Command as Command77 } from "commander";
8238
+ import chalk11 from "chalk";
7531
8239
  function confidenceLabel(maxConfidence) {
7532
8240
  if (maxConfidence >= 0.8) return "explicit";
7533
8241
  if (maxConfidence > 0) return "inferred";
@@ -7536,13 +8244,13 @@ function confidenceLabel(maxConfidence) {
7536
8244
  function statusIcon(status) {
7537
8245
  switch (status) {
7538
8246
  case "full":
7539
- return chalk10.green("\u2713 full");
8247
+ return chalk11.green("\u2713 full");
7540
8248
  case "code-only":
7541
- return chalk10.yellow("\u25D0 code-only");
8249
+ return chalk11.yellow("\u25D0 code-only");
7542
8250
  case "test-only":
7543
- return chalk10.yellow("\u25D0 test-only");
8251
+ return chalk11.yellow("\u25D0 test-only");
7544
8252
  case "none":
7545
- return chalk10.red("\u2717 none");
8253
+ return chalk11.red("\u2717 none");
7546
8254
  default:
7547
8255
  return status;
7548
8256
  }
@@ -7584,14 +8292,14 @@ function handleEmptyResults(mode) {
7584
8292
  }
7585
8293
  function printResultTable(result, mode) {
7586
8294
  const specLabel = result.specPath || result.featureName || "Unknown";
7587
- console.log(` ${chalk10.cyan(specLabel)} ${chalk10.dim(`(${result.summary.total} requirements)`)}`);
8295
+ console.log(` ${chalk11.cyan(specLabel)} ${chalk11.dim(`(${result.summary.total} requirements)`)}`);
7588
8296
  console.log("");
7589
8297
  const numWidth = 4;
7590
8298
  const nameWidth = mode === OutputMode.VERBOSE ? 44 : 36;
7591
8299
  const codeWidth = 6;
7592
8300
  const testWidth = 7;
7593
8301
  const confWidth = 12;
7594
- const header = chalk10.dim(
8302
+ const header = chalk11.dim(
7595
8303
  ` ${pad("#", numWidth)}${pad("Requirement", nameWidth)}${pad("Code", codeWidth)}${pad("Tests", testWidth)}${pad("Confidence", confWidth)}Status`
7596
8304
  );
7597
8305
  console.log(header);
@@ -7620,10 +8328,10 @@ function printRequirementRows(requirements, mode, cols) {
7620
8328
  );
7621
8329
  if (mode === OutputMode.VERBOSE) {
7622
8330
  for (const f of req.codeFiles) {
7623
- console.log(chalk10.dim(` code: ${f.path} (${f.method})`));
8331
+ console.log(chalk11.dim(` code: ${f.path} (${f.method})`));
7624
8332
  }
7625
8333
  for (const f of req.testFiles) {
7626
- console.log(chalk10.dim(` test: ${f.path} (${f.method})`));
8334
+ console.log(chalk11.dim(` test: ${f.path} (${f.method})`));
7627
8335
  }
7628
8336
  }
7629
8337
  }
@@ -7634,7 +8342,7 @@ function printCoverageSummary(summary) {
7634
8342
  const codePct = s.total > 0 ? Math.round(s.withCode / s.total * 100) : 0;
7635
8343
  const testPct = s.total > 0 ? Math.round(s.withTests / s.total * 100) : 0;
7636
8344
  console.log(
7637
- ` ${chalk10.bold("Coverage:")} ${fullyPct}% fully traced (${s.fullyTraced}/${s.total}), ${codePct}% with code (${s.withCode}/${s.total}), ${testPct}% with tests (${s.withTests}/${s.total})`
8345
+ ` ${chalk11.bold("Coverage:")} ${fullyPct}% fully traced (${s.fullyTraced}/${s.total}), ${codePct}% with code (${s.withCode}/${s.total}), ${testPct}% with tests (${s.withTests}/${s.total})`
7638
8346
  );
7639
8347
  }
7640
8348
  async function runTraceability(options) {
@@ -7642,7 +8350,7 @@ async function runTraceability(options) {
7642
8350
  const projectPath = process.cwd();
7643
8351
  const store = await loadGraphStore(projectPath);
7644
8352
  if (!store) handleNoStore(mode);
7645
- const graphModule = await import("./dist-QW5G3GX3.js");
8353
+ const graphModule = await import("./dist-RADHOOXG.js");
7646
8354
  const filterOptions = buildFilterOptions(options);
7647
8355
  const results = graphModule.queryTraceability(store, filterOptions);
7648
8356
  if (results.length === 0) handleEmptyResults(mode);
@@ -7650,14 +8358,14 @@ async function runTraceability(options) {
7650
8358
  console.log(JSON.stringify(results, null, 2));
7651
8359
  } else {
7652
8360
  console.log("");
7653
- console.log(chalk10.bold("Spec-to-Implementation Traceability"));
8361
+ console.log(chalk11.bold("Spec-to-Implementation Traceability"));
7654
8362
  console.log("");
7655
8363
  for (const result of results) printResultTable(result, mode);
7656
8364
  }
7657
8365
  process.exit(ExitCode.SUCCESS);
7658
8366
  }
7659
8367
  function createTraceabilityCommand() {
7660
- return new Command73("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) => {
8368
+ return new Command77("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) => {
7661
8369
  const globalOpts = cmd.optsWithGlobals();
7662
8370
  await runTraceability({
7663
8371
  spec: opts.spec,
@@ -7670,15 +8378,15 @@ function createTraceabilityCommand() {
7670
8378
  }
7671
8379
 
7672
8380
  // src/commands/uninstall.ts
7673
- import * as path56 from "path";
7674
- import { Command as Command74 } from "commander";
8381
+ import * as path60 from "path";
8382
+ import { Command as Command78 } from "commander";
7675
8383
  async function runUninstall(skillName, options) {
7676
8384
  const packageName = resolvePackageName(skillName);
7677
8385
  const shortName = extractSkillName(packageName);
7678
8386
  const globalDir = resolveGlobalSkillsDir();
7679
- const skillsDir = path56.dirname(globalDir);
7680
- const communityBase = path56.join(skillsDir, "community");
7681
- const lockfilePath = path56.join(communityBase, "skills-lock.json");
8387
+ const skillsDir = path60.dirname(globalDir);
8388
+ const communityBase = path60.join(skillsDir, "community");
8389
+ const lockfilePath = path60.join(communityBase, "skills-lock.json");
7682
8390
  const lockfile = readLockfile2(lockfilePath);
7683
8391
  const entry = lockfile.skills[packageName];
7684
8392
  if (!entry) {
@@ -7708,7 +8416,7 @@ async function runUninstall(skillName, options) {
7708
8416
  return result;
7709
8417
  }
7710
8418
  function createUninstallCommand() {
7711
- const cmd = new Command74("uninstall");
8419
+ const cmd = new Command78("uninstall");
7712
8420
  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) => {
7713
8421
  try {
7714
8422
  const result = await runUninstall(skill, opts);
@@ -7727,9 +8435,10 @@ function createUninstallCommand() {
7727
8435
  }
7728
8436
 
7729
8437
  // src/commands/uninstall-constraints.ts
7730
- import * as fs35 from "fs/promises";
7731
- import * as path57 from "path";
7732
- import { Command as Command75 } from "commander";
8438
+ init_dist();
8439
+ import * as fs40 from "fs/promises";
8440
+ import * as path61 from "path";
8441
+ import { Command as Command79 } from "commander";
7733
8442
  async function runUninstallConstraints(options) {
7734
8443
  const { packageName, configPath, lockfilePath } = options;
7735
8444
  const lockfileResult = await readLockfile(lockfilePath);
@@ -7749,7 +8458,7 @@ async function runUninstallConstraints(options) {
7749
8458
  }
7750
8459
  let localConfig;
7751
8460
  try {
7752
- const raw = await fs35.readFile(configPath, "utf-8");
8461
+ const raw = await fs40.readFile(configPath, "utf-8");
7753
8462
  localConfig = JSON.parse(raw);
7754
8463
  } catch (err) {
7755
8464
  return {
@@ -7786,11 +8495,11 @@ async function runUninstallConstraints(options) {
7786
8495
  };
7787
8496
  }
7788
8497
  function createUninstallConstraintsCommand() {
7789
- const cmd = new Command75("uninstall-constraints");
8498
+ const cmd = new Command79("uninstall-constraints");
7790
8499
  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) => {
7791
8500
  let configPath;
7792
8501
  if (opts.config) {
7793
- configPath = path57.resolve(opts.config);
8502
+ configPath = path61.resolve(opts.config);
7794
8503
  } else {
7795
8504
  const found = findConfigFile();
7796
8505
  if (!found.ok) {
@@ -7799,8 +8508,8 @@ function createUninstallConstraintsCommand() {
7799
8508
  }
7800
8509
  configPath = found.value;
7801
8510
  }
7802
- const projectRoot = path57.dirname(configPath);
7803
- const lockfilePath = path57.join(projectRoot, ".harness", "constraints.lock.json");
8511
+ const projectRoot = path61.dirname(configPath);
8512
+ const lockfilePath = path61.join(projectRoot, ".harness", "constraints.lock.json");
7804
8513
  const result = await runUninstallConstraints({
7805
8514
  packageName: name,
7806
8515
  configPath,
@@ -7825,13 +8534,13 @@ function createUninstallConstraintsCommand() {
7825
8534
  }
7826
8535
 
7827
8536
  // src/commands/update.ts
7828
- import { Command as Command76 } from "commander";
8537
+ import { Command as Command80 } from "commander";
7829
8538
  import { execFile, execFileSync as execFileSync6 } from "child_process";
7830
- import { realpathSync, existsSync as existsSync33, readFileSync as readFileSync20 } from "fs";
7831
- import { join as join46 } from "path";
8539
+ import { realpathSync, existsSync as existsSync36, readFileSync as readFileSync25 } from "fs";
8540
+ import { join as join47 } from "path";
7832
8541
  import { promisify } from "util";
7833
- import readline2 from "readline";
7834
- import chalk11 from "chalk";
8542
+ import readline3 from "readline";
8543
+ import chalk12 from "chalk";
7835
8544
  function detectPackageManager() {
7836
8545
  try {
7837
8546
  const argv1 = process.argv[1];
@@ -7889,26 +8598,35 @@ function getInstalledPackages(pm) {
7889
8598
  return ["@harness-engineering/cli", "@harness-engineering/core"];
7890
8599
  }
7891
8600
  }
7892
- function prompt(question) {
7893
- const rl = readline2.createInterface({
8601
+ function prompt2(question) {
8602
+ const rl = readline3.createInterface({
7894
8603
  input: process.stdin,
7895
8604
  output: process.stdout
7896
8605
  });
7897
- return new Promise((resolve32) => {
8606
+ return new Promise((resolve35) => {
7898
8607
  rl.question(question, (answer) => {
7899
8608
  rl.close();
7900
- resolve32(answer.trim().toLowerCase());
8609
+ resolve35(answer.trim().toLowerCase());
7901
8610
  });
7902
8611
  });
7903
8612
  }
8613
+ async function ensureTelemetryIfNeeded() {
8614
+ const cwd = process.cwd();
8615
+ const result = await ensureTelemetryConfigured(cwd);
8616
+ if (result.status === "pass") {
8617
+ logger.success(result.message);
8618
+ } else if (result.status === "warn") {
8619
+ logger.warn(result.message);
8620
+ }
8621
+ }
7904
8622
  function refreshHooks() {
7905
8623
  const cwd = process.cwd();
7906
- const configPath = join46(cwd, "harness.config.json");
7907
- if (!existsSync33(configPath)) return;
8624
+ const configPath = join47(cwd, "harness.config.json");
8625
+ if (!existsSync36(configPath)) return;
7908
8626
  let profile = "standard";
7909
- const profilePath = join46(cwd, ".harness", "hooks", "profile.json");
8627
+ const profilePath = join47(cwd, ".harness", "hooks", "profile.json");
7910
8628
  try {
7911
- const data = JSON.parse(readFileSync20(profilePath, "utf-8"));
8629
+ const data = JSON.parse(readFileSync25(profilePath, "utf-8"));
7912
8630
  if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
7913
8631
  profile = data.profile;
7914
8632
  }
@@ -7928,16 +8646,16 @@ function runLocalGraphScan() {
7928
8646
  execFileSync6("harness", ["graph", "scan", "."], { stdio: "inherit" });
7929
8647
  } catch {
7930
8648
  logger.warn("Graph scan failed. Run manually:");
7931
- console.log(` ${chalk11.cyan("harness graph scan .")}`);
8649
+ console.log(` ${chalk12.cyan("harness graph scan .")}`);
7932
8650
  }
7933
8651
  }
7934
8652
  async function offerRegeneration() {
7935
8653
  console.log("");
7936
- const regenAnswer = await prompt(
8654
+ const regenAnswer = await prompt2(
7937
8655
  "Regenerate slash commands, agent definitions, and knowledge graph? (Y/n) "
7938
8656
  );
7939
8657
  if (regenAnswer === "n" || regenAnswer === "no") return;
7940
- const scopeAnswer = await prompt("Generate for (G)lobal or (l)ocal project? (G/l) ");
8658
+ const scopeAnswer = await prompt2("Generate for (G)lobal or (l)ocal project? (G/l) ");
7941
8659
  const isGlobal = scopeAnswer !== "l" && scopeAnswer !== "local";
7942
8660
  try {
7943
8661
  execFileSync6("harness", ["generate", ...isGlobal ? ["--global"] : []], {
@@ -7945,7 +8663,7 @@ async function offerRegeneration() {
7945
8663
  });
7946
8664
  } catch {
7947
8665
  logger.warn("Generation failed. Run manually:");
7948
- console.log(` ${chalk11.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
8666
+ console.log(` ${chalk12.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
7949
8667
  }
7950
8668
  if (!isGlobal) {
7951
8669
  runLocalGraphScan();
@@ -8001,14 +8719,15 @@ async function runUpdateAction(opts, globalOpts) {
8001
8719
  if (!hasUpdates) {
8002
8720
  logger.success("All packages are up to date");
8003
8721
  refreshHooks();
8722
+ await ensureTelemetryIfNeeded();
8004
8723
  await offerRegeneration();
8005
8724
  process.exit(ExitCode.SUCCESS);
8006
8725
  }
8007
8726
  console.log("");
8008
8727
  for (const { pkg, current, latest } of outdated) {
8009
8728
  const shortName = pkg.replace("@harness-engineering/", "");
8010
- const currentStr = current ? chalk11.dim(`v${current}`) : chalk11.dim("not installed");
8011
- logger.info(`${shortName}: ${currentStr} \u2192 ${chalk11.green(`v${latest}`)}`);
8729
+ const currentStr = current ? chalk12.dim(`v${current}`) : chalk12.dim("not installed");
8730
+ logger.info(`${shortName}: ${currentStr} \u2192 ${chalk12.green(`v${latest}`)}`);
8012
8731
  }
8013
8732
  console.log("");
8014
8733
  }
@@ -8024,15 +8743,16 @@ async function runUpdateAction(opts, globalOpts) {
8024
8743
  } catch {
8025
8744
  console.log("");
8026
8745
  logger.error("Update failed. You can try manually:");
8027
- console.log(` ${chalk11.cyan(installCmd)}`);
8746
+ console.log(` ${chalk12.cyan(installCmd)}`);
8028
8747
  process.exit(ExitCode.ERROR);
8029
8748
  }
8030
8749
  refreshHooks();
8750
+ await ensureTelemetryIfNeeded();
8031
8751
  await offerRegeneration();
8032
8752
  process.exit(ExitCode.SUCCESS);
8033
8753
  }
8034
8754
  function createUpdateCommand() {
8035
- return new Command76("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(
8755
+ return new Command80("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(
8036
8756
  "--regenerate",
8037
8757
  "Only regenerate slash commands and agent definitions (skip package updates)"
8038
8758
  ).action(async (opts, cmd) => {
@@ -8042,15 +8762,15 @@ function createUpdateCommand() {
8042
8762
  }
8043
8763
 
8044
8764
  // src/commands/usage.ts
8045
- import { Command as Command77 } from "commander";
8765
+ import { Command as Command81 } from "commander";
8046
8766
  async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
8047
- const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-7EBSGAHX.js");
8767
+ const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-WCSJHQPK.js");
8048
8768
  const records = readCostRecords(cwd);
8049
8769
  if (includeClaudeSessions) {
8050
8770
  const ccRecords = parseCCRecords();
8051
8771
  records.push(...ccRecords);
8052
8772
  }
8053
- if (records.length === 0) return records;
8773
+ if (records.length === 0) return { records, pricingData: null };
8054
8774
  const pricingData = await loadPricingData(cwd);
8055
8775
  for (const record of records) {
8056
8776
  if (record.model && record.costMicroUSD == null) {
@@ -8058,7 +8778,14 @@ async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
8058
8778
  if (cost != null) record.costMicroUSD = cost;
8059
8779
  }
8060
8780
  }
8061
- return records;
8781
+ return { records, pricingData };
8782
+ }
8783
+ function computeCacheSavings(cacheReadTokens, model, pricingData) {
8784
+ if (!cacheReadTokens || !model || !pricingData) return null;
8785
+ const pricing = pricingData.get(model);
8786
+ if (!pricing || pricing.cacheReadPer1M == null) return null;
8787
+ const savingsUSD = cacheReadTokens / 1e6 * (pricing.inputPer1M - pricing.cacheReadPer1M);
8788
+ return Math.round(savingsUSD * 1e6);
8062
8789
  }
8063
8790
  function formatMicroUSD(microUSD) {
8064
8791
  if (microUSD == null) return "N/A";
@@ -8086,7 +8813,10 @@ function registerDailyCommand(usage) {
8086
8813
  const globalOpts = cmd.optsWithGlobals();
8087
8814
  const days = Math.min(Math.max(parseInt(opts.days, 10) || 7, 1), 90);
8088
8815
  const cwd = process.cwd();
8089
- const records = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
8816
+ const { records, pricingData } = await loadAndPriceRecords(
8817
+ cwd,
8818
+ globalOpts.includeClaudeSessions
8819
+ );
8090
8820
  if (records.length === 0) {
8091
8821
  if (globalOpts.json) {
8092
8822
  console.log(JSON.stringify([]));
@@ -8095,23 +8825,25 @@ function registerDailyCommand(usage) {
8095
8825
  }
8096
8826
  return;
8097
8827
  }
8098
- const { aggregateByDay } = await import("./dist-7EBSGAHX.js");
8828
+ const { aggregateByDay } = await import("./dist-WCSJHQPK.js");
8099
8829
  const dailyData = aggregateByDay(records);
8100
8830
  const limited = dailyData.slice(0, days);
8101
8831
  if (globalOpts.json) {
8102
8832
  const enriched = limited.map((day) => {
8103
8833
  const hitRate = computeCacheHitRate(day.cacheReadTokens, day.tokens.inputTokens);
8834
+ const savings = computeCacheSavings(day.cacheReadTokens, day.models[0], pricingData);
8104
8835
  return {
8105
8836
  ...day,
8106
- ...hitRate != null ? { cacheHitRate: Math.round(hitRate * 1e3) / 1e3 } : {}
8837
+ ...hitRate != null ? { cacheHitRate: Math.round(hitRate * 1e3) / 1e3 } : {},
8838
+ ...savings != null ? { cacheSavingsMicroUSD: savings } : {}
8107
8839
  };
8108
8840
  });
8109
8841
  console.log(JSON.stringify(enriched, null, 2));
8110
8842
  return;
8111
8843
  }
8112
8844
  const hasCacheData = limited.some((d) => d.cacheReadTokens != null && d.cacheReadTokens > 0);
8113
- const cacheHeader = hasCacheData ? " | Cache " : "";
8114
- const cacheDivider = hasCacheData ? " | ------" : "";
8845
+ const cacheHeader = hasCacheData ? " | Cache | Saved " : "";
8846
+ const cacheDivider = hasCacheData ? " | ------ | -------" : "";
8115
8847
  const header = "Date | Sessions | Input | Output | Model(s) | Cost " + cacheHeader;
8116
8848
  const divider = "-------------|----------|-----------|-----------|------------------------------|-------" + cacheDivider;
8117
8849
  logger.info(header);
@@ -8125,7 +8857,10 @@ function registerDailyCommand(usage) {
8125
8857
  const cost = formatMicroUSD(day.costMicroUSD);
8126
8858
  const cacheCol = hasCacheData ? (() => {
8127
8859
  const rate = computeCacheHitRate(day.cacheReadTokens, day.tokens.inputTokens);
8128
- return " | " + (rate != null ? formatPercent(rate).padStart(5) : " -");
8860
+ const savings = computeCacheSavings(day.cacheReadTokens, day.models[0], pricingData);
8861
+ const rateStr = rate != null ? formatPercent(rate).padStart(5) : " -";
8862
+ const savingsStr = savings != null ? formatMicroUSD(savings).padStart(7) : " N/A";
8863
+ return " | " + rateStr + " | " + savingsStr;
8129
8864
  })() : "";
8130
8865
  logger.info(
8131
8866
  `${date} | ${sessions} | ${input} | ${output} | ${models} | ${cost}${cacheCol}`
@@ -8138,7 +8873,7 @@ function registerSessionsCommand(usage) {
8138
8873
  const globalOpts = cmd.optsWithGlobals();
8139
8874
  const limit = Math.min(Math.max(parseInt(opts.limit, 10) || 10, 1), 100);
8140
8875
  const cwd = process.cwd();
8141
- const records = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
8876
+ const { records } = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
8142
8877
  if (records.length === 0) {
8143
8878
  if (globalOpts.json) {
8144
8879
  console.log(JSON.stringify([]));
@@ -8147,7 +8882,7 @@ function registerSessionsCommand(usage) {
8147
8882
  }
8148
8883
  return;
8149
8884
  }
8150
- const { aggregateBySession } = await import("./dist-7EBSGAHX.js");
8885
+ const { aggregateBySession } = await import("./dist-WCSJHQPK.js");
8151
8886
  const sessionData = aggregateBySession(records);
8152
8887
  const limited = sessionData.slice(0, limit);
8153
8888
  if (globalOpts.json) {
@@ -8189,7 +8924,7 @@ function reportSessionNotFound(id, sessionData, useJson) {
8189
8924
  }
8190
8925
  }
8191
8926
  }
8192
- function printSessionDetail(match) {
8927
+ function printSessionDetail(match, pricingData) {
8193
8928
  logger.info(`Session: ${match.sessionId}`);
8194
8929
  logger.info(`Started: ${match.firstTimestamp}`);
8195
8930
  logger.info(`Ended: ${match.lastTimestamp}`);
@@ -8208,9 +8943,13 @@ function printSessionDetail(match) {
8208
8943
  }
8209
8944
  const hitRate = computeCacheHitRate(match.cacheReadTokens, match.tokens.inputTokens);
8210
8945
  if (hitRate != null) {
8946
+ const savings = computeCacheSavings(match.cacheReadTokens, match.model, pricingData);
8211
8947
  logger.info("");
8212
8948
  logger.info("Cache Performance:");
8213
8949
  logger.info(` Cache hit rate: ${formatPercent(hitRate)}`);
8950
+ if (savings != null) {
8951
+ logger.info(` Estimated savings: ${formatMicroUSD(savings)}`);
8952
+ }
8214
8953
  }
8215
8954
  logger.info("");
8216
8955
  logger.info(`Cost: ${formatMicroUSD(match.costMicroUSD)}`);
@@ -8219,8 +8958,11 @@ function registerSessionCommand(usage) {
8219
8958
  usage.command("session <id>").description("Show detailed token breakdown for a specific session").action(async (id, _opts, cmd) => {
8220
8959
  const globalOpts = cmd.optsWithGlobals();
8221
8960
  const cwd = process.cwd();
8222
- const records = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
8223
- const { aggregateBySession } = await import("./dist-7EBSGAHX.js");
8961
+ const { records, pricingData } = await loadAndPriceRecords(
8962
+ cwd,
8963
+ globalOpts.includeClaudeSessions
8964
+ );
8965
+ const { aggregateBySession } = await import("./dist-WCSJHQPK.js");
8224
8966
  const sessionData = aggregateBySession(records);
8225
8967
  const match = sessionData.find((s) => s.sessionId === id);
8226
8968
  if (!match) {
@@ -8230,21 +8972,23 @@ function registerSessionCommand(usage) {
8230
8972
  }
8231
8973
  if (globalOpts.json) {
8232
8974
  const hitRate = computeCacheHitRate(match.cacheReadTokens, match.tokens.inputTokens);
8975
+ const savings = computeCacheSavings(match.cacheReadTokens, match.model, pricingData);
8233
8976
  const enriched = {
8234
8977
  ...match,
8235
- ...hitRate != null ? { cacheHitRate: Math.round(hitRate * 1e3) / 1e3 } : {}
8978
+ ...hitRate != null ? { cacheHitRate: Math.round(hitRate * 1e3) / 1e3 } : {},
8979
+ ...savings != null ? { cacheSavingsMicroUSD: savings } : {}
8236
8980
  };
8237
8981
  console.log(JSON.stringify(enriched, null, 2));
8238
8982
  return;
8239
8983
  }
8240
- printSessionDetail(match);
8984
+ printSessionDetail(match, pricingData);
8241
8985
  });
8242
8986
  }
8243
8987
  function registerLatestCommand(usage) {
8244
8988
  usage.command("latest").description("Show the most recently completed session cost summary").action(async (_opts, cmd) => {
8245
8989
  const globalOpts = cmd.optsWithGlobals();
8246
8990
  const cwd = process.cwd();
8247
- const records = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
8991
+ const { records } = await loadAndPriceRecords(cwd, globalOpts.includeClaudeSessions);
8248
8992
  if (records.length === 0) {
8249
8993
  if (globalOpts.json) {
8250
8994
  console.log(JSON.stringify({ error: "No usage data found" }));
@@ -8253,7 +8997,7 @@ function registerLatestCommand(usage) {
8253
8997
  }
8254
8998
  return;
8255
8999
  }
8256
- const { aggregateBySession } = await import("./dist-7EBSGAHX.js");
9000
+ const { aggregateBySession } = await import("./dist-WCSJHQPK.js");
8257
9001
  const sessionData = aggregateBySession(records);
8258
9002
  const latest = sessionData[0];
8259
9003
  if (!latest) {
@@ -8279,7 +9023,7 @@ function registerLatestCommand(usage) {
8279
9023
  });
8280
9024
  }
8281
9025
  function createUsageCommand() {
8282
- const usage = new Command77("usage").description("Token usage and cost tracking");
9026
+ const usage = new Command81("usage").description("Token usage and cost tracking");
8283
9027
  usage.option(
8284
9028
  "--include-claude-sessions",
8285
9029
  "Include Claude Code session data from ~/.claude/projects/"
@@ -8292,15 +9036,17 @@ function createUsageCommand() {
8292
9036
  }
8293
9037
 
8294
9038
  // src/commands/validate.ts
8295
- import { Command as Command78 } from "commander";
8296
- import * as path58 from "path";
9039
+ init_dist();
9040
+ init_dist();
9041
+ import { Command as Command82 } from "commander";
9042
+ import * as path62 from "path";
8297
9043
  async function runValidate(options) {
8298
9044
  const configResult = resolveConfig(options.configPath);
8299
9045
  if (!configResult.ok) {
8300
9046
  return configResult;
8301
9047
  }
8302
9048
  const config = configResult.value;
8303
- const cwd = options.cwd ?? (options.configPath ? path58.dirname(path58.resolve(options.configPath)) : process.cwd());
9049
+ const cwd = options.cwd ?? (options.configPath ? path62.dirname(path62.resolve(options.configPath)) : process.cwd());
8304
9050
  const result = {
8305
9051
  valid: true,
8306
9052
  checks: {
@@ -8310,7 +9056,7 @@ async function runValidate(options) {
8310
9056
  },
8311
9057
  issues: []
8312
9058
  };
8313
- const agentsMapPath = path58.resolve(cwd, config.agentsMapPath);
9059
+ const agentsMapPath = path62.resolve(cwd, config.agentsMapPath);
8314
9060
  const agentsResult = await validateAgentsMap(agentsMapPath);
8315
9061
  if (agentsResult.ok) {
8316
9062
  result.checks.agentsMap = true;
@@ -8346,6 +9092,26 @@ async function runValidate(options) {
8346
9092
  });
8347
9093
  }
8348
9094
  result.checks.fileStructure = true;
9095
+ if (options.agentConfigs) {
9096
+ const agentCfg = await validateAgentConfigs(cwd, {
9097
+ strict: options.strict === true,
9098
+ ...options.agnixBin !== void 0 && { agnixBin: options.agnixBin }
9099
+ });
9100
+ result.agentConfigs = agentCfg;
9101
+ result.checks.agentConfigs = agentCfg.valid;
9102
+ if (!agentCfg.valid) result.valid = false;
9103
+ for (const finding of agentCfg.issues) {
9104
+ result.issues.push({
9105
+ check: "agentConfigs",
9106
+ file: finding.file,
9107
+ ...finding.line !== void 0 && { line: finding.line },
9108
+ ruleId: finding.ruleId,
9109
+ severity: finding.severity,
9110
+ message: finding.message,
9111
+ ...finding.suggestion !== void 0 && { suggestion: finding.suggestion }
9112
+ });
9113
+ }
9114
+ }
8349
9115
  return Ok(result);
8350
9116
  }
8351
9117
  function resolveValidateMode(globalOpts) {
@@ -8355,11 +9121,11 @@ function resolveValidateMode(globalOpts) {
8355
9121
  return OutputMode.TEXT;
8356
9122
  }
8357
9123
  async function printCrossCheckWarnings(mode) {
8358
- const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-Y4PDR63C.js");
9124
+ const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-ZOWFA3DB.js");
8359
9125
  const cwd = process.cwd();
8360
9126
  const crossResult = await runCrossCheck2({
8361
- specsDir: path58.join(cwd, "docs", "specs"),
8362
- plansDir: path58.join(cwd, "docs", "plans"),
9127
+ specsDir: path62.join(cwd, "docs", "specs"),
9128
+ plansDir: path62.join(cwd, "docs", "plans"),
8363
9129
  projectPath: cwd
8364
9130
  });
8365
9131
  if (!crossResult.ok || crossResult.value.warnings === 0) return;
@@ -8371,37 +9137,59 @@ async function printCrossCheckWarnings(mode) {
8371
9137
  ${crossResult.value.warnings} warnings`);
8372
9138
  }
8373
9139
  function createValidateCommand3() {
8374
- const command = new Command78("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").action(async (opts, cmd) => {
8375
- const globalOpts = cmd.optsWithGlobals();
8376
- const mode = resolveValidateMode(globalOpts);
8377
- const formatter = new OutputFormatter(mode);
8378
- const result = await runValidate({
8379
- configPath: globalOpts.config,
8380
- json: globalOpts.json,
8381
- verbose: globalOpts.verbose,
8382
- quiet: globalOpts.quiet
8383
- });
8384
- if (!result.ok) {
8385
- if (mode === OutputMode.JSON) console.log(JSON.stringify({ error: result.error.message }));
8386
- else logger.error(result.error.message);
8387
- process.exit(result.error.exitCode);
8388
- }
8389
- if (opts.crossCheck) await printCrossCheckWarnings(mode);
8390
- const output = formatter.formatValidation({
8391
- valid: result.value.valid,
8392
- issues: result.value.issues
8393
- });
8394
- if (output) console.log(output);
8395
- process.exit(result.value.valid ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
8396
- });
9140
+ const command = new Command82("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
9141
+ "--agent-configs",
9142
+ "Validate agent configs (CLAUDE.md, hooks, skills) via agnix or built-in fallback rules"
9143
+ ).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()));
8397
9144
  return command;
8398
9145
  }
9146
+ async function runValidateAction(opts, globalOpts) {
9147
+ const mode = resolveValidateMode(globalOpts);
9148
+ const formatter = new OutputFormatter(mode);
9149
+ const result = await runValidate({
9150
+ ...typeof globalOpts.config === "string" && { configPath: globalOpts.config },
9151
+ json: globalOpts.json === true,
9152
+ verbose: globalOpts.verbose === true,
9153
+ quiet: globalOpts.quiet === true,
9154
+ agentConfigs: opts.agentConfigs === true,
9155
+ strict: opts.strict === true,
9156
+ ...typeof opts.agnixBin === "string" && { agnixBin: opts.agnixBin }
9157
+ });
9158
+ if (!result.ok) {
9159
+ if (mode === OutputMode.JSON) console.log(JSON.stringify({ error: result.error.message }));
9160
+ else logger.error(result.error.message);
9161
+ process.exit(result.error.exitCode);
9162
+ }
9163
+ if (opts.crossCheck) await printCrossCheckWarnings(mode);
9164
+ emitValidateOutput(result.value, mode, formatter);
9165
+ process.exit(result.value.valid ? ExitCode.SUCCESS : ExitCode.VALIDATION_FAILED);
9166
+ }
9167
+ function emitValidateOutput(value, mode, formatter) {
9168
+ if (mode === OutputMode.JSON) {
9169
+ console.log(JSON.stringify(value, null, 2));
9170
+ return;
9171
+ }
9172
+ const output = formatter.formatValidation({ valid: value.valid, issues: value.issues });
9173
+ if (output) console.log(output);
9174
+ if (value.agentConfigs) printAgentConfigSummary(value.agentConfigs, mode);
9175
+ }
9176
+ function printAgentConfigSummary(cfg, mode) {
9177
+ if (mode === OutputMode.QUIET) return;
9178
+ const engineLabel = cfg.engine === "agnix" ? "agnix" : "built-in fallback rules";
9179
+ const note = cfg.fellBackBecause ? ` (${cfg.fellBackBecause})` : "";
9180
+ console.log(`
9181
+ Agent configs checked via ${engineLabel}${note}`);
9182
+ if (cfg.engine === "fallback" && cfg.fellBackBecause === "binary-not-found") {
9183
+ console.log(" Install agnix for 385+ rule coverage: https://github.com/agent-sh/agnix");
9184
+ }
9185
+ }
8399
9186
 
8400
9187
  // src/commands/_registry.ts
8401
9188
  var commandCreators = [
8402
9189
  createAddCommand,
8403
9190
  createAdoptionCommand,
8404
9191
  createAgentCommand,
9192
+ createAuditProtectedCommand,
8405
9193
  createBlueprintCommand,
8406
9194
  createCheckArchCommand,
8407
9195
  createCheckDepsCommand,
@@ -8434,6 +9222,7 @@ var commandCreators = [
8434
9222
  createPerfCommand,
8435
9223
  createPersonaCommand,
8436
9224
  createPredictCommand,
9225
+ createPublishAnalysesCommand,
8437
9226
  createQueryCommand,
8438
9227
  createRecommendCommand,
8439
9228
  createScanCommand,
@@ -8444,6 +9233,7 @@ var commandCreators = [
8444
9233
  createSkillCommand,
8445
9234
  createSnapshotCommand,
8446
9235
  createStateCommand,
9236
+ createSyncAnalysesCommand,
8447
9237
  createTaintCommand,
8448
9238
  createTelemetryCommand,
8449
9239
  createTraceabilityCommand,
@@ -8456,7 +9246,7 @@ var commandCreators = [
8456
9246
 
8457
9247
  // src/index.ts
8458
9248
  function createProgram() {
8459
- const program = new Command79();
9249
+ const program = new Command83();
8460
9250
  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");
8461
9251
  for (const creator of commandCreators) {
8462
9252
  program.addCommand(creator());