@harness-engineering/cli 2.2.0 → 2.3.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 (51) hide show
  1. package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +13 -7
  2. package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +13 -7
  3. package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +13 -7
  4. package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +13 -7
  5. package/dist/{agents-md-L4X4MOWT.js → agents-md-N7YBQPE3.js} +2 -2
  6. package/dist/{architecture-WJRIYQ45.js → architecture-PP7WERSV.js} +3 -3
  7. package/dist/{assess-project-PHC2HO3V.js → assess-project-WXFCJQTX.js} +1 -1
  8. package/dist/bin/harness-mcp.js +13 -13
  9. package/dist/bin/harness.js +22 -22
  10. package/dist/{check-phase-gate-646KY67H.js → check-phase-gate-R3KQFBAH.js} +3 -3
  11. package/dist/{chunk-GOOTYTTV.js → chunk-35FI23SO.js} +855 -428
  12. package/dist/{chunk-L2IDE7WS.js → chunk-3LPOTTPX.js} +255 -89
  13. package/dist/{chunk-K4WRQTEF.js → chunk-4DWOMGUM.js} +1661 -434
  14. package/dist/{chunk-W4AFGFFB.js → chunk-4NFV5UZO.js} +2 -2
  15. package/dist/{chunk-224XKVLP.js → chunk-5KTTKXQN.js} +1 -1
  16. package/dist/{chunk-KV7A5OZT.js → chunk-5PPV4WYY.js} +3 -3
  17. package/dist/{chunk-CPYL6LJR.js → chunk-6CHNY3NJ.js} +1 -1
  18. package/dist/{chunk-VKDBM3RX.js → chunk-7PGYJO3L.js} +3 -3
  19. package/dist/{chunk-E7W3YOXL.js → chunk-D2LZUJLP.js} +2 -2
  20. package/dist/{chunk-4HKVZO7R.js → chunk-DLBMYLYR.js} +1 -1
  21. package/dist/{chunk-YWD6WXXM.js → chunk-EJPR5VCT.js} +6 -6
  22. package/dist/{chunk-2ZURBWEV.js → chunk-GTXUUGFG.js} +3 -3
  23. package/dist/{chunk-OJMO4JBQ.js → chunk-GUIX2TMZ.js} +1 -1
  24. package/dist/{chunk-TNZYQTEE.js → chunk-KUVPSUG4.js} +1 -1
  25. package/dist/{chunk-YLTRFZAT.js → chunk-KWD6FF7M.js} +6 -6
  26. package/dist/{chunk-VJQLUS5I.js → chunk-L3CEN42B.js} +1 -1
  27. package/dist/{chunk-YLOAQZLA.js → chunk-LM4F5KBK.js} +2 -2
  28. package/dist/{chunk-JPWICLXQ.js → chunk-MKPRB4PL.js} +1 -1
  29. package/dist/{chunk-2QPHCR22.js → chunk-MT2MMBUA.js} +5 -5
  30. package/dist/{chunk-QTUPHTTK.js → chunk-NP2ZI6E3.js} +1 -1
  31. package/dist/{chunk-LO7ZLV7S.js → chunk-PW3U4YJV.js} +4 -2
  32. package/dist/{chunk-36X7TRUI.js → chunk-YEBUFRTT.js} +2 -2
  33. package/dist/{ci-workflow-TOS5X527.js → ci-workflow-GFCXFJ4G.js} +2 -2
  34. package/dist/{dist-6RT2AVYU.js → dist-I4LWG3IN.js} +23 -1
  35. package/dist/{docs-HOJMQYDZ.js → docs-UXKDKPJF.js} +3 -3
  36. package/dist/{engine-D6UYH6DB.js → engine-A63FRDLF.js} +2 -2
  37. package/dist/{entropy-LZ4IDGZR.js → entropy-IFIP4ZP4.js} +2 -2
  38. package/dist/{feedback-WV7EQVK7.js → feedback-W36DSJQA.js} +1 -1
  39. package/dist/{generate-agent-definitions-GFNXJCBY.js → generate-agent-definitions-F4YMKQLP.js} +3 -3
  40. package/dist/hooks/block-no-verify.js +19 -1
  41. package/dist/index.d.ts +15 -9
  42. package/dist/index.js +22 -22
  43. package/dist/{loader-Z23JTXIZ.js → loader-4UAOGUSS.js} +2 -2
  44. package/dist/{mcp-JDJGELGD.js → mcp-YW7PLXVQ.js} +13 -13
  45. package/dist/{performance-7ATLHTQU.js → performance-AZ5UYPOQ.js} +3 -3
  46. package/dist/{review-pipeline-COBGGXHJ.js → review-pipeline-OLQVGBWJ.js} +2 -2
  47. package/dist/{runtime-KCBNQUXK.js → runtime-GG3U5HH5.js} +2 -2
  48. package/dist/{security-MAPRIFQT.js → security-MYTRFSR7.js} +1 -1
  49. package/dist/{validate-74XTQR7Q.js → validate-QI4V4JY6.js} +3 -3
  50. package/dist/{validate-cross-check-MI5MZ7MB.js → validate-cross-check-XRSSAXJP.js} +2 -2
  51. package/package.json +4 -4
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  generateRuntime
3
- } from "./chunk-TNZYQTEE.js";
3
+ } from "./chunk-KUVPSUG4.js";
4
4
  import {
5
5
  generateAgentsMd
6
- } from "./chunk-4HKVZO7R.js";
6
+ } from "./chunk-DLBMYLYR.js";
7
7
  import {
8
8
  generateCIWorkflow
9
- } from "./chunk-JPWICLXQ.js";
9
+ } from "./chunk-MKPRB4PL.js";
10
10
  import {
11
11
  TemplateEngine
12
- } from "./chunk-224XKVLP.js";
12
+ } from "./chunk-5KTTKXQN.js";
13
13
  import {
14
14
  generate,
15
15
  validate
@@ -28,18 +28,18 @@ import {
28
28
  OutputMode,
29
29
  createCheckPhaseGateCommand,
30
30
  findFiles
31
- } from "./chunk-E7W3YOXL.js";
31
+ } from "./chunk-D2LZUJLP.js";
32
32
  import {
33
33
  createGenerateAgentDefinitionsCommand,
34
34
  generateAgentDefinitions
35
- } from "./chunk-OJMO4JBQ.js";
35
+ } from "./chunk-GUIX2TMZ.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-VJQLUS5I.js";
42
+ } from "./chunk-L3CEN42B.js";
43
43
  import {
44
44
  createScanCommand,
45
45
  loadIngestOptions
@@ -57,7 +57,7 @@ import {
57
57
  loadCachedSnapshot,
58
58
  persistToolingConfig,
59
59
  recommend
60
- } from "./chunk-L2IDE7WS.js";
60
+ } from "./chunk-3LPOTTPX.js";
61
61
  import {
62
62
  loadGraphStore
63
63
  } from "./chunk-KTWKW6KJ.js";
@@ -67,7 +67,7 @@ import {
67
67
  import {
68
68
  findConfigFile,
69
69
  resolveConfig
70
- } from "./chunk-LO7ZLV7S.js";
70
+ } from "./chunk-PW3U4YJV.js";
71
71
  import {
72
72
  VALID_PLATFORMS
73
73
  } from "./chunk-3ISINLYT.js";
@@ -115,6 +115,7 @@ import {
115
115
  computeWindow,
116
116
  createFixes,
117
117
  createStream,
118
+ createTrackerClient,
118
119
  crossReferenceUndocumentedFixes,
119
120
  deepMergeConstraints,
120
121
  defineLayer,
@@ -133,14 +134,18 @@ import {
133
134
  isoWeek,
134
135
  listStreams,
135
136
  listTaintedSessions,
137
+ loadProjectRoadmapMode,
136
138
  loadState,
137
139
  loadStreamIndex,
140
+ loadTrackerClientConfigFromProject,
138
141
  loadTrackerSyncConfig,
139
142
  mapInjectionFindings,
140
143
  mapSecurityFindings,
144
+ migrate_exports,
141
145
  parseDiff,
142
146
  parseFileRegions,
143
147
  parseManifest,
148
+ parseRoadmap,
144
149
  parseSecurityConfig,
145
150
  pruneLearnings,
146
151
  readIdentity,
@@ -161,10 +166,11 @@ import {
161
166
  validateDependencies,
162
167
  validateKnowledgeMap,
163
168
  validatePulseConfig,
169
+ validateRoadmapMode,
164
170
  validateSolutionsDir,
165
171
  writeConfig,
166
172
  writeLockfile
167
- } from "./chunk-K4WRQTEF.js";
173
+ } from "./chunk-4DWOMGUM.js";
168
174
  import {
169
175
  Err,
170
176
  Ok
@@ -189,7 +195,7 @@ import {
189
195
  } from "./chunk-KFQGP6VL.js";
190
196
 
191
197
  // src/index.ts
192
- import { Command as Command90 } from "commander";
198
+ import { Command as Command93 } from "commander";
193
199
 
194
200
  // src/commands/add.ts
195
201
  init_dist();
@@ -378,7 +384,7 @@ function registerSkillsCommand(adoption) {
378
384
  const globalOpts = cmd.optsWithGlobals();
379
385
  const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
380
386
  const cwd = process.cwd();
381
- const { readAdoptionRecords, aggregateBySkill } = await import("./dist-6RT2AVYU.js");
387
+ const { readAdoptionRecords, aggregateBySkill } = await import("./dist-I4LWG3IN.js");
382
388
  const records = readAdoptionRecords(cwd);
383
389
  if (records.length === 0) {
384
390
  if (globalOpts.json) {
@@ -414,7 +420,7 @@ function registerRecentCommand(adoption) {
414
420
  const globalOpts = cmd.optsWithGlobals();
415
421
  const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
416
422
  const cwd = process.cwd();
417
- const { readAdoptionRecords } = await import("./dist-6RT2AVYU.js");
423
+ const { readAdoptionRecords } = await import("./dist-I4LWG3IN.js");
418
424
  const records = readAdoptionRecords(cwd);
419
425
  if (records.length === 0) {
420
426
  if (globalOpts.json) {
@@ -492,7 +498,7 @@ function registerSkillCommand(adoption) {
492
498
  adoption.command("skill <name>").description("Show detail for a specific skill").action(async (name, _opts, cmd) => {
493
499
  const globalOpts = cmd.optsWithGlobals();
494
500
  const cwd = process.cwd();
495
- const { readAdoptionRecords, aggregateBySkill } = await import("./dist-6RT2AVYU.js");
501
+ const { readAdoptionRecords, aggregateBySkill } = await import("./dist-I4LWG3IN.js");
496
502
  const records = readAdoptionRecords(cwd);
497
503
  const skillRecords = records.filter((r) => r.skill === name);
498
504
  if (skillRecords.length === 0) {
@@ -1436,10 +1442,10 @@ async function runCheckSecurity(cwd, options) {
1436
1442
  const projectRoot = path8.resolve(cwd);
1437
1443
  let configData = {};
1438
1444
  try {
1439
- const fs42 = await import("fs");
1445
+ const fs44 = await import("fs");
1440
1446
  const configPath = path8.join(projectRoot, "harness.config.json");
1441
- if (fs42.existsSync(configPath)) {
1442
- const raw = fs42.readFileSync(configPath, "utf-8");
1447
+ if (fs44.existsSync(configPath)) {
1448
+ const raw = fs44.readFileSync(configPath, "utf-8");
1443
1449
  const parsed = JSON.parse(raw);
1444
1450
  configData = parsed.security ?? {};
1445
1451
  }
@@ -2888,11 +2894,11 @@ import { Command as Command27 } from "commander";
2888
2894
  // src/commands/graph/status.ts
2889
2895
  import * as path15 from "path";
2890
2896
  async function readConnectorSyncStatus(graphDir) {
2891
- const fs42 = await import("fs/promises");
2897
+ const fs44 = await import("fs/promises");
2892
2898
  const result = {};
2893
2899
  try {
2894
2900
  const syncMetaPath = path15.join(graphDir, "sync-metadata.json");
2895
- const syncMeta = JSON.parse(await fs42.readFile(syncMetaPath, "utf-8"));
2901
+ const syncMeta = JSON.parse(await fs44.readFile(syncMetaPath, "utf-8"));
2896
2902
  for (const [name, data] of Object.entries(syncMeta.connectors ?? {})) {
2897
2903
  result[name] = data.lastSyncTimestamp;
2898
2904
  }
@@ -3042,9 +3048,9 @@ import { Command as Command26 } from "commander";
3042
3048
  import * as path18 from "path";
3043
3049
  async function loadConnectorConfig(projectPath, source) {
3044
3050
  try {
3045
- const fs42 = await import("fs/promises");
3051
+ const fs44 = await import("fs/promises");
3046
3052
  const configPath = path18.join(projectPath, "harness.config.json");
3047
- const config = JSON.parse(await fs42.readFile(configPath, "utf-8"));
3053
+ const config = JSON.parse(await fs44.readFile(configPath, "utf-8"));
3048
3054
  const connector = config.graph?.connectors?.[source];
3049
3055
  return connector ?? {};
3050
3056
  } catch {
@@ -4372,8 +4378,8 @@ function extractSkillName(packageName) {
4372
4378
  return packageName;
4373
4379
  }
4374
4380
  function readNpmrcToken(registryUrl) {
4375
- const { hostname, pathname } = new URL(registryUrl);
4376
- const registryPath = `//${hostname}${pathname.replace(/\/$/, "")}/:_authToken=`;
4381
+ const { hostname: hostname2, pathname } = new URL(registryUrl);
4382
+ const registryPath = `//${hostname2}${pathname.replace(/\/$/, "")}/:_authToken=`;
4377
4383
  const candidates = [path28.join(process.cwd(), ".npmrc"), path28.join(os3.homedir(), ".npmrc")];
4378
4384
  for (const npmrcPath of candidates) {
4379
4385
  try {
@@ -5461,8 +5467,8 @@ function createKnowledgePipelineCommand() {
5461
5467
  const projectDir = process.cwd();
5462
5468
  try {
5463
5469
  const graphDir = path38.join(projectDir, ".harness", "graph");
5464
- const fs42 = await import("fs/promises");
5465
- await fs42.mkdir(graphDir, { recursive: true });
5470
+ const fs44 = await import("fs/promises");
5471
+ await fs44.mkdir(graphDir, { recursive: true });
5466
5472
  const { GraphStore, KnowledgePipelineRunner } = await import("./dist-D27LJR2T.js");
5467
5473
  const store = new GraphStore();
5468
5474
  try {
@@ -5805,7 +5811,7 @@ function createMcpCommand() {
5805
5811
  parseBudget
5806
5812
  ).action(async (opts) => {
5807
5813
  const [{ startServer: startServer2, getToolDefinitions: getToolDefinitions2 }, { selectTier }] = await Promise.all([
5808
- import("./mcp-JDJGELGD.js"),
5814
+ import("./mcp-YW7PLXVQ.js"),
5809
5815
  import("./tool-tiers-7QGZ3FKY.js")
5810
5816
  ]);
5811
5817
  if (opts.tools && opts.tools.length > 0) {
@@ -5867,18 +5873,20 @@ function walk(dir, predicate) {
5867
5873
  }
5868
5874
  return out;
5869
5875
  }
5876
+ function extractAutopilotTopic(state) {
5877
+ const match = (state.specPath ?? "").match(/^docs\/changes\/([^/]+)\/proposal\.md$/);
5878
+ return match?.[1] ?? null;
5879
+ }
5870
5880
  function buildAutopilotMap(cwd) {
5871
5881
  const map = /* @__PURE__ */ new Map();
5872
5882
  const sessionsDir = path40.join(cwd, ".harness", "sessions");
5873
5883
  if (!fs24.existsSync(sessionsDir)) return map;
5874
5884
  for (const session of listDirs(sessionsDir)) {
5875
5885
  if (!session.startsWith("changes--")) continue;
5876
- const statePath = path40.join(sessionsDir, session, "autopilot-state.json");
5877
- const state = readJson2(statePath);
5886
+ const state = readJson2(path40.join(sessionsDir, session, "autopilot-state.json"));
5878
5887
  if (!state) continue;
5879
- const specMatch = (state.specPath ?? "").match(/^docs\/changes\/([^/]+)\/proposal\.md$/);
5880
- if (!specMatch || !specMatch[1]) continue;
5881
- const topic = specMatch[1];
5888
+ const topic = extractAutopilotTopic(state);
5889
+ if (!topic) continue;
5882
5890
  for (const phase of state.phases ?? []) {
5883
5891
  if (phase.planPath) map.set(phase.planPath, topic);
5884
5892
  }
@@ -5912,8 +5920,7 @@ function extractTopicFromFilename(filename, proposalTopics) {
5912
5920
  }
5913
5921
  return best;
5914
5922
  }
5915
- async function buildPlan(opts) {
5916
- const cwd = opts.cwd ?? process.cwd();
5923
+ function resolveDocsDir(cwd) {
5917
5924
  const configPath = path40.join(cwd, "harness.config.json");
5918
5925
  const configResult = fs24.existsSync(configPath) ? resolveConfig(configPath) : null;
5919
5926
  let docsDir;
@@ -5929,71 +5936,72 @@ async function buildPlan(opts) {
5929
5936
  }
5930
5937
  const docsAbs = path40.resolve(cwd, docsDir);
5931
5938
  const relRaw = path40.relative(cwd, docsAbs).replaceAll("\\", "/");
5932
- const docsRel = relRaw === "" ? "docs" : relRaw;
5939
+ return relRaw === "" ? "docs" : relRaw;
5940
+ }
5941
+ function collectAdrMoves(cwd, docsRel) {
5942
+ const moves = [];
5943
+ const legacyAdrDir = path40.join(cwd, ".harness", "architecture");
5944
+ if (!fs24.existsSync(legacyAdrDir)) return moves;
5945
+ for (const topic of listDirs(legacyAdrDir)) {
5946
+ const topicSrc = path40.join(legacyAdrDir, topic);
5947
+ for (const file of listFiles(topicSrc, (n) => n.endsWith(".md"))) {
5948
+ moves.push({
5949
+ src: `.harness/architecture/${topic}/${file}`,
5950
+ dest: `${docsRel}/architecture/${topic}/${file}`
5951
+ });
5952
+ }
5953
+ }
5954
+ return moves;
5955
+ }
5956
+ function collectProposalTopics(cwd) {
5957
+ const topics = /* @__PURE__ */ new Set();
5958
+ const changesDir = path40.join(cwd, "docs", "changes");
5959
+ for (const topic of listDirs(changesDir)) {
5960
+ if (fs24.existsSync(path40.join(changesDir, topic, "proposal.md"))) {
5961
+ topics.add(topic);
5962
+ }
5963
+ }
5964
+ return topics;
5965
+ }
5966
+ function classifyPlan(planRel, planAbs, filename, autopilotMap, proposalTopics) {
5967
+ const fromAutopilot = autopilotMap.get(planRel);
5968
+ if (fromAutopilot) return { topic: fromAutopilot, via: "autopilot" };
5969
+ const fromHeader = extractTopicFromHeader(planAbs, proposalTopics);
5970
+ if (fromHeader) return { topic: fromHeader, via: "header" };
5971
+ const fromFilename = extractTopicFromFilename(filename, proposalTopics);
5972
+ if (fromFilename) return { topic: fromFilename, via: "filename" };
5973
+ return null;
5974
+ }
5975
+ async function buildPlan(opts) {
5976
+ const cwd = opts.cwd ?? process.cwd();
5977
+ const docsRel = resolveDocsDir(cwd);
5933
5978
  const plan = {
5934
5979
  cwd,
5935
5980
  isGitRepo: isGitRepo(cwd),
5936
5981
  docsDir: docsRel,
5937
- adrMoves: [],
5982
+ adrMoves: collectAdrMoves(cwd, docsRel),
5938
5983
  planMoves: [],
5939
5984
  orphanPlans: [],
5940
- proposalTopics: /* @__PURE__ */ new Set()
5985
+ proposalTopics: collectProposalTopics(cwd)
5941
5986
  };
5942
- const legacyAdrDir = path40.join(cwd, ".harness", "architecture");
5943
- if (fs24.existsSync(legacyAdrDir)) {
5944
- for (const topic of listDirs(legacyAdrDir)) {
5945
- const topicSrc = path40.join(legacyAdrDir, topic);
5946
- for (const file of listFiles(topicSrc, (n) => n.endsWith(".md"))) {
5947
- const src = `.harness/architecture/${topic}/${file}`;
5948
- const dest = `${docsRel}/architecture/${topic}/${file}`;
5949
- plan.adrMoves.push({ src, dest });
5950
- }
5951
- }
5952
- }
5953
5987
  const legacyPlanDir = path40.join(cwd, "docs", "plans");
5954
- const changesDir = path40.join(cwd, "docs", "changes");
5955
- for (const topic of listDirs(changesDir)) {
5956
- if (fs24.existsSync(path40.join(changesDir, topic, "proposal.md"))) {
5957
- plan.proposalTopics.add(topic);
5958
- }
5959
- }
5960
- if (fs24.existsSync(legacyPlanDir)) {
5961
- const autopilotMap = buildAutopilotMap(cwd);
5962
- for (const file of listFiles(legacyPlanDir, (n) => n.endsWith(".md") && n !== "index.md")) {
5963
- const planRel = `docs/plans/${file}`;
5964
- const planAbs = path40.join(legacyPlanDir, file);
5965
- const isVerification = file.includes("VERIFICATION");
5966
- const subdir = isVerification ? "verifications" : "plans";
5967
- let topic = null;
5968
- let via = null;
5969
- const fromAutopilot = autopilotMap.get(planRel);
5970
- if (fromAutopilot) {
5971
- topic = fromAutopilot;
5972
- via = "autopilot";
5973
- } else {
5974
- const fromHeader = extractTopicFromHeader(planAbs, plan.proposalTopics);
5975
- if (fromHeader) {
5976
- topic = fromHeader;
5977
- via = "header";
5978
- } else {
5979
- const fromFilename = extractTopicFromFilename(file, plan.proposalTopics);
5980
- if (fromFilename) {
5981
- topic = fromFilename;
5982
- via = "filename";
5983
- }
5984
- }
5985
- }
5986
- if (topic && via) {
5987
- plan.planMoves.push({
5988
- src: planRel,
5989
- dest: `docs/changes/${topic}/${subdir}/${file}`,
5990
- topic,
5991
- via,
5992
- subdir
5993
- });
5994
- } else {
5995
- plan.orphanPlans.push(planRel);
5996
- }
5988
+ if (!fs24.existsSync(legacyPlanDir)) return plan;
5989
+ const autopilotMap = buildAutopilotMap(cwd);
5990
+ for (const file of listFiles(legacyPlanDir, (n) => n.endsWith(".md") && n !== "index.md")) {
5991
+ const planRel = `docs/plans/${file}`;
5992
+ const planAbs = path40.join(legacyPlanDir, file);
5993
+ const subdir = file.includes("VERIFICATION") ? "verifications" : "plans";
5994
+ const classified = classifyPlan(planRel, planAbs, file, autopilotMap, plan.proposalTopics);
5995
+ if (classified) {
5996
+ plan.planMoves.push({
5997
+ src: planRel,
5998
+ dest: `docs/changes/${classified.topic}/${subdir}/${file}`,
5999
+ topic: classified.topic,
6000
+ via: classified.via,
6001
+ subdir
6002
+ });
6003
+ } else {
6004
+ plan.orphanPlans.push(planRel);
5997
6005
  }
5998
6006
  }
5999
6007
  return plan;
@@ -6068,7 +6076,7 @@ function updateReferences(plan) {
6068
6076
  }
6069
6077
  async function prompt(question, def = "n") {
6070
6078
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
6071
- const answer = await new Promise((resolve39) => rl.question(question, resolve39));
6079
+ const answer = await new Promise((resolve40) => rl.question(question, resolve40));
6072
6080
  rl.close();
6073
6081
  return (answer.trim() || def).toLowerCase();
6074
6082
  }
@@ -6166,6 +6174,29 @@ async function detectLegacyArtifacts(cwd) {
6166
6174
  const planLegacy = fs24.existsSync(planLegacyDir) && listFiles(planLegacyDir, (n) => n.endsWith(".md") && n !== "index.md").length > 0;
6167
6175
  return { adrLegacy, planLegacy };
6168
6176
  }
6177
+ async function confirmApply(opts) {
6178
+ if (opts.yes || !process.stdin.isTTY) return true;
6179
+ const answer = await prompt("Apply this migration? [y/N] ", "n");
6180
+ return answer === "y" || answer === "yes";
6181
+ }
6182
+ function applyMigration(plan, opts) {
6183
+ const { moved, failed } = executeMigration(plan);
6184
+ console.log("");
6185
+ if (failed > 0) logger.error(` Moved ${moved} file(s); ${failed} failed.`);
6186
+ else logger.success(` Moved ${moved} file(s).`);
6187
+ let references = { files: 0, replacements: 0 };
6188
+ if (!opts.skipReferences) {
6189
+ references = updateReferences(plan);
6190
+ if (references.replacements > 0) {
6191
+ logger.success(
6192
+ ` Updated ${references.replacements} reference(s) across ${references.files} file(s).`
6193
+ );
6194
+ } else {
6195
+ logger.info(" No reference updates needed.");
6196
+ }
6197
+ }
6198
+ return { moved, failed, references };
6199
+ }
6169
6200
  async function runMigrate(opts) {
6170
6201
  const cwd = opts.cwd ?? process.cwd();
6171
6202
  const plan = await buildPlan({ ...opts, cwd });
@@ -6188,34 +6219,13 @@ async function runMigrate(opts) {
6188
6219
  const movesPlanned = plan.adrMoves.length + plan.planMoves.length;
6189
6220
  if (opts.dryRun) {
6190
6221
  logger.info(" Dry run \u2014 no files moved.");
6191
- return Ok({
6192
- ...empty,
6193
- movesPlanned,
6194
- orphansRemaining: plan.orphanPlans.length
6195
- });
6222
+ return Ok({ ...empty, movesPlanned, orphansRemaining: plan.orphanPlans.length });
6196
6223
  }
6197
- if (!opts.yes && process.stdin.isTTY) {
6198
- const answer = await prompt("Apply this migration? [y/N] ", "n");
6199
- if (answer !== "y" && answer !== "yes") {
6200
- logger.info(" Cancelled.");
6201
- return Ok({ ...empty, movesPlanned, cancelled: true });
6202
- }
6203
- }
6204
- const { moved, failed } = executeMigration(plan);
6205
- console.log("");
6206
- if (failed > 0) logger.error(` Moved ${moved} file(s); ${failed} failed.`);
6207
- else logger.success(` Moved ${moved} file(s).`);
6208
- let references = { files: 0, replacements: 0 };
6209
- if (!opts.skipReferences) {
6210
- references = updateReferences(plan);
6211
- if (references.replacements > 0) {
6212
- logger.success(
6213
- ` Updated ${references.replacements} reference(s) across ${references.files} file(s).`
6214
- );
6215
- } else {
6216
- logger.info(" No reference updates needed.");
6217
- }
6224
+ if (!await confirmApply(opts)) {
6225
+ logger.info(" Cancelled.");
6226
+ return Ok({ ...empty, movesPlanned, cancelled: true });
6218
6227
  }
6228
+ const { moved, failed, references } = applyMigration(plan, opts);
6219
6229
  console.log("");
6220
6230
  logger.info(" Next: review changes with `git status` / `git diff`, then commit.");
6221
6231
  return Ok({
@@ -6296,7 +6306,7 @@ function registerBenchCommand(perf) {
6296
6306
  perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob2, _opts, cmd) => {
6297
6307
  const globalOpts = cmd.optsWithGlobals();
6298
6308
  const cwd = process.cwd();
6299
- const { BenchmarkRunner } = await import("./dist-6RT2AVYU.js");
6309
+ const { BenchmarkRunner } = await import("./dist-I4LWG3IN.js");
6300
6310
  const runner = new BenchmarkRunner();
6301
6311
  const benchFiles = runner.discover(cwd, glob2);
6302
6312
  if (benchFiles.length === 0) {
@@ -6360,7 +6370,7 @@ async function runBaselinesShow(globalOpts) {
6360
6370
  }
6361
6371
  async function runBaselinesUpdate(globalOpts) {
6362
6372
  const cwd = process.cwd();
6363
- const { BenchmarkRunner } = await import("./dist-6RT2AVYU.js");
6373
+ const { BenchmarkRunner } = await import("./dist-I4LWG3IN.js");
6364
6374
  const runner = new BenchmarkRunner();
6365
6375
  const manager = new BaselineManager(cwd);
6366
6376
  logger.info("Running benchmarks to update baselines...");
@@ -6401,7 +6411,7 @@ function registerReportCommand(perf) {
6401
6411
  perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
6402
6412
  const globalOpts = cmd.optsWithGlobals();
6403
6413
  const cwd = process.cwd();
6404
- const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-6RT2AVYU.js");
6414
+ const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-I4LWG3IN.js");
6405
6415
  const analyzer = new EntropyAnalyzer2({
6406
6416
  rootDir: path42.resolve(cwd),
6407
6417
  analyze: { complexity: true, coupling: true }
@@ -6735,14 +6745,39 @@ function bootstrapTrackerCommand(opts, verb) {
6735
6745
  }
6736
6746
  return { token, projectPath, trackerConfig };
6737
6747
  }
6738
- function buildNameToExternalIdMap(projectPath) {
6748
+ async function buildNameToExternalIdMap(projectPath) {
6749
+ const mode = loadProjectRoadmapMode(projectPath);
6750
+ if (mode === "file-less") {
6751
+ const trackerCfg = loadTrackerClientConfigFromProject(projectPath);
6752
+ if (!trackerCfg.ok) {
6753
+ logger.error(`File-less mode: ${trackerCfg.error.message}`);
6754
+ return null;
6755
+ }
6756
+ const clientR = createTrackerClient(trackerCfg.value);
6757
+ if (!clientR.ok) {
6758
+ logger.error(`File-less mode: ${clientR.error.message}`);
6759
+ return null;
6760
+ }
6761
+ const r = await clientR.value.fetchAll();
6762
+ if (!r.ok) {
6763
+ logger.error(`File-less mode: failed to fetch features from tracker: ${r.error.message}`);
6764
+ return null;
6765
+ }
6766
+ const fileLessMap = /* @__PURE__ */ new Map();
6767
+ for (const f of r.value.features) {
6768
+ if (f.externalId) {
6769
+ fileLessMap.set(f.name.toLowerCase(), f.externalId);
6770
+ }
6771
+ }
6772
+ return fileLessMap;
6773
+ }
6739
6774
  const roadmapFile = path44.join(projectPath, "docs", "roadmap.md");
6740
6775
  if (!fs26.existsSync(roadmapFile)) {
6741
6776
  logger.error("No docs/roadmap.md found. Cannot map issue hashes to external IDs.");
6742
6777
  return null;
6743
6778
  }
6744
- const { parseRoadmap } = (init_dist(), __toCommonJS(dist_exports));
6745
- const roadmapParsed = parseRoadmap(fs26.readFileSync(roadmapFile, "utf-8"));
6779
+ const { parseRoadmap: parseRoadmap2 } = (init_dist(), __toCommonJS(dist_exports));
6780
+ const roadmapParsed = parseRoadmap2(fs26.readFileSync(roadmapFile, "utf-8"));
6746
6781
  if (!roadmapParsed.ok) {
6747
6782
  logger.error("Failed to parse docs/roadmap.md");
6748
6783
  return null;
@@ -6789,10 +6824,10 @@ async function runPublishAnalyses(opts) {
6789
6824
  const bootstrap = bootstrapTrackerCommand(opts, "publish");
6790
6825
  if (!bootstrap) return process.exit(1);
6791
6826
  const { token, projectPath, trackerConfig } = bootstrap;
6792
- const nameToExternalId = buildNameToExternalIdMap(projectPath);
6827
+ const nameToExternalId = await buildNameToExternalIdMap(projectPath);
6793
6828
  if (!nameToExternalId) return process.exit(1);
6794
6829
  const { AnalysisArchive } = await import("@harness-engineering/orchestrator");
6795
- const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-6RT2AVYU.js");
6830
+ const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-I4LWG3IN.js");
6796
6831
  const archive = new AnalysisArchive(path44.join(projectPath, ".harness", "analyses"));
6797
6832
  const analyses = await archive.list();
6798
6833
  if (analyses.length === 0) {
@@ -7031,11 +7066,326 @@ function createRecommendCommand() {
7031
7066
  return command;
7032
7067
  }
7033
7068
 
7034
- // src/commands/scan-config.ts
7069
+ // src/commands/roadmap/index.ts
7070
+ import { Command as Command62 } from "commander";
7071
+
7072
+ // src/commands/roadmap/migrate.ts
7035
7073
  init_dist();
7036
7074
  import { Command as Command61 } from "commander";
7037
- import { existsSync as existsSync23, readFileSync as readFileSync16, writeFileSync as writeFileSync15 } from "fs";
7038
- import { join as join34, relative as relative3 } from "path";
7075
+ import * as fs28 from "fs";
7076
+ import * as path46 from "path";
7077
+ import chalk10 from "chalk";
7078
+
7079
+ // src/commands/roadmap/migrate-lock.ts
7080
+ import * as fs27 from "fs";
7081
+ import * as path45 from "path";
7082
+ import * as os6 from "os";
7083
+ var LOCK_FILE_NAME = "migrate.lock";
7084
+ var STALE_LOCK_MS = 30 * 60 * 1e3;
7085
+ function isPidAlive(pid) {
7086
+ if (!Number.isInteger(pid) || pid <= 0) return false;
7087
+ try {
7088
+ process.kill(pid, 0);
7089
+ return true;
7090
+ } catch {
7091
+ return false;
7092
+ }
7093
+ }
7094
+ function acquireMigrateLock(projectRoot) {
7095
+ const harnessDir = path45.join(projectRoot, ".harness");
7096
+ const lockPath = path45.join(harnessDir, LOCK_FILE_NAME);
7097
+ if (!fs27.existsSync(harnessDir)) fs27.mkdirSync(harnessDir, { recursive: true });
7098
+ if (fs27.existsSync(lockPath)) {
7099
+ const existingRaw = (() => {
7100
+ try {
7101
+ return fs27.readFileSync(lockPath, "utf-8");
7102
+ } catch {
7103
+ return null;
7104
+ }
7105
+ })();
7106
+ const existing = (() => {
7107
+ if (!existingRaw) return null;
7108
+ try {
7109
+ return JSON.parse(existingRaw);
7110
+ } catch {
7111
+ return null;
7112
+ }
7113
+ })();
7114
+ if (existing) {
7115
+ const ageMs = Date.now() - new Date(existing.startedAt).getTime();
7116
+ const stale = !isPidAlive(existing.pid) || ageMs > STALE_LOCK_MS;
7117
+ if (!stale) {
7118
+ return {
7119
+ reason: "in-progress",
7120
+ existing,
7121
+ message: `another migration is in progress (pid ${existing.pid} on ${existing.hostname}, started ${existing.startedAt})`
7122
+ };
7123
+ }
7124
+ }
7125
+ }
7126
+ const payload = {
7127
+ pid: process.pid,
7128
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
7129
+ hostname: os6.hostname()
7130
+ };
7131
+ fs27.writeFileSync(lockPath, JSON.stringify(payload, null, 2) + "\n");
7132
+ return {
7133
+ release: () => {
7134
+ try {
7135
+ fs27.unlinkSync(lockPath);
7136
+ } catch {
7137
+ }
7138
+ }
7139
+ };
7140
+ }
7141
+ function isRefusal(r) {
7142
+ return r.reason === "in-progress";
7143
+ }
7144
+
7145
+ // src/commands/roadmap/migrate.ts
7146
+ var MigrateExitCode = {
7147
+ SUCCESS: 0,
7148
+ GENERIC_FAILURE: 1,
7149
+ AMBIGUOUS: 2,
7150
+ ARCHIVE_COLLISION: 3,
7151
+ CONFIG_ERROR: 4,
7152
+ PARTIAL_CREATE: 5
7153
+ };
7154
+ function reportToExitCode(report) {
7155
+ if (report.mode !== "aborted") return MigrateExitCode.SUCCESS;
7156
+ const reason = report.abortReason ?? "";
7157
+ if (reason.startsWith("create failed") && report.createdSoFar && report.createdSoFar.length > 0) {
7158
+ return MigrateExitCode.PARTIAL_CREATE;
7159
+ }
7160
+ if (reason.startsWith("ambiguous features")) return MigrateExitCode.AMBIGUOUS;
7161
+ if (reason.startsWith("archive-collision")) return MigrateExitCode.ARCHIVE_COLLISION;
7162
+ if (reason.startsWith("config rewrite failed")) return MigrateExitCode.CONFIG_ERROR;
7163
+ return MigrateExitCode.GENERIC_FAILURE;
7164
+ }
7165
+ function printPlanSummary(plan, dryRun) {
7166
+ const banner = dryRun ? chalk10.cyan("DRY RUN ") : "";
7167
+ console.log(`${banner}Migration plan:`);
7168
+ console.log(` Would create: ${plan.toCreate.length}`);
7169
+ for (const e of plan.toCreate) console.log(` - ${e.name}`);
7170
+ console.log(` Would update: ${plan.toUpdate.length}`);
7171
+ for (const e of plan.toUpdate) console.log(` - ${e.name} (${e.externalId}): ${e.diff}`);
7172
+ console.log(` Unchanged: ${plan.unchanged.length}`);
7173
+ console.log(` Would append history: ${plan.historyToAppend.length}`);
7174
+ console.log(` Ambiguous: ${plan.ambiguous.length}`);
7175
+ for (const a of plan.ambiguous) {
7176
+ console.log(` - ${a.name} (existing: ${a.existingIssueRef})`);
7177
+ }
7178
+ }
7179
+ function printReport(report) {
7180
+ if (report.mode === "aborted") {
7181
+ logger.error(`Migration aborted: ${report.abortReason ?? "unknown reason"}`);
7182
+ if (report.createdSoFar && report.createdSoFar.length > 0) {
7183
+ logger.warn(
7184
+ `Features created before abort (record manually): ${report.createdSoFar.map((c) => `${c.name} \u2192 ${c.externalId}`).join(", ")}`
7185
+ );
7186
+ }
7187
+ return;
7188
+ }
7189
+ if (report.mode === "dry-run") {
7190
+ logger.info(`DRY RUN complete: ${report.created + report.updated} writes would be performed.`);
7191
+ return;
7192
+ }
7193
+ if (report.mode === "already-migrated") {
7194
+ logger.success("Already migrated; nothing to do.");
7195
+ return;
7196
+ }
7197
+ logger.success(
7198
+ `Migration applied: ${report.created} created, ${report.updated} updated, ${report.unchanged} unchanged, ${report.historyAppended} history events appended.`
7199
+ );
7200
+ if (report.archivedTo) logger.info(`Archived: ${report.archivedFrom} -> ${report.archivedTo}`);
7201
+ if (report.configBackup) logger.info(`Config backup: ${report.configBackup}`);
7202
+ }
7203
+ async function collectHistoryHashes(client, externalId) {
7204
+ const result = await client.fetchHistory(externalId);
7205
+ const set = /* @__PURE__ */ new Set();
7206
+ if (!result.ok) return set;
7207
+ for (const e of result.value) set.add(migrate_exports.hashHistoryEvent(e));
7208
+ return set;
7209
+ }
7210
+ function makeRawBodyResolver(_client, _features) {
7211
+ return async () => null;
7212
+ }
7213
+ function buildJsonOutput(plan, report, error, exitCode) {
7214
+ const out = {
7215
+ ok: exitCode === MigrateExitCode.SUCCESS,
7216
+ mode: report ? report.mode : "error",
7217
+ exitCode
7218
+ };
7219
+ if (plan) {
7220
+ out.plan = {
7221
+ toCreate: plan.toCreate.map((e) => ({ name: e.name })),
7222
+ toUpdate: plan.toUpdate.map((e) => ({
7223
+ name: e.name,
7224
+ externalId: e.externalId,
7225
+ diff: e.diff
7226
+ })),
7227
+ unchanged: plan.unchanged,
7228
+ historyToAppend: plan.historyToAppend.map((e) => ({
7229
+ externalId: e.externalId,
7230
+ type: e.event.type
7231
+ })),
7232
+ ambiguous: plan.ambiguous
7233
+ };
7234
+ }
7235
+ if (report) out.report = report;
7236
+ if (error) out.error = error;
7237
+ return out;
7238
+ }
7239
+ async function runRoadmapMigrate(opts) {
7240
+ const cwd = opts.cwd ?? process.cwd();
7241
+ const format = opts.format ?? "human";
7242
+ const isJson = format === "json";
7243
+ if (!opts.to) {
7244
+ return Err(new CLIError("missing required argument: --to <target>", ExitCode.ERROR));
7245
+ }
7246
+ if (opts.to === "file-backed") {
7247
+ return Err(
7248
+ new CLIError(
7249
+ "--to=file-backed reverse migration is not yet implemented; track in a future spec"
7250
+ )
7251
+ );
7252
+ }
7253
+ if (opts.to !== "file-less") {
7254
+ return Err(
7255
+ new CLIError(`unsupported migration target: ${opts.to} (only "file-less" supported today)`)
7256
+ );
7257
+ }
7258
+ if (loadProjectRoadmapMode(cwd) === "file-less") {
7259
+ const alreadyMigratedReport = {
7260
+ created: 0,
7261
+ updated: 0,
7262
+ unchanged: 0,
7263
+ historyAppended: 0,
7264
+ archivedFrom: null,
7265
+ archivedTo: null,
7266
+ configBackup: null,
7267
+ mode: "already-migrated"
7268
+ };
7269
+ if (isJson) {
7270
+ console.log(
7271
+ JSON.stringify(
7272
+ buildJsonOutput(void 0, alreadyMigratedReport, void 0, MigrateExitCode.SUCCESS)
7273
+ )
7274
+ );
7275
+ } else {
7276
+ logger.success("Already migrated; nothing to do.");
7277
+ }
7278
+ return Ok(alreadyMigratedReport);
7279
+ }
7280
+ const lockResult = acquireMigrateLock(cwd);
7281
+ if (isRefusal(lockResult)) {
7282
+ return Err(new CLIError(lockResult.message));
7283
+ }
7284
+ try {
7285
+ let client;
7286
+ if (opts.client) {
7287
+ client = opts.client;
7288
+ } else {
7289
+ const cfgR = loadTrackerClientConfigFromProject(cwd);
7290
+ if (!cfgR.ok) return Err(new CLIError(cfgR.error.message));
7291
+ const clientR = createTrackerClient(cfgR.value);
7292
+ if (!clientR.ok) return Err(new CLIError(clientR.error.message));
7293
+ client = clientR.value;
7294
+ }
7295
+ const roadmapPath = path46.join(cwd, "docs", "roadmap.md");
7296
+ if (!fs28.existsSync(roadmapPath)) {
7297
+ return Err(new CLIError(`docs/roadmap.md not found in ${cwd}`));
7298
+ }
7299
+ const roadmapR = parseRoadmap(fs28.readFileSync(roadmapPath, "utf-8"));
7300
+ if (!roadmapR.ok) {
7301
+ return Err(new CLIError(`failed to parse docs/roadmap.md: ${roadmapR.error.message}`));
7302
+ }
7303
+ const roadmap = roadmapR.value;
7304
+ const fetchR = await client.fetchAll();
7305
+ if (!fetchR.ok) {
7306
+ return Err(new CLIError(`failed to fetch tracker features: ${fetchR.error.message}`));
7307
+ }
7308
+ const existingFeatures = fetchR.value.features;
7309
+ const getRawBody = makeRawBodyResolver(client, existingFeatures);
7310
+ const fetchHashes = (id) => collectHistoryHashes(client, id);
7311
+ const plan = await migrate_exports.buildMigrationPlan(
7312
+ roadmap,
7313
+ existingFeatures,
7314
+ fetchHashes,
7315
+ getRawBody
7316
+ );
7317
+ if (!isJson) printPlanSummary(plan, opts.dryRun);
7318
+ const deps = {
7319
+ client,
7320
+ readFile: (p) => fs28.readFileSync(p, "utf-8"),
7321
+ writeFile: (p, b) => fs28.writeFileSync(p, b),
7322
+ renameFile: (from, to) => fs28.renameSync(from, to),
7323
+ existsFile: (p) => fs28.existsSync(p)
7324
+ };
7325
+ const reportR = await migrate_exports.runMigrationPlan(plan, deps, {
7326
+ projectRoot: cwd,
7327
+ dryRun: opts.dryRun
7328
+ });
7329
+ if (!reportR.ok) {
7330
+ return Err(new CLIError(`migration failed: ${reportR.error.message}`));
7331
+ }
7332
+ if (isJson) {
7333
+ const exitCode = reportToExitCode(reportR.value);
7334
+ console.log(JSON.stringify(buildJsonOutput(plan, reportR.value, void 0, exitCode)));
7335
+ } else {
7336
+ printReport(reportR.value);
7337
+ }
7338
+ return Ok(reportR.value);
7339
+ } finally {
7340
+ lockResult.release();
7341
+ }
7342
+ }
7343
+ function createRoadmapMigrateCommand() {
7344
+ return new Command61("migrate").description("Migrate the project roadmap to a different storage mode").requiredOption("--to <target>", 'Migration target (only "file-less" supported today)').option("--dry-run", "Print the migration plan without making any changes", false).option(
7345
+ "--format <fmt>",
7346
+ 'Output format: "human" (default) or "json" (single JSON object for CI consumers)',
7347
+ "human"
7348
+ ).action(async (options) => {
7349
+ const format = options.format === "json" ? "json" : "human";
7350
+ const result = await runRoadmapMigrate({
7351
+ to: options.to,
7352
+ dryRun: Boolean(options.dryRun),
7353
+ format
7354
+ });
7355
+ if (!result.ok) {
7356
+ if (format === "json") {
7357
+ console.log(
7358
+ JSON.stringify(
7359
+ buildJsonOutput(
7360
+ void 0,
7361
+ void 0,
7362
+ result.error.message,
7363
+ MigrateExitCode.CONFIG_ERROR
7364
+ )
7365
+ )
7366
+ );
7367
+ } else {
7368
+ logger.error(result.error.message);
7369
+ }
7370
+ process.exit(format === "json" ? MigrateExitCode.CONFIG_ERROR : result.error.exitCode);
7371
+ }
7372
+ const exitCode = reportToExitCode(result.value);
7373
+ process.exit(exitCode);
7374
+ });
7375
+ }
7376
+
7377
+ // src/commands/roadmap/index.ts
7378
+ function createRoadmapCommand() {
7379
+ const roadmap = new Command62("roadmap").description("Roadmap management");
7380
+ roadmap.addCommand(createRoadmapMigrateCommand());
7381
+ return roadmap;
7382
+ }
7383
+
7384
+ // src/commands/scan-config.ts
7385
+ init_dist();
7386
+ import { Command as Command63 } from "commander";
7387
+ import { existsSync as existsSync25, readFileSync as readFileSync18, writeFileSync as writeFileSync17 } from "fs";
7388
+ import { join as join36, relative as relative3 } from "path";
7039
7389
  var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
7040
7390
  function stripHighSeverityPatterns(content, injectionFindings) {
7041
7391
  const highLines = /* @__PURE__ */ new Set();
@@ -7061,17 +7411,17 @@ function applyFix(filePath, targetDir, content, injectionFindings) {
7061
7411
  if (!hasHighSeverity) return;
7062
7412
  const { cleaned, linesStripped } = stripHighSeverityPatterns(content, injectionFindings);
7063
7413
  if (linesStripped > 0) {
7064
- writeFileSync15(filePath, cleaned);
7414
+ writeFileSync17(filePath, cleaned);
7065
7415
  logger.info(
7066
7416
  `scan-config --fix: stripped ${linesStripped} high-severity line(s) from ${relative3(targetDir, filePath).replaceAll("\\", "/")}`
7067
7417
  );
7068
7418
  }
7069
7419
  }
7070
7420
  function scanSingleFile(filePath, targetDir, scanner, options) {
7071
- if (!existsSync23(filePath)) return null;
7421
+ if (!existsSync25(filePath)) return null;
7072
7422
  let content;
7073
7423
  try {
7074
- content = readFileSync16(filePath, "utf8");
7424
+ content = readFileSync18(filePath, "utf8");
7075
7425
  } catch {
7076
7426
  return null;
7077
7427
  }
@@ -7092,7 +7442,7 @@ async function runScanConfig(targetDir, options) {
7092
7442
  const scanner = new SecurityScanner(parseSecurityConfig({}));
7093
7443
  const results = [];
7094
7444
  for (const configFile of CONFIG_FILES) {
7095
- const result = scanSingleFile(join34(targetDir, configFile), targetDir, scanner, options);
7445
+ const result = scanSingleFile(join36(targetDir, configFile), targetDir, scanner, options);
7096
7446
  if (result) results.push(result);
7097
7447
  }
7098
7448
  return { exitCode: computeScanExitCode(results), results };
@@ -7122,7 +7472,7 @@ function formatTextOutput(result) {
7122
7472
  }
7123
7473
  }
7124
7474
  function createScanConfigCommand() {
7125
- const command = new Command61("scan-config").description(
7475
+ const command = new Command63("scan-config").description(
7126
7476
  "Scan CLAUDE.md, AGENTS.md, .gemini/settings.json, and skill.yaml for prompt injection patterns"
7127
7477
  ).option("--path <dir>", "Target directory to scan (default: cwd)").option("--fix", "Strip high-severity patterns from files in-place").action(async (opts, cmd) => {
7128
7478
  const globalOpts = cmd.optsWithGlobals();
@@ -7139,24 +7489,24 @@ function createScanConfigCommand() {
7139
7489
  }
7140
7490
 
7141
7491
  // src/commands/setup.ts
7142
- import { Command as Command62 } from "commander";
7492
+ import { Command as Command64 } from "commander";
7493
+ import * as fs31 from "fs";
7494
+ import * as os8 from "os";
7495
+ import * as path49 from "path";
7496
+ import chalk12 from "chalk";
7497
+
7498
+ // src/utils/first-run.ts
7143
7499
  import * as fs29 from "fs";
7144
7500
  import * as os7 from "os";
7145
7501
  import * as path47 from "path";
7146
- import chalk11 from "chalk";
7147
-
7148
- // src/utils/first-run.ts
7149
- import * as fs27 from "fs";
7150
- import * as os6 from "os";
7151
- import * as path45 from "path";
7152
- var HARNESS_DIR = path45.join(os6.homedir(), ".harness");
7153
- var MARKER_FILE = path45.join(HARNESS_DIR, ".setup-complete");
7502
+ var HARNESS_DIR = path47.join(os7.homedir(), ".harness");
7503
+ var MARKER_FILE = path47.join(HARNESS_DIR, ".setup-complete");
7154
7504
  function isFirstRun() {
7155
- return !fs27.existsSync(MARKER_FILE);
7505
+ return !fs29.existsSync(MARKER_FILE);
7156
7506
  }
7157
7507
  function markSetupComplete() {
7158
- fs27.mkdirSync(HARNESS_DIR, { recursive: true });
7159
- fs27.writeFileSync(MARKER_FILE, "", "utf-8");
7508
+ fs29.mkdirSync(HARNESS_DIR, { recursive: true });
7509
+ fs29.writeFileSync(MARKER_FILE, "", "utf-8");
7160
7510
  }
7161
7511
  function printFirstRunWelcome() {
7162
7512
  try {
@@ -7169,19 +7519,19 @@ function printFirstRunWelcome() {
7169
7519
  }
7170
7520
 
7171
7521
  // src/commands/telemetry-wizard.ts
7172
- import * as fs28 from "fs";
7173
- import * as path46 from "path";
7522
+ import * as fs30 from "fs";
7523
+ import * as path48 from "path";
7174
7524
  import readline2 from "readline";
7175
- import chalk10 from "chalk";
7525
+ import chalk11 from "chalk";
7176
7526
  function prompt2(question) {
7177
7527
  const rl = readline2.createInterface({
7178
7528
  input: process.stdin,
7179
7529
  output: process.stdout
7180
7530
  });
7181
- return new Promise((resolve39) => {
7531
+ return new Promise((resolve40) => {
7182
7532
  rl.question(question, (answer) => {
7183
7533
  rl.close();
7184
- resolve39(answer.trim().toLowerCase());
7534
+ resolve40(answer.trim().toLowerCase());
7185
7535
  });
7186
7536
  });
7187
7537
  }
@@ -7190,10 +7540,10 @@ function promptRaw(question) {
7190
7540
  input: process.stdin,
7191
7541
  output: process.stdout
7192
7542
  });
7193
- return new Promise((resolve39) => {
7543
+ return new Promise((resolve40) => {
7194
7544
  rl.question(question, (answer) => {
7195
7545
  rl.close();
7196
- resolve39(answer.trim());
7546
+ resolve40(answer.trim());
7197
7547
  });
7198
7548
  });
7199
7549
  }
@@ -7201,21 +7551,21 @@ function isNo(answer) {
7201
7551
  return answer === "n" || answer === "no";
7202
7552
  }
7203
7553
  function isTelemetryConfigured(cwd) {
7204
- const configPath = path46.join(cwd, "harness.config.json");
7554
+ const configPath = path48.join(cwd, "harness.config.json");
7205
7555
  try {
7206
- const raw = JSON.parse(fs28.readFileSync(configPath, "utf-8"));
7556
+ const raw = JSON.parse(fs30.readFileSync(configPath, "utf-8"));
7207
7557
  return raw.telemetry !== void 0 && raw.adoption !== void 0;
7208
7558
  } catch {
7209
7559
  return false;
7210
7560
  }
7211
7561
  }
7212
7562
  function writeTelemetryConfig(cwd, result) {
7213
- const configPath = path46.join(cwd, "harness.config.json");
7563
+ const configPath = path48.join(cwd, "harness.config.json");
7214
7564
  try {
7215
- const raw = JSON.parse(fs28.readFileSync(configPath, "utf-8"));
7565
+ const raw = JSON.parse(fs30.readFileSync(configPath, "utf-8"));
7216
7566
  raw.telemetry = { enabled: result.telemetryEnabled };
7217
7567
  raw.adoption = { enabled: result.adoptionEnabled };
7218
- fs28.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
7568
+ fs30.writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
7219
7569
  } catch (err) {
7220
7570
  console.warn(
7221
7571
  `\u26A0 Could not update ${configPath}: ${err instanceof Error ? err.message : String(err)}`
@@ -7223,15 +7573,15 @@ function writeTelemetryConfig(cwd, result) {
7223
7573
  }
7224
7574
  const hasIdentity = result.identity.project || result.identity.team || result.identity.alias;
7225
7575
  if (hasIdentity) {
7226
- const harnessDir = path46.join(cwd, ".harness");
7227
- fs28.mkdirSync(harnessDir, { recursive: true });
7228
- const telemetryFile = path46.join(harnessDir, "telemetry.json");
7229
- fs28.writeFileSync(telemetryFile, JSON.stringify({ identity: result.identity }, null, 2) + "\n");
7576
+ const harnessDir = path48.join(cwd, ".harness");
7577
+ fs30.mkdirSync(harnessDir, { recursive: true });
7578
+ const telemetryFile = path48.join(harnessDir, "telemetry.json");
7579
+ fs30.writeFileSync(telemetryFile, JSON.stringify({ identity: result.identity }, null, 2) + "\n");
7230
7580
  }
7231
7581
  }
7232
7582
  async function promptIdentity() {
7233
7583
  console.log(
7234
- ` ${chalk10.cyan("Identity")} (optional) \u2014 tag telemetry with project/team/alias for filtering.`
7584
+ ` ${chalk11.cyan("Identity")} (optional) \u2014 tag telemetry with project/team/alias for filtering.`
7235
7585
  );
7236
7586
  console.log(" Leave blank to keep anonymous.");
7237
7587
  const answer = await prompt2(" Set identity fields? (y/N) ");
@@ -7249,20 +7599,20 @@ async function promptIdentity() {
7249
7599
  async function runTelemetryWizard() {
7250
7600
  if (!process.stdin.isTTY) return null;
7251
7601
  console.log("");
7252
- console.log(` ${chalk10.bold("Telemetry Configuration")}`);
7602
+ console.log(` ${chalk11.bold("Telemetry Configuration")}`);
7253
7603
  console.log("");
7254
7604
  console.log(" Harness can collect anonymous usage data to help improve the tool.");
7255
7605
  console.log(" You can change these settings anytime in harness.config.json.");
7256
7606
  console.log("");
7257
7607
  console.log(
7258
- ` ${chalk10.cyan("Anonymous telemetry")} \u2014 error rates, command usage, performance metrics.`
7608
+ ` ${chalk11.cyan("Anonymous telemetry")} \u2014 error rates, command usage, performance metrics.`
7259
7609
  );
7260
7610
  console.log(" No code, file contents, or personally identifiable info is sent.");
7261
7611
  const telemetryAnswer = await prompt2(" Enable anonymous telemetry? (Y/n) ");
7262
7612
  const telemetryEnabled = !isNo(telemetryAnswer);
7263
7613
  console.log("");
7264
7614
  console.log(
7265
- ` ${chalk10.cyan("Adoption tracking")} \u2014 which skills are used, how often, and success rates.`
7615
+ ` ${chalk11.cyan("Adoption tracking")} \u2014 which skills are used, how often, and success rates.`
7266
7616
  );
7267
7617
  console.log(" Stored locally in .harness/adoption/. Never sent externally.");
7268
7618
  const adoptionAnswer = await prompt2(" Enable local adoption tracking? (Y/n) ");
@@ -7272,8 +7622,8 @@ async function runTelemetryWizard() {
7272
7622
  return { telemetryEnabled, adoptionEnabled, identity };
7273
7623
  }
7274
7624
  async function ensureTelemetryConfigured(cwd) {
7275
- const configPath = path46.join(cwd, "harness.config.json");
7276
- if (!fs28.existsSync(configPath)) {
7625
+ const configPath = path48.join(cwd, "harness.config.json");
7626
+ if (!fs30.existsSync(configPath)) {
7277
7627
  return { status: "warn", message: "Not a harness project \u2014 skipped telemetry configuration" };
7278
7628
  }
7279
7629
  if (isTelemetryConfigured(cwd)) {
@@ -7319,7 +7669,7 @@ function runSlashCommandGeneration() {
7319
7669
  }
7320
7670
  }
7321
7671
  function detectClient(dirName) {
7322
- return fs29.existsSync(path47.join(os7.homedir(), dirName));
7672
+ return fs31.existsSync(path49.join(os8.homedir(), dirName));
7323
7673
  }
7324
7674
  async function runMcpSetup(cwd) {
7325
7675
  const results = [];
@@ -7335,7 +7685,7 @@ async function runMcpSetup(cwd) {
7335
7685
  { name: "Cursor", dir: ".cursor", client: "cursor", configTarget: ".cursor/mcp.json" },
7336
7686
  {
7337
7687
  name: "OpenCode",
7338
- dir: path47.join(".config", "opencode"),
7688
+ dir: path49.join(".config", "opencode"),
7339
7689
  client: "opencode",
7340
7690
  configTarget: "opencode.json"
7341
7691
  }
@@ -7362,12 +7712,12 @@ async function runMcpSetup(cwd) {
7362
7712
  return results;
7363
7713
  }
7364
7714
  function formatStep(result) {
7365
- const icon = result.status === "pass" ? chalk11.green("\u2713") : result.status === "warn" ? chalk11.yellow("\u26A0") : chalk11.red("\u2717");
7715
+ const icon = result.status === "pass" ? chalk12.green("\u2713") : result.status === "warn" ? chalk12.yellow("\u26A0") : chalk12.red("\u2717");
7366
7716
  return ` ${icon} ${result.message}`;
7367
7717
  }
7368
7718
  function configureTier0Integrations(cwd) {
7369
7719
  try {
7370
- const mcpPath = path47.join(cwd, ".mcp.json");
7720
+ const mcpPath = path49.join(cwd, ".mcp.json");
7371
7721
  const config = readMcpConfig(mcpPath);
7372
7722
  const tier0 = INTEGRATION_REGISTRY.filter((i) => i.tier === 0);
7373
7723
  const added = [];
@@ -7376,9 +7726,9 @@ function configureTier0Integrations(cwd) {
7376
7726
  writeMcpEntry(mcpPath, integration.name, integration.mcpConfig);
7377
7727
  added.push(integration.displayName);
7378
7728
  }
7379
- const geminiDir = path47.join(cwd, ".gemini");
7380
- if (fs29.existsSync(geminiDir)) {
7381
- const geminiPath = path47.join(geminiDir, "settings.json");
7729
+ const geminiDir = path49.join(cwd, ".gemini");
7730
+ if (fs31.existsSync(geminiDir)) {
7731
+ const geminiPath = path49.join(geminiDir, "settings.json");
7382
7732
  const geminiConfig = readMcpConfig(geminiPath);
7383
7733
  for (const integration of tier0) {
7384
7734
  if (!geminiConfig.mcpServers[integration.name]) {
@@ -7386,9 +7736,9 @@ function configureTier0Integrations(cwd) {
7386
7736
  }
7387
7737
  }
7388
7738
  }
7389
- const opencodePath = path47.join(cwd, "opencode.json");
7390
- const opencodeGlobalDir = path47.join(os7.homedir(), ".config", "opencode");
7391
- if (fs29.existsSync(opencodePath) || fs29.existsSync(opencodeGlobalDir)) {
7739
+ const opencodePath = path49.join(cwd, "opencode.json");
7740
+ const opencodeGlobalDir = path49.join(os8.homedir(), ".config", "opencode");
7741
+ if (fs31.existsSync(opencodePath) || fs31.existsSync(opencodeGlobalDir)) {
7392
7742
  for (const integration of tier0) {
7393
7743
  writeOpencodeMcpEntry(opencodePath, integration.name, integration.mcpConfig);
7394
7744
  }
@@ -7406,14 +7756,14 @@ function configureTier0Integrations(cwd) {
7406
7756
  }
7407
7757
  }
7408
7758
  function ensureHooks(cwd) {
7409
- const configPath = path47.join(cwd, "harness.config.json");
7410
- if (!fs29.existsSync(configPath)) {
7759
+ const configPath = path49.join(cwd, "harness.config.json");
7760
+ if (!fs31.existsSync(configPath)) {
7411
7761
  return { status: "warn", message: "Not a harness project \u2014 skipped hook installation" };
7412
7762
  }
7413
7763
  let profile = "standard";
7414
- const profilePath = path47.join(cwd, ".harness", "hooks", "profile.json");
7764
+ const profilePath = path49.join(cwd, ".harness", "hooks", "profile.json");
7415
7765
  try {
7416
- const data = JSON.parse(fs29.readFileSync(profilePath, "utf-8"));
7766
+ const data = JSON.parse(fs31.readFileSync(profilePath, "utf-8"));
7417
7767
  if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
7418
7768
  profile = data.profile;
7419
7769
  }
@@ -7484,10 +7834,10 @@ async function runSetup(cwd) {
7484
7834
  return { steps, success };
7485
7835
  }
7486
7836
  function createSetupCommand() {
7487
- return new Command62("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
7837
+ return new Command64("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
7488
7838
  const cwd = process.cwd();
7489
7839
  console.log("");
7490
- console.log(` ${chalk11.bold("harness setup")}`);
7840
+ console.log(` ${chalk12.bold("harness setup")}`);
7491
7841
  console.log("");
7492
7842
  const { steps, success } = await runSetup(cwd);
7493
7843
  for (const step of steps) {
@@ -7507,15 +7857,15 @@ function createSetupCommand() {
7507
7857
 
7508
7858
  // src/commands/share.ts
7509
7859
  init_dist();
7510
- import { Command as Command63 } from "commander";
7511
- import * as fs30 from "fs";
7512
- import * as path48 from "path";
7860
+ import { Command as Command65 } from "commander";
7861
+ import * as fs32 from "fs";
7862
+ import * as path50 from "path";
7513
7863
  import { parse as parseYaml } from "yaml";
7514
7864
  var MANIFEST_FILENAME = "constraints.yaml";
7515
7865
  async function runShareAction(projectPath, options) {
7516
- const rootDir = path48.resolve(projectPath);
7517
- const manifestPath = path48.join(rootDir, MANIFEST_FILENAME);
7518
- if (!fs30.existsSync(manifestPath)) {
7866
+ const rootDir = path50.resolve(projectPath);
7867
+ const manifestPath = path50.join(rootDir, MANIFEST_FILENAME);
7868
+ if (!fs32.existsSync(manifestPath)) {
7519
7869
  logger.error(
7520
7870
  `No ${MANIFEST_FILENAME} found at ${manifestPath}.
7521
7871
  Create a constraints.yaml in your project root to define what to share.`
@@ -7524,7 +7874,7 @@ Create a constraints.yaml in your project root to define what to share.`
7524
7874
  }
7525
7875
  let parsed;
7526
7876
  try {
7527
- const raw = fs30.readFileSync(manifestPath, "utf-8");
7877
+ const raw = fs32.readFileSync(manifestPath, "utf-8");
7528
7878
  parsed = parseYaml(raw);
7529
7879
  } catch (err) {
7530
7880
  logger.error(
@@ -7538,7 +7888,7 @@ Create a constraints.yaml in your project root to define what to share.`
7538
7888
  process.exit(1);
7539
7889
  }
7540
7890
  const manifest = manifestResult.value;
7541
- const configResult = resolveConfig(path48.join(rootDir, "harness.config.json"));
7891
+ const configResult = resolveConfig(path50.join(rootDir, "harness.config.json"));
7542
7892
  if (!configResult.ok) {
7543
7893
  logger.error(configResult.error.message);
7544
7894
  process.exit(1);
@@ -7556,8 +7906,8 @@ Create a constraints.yaml in your project root to define what to share.`
7556
7906
  );
7557
7907
  process.exit(1);
7558
7908
  }
7559
- const outputDir = path48.resolve(options.output);
7560
- const outputPath = path48.join(outputDir, `${manifest.name}.harness-constraints.json`);
7909
+ const outputDir = path50.resolve(options.output);
7910
+ const outputPath = path50.join(outputDir, `${manifest.name}.harness-constraints.json`);
7561
7911
  const writeResult = await writeConfig(outputPath, bundle);
7562
7912
  if (!writeResult.ok) {
7563
7913
  logger.error(`Failed to write bundle: ${writeResult.error.message}`);
@@ -7566,28 +7916,28 @@ Create a constraints.yaml in your project root to define what to share.`
7566
7916
  logger.success(`Bundle written to ${outputPath}`);
7567
7917
  }
7568
7918
  function createShareCommand() {
7569
- return new Command63("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) => {
7919
+ return new Command65("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) => {
7570
7920
  await runShareAction(projectPath, options);
7571
7921
  });
7572
7922
  }
7573
7923
 
7574
7924
  // src/commands/skill/index.ts
7575
- import { Command as Command71 } from "commander";
7925
+ import { Command as Command73 } from "commander";
7576
7926
 
7577
7927
  // src/commands/skill/list.ts
7578
- import { Command as Command64 } from "commander";
7579
- import * as fs31 from "fs";
7580
- import * as path49 from "path";
7928
+ import { Command as Command66 } from "commander";
7929
+ import * as fs33 from "fs";
7930
+ import * as path51 from "path";
7581
7931
  import { parse } from "yaml";
7582
7932
  function scanDirectory(dirPath, source) {
7583
- if (!fs31.existsSync(dirPath)) return [];
7584
- const entries = fs31.readdirSync(dirPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
7933
+ if (!fs33.existsSync(dirPath)) return [];
7934
+ const entries = fs33.readdirSync(dirPath, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
7585
7935
  const skills = [];
7586
7936
  for (const name of entries) {
7587
- const yamlPath = path49.join(dirPath, name, "skill.yaml");
7588
- if (!fs31.existsSync(yamlPath)) continue;
7937
+ const yamlPath = path51.join(dirPath, name, "skill.yaml");
7938
+ if (!fs33.existsSync(yamlPath)) continue;
7589
7939
  try {
7590
- const raw = fs31.readFileSync(yamlPath, "utf-8");
7940
+ const raw = fs33.readFileSync(yamlPath, "utf-8");
7591
7941
  const parsed = parse(raw);
7592
7942
  const result = SkillMetadataSchema.safeParse(parsed);
7593
7943
  if (result.success) {
@@ -7605,10 +7955,10 @@ function scanDirectory(dirPath, source) {
7605
7955
  }
7606
7956
  function collectCommunitySkills(seen, allSkills) {
7607
7957
  const globalDir = resolveGlobalSkillsDir();
7608
- const skillsDir = path49.dirname(globalDir);
7609
- const communityBase = path49.join(skillsDir, "community");
7610
- const communityPlatformDir = path49.join(communityBase, "claude-code");
7611
- const lockfilePath = path49.join(communityBase, "skills-lock.json");
7958
+ const skillsDir = path51.dirname(globalDir);
7959
+ const communityBase = path51.join(skillsDir, "community");
7960
+ const communityPlatformDir = path51.join(communityBase, "claude-code");
7961
+ const lockfilePath = path51.join(communityBase, "skills-lock.json");
7612
7962
  const lockfile = readLockfile2(lockfilePath);
7613
7963
  const communitySkills = scanDirectory(communityPlatformDir, "community");
7614
7964
  for (const skill of communitySkills) {
@@ -7678,7 +8028,7 @@ function printSkillsVerbose(skills) {
7678
8028
  for (const s of skills) printSkillEntry(s);
7679
8029
  }
7680
8030
  function createListCommand3() {
7681
- return new Command64("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) => {
8031
+ return new Command66("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) => {
7682
8032
  const globalOpts = cmd.optsWithGlobals();
7683
8033
  const skills = collectSkills({ filter: resolveFilter(opts) });
7684
8034
  if (globalOpts.json) {
@@ -7693,9 +8043,9 @@ function createListCommand3() {
7693
8043
  }
7694
8044
 
7695
8045
  // src/commands/skill/run.ts
7696
- import { Command as Command65 } from "commander";
7697
- import * as fs32 from "fs";
7698
- import * as path50 from "path";
8046
+ import { Command as Command67 } from "commander";
8047
+ import * as fs34 from "fs";
8048
+ import * as path52 from "path";
7699
8049
  import { parse as parse2 } from "yaml";
7700
8050
 
7701
8051
  // src/skill/complexity.ts
@@ -7791,10 +8141,10 @@ ${options.principles}`);
7791
8141
 
7792
8142
  // src/commands/skill/run.ts
7793
8143
  function loadSkillMetadata(skillDir) {
7794
- const yamlPath = path50.join(skillDir, "skill.yaml");
7795
- if (!fs32.existsSync(yamlPath)) return null;
8144
+ const yamlPath = path52.join(skillDir, "skill.yaml");
8145
+ if (!fs34.existsSync(yamlPath)) return null;
7796
8146
  try {
7797
- const result = SkillMetadataSchema.safeParse(parse2(fs32.readFileSync(yamlPath, "utf-8")));
8147
+ const result = SkillMetadataSchema.safeParse(parse2(fs34.readFileSync(yamlPath, "utf-8")));
7798
8148
  return result.success ? result.data : null;
7799
8149
  } catch {
7800
8150
  return null;
@@ -7806,22 +8156,22 @@ function resolveComplexity(metadata, requested, projectPath) {
7806
8156
  return requested;
7807
8157
  }
7808
8158
  function loadPrinciples(projectPath) {
7809
- const principlesPath = path50.join(projectPath, "docs", "principles.md");
7810
- return fs32.existsSync(principlesPath) ? fs32.readFileSync(principlesPath, "utf-8") : void 0;
8159
+ const principlesPath = path52.join(projectPath, "docs", "principles.md");
8160
+ return fs34.existsSync(principlesPath) ? fs34.readFileSync(principlesPath, "utf-8") : void 0;
7811
8161
  }
7812
8162
  function readMostRecentFileInDir(dirPath) {
7813
- const files = fs32.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs32.statSync(path50.join(dirPath, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
7814
- if (files.length > 0) return fs32.readFileSync(path50.join(dirPath, files[0].name), "utf-8");
8163
+ const files = fs34.readdirSync(dirPath).map((f) => ({ name: f, mtime: fs34.statSync(path52.join(dirPath, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
8164
+ if (files.length > 0) return fs34.readFileSync(path52.join(dirPath, files[0].name), "utf-8");
7815
8165
  return void 0;
7816
8166
  }
7817
8167
  function loadPriorState(metadata, projectPath) {
7818
8168
  if (!metadata?.state.persistent || metadata.state.files.length === 0) return void 0;
7819
8169
  for (const stateFilePath of metadata.state.files) {
7820
- const fullPath = path50.join(projectPath, stateFilePath);
7821
- if (!fs32.existsSync(fullPath)) continue;
7822
- const stat = fs32.statSync(fullPath);
8170
+ const fullPath = path52.join(projectPath, stateFilePath);
8171
+ if (!fs34.existsSync(fullPath)) continue;
8172
+ const stat = fs34.statSync(fullPath);
7823
8173
  if (stat.isDirectory()) return readMostRecentFileInDir(fullPath);
7824
- return fs32.readFileSync(fullPath, "utf-8");
8174
+ return fs34.readFileSync(fullPath, "utf-8");
7825
8175
  }
7826
8176
  return void 0;
7827
8177
  }
@@ -7841,9 +8191,9 @@ function resolvePhaseState(metadata, projectPath, phase) {
7841
8191
  }
7842
8192
  function appendProjectState(content, metadata, projectPath, hasPathOpt) {
7843
8193
  if (!metadata?.state.persistent || !hasPathOpt) return content;
7844
- const stateFile = path50.join(projectPath, ".harness", "state.json");
7845
- if (!fs32.existsSync(stateFile)) return content;
7846
- const stateContent = fs32.readFileSync(stateFile, "utf-8");
8194
+ const stateFile = path52.join(projectPath, ".harness", "state.json");
8195
+ if (!fs34.existsSync(stateFile)) return content;
8196
+ const stateContent = fs34.readFileSync(stateFile, "utf-8");
7847
8197
  return content + `
7848
8198
 
7849
8199
  ---
@@ -7855,14 +8205,14 @@ ${stateContent}
7855
8205
  }
7856
8206
  async function runSkill(name, opts) {
7857
8207
  const skillsDir = resolveSkillsDir();
7858
- const skillDir = path50.join(skillsDir, name);
7859
- if (!fs32.existsSync(skillDir)) {
8208
+ const skillDir = path52.join(skillsDir, name);
8209
+ if (!fs34.existsSync(skillDir)) {
7860
8210
  logger.error(`Skill not found: ${name}`);
7861
8211
  process.exit(ExitCode.ERROR);
7862
8212
  return;
7863
8213
  }
7864
8214
  const metadata = loadSkillMetadata(skillDir);
7865
- const projectPath = opts.path ? path50.resolve(opts.path) : process.cwd();
8215
+ const projectPath = opts.path ? path52.resolve(opts.path) : process.cwd();
7866
8216
  const complexity = resolveComplexity(
7867
8217
  metadata,
7868
8218
  opts.complexity ?? "standard",
@@ -7889,14 +8239,14 @@ async function runSkill(name, opts) {
7889
8239
  ...stateWarning !== void 0 && { stateWarning },
7890
8240
  ...opts.party !== void 0 && { party: opts.party }
7891
8241
  });
7892
- const skillMdPath = path50.join(skillDir, "SKILL.md");
7893
- if (!fs32.existsSync(skillMdPath)) {
8242
+ const skillMdPath = path52.join(skillDir, "SKILL.md");
8243
+ if (!fs34.existsSync(skillMdPath)) {
7894
8244
  logger.error(`SKILL.md not found for skill: ${name}`);
7895
8245
  process.exit(ExitCode.ERROR);
7896
8246
  return;
7897
8247
  }
7898
8248
  const content = appendProjectState(
7899
- fs32.readFileSync(skillMdPath, "utf-8"),
8249
+ fs34.readFileSync(skillMdPath, "utf-8"),
7900
8250
  metadata,
7901
8251
  projectPath,
7902
8252
  !!opts.path
@@ -7905,13 +8255,13 @@ async function runSkill(name, opts) {
7905
8255
  process.exit(ExitCode.SUCCESS);
7906
8256
  }
7907
8257
  function createRunCommand3() {
7908
- return new Command65("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));
8258
+ return new Command67("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));
7909
8259
  }
7910
8260
 
7911
8261
  // src/commands/skill/validate.ts
7912
- import { Command as Command66 } from "commander";
7913
- import * as fs33 from "fs";
7914
- import * as path51 from "path";
8262
+ import { Command as Command68 } from "commander";
8263
+ import * as fs35 from "fs";
8264
+ import * as path53 from "path";
7915
8265
  import { parse as parse3 } from "yaml";
7916
8266
  var BEHAVIORAL_REQUIRED_SECTIONS = [
7917
8267
  "## When to Use",
@@ -7923,11 +8273,11 @@ var BEHAVIORAL_REQUIRED_SECTIONS = [
7923
8273
  ];
7924
8274
  var KNOWLEDGE_REQUIRED_SECTIONS = ["## Instructions"];
7925
8275
  function validateSkillMd(name, skillMdPath, skillType, errors) {
7926
- if (!fs33.existsSync(skillMdPath)) {
8276
+ if (!fs35.existsSync(skillMdPath)) {
7927
8277
  errors.push(`${name}: missing SKILL.md`);
7928
8278
  return;
7929
8279
  }
7930
- const mdContent = fs33.readFileSync(skillMdPath, "utf-8");
8280
+ const mdContent = fs35.readFileSync(skillMdPath, "utf-8");
7931
8281
  if (!mdContent.trim().startsWith("# ")) {
7932
8282
  errors.push(`${name}/SKILL.md: must start with an h1 heading`);
7933
8283
  }
@@ -7952,20 +8302,20 @@ function validateSkillMd(name, skillMdPath, skillType, errors) {
7952
8302
  }
7953
8303
  }
7954
8304
  function validateSkillEntry(name, skillsDir, errors) {
7955
- const skillDir = path51.join(skillsDir, name);
7956
- const yamlPath = path51.join(skillDir, "skill.yaml");
7957
- if (!fs33.existsSync(yamlPath)) {
8305
+ const skillDir = path53.join(skillsDir, name);
8306
+ const yamlPath = path53.join(skillDir, "skill.yaml");
8307
+ if (!fs35.existsSync(yamlPath)) {
7958
8308
  errors.push(`${name}: missing skill.yaml`);
7959
8309
  return false;
7960
8310
  }
7961
8311
  try {
7962
- const raw = fs33.readFileSync(yamlPath, "utf-8");
8312
+ const raw = fs35.readFileSync(yamlPath, "utf-8");
7963
8313
  const result = SkillMetadataSchema.safeParse(parse3(raw));
7964
8314
  if (!result.success) {
7965
8315
  errors.push(`${name}/skill.yaml: ${result.error.message}`);
7966
8316
  return false;
7967
8317
  }
7968
- validateSkillMd(name, path51.join(skillDir, "SKILL.md"), result.data.type, errors);
8318
+ validateSkillMd(name, path53.join(skillDir, "SKILL.md"), result.data.type, errors);
7969
8319
  return true;
7970
8320
  } catch (e) {
7971
8321
  errors.push(`${name}: parse error \u2014 ${e instanceof Error ? e.message : String(e)}`);
@@ -7973,15 +8323,15 @@ function validateSkillEntry(name, skillsDir, errors) {
7973
8323
  }
7974
8324
  }
7975
8325
  function createValidateCommand2() {
7976
- return new Command66("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
8326
+ return new Command68("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
7977
8327
  const globalOpts = cmd.optsWithGlobals();
7978
8328
  const skillsDir = resolveSkillsDir();
7979
- if (!fs33.existsSync(skillsDir)) {
8329
+ if (!fs35.existsSync(skillsDir)) {
7980
8330
  logger.info("No skills directory found.");
7981
8331
  process.exit(ExitCode.SUCCESS);
7982
8332
  return;
7983
8333
  }
7984
- const entries = fs33.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
8334
+ const entries = fs35.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
7985
8335
  const errors = [];
7986
8336
  let validated = 0;
7987
8337
  for (const name of entries) {
@@ -8003,24 +8353,24 @@ function createValidateCommand2() {
8003
8353
  }
8004
8354
 
8005
8355
  // src/commands/skill/info.ts
8006
- import { Command as Command67 } from "commander";
8007
- import * as fs34 from "fs";
8008
- import * as path52 from "path";
8356
+ import { Command as Command69 } from "commander";
8357
+ import * as fs36 from "fs";
8358
+ import * as path54 from "path";
8009
8359
  import { parse as parse4 } from "yaml";
8010
8360
  function loadSkillMetadata2(name) {
8011
8361
  const skillsDir = resolveSkillsDir();
8012
- const skillDir = path52.join(skillsDir, name);
8013
- if (!fs34.existsSync(skillDir)) {
8362
+ const skillDir = path54.join(skillsDir, name);
8363
+ if (!fs36.existsSync(skillDir)) {
8014
8364
  logger.error(`Skill not found: ${name}`);
8015
8365
  return { ok: false, exitCode: ExitCode.ERROR };
8016
8366
  }
8017
- const yamlPath = path52.join(skillDir, "skill.yaml");
8018
- if (!fs34.existsSync(yamlPath)) {
8367
+ const yamlPath = path54.join(skillDir, "skill.yaml");
8368
+ if (!fs36.existsSync(yamlPath)) {
8019
8369
  logger.error(`skill.yaml not found for skill: ${name}`);
8020
8370
  return { ok: false, exitCode: ExitCode.ERROR };
8021
8371
  }
8022
8372
  try {
8023
- const raw = fs34.readFileSync(yamlPath, "utf-8");
8373
+ const raw = fs36.readFileSync(yamlPath, "utf-8");
8024
8374
  const parsed = parse4(raw);
8025
8375
  const result = SkillMetadataSchema.safeParse(parsed);
8026
8376
  if (!result.success) {
@@ -8049,7 +8399,7 @@ function printSkillInfo(skill) {
8049
8399
  console.log(`Persistent: ${skill.state.persistent}`);
8050
8400
  }
8051
8401
  function createInfoCommand() {
8052
- return new Command67("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
8402
+ return new Command69("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
8053
8403
  const globalOpts = cmd.optsWithGlobals();
8054
8404
  const loaded = loadSkillMetadata2(name);
8055
8405
  if (!loaded.ok) {
@@ -8066,7 +8416,7 @@ function createInfoCommand() {
8066
8416
  }
8067
8417
 
8068
8418
  // src/commands/skill/search.ts
8069
- import { Command as Command68 } from "commander";
8419
+ import { Command as Command70 } from "commander";
8070
8420
  async function runSearch(query, opts) {
8071
8421
  const results = await searchNpmRegistry(query, opts.registry);
8072
8422
  return results.filter((r) => {
@@ -8111,15 +8461,15 @@ async function runSearchAction(query, opts, globalOpts) {
8111
8461
  }
8112
8462
  }
8113
8463
  function createSearchCommand() {
8114
- return new Command68("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) => {
8464
+ return new Command70("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) => {
8115
8465
  await runSearchAction(query, opts, cmd.optsWithGlobals());
8116
8466
  });
8117
8467
  }
8118
8468
 
8119
8469
  // src/commands/skill/create.ts
8120
- import { Command as Command69 } from "commander";
8121
- import * as path53 from "path";
8122
- import * as fs35 from "fs";
8470
+ import { Command as Command71 } from "commander";
8471
+ import * as path55 from "path";
8472
+ import * as fs37 from "fs";
8123
8473
  import YAML from "yaml";
8124
8474
  var KEBAB_CASE_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
8125
8475
  function buildReadme(name, description) {
@@ -8203,22 +8553,22 @@ function runCreate(name, opts) {
8203
8553
  if (!KEBAB_CASE_RE.test(name)) {
8204
8554
  throw new Error(`Invalid skill name "${name}". Must be kebab-case (e.g., my-skill).`);
8205
8555
  }
8206
- const baseDir = opts.outputDir ?? path53.join(process.cwd(), "agents", "skills", "claude-code");
8207
- const skillDir = path53.join(baseDir, name);
8208
- if (fs35.existsSync(skillDir)) {
8556
+ const baseDir = opts.outputDir ?? path55.join(process.cwd(), "agents", "skills", "claude-code");
8557
+ const skillDir = path55.join(baseDir, name);
8558
+ if (fs37.existsSync(skillDir)) {
8209
8559
  throw new Error(`Skill directory already exists: ${skillDir}`);
8210
8560
  }
8211
- fs35.mkdirSync(skillDir, { recursive: true });
8561
+ fs37.mkdirSync(skillDir, { recursive: true });
8212
8562
  const description = opts.description || `A community skill: ${name}`;
8213
8563
  const skillYaml = buildSkillYaml(name, opts);
8214
- const skillYamlPath = path53.join(skillDir, "skill.yaml");
8215
- fs35.writeFileSync(skillYamlPath, YAML.stringify(skillYaml));
8564
+ const skillYamlPath = path55.join(skillDir, "skill.yaml");
8565
+ fs37.writeFileSync(skillYamlPath, YAML.stringify(skillYaml));
8216
8566
  const skillMd = buildSkillMd(name, description);
8217
- const skillMdPath = path53.join(skillDir, "SKILL.md");
8218
- fs35.writeFileSync(skillMdPath, skillMd);
8567
+ const skillMdPath = path55.join(skillDir, "SKILL.md");
8568
+ fs37.writeFileSync(skillMdPath, skillMd);
8219
8569
  const readme = buildReadme(name, description);
8220
- const readmePath = path53.join(skillDir, "README.md");
8221
- fs35.writeFileSync(readmePath, readme);
8570
+ const readmePath = path55.join(skillDir, "README.md");
8571
+ fs37.writeFileSync(readmePath, readme);
8222
8572
  return {
8223
8573
  name,
8224
8574
  directory: skillDir,
@@ -8232,12 +8582,12 @@ function printCreateResult(name, result) {
8232
8582
  }
8233
8583
  logger.info(`
8234
8584
  Next steps:`);
8235
- logger.info(` 1. Edit ${path53.join(result.directory, "SKILL.md")} with your skill content`);
8585
+ logger.info(` 1. Edit ${path55.join(result.directory, "SKILL.md")} with your skill content`);
8236
8586
  logger.info(` 2. Run: harness skill validate ${name}`);
8237
8587
  logger.info(` 3. Run: harness skills publish`);
8238
8588
  }
8239
8589
  function createCreateCommand() {
8240
- return new Command69("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) => {
8590
+ return new Command71("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) => {
8241
8591
  const globalOpts = cmd.optsWithGlobals();
8242
8592
  try {
8243
8593
  const result = runCreate(name, {
@@ -8260,26 +8610,26 @@ function createCreateCommand() {
8260
8610
  }
8261
8611
 
8262
8612
  // src/commands/skill/publish.ts
8263
- import { Command as Command70 } from "commander";
8264
- import * as fs37 from "fs";
8265
- import * as path55 from "path";
8613
+ import { Command as Command72 } from "commander";
8614
+ import * as fs39 from "fs";
8615
+ import * as path57 from "path";
8266
8616
  import { execFileSync as execFileSync6 } from "child_process";
8267
8617
 
8268
8618
  // src/registry/validator.ts
8269
- import * as fs36 from "fs";
8270
- import * as path54 from "path";
8619
+ import * as fs38 from "fs";
8620
+ import * as path56 from "path";
8271
8621
  import { parse as parse5 } from "yaml";
8272
8622
  import semver4 from "semver";
8273
8623
  async function validateForPublish(skillDir, registryUrl) {
8274
8624
  const errors = [];
8275
- const skillYamlPath = path54.join(skillDir, "skill.yaml");
8276
- if (!fs36.existsSync(skillYamlPath)) {
8625
+ const skillYamlPath = path56.join(skillDir, "skill.yaml");
8626
+ if (!fs38.existsSync(skillYamlPath)) {
8277
8627
  errors.push("skill.yaml not found. Create one with: harness skill create <name>");
8278
8628
  return { valid: false, errors };
8279
8629
  }
8280
8630
  let skillMeta;
8281
8631
  try {
8282
- const raw = fs36.readFileSync(skillYamlPath, "utf-8");
8632
+ const raw = fs38.readFileSync(skillYamlPath, "utf-8");
8283
8633
  const parsed = parse5(raw);
8284
8634
  const result = SkillMetadataSchema.safeParse(parsed);
8285
8635
  if (!result.success) {
@@ -8301,11 +8651,11 @@ async function validateForPublish(skillDir, registryUrl) {
8301
8651
  if (!skillMeta.triggers || skillMeta.triggers.length === 0) {
8302
8652
  errors.push("At least one trigger is required. Add triggers to skill.yaml.");
8303
8653
  }
8304
- const skillMdPath = path54.join(skillDir, "SKILL.md");
8305
- if (!fs36.existsSync(skillMdPath)) {
8654
+ const skillMdPath = path56.join(skillDir, "SKILL.md");
8655
+ if (!fs38.existsSync(skillMdPath)) {
8306
8656
  errors.push("SKILL.md not found. Create it with content describing your skill.");
8307
8657
  } else {
8308
- const content = fs36.readFileSync(skillMdPath, "utf-8");
8658
+ const content = fs38.readFileSync(skillMdPath, "utf-8");
8309
8659
  if (!content.includes("## When to Use")) {
8310
8660
  errors.push('SKILL.md must contain a "## When to Use" section.');
8311
8661
  }
@@ -8385,11 +8735,11 @@ ${errorList}`);
8385
8735
  }
8386
8736
  const meta = validation.skillMeta;
8387
8737
  const pkg = derivePackageJson(meta);
8388
- const pkgPath = path55.join(skillDir, "package.json");
8389
- fs37.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
8390
- const readmePath = path55.join(skillDir, "README.md");
8391
- if (!fs37.existsSync(readmePath)) {
8392
- const skillMdContent = fs37.readFileSync(path55.join(skillDir, "SKILL.md"), "utf-8");
8738
+ const pkgPath = path57.join(skillDir, "package.json");
8739
+ fs39.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
8740
+ const readmePath = path57.join(skillDir, "README.md");
8741
+ if (!fs39.existsSync(readmePath)) {
8742
+ const skillMdContent = fs39.readFileSync(path57.join(skillDir, "SKILL.md"), "utf-8");
8393
8743
  const readme = `# ${pkg.name}
8394
8744
 
8395
8745
  ${meta.description}
@@ -8403,7 +8753,7 @@ harness install ${meta.name}
8403
8753
  ---
8404
8754
 
8405
8755
  ${skillMdContent}`;
8406
- fs37.writeFileSync(readmePath, readme);
8756
+ fs39.writeFileSync(readmePath, readme);
8407
8757
  }
8408
8758
  if (opts.dryRun) {
8409
8759
  return {
@@ -8429,7 +8779,7 @@ ${skillMdContent}`;
8429
8779
  };
8430
8780
  }
8431
8781
  function createPublishCommand() {
8432
- return new Command70("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) => {
8782
+ return new Command72("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) => {
8433
8783
  const globalOpts = cmd.optsWithGlobals();
8434
8784
  const skillDir = opts.dir || process.cwd();
8435
8785
  try {
@@ -8454,7 +8804,7 @@ function createPublishCommand() {
8454
8804
 
8455
8805
  // src/commands/skill/index.ts
8456
8806
  function createSkillCommand() {
8457
- const command = new Command71("skill").description("Skill management commands");
8807
+ const command = new Command73("skill").description("Skill management commands");
8458
8808
  command.addCommand(createListCommand3());
8459
8809
  command.addCommand(createRunCommand3());
8460
8810
  command.addCommand(createValidateCommand2());
@@ -8467,9 +8817,9 @@ function createSkillCommand() {
8467
8817
 
8468
8818
  // src/commands/snapshot.ts
8469
8819
  init_dist();
8470
- import { Command as Command72 } from "commander";
8820
+ import { Command as Command74 } from "commander";
8471
8821
  import { execSync as execSync5 } from "child_process";
8472
- import chalk12 from "chalk";
8822
+ import chalk13 from "chalk";
8473
8823
  function getCommitHash3(cwd) {
8474
8824
  try {
8475
8825
  return execSync5("git rev-parse --short HEAD", { cwd, encoding: "utf-8" }).toString().trim();
@@ -8494,9 +8844,9 @@ function formatDelta(delta) {
8494
8844
  function directionSymbol(direction) {
8495
8845
  switch (direction) {
8496
8846
  case "improving":
8497
- return chalk12.green("improving");
8847
+ return chalk13.green("improving");
8498
8848
  case "declining":
8499
- return chalk12.red("declining");
8849
+ return chalk13.red("declining");
8500
8850
  case "stable":
8501
8851
  return "=";
8502
8852
  }
@@ -8649,7 +8999,7 @@ function registerListCommand(parent) {
8649
8999
  });
8650
9000
  }
8651
9001
  function createSnapshotCommand() {
8652
- const command = new Command72("snapshot").description("Architecture timeline snapshot commands");
9002
+ const command = new Command74("snapshot").description("Architecture timeline snapshot commands");
8653
9003
  registerCaptureCommand(command);
8654
9004
  registerTrendsCommand(command);
8655
9005
  registerListCommand(command);
@@ -8657,12 +9007,12 @@ function createSnapshotCommand() {
8657
9007
  }
8658
9008
 
8659
9009
  // src/commands/state/index.ts
8660
- import { Command as Command77 } from "commander";
9010
+ import { Command as Command79 } from "commander";
8661
9011
 
8662
9012
  // src/commands/state/show.ts
8663
9013
  init_dist();
8664
- import { Command as Command73 } from "commander";
8665
- import * as path56 from "path";
9014
+ import { Command as Command75 } from "commander";
9015
+ import * as path58 from "path";
8666
9016
  function printStateText(state, stream) {
8667
9017
  if (stream) console.log(`Stream: ${stream}`);
8668
9018
  console.log(`Schema Version: ${state.schemaVersion}`);
@@ -8686,9 +9036,9 @@ function printStateProgress(progress) {
8686
9036
  }
8687
9037
  }
8688
9038
  function createShowCommand() {
8689
- return new Command73("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
9039
+ return new Command75("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
8690
9040
  const globalOpts = cmd.optsWithGlobals();
8691
- const result = await loadState(path56.resolve(opts.path), opts.stream);
9041
+ const result = await loadState(path58.resolve(opts.path), opts.stream);
8692
9042
  if (!result.ok) {
8693
9043
  logger.error(result.error.message);
8694
9044
  process.exit(ExitCode.ERROR);
@@ -8704,9 +9054,9 @@ function createShowCommand() {
8704
9054
 
8705
9055
  // src/commands/state/reset.ts
8706
9056
  init_dist();
8707
- import { Command as Command74 } from "commander";
8708
- import * as fs38 from "fs";
8709
- import * as path57 from "path";
9057
+ import { Command as Command76 } from "commander";
9058
+ import * as fs40 from "fs";
9059
+ import * as path59 from "path";
8710
9060
  import * as readline3 from "readline";
8711
9061
  async function resolveStatePath(projectPath, stream) {
8712
9062
  if (stream) {
@@ -8715,22 +9065,22 @@ async function resolveStatePath(projectPath, stream) {
8715
9065
  logger.error(streamResult.error.message);
8716
9066
  process.exit(ExitCode.ERROR);
8717
9067
  }
8718
- return path57.join(streamResult.value, "state.json");
9068
+ return path59.join(streamResult.value, "state.json");
8719
9069
  }
8720
- return path57.join(projectPath, ".harness", "state.json");
9070
+ return path59.join(projectPath, ".harness", "state.json");
8721
9071
  }
8722
9072
  async function confirmReset() {
8723
9073
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
8724
- const answer = await new Promise((resolve39) => {
8725
- rl.question("Reset project state? This cannot be undone. [y/N] ", resolve39);
9074
+ const answer = await new Promise((resolve40) => {
9075
+ rl.question("Reset project state? This cannot be undone. [y/N] ", resolve40);
8726
9076
  });
8727
9077
  rl.close();
8728
9078
  return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
8729
9079
  }
8730
9080
  async function runReset(opts) {
8731
- const projectPath = path57.resolve(opts.path);
9081
+ const projectPath = path59.resolve(opts.path);
8732
9082
  const statePath = await resolveStatePath(projectPath, opts.stream);
8733
- if (!fs38.existsSync(statePath)) {
9083
+ if (!fs40.existsSync(statePath)) {
8734
9084
  logger.info("No state file found. Nothing to reset.");
8735
9085
  process.exit(ExitCode.SUCCESS);
8736
9086
  }
@@ -8739,7 +9089,7 @@ async function runReset(opts) {
8739
9089
  process.exit(ExitCode.SUCCESS);
8740
9090
  }
8741
9091
  try {
8742
- fs38.unlinkSync(statePath);
9092
+ fs40.unlinkSync(statePath);
8743
9093
  logger.success("Project state reset.");
8744
9094
  } catch (e) {
8745
9095
  logger.error(`Failed to reset state: ${e instanceof Error ? e.message : String(e)}`);
@@ -8748,16 +9098,16 @@ async function runReset(opts) {
8748
9098
  process.exit(ExitCode.SUCCESS);
8749
9099
  }
8750
9100
  function createResetCommand() {
8751
- return new Command74("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));
9101
+ return new Command76("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));
8752
9102
  }
8753
9103
 
8754
9104
  // src/commands/state/learn.ts
8755
9105
  init_dist();
8756
- import { Command as Command75 } from "commander";
8757
- import * as path58 from "path";
9106
+ import { Command as Command77 } from "commander";
9107
+ import * as path60 from "path";
8758
9108
  function createLearnCommand() {
8759
- return new Command75("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) => {
8760
- const projectPath = path58.resolve(opts.path);
9109
+ return new Command77("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) => {
9110
+ const projectPath = path60.resolve(opts.path);
8761
9111
  const result = await appendLearning(projectPath, message, void 0, void 0, opts.stream);
8762
9112
  if (!result.ok) {
8763
9113
  logger.error(result.error.message);
@@ -8771,10 +9121,10 @@ function createLearnCommand() {
8771
9121
 
8772
9122
  // src/commands/state/streams.ts
8773
9123
  init_dist();
8774
- import { Command as Command76 } from "commander";
8775
- import * as path59 from "path";
9124
+ import { Command as Command78 } from "commander";
9125
+ import * as path61 from "path";
8776
9126
  async function runListStreams(opts, globalOpts) {
8777
- const projectPath = path59.resolve(opts.path);
9127
+ const projectPath = path61.resolve(opts.path);
8778
9128
  const indexResult = await loadStreamIndex(projectPath);
8779
9129
  const result = await listStreams(projectPath);
8780
9130
  if (!result.ok) {
@@ -8795,7 +9145,7 @@ async function runListStreams(opts, globalOpts) {
8795
9145
  process.exit(ExitCode.SUCCESS);
8796
9146
  }
8797
9147
  async function runCreateStream(name, opts) {
8798
- const result = await createStream(path59.resolve(opts.path), name, opts.branch);
9148
+ const result = await createStream(path61.resolve(opts.path), name, opts.branch);
8799
9149
  if (!result.ok) {
8800
9150
  logger.error(result.error.message);
8801
9151
  process.exit(ExitCode.ERROR);
@@ -8804,7 +9154,7 @@ async function runCreateStream(name, opts) {
8804
9154
  process.exit(ExitCode.SUCCESS);
8805
9155
  }
8806
9156
  async function runArchiveStream(name, opts) {
8807
- const result = await archiveStream(path59.resolve(opts.path), name);
9157
+ const result = await archiveStream(path61.resolve(opts.path), name);
8808
9158
  if (!result.ok) {
8809
9159
  logger.error(result.error.message);
8810
9160
  process.exit(ExitCode.ERROR);
@@ -8813,7 +9163,7 @@ async function runArchiveStream(name, opts) {
8813
9163
  process.exit(ExitCode.SUCCESS);
8814
9164
  }
8815
9165
  async function runActivateStream(name, opts) {
8816
- const result = await setActiveStream(path59.resolve(opts.path), name);
9166
+ const result = await setActiveStream(path61.resolve(opts.path), name);
8817
9167
  if (!result.ok) {
8818
9168
  logger.error(result.error.message);
8819
9169
  process.exit(ExitCode.ERROR);
@@ -8822,7 +9172,7 @@ async function runActivateStream(name, opts) {
8822
9172
  process.exit(ExitCode.SUCCESS);
8823
9173
  }
8824
9174
  function createStreamsCommand() {
8825
- const command = new Command76("streams").description("Manage state streams");
9175
+ const command = new Command78("streams").description("Manage state streams");
8826
9176
  command.command("list").description("List all known streams").option("--path <path>", "Project root path", ".").action(async (opts, cmd) => runListStreams(opts, cmd.optsWithGlobals()));
8827
9177
  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));
8828
9178
  command.command("archive <name>").description("Archive a stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => runArchiveStream(name, opts));
@@ -8832,7 +9182,7 @@ function createStreamsCommand() {
8832
9182
 
8833
9183
  // src/commands/state/index.ts
8834
9184
  function createStateCommand() {
8835
- const command = new Command77("state").description("Project state management commands");
9185
+ const command = new Command79("state").description("Project state management commands");
8836
9186
  command.addCommand(createShowCommand());
8837
9187
  command.addCommand(createResetCommand());
8838
9188
  command.addCommand(createLearnCommand());
@@ -8841,9 +9191,9 @@ function createStateCommand() {
8841
9191
  }
8842
9192
 
8843
9193
  // src/commands/sync-analyses.ts
8844
- import * as fs39 from "fs";
8845
- import * as path60 from "path";
8846
- import { Command as Command78 } from "commander";
9194
+ import * as fs41 from "fs";
9195
+ import * as path62 from "path";
9196
+ import { Command as Command80 } from "commander";
8847
9197
  init_dist();
8848
9198
  function isValidRecord(record) {
8849
9199
  return typeof record.issueId === "string" && !!record.issueId && typeof record.identifier === "string" && !!record.identifier && typeof record.analyzedAt === "string" && !/[/\\]/.test(record.issueId);
@@ -8869,7 +9219,7 @@ function extractAnalysisFromComments(comments) {
8869
9219
  return null;
8870
9220
  }
8871
9221
  function bootstrapTrackerCommand2(opts, verb) {
8872
- const projectPath = path60.resolve(opts.dir);
9222
+ const projectPath = path62.resolve(opts.dir);
8873
9223
  const trackerConfig = loadTrackerSyncConfig(projectPath);
8874
9224
  if (!trackerConfig) {
8875
9225
  logger.error(`No tracker config found in harness.config.json. Cannot ${verb}.`);
@@ -8881,8 +9231,8 @@ function bootstrapTrackerCommand2(opts, verb) {
8881
9231
  );
8882
9232
  return null;
8883
9233
  }
8884
- const projectEnvPath = path60.join(projectPath, ".env");
8885
- if (fs39.existsSync(projectEnvPath) && !process.env.GITHUB_TOKEN) {
9234
+ const projectEnvPath = path62.join(projectPath, ".env");
9235
+ if (fs41.existsSync(projectEnvPath) && !process.env.GITHUB_TOKEN) {
8886
9236
  __require("dotenv").config({ path: projectEnvPath });
8887
9237
  }
8888
9238
  const token = process.env.GITHUB_TOKEN;
@@ -8892,14 +9242,33 @@ function bootstrapTrackerCommand2(opts, verb) {
8892
9242
  }
8893
9243
  return { token, projectPath, trackerConfig };
8894
9244
  }
8895
- function loadRoadmapFeatures(projectPath) {
8896
- const roadmapFile = path60.join(projectPath, "docs", "roadmap.md");
8897
- if (!fs39.existsSync(roadmapFile)) {
9245
+ async function loadRoadmapFeatures(projectPath) {
9246
+ const mode = loadProjectRoadmapMode(projectPath);
9247
+ if (mode === "file-less") {
9248
+ const trackerCfg = loadTrackerClientConfigFromProject(projectPath);
9249
+ if (!trackerCfg.ok) {
9250
+ logger.error(`File-less mode: ${trackerCfg.error.message}`);
9251
+ return null;
9252
+ }
9253
+ const clientR = createTrackerClient(trackerCfg.value);
9254
+ if (!clientR.ok) {
9255
+ logger.error(`File-less mode: ${clientR.error.message}`);
9256
+ return null;
9257
+ }
9258
+ const r = await clientR.value.fetchAll();
9259
+ if (!r.ok) {
9260
+ logger.error(`File-less mode: failed to fetch features from tracker: ${r.error.message}`);
9261
+ return null;
9262
+ }
9263
+ return r.value.features.filter((f) => !!f.externalId).map((f) => ({ name: f.name, externalId: f.externalId }));
9264
+ }
9265
+ const roadmapFile = path62.join(projectPath, "docs", "roadmap.md");
9266
+ if (!fs41.existsSync(roadmapFile)) {
8898
9267
  logger.error("No docs/roadmap.md found. Cannot discover features with externalIds.");
8899
9268
  return null;
8900
9269
  }
8901
- const { parseRoadmap } = (init_dist(), __toCommonJS(dist_exports));
8902
- const roadmapParsed = parseRoadmap(fs39.readFileSync(roadmapFile, "utf-8"));
9270
+ const { parseRoadmap: parseRoadmap2 } = (init_dist(), __toCommonJS(dist_exports));
9271
+ const roadmapParsed = parseRoadmap2(fs41.readFileSync(roadmapFile, "utf-8"));
8903
9272
  if (!roadmapParsed.ok) {
8904
9273
  logger.error("Failed to parse docs/roadmap.md");
8905
9274
  return null;
@@ -8943,16 +9312,16 @@ async function runSyncAnalyses(opts) {
8943
9312
  const bootstrap = bootstrapTrackerCommand2(opts, "sync");
8944
9313
  if (!bootstrap) return process.exit(1);
8945
9314
  const { token, projectPath, trackerConfig } = bootstrap;
8946
- const features = loadRoadmapFeatures(projectPath);
9315
+ const features = await loadRoadmapFeatures(projectPath);
8947
9316
  if (!features) return process.exit(1);
8948
9317
  if (features.length === 0) {
8949
9318
  logger.info("No roadmap features have externalIds. Nothing to sync.");
8950
9319
  return;
8951
9320
  }
8952
9321
  const { AnalysisArchive, loadPublishedIndex: loadPublishedIndex2, savePublishedIndex: savePublishedIndex2 } = await import("@harness-engineering/orchestrator");
8953
- const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-6RT2AVYU.js");
9322
+ const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-I4LWG3IN.js");
8954
9323
  const adapter = new GitHubIssuesSyncAdapter2({ token, config: trackerConfig });
8955
- const archive = new AnalysisArchive(path60.join(projectPath, ".harness", "analyses"));
9324
+ const archive = new AnalysisArchive(path62.join(projectPath, ".harness", "analyses"));
8956
9325
  const publishedIndex = loadPublishedIndex2(projectPath);
8957
9326
  const { syncedCount, skippedCount, warnCount } = await syncFeatureAnalyses(
8958
9327
  features,
@@ -8972,7 +9341,7 @@ async function runSyncAnalyses(opts) {
8972
9341
  }
8973
9342
  }
8974
9343
  function createSyncAnalysesCommand() {
8975
- const command = new Command78("sync-analyses").description(
9344
+ const command = new Command80("sync-analyses").description(
8976
9345
  "Pull published intelligence analyses from the external issue tracker into the local .harness/analyses/ directory"
8977
9346
  ).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
8978
9347
  try {
@@ -8985,9 +9354,48 @@ function createSyncAnalysesCommand() {
8985
9354
  return command;
8986
9355
  }
8987
9356
 
9357
+ // src/commands/sync-main.ts
9358
+ import { Command as Command81 } from "commander";
9359
+ import * as path63 from "path";
9360
+ import {
9361
+ syncMain as defaultSyncMain
9362
+ } from "@harness-engineering/orchestrator";
9363
+ async function runSyncMain(opts) {
9364
+ const cwd = opts.cwd ?? process.cwd();
9365
+ const fn = opts.syncMainFn ?? ((root) => defaultSyncMain(root));
9366
+ const result = await fn(cwd);
9367
+ if (opts.json) {
9368
+ process.stdout.write(`${JSON.stringify(result)}
9369
+ `);
9370
+ } else {
9371
+ process.stdout.write(`${formatHuman(result)}
9372
+ `);
9373
+ }
9374
+ return result.status === "error" ? ExitCode.ERROR : ExitCode.SUCCESS;
9375
+ }
9376
+ function formatHuman(r) {
9377
+ switch (r.status) {
9378
+ case "updated":
9379
+ return `updated ${r.defaultBranch}: ${r.from.slice(0, 7)} -> ${r.to.slice(0, 7)}`;
9380
+ case "no-op":
9381
+ return `up-to-date: ${r.defaultBranch}`;
9382
+ case "skipped":
9383
+ return `skipped (${r.reason}): ${r.detail}`;
9384
+ case "error":
9385
+ return `error: ${r.message}`;
9386
+ }
9387
+ }
9388
+ function createSyncMainCommand() {
9389
+ return new Command81("sync-main").description("Fast-forward the local default branch from origin (no-op on conflict)").option("--json", "Emit a SyncMainResult JSON object", false).option("--path <path>", "Project root path", ".").action(async (opts) => {
9390
+ const cwd = path63.resolve(opts.path ?? ".");
9391
+ const exitCode = await runSyncMain({ cwd, json: Boolean(opts.json) });
9392
+ process.exit(exitCode);
9393
+ });
9394
+ }
9395
+
8988
9396
  // src/commands/taint.ts
8989
9397
  init_dist();
8990
- import { Command as Command79 } from "commander";
9398
+ import { Command as Command82 } from "commander";
8991
9399
  function getProjectRoot() {
8992
9400
  return process.cwd();
8993
9401
  }
@@ -9059,28 +9467,28 @@ function registerStatusCommand(taint) {
9059
9467
  });
9060
9468
  }
9061
9469
  function createTaintCommand() {
9062
- const taint = new Command79("taint").description("Manage sentinel session taint state");
9470
+ const taint = new Command82("taint").description("Manage sentinel session taint state");
9063
9471
  registerClearCommand(taint);
9064
9472
  registerStatusCommand(taint);
9065
9473
  return taint;
9066
9474
  }
9067
9475
 
9068
9476
  // src/commands/telemetry/index.ts
9069
- import { Command as Command83 } from "commander";
9477
+ import { Command as Command86 } from "commander";
9070
9478
 
9071
9479
  // src/commands/telemetry/identify.ts
9072
9480
  init_dist();
9073
- import { Command as Command80 } from "commander";
9074
- import * as fs40 from "fs";
9075
- import * as path61 from "path";
9481
+ import { Command as Command83 } from "commander";
9482
+ import * as fs42 from "fs";
9483
+ import * as path64 from "path";
9076
9484
  function telemetryFilePath(cwd) {
9077
- return path61.join(cwd, ".harness", "telemetry.json");
9485
+ return path64.join(cwd, ".harness", "telemetry.json");
9078
9486
  }
9079
9487
  function writeTelemetryFile(cwd, data) {
9080
9488
  const filePath = telemetryFilePath(cwd);
9081
- const dir = path61.dirname(filePath);
9082
- fs40.mkdirSync(dir, { recursive: true });
9083
- fs40.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
9489
+ const dir = path64.dirname(filePath);
9490
+ fs42.mkdirSync(dir, { recursive: true });
9491
+ fs42.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
9084
9492
  }
9085
9493
  var IDENTITY_FIELDS = ["project", "team", "alias"];
9086
9494
  function applyIdentityFields(opts, identity) {
@@ -9094,7 +9502,7 @@ function printIdentity(identity) {
9094
9502
  }
9095
9503
  }
9096
9504
  function createIdentifyCommand() {
9097
- const cmd = new Command80("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) => {
9505
+ const cmd = new Command83("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) => {
9098
9506
  const cwd = process.cwd();
9099
9507
  if (opts.clear) {
9100
9508
  writeTelemetryFile(cwd, { identity: {} });
@@ -9119,7 +9527,7 @@ function createIdentifyCommand() {
9119
9527
 
9120
9528
  // src/commands/telemetry/status.ts
9121
9529
  init_dist();
9122
- import { Command as Command81 } from "commander";
9530
+ import { Command as Command84 } from "commander";
9123
9531
  function gatherEnvOverrides() {
9124
9532
  const overrides = {};
9125
9533
  if (process.env.DO_NOT_TRACK) overrides.DO_NOT_TRACK = process.env.DO_NOT_TRACK;
@@ -9161,7 +9569,7 @@ function printHumanStatus(result) {
9161
9569
  printEnvOverrides(result.envOverrides);
9162
9570
  }
9163
9571
  function createStatusCommand() {
9164
- const cmd = new Command81("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
9572
+ const cmd = new Command84("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
9165
9573
  const cwd = process.cwd();
9166
9574
  const envOverrides = gatherEnvOverrides();
9167
9575
  const consent = resolveConsent(cwd, void 0);
@@ -9194,20 +9602,20 @@ function createStatusCommand() {
9194
9602
 
9195
9603
  // src/commands/telemetry/test.ts
9196
9604
  init_dist();
9197
- import { Command as Command82 } from "commander";
9605
+ import { Command as Command85 } from "commander";
9198
9606
 
9199
9607
  // src/bin/command-telemetry.ts
9200
- import { existsSync as existsSync37, readFileSync as readFileSync27, mkdirSync as mkdirSync18, appendFileSync, writeFileSync as writeFileSync21 } from "fs";
9201
- import { join as join49, parse as parsePath, resolve as resolve36 } from "path";
9608
+ import { existsSync as existsSync39, readFileSync as readFileSync29, mkdirSync as mkdirSync19, appendFileSync, writeFileSync as writeFileSync23 } from "fs";
9609
+ import { join as join51, parse as parsePath, resolve as resolve37 } from "path";
9202
9610
  import { spawn as spawn2 } from "child_process";
9203
9611
  var POSTHOG_API_KEY = "phc_wNTdCMcfJXZPgdNeDociZW6vwoGGo4nb7vqEfWThFfsG";
9204
9612
  var EXCLUDED_COMMANDS = /* @__PURE__ */ new Set(["help", "completion"]);
9205
9613
  function findProjectRoot(cwd) {
9206
- let dir = resolve36(cwd);
9614
+ let dir = resolve37(cwd);
9207
9615
  const { root } = parsePath(dir);
9208
9616
  while (dir !== root) {
9209
- if (existsSync37(join49(dir, "harness.config.json"))) return dir;
9210
- dir = resolve36(dir, "..");
9617
+ if (existsSync39(join51(dir, "harness.config.json"))) return dir;
9618
+ dir = resolve37(dir, "..");
9211
9619
  }
9212
9620
  return cwd;
9213
9621
  }
@@ -9244,8 +9652,8 @@ function resolveCommandName(cmd) {
9244
9652
  }
9245
9653
  function writeCommandRecordSync(cwd, command, duration, outcome) {
9246
9654
  try {
9247
- const metricsDir = join49(cwd, ".harness", "metrics");
9248
- mkdirSync18(metricsDir, { recursive: true });
9655
+ const metricsDir = join51(cwd, ".harness", "metrics");
9656
+ mkdirSync19(metricsDir, { recursive: true });
9249
9657
  const record = {
9250
9658
  skill: command,
9251
9659
  session: `cli-${Date.now()}`,
@@ -9254,16 +9662,16 @@ function writeCommandRecordSync(cwd, command, duration, outcome) {
9254
9662
  outcome,
9255
9663
  phasesReached: []
9256
9664
  };
9257
- const adoptionFile = join49(metricsDir, "adoption.jsonl");
9665
+ const adoptionFile = join51(metricsDir, "adoption.jsonl");
9258
9666
  appendFileSync(adoptionFile, JSON.stringify(record) + "\n");
9259
9667
  } catch {
9260
9668
  }
9261
9669
  }
9262
9670
  function isTelemetryDisabledByConfig(cwd) {
9263
- const configPath = join49(cwd, "harness.config.json");
9264
- if (!existsSync37(configPath)) return false;
9671
+ const configPath = join51(cwd, "harness.config.json");
9672
+ if (!existsSync39(configPath)) return false;
9265
9673
  try {
9266
- const config = JSON.parse(readFileSync27(configPath, "utf-8"));
9674
+ const config = JSON.parse(readFileSync29(configPath, "utf-8"));
9267
9675
  return config?.telemetry?.enabled === false;
9268
9676
  } catch {
9269
9677
  return false;
@@ -9275,11 +9683,11 @@ function isTelemetryOptedOut(cwd) {
9275
9683
  }
9276
9684
  function flushTelemetryBackground(cwd) {
9277
9685
  try {
9278
- const adoptionFile = join49(cwd, ".harness", "metrics", "adoption.jsonl");
9279
- if (!existsSync37(adoptionFile)) return;
9686
+ const adoptionFile = join51(cwd, ".harness", "metrics", "adoption.jsonl");
9687
+ if (!existsSync39(adoptionFile)) return;
9280
9688
  if (isTelemetryOptedOut(cwd)) return;
9281
- const reporterPath = join49(cwd, ".harness", "hooks", "telemetry-reporter.js");
9282
- if (!existsSync37(reporterPath)) return;
9689
+ const reporterPath = join51(cwd, ".harness", "hooks", "telemetry-reporter.js");
9690
+ if (!existsSync39(reporterPath)) return;
9283
9691
  const child = spawn2(process.execPath, [reporterPath], {
9284
9692
  cwd,
9285
9693
  stdio: ["pipe", "ignore", "ignore"],
@@ -9316,7 +9724,7 @@ function reportTestSuccess(status, distinctId, identity) {
9316
9724
  if (identity.team) logger.info(` team: ${identity.team}`);
9317
9725
  }
9318
9726
  function createTestCommand() {
9319
- return new Command82("test").description("Send a test event to PostHog and verify connectivity").action(async () => {
9727
+ return new Command85("test").description("Send a test event to PostHog and verify connectivity").action(async () => {
9320
9728
  const cwd = process.cwd();
9321
9729
  const consent = resolveConsent(cwd, void 0);
9322
9730
  if (!consent.allowed) {
@@ -9353,7 +9761,7 @@ function createTestCommand() {
9353
9761
 
9354
9762
  // src/commands/telemetry/index.ts
9355
9763
  function createTelemetryCommand() {
9356
- const command = new Command83("telemetry").description("Telemetry identity and status management");
9764
+ const command = new Command86("telemetry").description("Telemetry identity and status management");
9357
9765
  command.addCommand(createIdentifyCommand());
9358
9766
  command.addCommand(createStatusCommand());
9359
9767
  command.addCommand(createTestCommand());
@@ -9361,8 +9769,8 @@ function createTelemetryCommand() {
9361
9769
  }
9362
9770
 
9363
9771
  // src/commands/traceability.ts
9364
- import { Command as Command84 } from "commander";
9365
- import chalk13 from "chalk";
9772
+ import { Command as Command87 } from "commander";
9773
+ import chalk14 from "chalk";
9366
9774
  function confidenceLabel(maxConfidence) {
9367
9775
  if (maxConfidence >= 0.8) return "explicit";
9368
9776
  if (maxConfidence > 0) return "inferred";
@@ -9371,13 +9779,13 @@ function confidenceLabel(maxConfidence) {
9371
9779
  function statusIcon(status) {
9372
9780
  switch (status) {
9373
9781
  case "full":
9374
- return chalk13.green("\u2713 full");
9782
+ return chalk14.green("\u2713 full");
9375
9783
  case "code-only":
9376
- return chalk13.yellow("\u25D0 code-only");
9784
+ return chalk14.yellow("\u25D0 code-only");
9377
9785
  case "test-only":
9378
- return chalk13.yellow("\u25D0 test-only");
9786
+ return chalk14.yellow("\u25D0 test-only");
9379
9787
  case "none":
9380
- return chalk13.red("\u2717 none");
9788
+ return chalk14.red("\u2717 none");
9381
9789
  default:
9382
9790
  return status;
9383
9791
  }
@@ -9424,14 +9832,14 @@ function handleEmptyResults(mode) {
9424
9832
  }
9425
9833
  function printResultTable(result, mode) {
9426
9834
  const specLabel = result.specPath || result.featureName || "Unknown";
9427
- console.log(` ${chalk13.cyan(specLabel)} ${chalk13.dim(`(${result.summary.total} requirements)`)}`);
9835
+ console.log(` ${chalk14.cyan(specLabel)} ${chalk14.dim(`(${result.summary.total} requirements)`)}`);
9428
9836
  console.log("");
9429
9837
  const numWidth = 4;
9430
9838
  const nameWidth = mode === OutputMode.VERBOSE ? 44 : 36;
9431
9839
  const codeWidth = 6;
9432
9840
  const testWidth = 7;
9433
9841
  const confWidth = 12;
9434
- const header = chalk13.dim(
9842
+ const header = chalk14.dim(
9435
9843
  ` ${pad("#", numWidth)}${pad("Requirement", nameWidth)}${pad("Code", codeWidth)}${pad("Tests", testWidth)}${pad("Confidence", confWidth)}Status`
9436
9844
  );
9437
9845
  console.log(header);
@@ -9460,10 +9868,10 @@ function printRequirementRows(requirements, mode, cols) {
9460
9868
  );
9461
9869
  if (mode === OutputMode.VERBOSE) {
9462
9870
  for (const f of req.codeFiles) {
9463
- console.log(chalk13.dim(` code: ${f.path} (${f.method})`));
9871
+ console.log(chalk14.dim(` code: ${f.path} (${f.method})`));
9464
9872
  }
9465
9873
  for (const f of req.testFiles) {
9466
- console.log(chalk13.dim(` test: ${f.path} (${f.method})`));
9874
+ console.log(chalk14.dim(` test: ${f.path} (${f.method})`));
9467
9875
  }
9468
9876
  }
9469
9877
  }
@@ -9474,7 +9882,7 @@ function printCoverageSummary(summary) {
9474
9882
  const codePct = s.total > 0 ? Math.round(s.withCode / s.total * 100) : 0;
9475
9883
  const testPct = s.total > 0 ? Math.round(s.withTests / s.total * 100) : 0;
9476
9884
  console.log(
9477
- ` ${chalk13.bold("Coverage:")} ${fullyPct}% fully traced (${s.fullyTraced}/${s.total}), ${codePct}% with code (${s.withCode}/${s.total}), ${testPct}% with tests (${s.withTests}/${s.total})`
9885
+ ` ${chalk14.bold("Coverage:")} ${fullyPct}% fully traced (${s.fullyTraced}/${s.total}), ${codePct}% with code (${s.withCode}/${s.total}), ${testPct}% with tests (${s.withTests}/${s.total})`
9478
9886
  );
9479
9887
  }
9480
9888
  async function runTraceability(options) {
@@ -9490,14 +9898,14 @@ async function runTraceability(options) {
9490
9898
  console.log(JSON.stringify(results, null, 2));
9491
9899
  } else {
9492
9900
  console.log("");
9493
- console.log(chalk13.bold("Spec-to-Implementation Traceability"));
9901
+ console.log(chalk14.bold("Spec-to-Implementation Traceability"));
9494
9902
  console.log("");
9495
9903
  for (const result of results) printResultTable(result, mode);
9496
9904
  }
9497
9905
  process.exit(ExitCode.SUCCESS);
9498
9906
  }
9499
9907
  function createTraceabilityCommand() {
9500
- return new Command84("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) => {
9908
+ return new Command87("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) => {
9501
9909
  const globalOpts = cmd.optsWithGlobals();
9502
9910
  await runTraceability({
9503
9911
  spec: opts.spec,
@@ -9510,15 +9918,15 @@ function createTraceabilityCommand() {
9510
9918
  }
9511
9919
 
9512
9920
  // src/commands/uninstall.ts
9513
- import * as path62 from "path";
9514
- import { Command as Command85 } from "commander";
9921
+ import * as path65 from "path";
9922
+ import { Command as Command88 } from "commander";
9515
9923
  async function runUninstall(skillName, options) {
9516
9924
  const packageName = resolvePackageName(skillName);
9517
9925
  const shortName = extractSkillName(packageName);
9518
9926
  const globalDir = resolveGlobalSkillsDir();
9519
- const skillsDir = path62.dirname(globalDir);
9520
- const communityBase = path62.join(skillsDir, "community");
9521
- const lockfilePath = path62.join(communityBase, "skills-lock.json");
9927
+ const skillsDir = path65.dirname(globalDir);
9928
+ const communityBase = path65.join(skillsDir, "community");
9929
+ const lockfilePath = path65.join(communityBase, "skills-lock.json");
9522
9930
  const lockfile = readLockfile2(lockfilePath);
9523
9931
  const entry = lockfile.skills[packageName];
9524
9932
  if (!entry) {
@@ -9548,7 +9956,7 @@ async function runUninstall(skillName, options) {
9548
9956
  return result;
9549
9957
  }
9550
9958
  function createUninstallCommand() {
9551
- const cmd = new Command85("uninstall");
9959
+ const cmd = new Command88("uninstall");
9552
9960
  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) => {
9553
9961
  try {
9554
9962
  const result = await runUninstall(skill, opts);
@@ -9568,9 +9976,9 @@ function createUninstallCommand() {
9568
9976
 
9569
9977
  // src/commands/uninstall-constraints.ts
9570
9978
  init_dist();
9571
- import * as fs41 from "fs/promises";
9572
- import * as path63 from "path";
9573
- import { Command as Command86 } from "commander";
9979
+ import * as fs43 from "fs/promises";
9980
+ import * as path66 from "path";
9981
+ import { Command as Command89 } from "commander";
9574
9982
  async function runUninstallConstraints(options) {
9575
9983
  const { packageName, configPath, lockfilePath } = options;
9576
9984
  const lockfileResult = await readLockfile(lockfilePath);
@@ -9590,7 +9998,7 @@ async function runUninstallConstraints(options) {
9590
9998
  }
9591
9999
  let localConfig;
9592
10000
  try {
9593
- const raw = await fs41.readFile(configPath, "utf-8");
10001
+ const raw = await fs43.readFile(configPath, "utf-8");
9594
10002
  localConfig = JSON.parse(raw);
9595
10003
  } catch (err) {
9596
10004
  return {
@@ -9627,11 +10035,11 @@ async function runUninstallConstraints(options) {
9627
10035
  };
9628
10036
  }
9629
10037
  function createUninstallConstraintsCommand() {
9630
- const cmd = new Command86("uninstall-constraints");
10038
+ const cmd = new Command89("uninstall-constraints");
9631
10039
  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) => {
9632
10040
  let configPath;
9633
10041
  if (opts.config) {
9634
- configPath = path63.resolve(opts.config);
10042
+ configPath = path66.resolve(opts.config);
9635
10043
  } else {
9636
10044
  const found = findConfigFile();
9637
10045
  if (!found.ok) {
@@ -9640,8 +10048,8 @@ function createUninstallConstraintsCommand() {
9640
10048
  }
9641
10049
  configPath = found.value;
9642
10050
  }
9643
- const projectRoot = path63.dirname(configPath);
9644
- const lockfilePath = path63.join(projectRoot, ".harness", "constraints.lock.json");
10051
+ const projectRoot = path66.dirname(configPath);
10052
+ const lockfilePath = path66.join(projectRoot, ".harness", "constraints.lock.json");
9645
10053
  const result = await runUninstallConstraints({
9646
10054
  packageName: name,
9647
10055
  configPath,
@@ -9666,13 +10074,13 @@ function createUninstallConstraintsCommand() {
9666
10074
  }
9667
10075
 
9668
10076
  // src/commands/update.ts
9669
- import { Command as Command87 } from "commander";
10077
+ import { Command as Command90 } from "commander";
9670
10078
  import { execFile, execFileSync as execFileSync7 } from "child_process";
9671
- import { realpathSync, existsSync as existsSync38, readFileSync as readFileSync28 } from "fs";
9672
- import { join as join52 } from "path";
10079
+ import { realpathSync, existsSync as existsSync40, readFileSync as readFileSync30 } from "fs";
10080
+ import { join as join54 } from "path";
9673
10081
  import { promisify } from "util";
9674
10082
  import readline4 from "readline";
9675
- import chalk14 from "chalk";
10083
+ import chalk15 from "chalk";
9676
10084
  function detectPackageManager() {
9677
10085
  try {
9678
10086
  const argv1 = process.argv[1];
@@ -9735,10 +10143,10 @@ function prompt3(question) {
9735
10143
  input: process.stdin,
9736
10144
  output: process.stdout
9737
10145
  });
9738
- return new Promise((resolve39) => {
10146
+ return new Promise((resolve40) => {
9739
10147
  rl.question(question, (answer) => {
9740
10148
  rl.close();
9741
- resolve39(answer.trim().toLowerCase());
10149
+ resolve40(answer.trim().toLowerCase());
9742
10150
  });
9743
10151
  });
9744
10152
  }
@@ -9753,12 +10161,12 @@ async function ensureTelemetryIfNeeded() {
9753
10161
  }
9754
10162
  function refreshHooks() {
9755
10163
  const cwd = process.cwd();
9756
- const configPath = join52(cwd, "harness.config.json");
9757
- if (!existsSync38(configPath)) return;
10164
+ const configPath = join54(cwd, "harness.config.json");
10165
+ if (!existsSync40(configPath)) return;
9758
10166
  let profile = "standard";
9759
- const profilePath = join52(cwd, ".harness", "hooks", "profile.json");
10167
+ const profilePath = join54(cwd, ".harness", "hooks", "profile.json");
9760
10168
  try {
9761
- const data = JSON.parse(readFileSync28(profilePath, "utf-8"));
10169
+ const data = JSON.parse(readFileSync30(profilePath, "utf-8"));
9762
10170
  if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
9763
10171
  profile = data.profile;
9764
10172
  }
@@ -9778,7 +10186,7 @@ function runLocalGraphScan() {
9778
10186
  execFileSync7("harness", ["graph", "scan", "."], { stdio: "inherit" });
9779
10187
  } catch {
9780
10188
  logger.warn("Graph scan failed. Run manually:");
9781
- console.log(` ${chalk14.cyan("harness graph scan .")}`);
10189
+ console.log(` ${chalk15.cyan("harness graph scan .")}`);
9782
10190
  }
9783
10191
  }
9784
10192
  async function offerRegeneration() {
@@ -9795,7 +10203,7 @@ async function offerRegeneration() {
9795
10203
  });
9796
10204
  } catch {
9797
10205
  logger.warn("Generation failed. Run manually:");
9798
- console.log(` ${chalk14.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
10206
+ console.log(` ${chalk15.cyan(`harness generate${isGlobal ? " --global" : ""}`)}`);
9799
10207
  }
9800
10208
  if (!isGlobal) {
9801
10209
  runLocalGraphScan();
@@ -9858,8 +10266,8 @@ async function runUpdateAction(opts, globalOpts) {
9858
10266
  console.log("");
9859
10267
  for (const { pkg, current, latest } of outdated) {
9860
10268
  const shortName = pkg.replace("@harness-engineering/", "");
9861
- const currentStr = current ? chalk14.dim(`v${current}`) : chalk14.dim("not installed");
9862
- logger.info(`${shortName}: ${currentStr} \u2192 ${chalk14.green(`v${latest}`)}`);
10269
+ const currentStr = current ? chalk15.dim(`v${current}`) : chalk15.dim("not installed");
10270
+ logger.info(`${shortName}: ${currentStr} \u2192 ${chalk15.green(`v${latest}`)}`);
9863
10271
  }
9864
10272
  console.log("");
9865
10273
  }
@@ -9875,7 +10283,7 @@ async function runUpdateAction(opts, globalOpts) {
9875
10283
  } catch {
9876
10284
  console.log("");
9877
10285
  logger.error("Update failed. You can try manually:");
9878
- console.log(` ${chalk14.cyan(installCmd)}`);
10286
+ console.log(` ${chalk15.cyan(installCmd)}`);
9879
10287
  process.exit(ExitCode.ERROR);
9880
10288
  }
9881
10289
  refreshHooks();
@@ -9884,7 +10292,7 @@ async function runUpdateAction(opts, globalOpts) {
9884
10292
  process.exit(ExitCode.SUCCESS);
9885
10293
  }
9886
10294
  function createUpdateCommand() {
9887
- return new Command87("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(
10295
+ return new Command90("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(
9888
10296
  "--regenerate",
9889
10297
  "Only regenerate slash commands and agent definitions (skip package updates)"
9890
10298
  ).action(async (opts, cmd) => {
@@ -9894,9 +10302,9 @@ function createUpdateCommand() {
9894
10302
  }
9895
10303
 
9896
10304
  // src/commands/usage.ts
9897
- import { Command as Command88 } from "commander";
10305
+ import { Command as Command91 } from "commander";
9898
10306
  async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
9899
- const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-6RT2AVYU.js");
10307
+ const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-I4LWG3IN.js");
9900
10308
  const records = readCostRecords(cwd);
9901
10309
  if (includeClaudeSessions) {
9902
10310
  const ccRecords = parseCCRecords();
@@ -9989,7 +10397,7 @@ function registerDailyCommand(usage) {
9989
10397
  else logger.info("No usage data found. Run some harness sessions first.");
9990
10398
  return;
9991
10399
  }
9992
- const { aggregateByDay } = await import("./dist-6RT2AVYU.js");
10400
+ const { aggregateByDay } = await import("./dist-I4LWG3IN.js");
9993
10401
  const limited = aggregateByDay(records).slice(0, days);
9994
10402
  if (globalOpts.json) {
9995
10403
  console.log(
@@ -10018,7 +10426,7 @@ function registerSessionsCommand(usage) {
10018
10426
  }
10019
10427
  return;
10020
10428
  }
10021
- const { aggregateBySession } = await import("./dist-6RT2AVYU.js");
10429
+ const { aggregateBySession } = await import("./dist-I4LWG3IN.js");
10022
10430
  const sessionData = aggregateBySession(records);
10023
10431
  const limited = sessionData.slice(0, limit);
10024
10432
  if (globalOpts.json) {
@@ -10098,7 +10506,7 @@ function registerSessionCommand(usage) {
10098
10506
  cwd,
10099
10507
  globalOpts.includeClaudeSessions
10100
10508
  );
10101
- const { aggregateBySession } = await import("./dist-6RT2AVYU.js");
10509
+ const { aggregateBySession } = await import("./dist-I4LWG3IN.js");
10102
10510
  const sessionData = aggregateBySession(records);
10103
10511
  const match = sessionData.find((s) => s.sessionId === id);
10104
10512
  if (!match) {
@@ -10133,7 +10541,7 @@ function registerLatestCommand(usage) {
10133
10541
  }
10134
10542
  return;
10135
10543
  }
10136
- const { aggregateBySession } = await import("./dist-6RT2AVYU.js");
10544
+ const { aggregateBySession } = await import("./dist-I4LWG3IN.js");
10137
10545
  const sessionData = aggregateBySession(records);
10138
10546
  const latest = sessionData[0];
10139
10547
  if (!latest) {
@@ -10159,7 +10567,7 @@ function registerLatestCommand(usage) {
10159
10567
  });
10160
10568
  }
10161
10569
  function createUsageCommand() {
10162
- const usage = new Command88("usage").description("Token usage and cost tracking");
10570
+ const usage = new Command91("usage").description("Token usage and cost tracking");
10163
10571
  usage.option(
10164
10572
  "--include-claude-sessions",
10165
10573
  "Include Claude Code session data from ~/.claude/projects/"
@@ -10174,15 +10582,15 @@ function createUsageCommand() {
10174
10582
  // src/commands/validate.ts
10175
10583
  init_dist();
10176
10584
  init_dist();
10177
- import { Command as Command89 } from "commander";
10178
- import * as path64 from "path";
10585
+ import { Command as Command92 } from "commander";
10586
+ import * as path67 from "path";
10179
10587
  async function runValidate(options) {
10180
10588
  const configResult = resolveConfig(options.configPath);
10181
10589
  if (!configResult.ok) {
10182
10590
  return configResult;
10183
10591
  }
10184
10592
  const config = configResult.value;
10185
- const cwd = options.cwd ?? (options.configPath ? path64.dirname(path64.resolve(options.configPath)) : process.cwd());
10593
+ const cwd = options.cwd ?? (options.configPath ? path67.dirname(path67.resolve(options.configPath)) : process.cwd());
10186
10594
  const result = {
10187
10595
  valid: true,
10188
10596
  checks: {
@@ -10192,7 +10600,7 @@ async function runValidate(options) {
10192
10600
  },
10193
10601
  issues: []
10194
10602
  };
10195
- const agentsMapPath = path64.resolve(cwd, config.agentsMapPath);
10603
+ const agentsMapPath = path67.resolve(cwd, config.agentsMapPath);
10196
10604
  const agentsResult = await validateAgentsMap(agentsMapPath);
10197
10605
  if (agentsResult.ok) {
10198
10606
  result.checks.agentsMap = true;
@@ -10256,6 +10664,23 @@ async function runValidate(options) {
10256
10664
  result.issues.push({ check: "solutionsDir", file: issue.file, message: issue.message });
10257
10665
  }
10258
10666
  }
10667
+ const roadmapModeResult = validateRoadmapMode(config, cwd);
10668
+ if (roadmapModeResult.ok) {
10669
+ result.checks.roadmapMode = true;
10670
+ } else {
10671
+ result.valid = false;
10672
+ result.checks.roadmapMode = false;
10673
+ result.issues.push({
10674
+ check: "roadmapMode",
10675
+ file: "harness.config.json",
10676
+ ruleId: roadmapModeResult.error.code,
10677
+ severity: "error",
10678
+ message: roadmapModeResult.error.message,
10679
+ ...roadmapModeResult.error.suggestions?.[0] !== void 0 && {
10680
+ suggestion: roadmapModeResult.error.suggestions[0]
10681
+ }
10682
+ });
10683
+ }
10259
10684
  if (options.agentConfigs) {
10260
10685
  const agentCfg = await validateAgentConfigs(cwd, {
10261
10686
  strict: options.strict === true,
@@ -10285,11 +10710,11 @@ function resolveValidateMode(globalOpts) {
10285
10710
  return OutputMode.TEXT;
10286
10711
  }
10287
10712
  async function printCrossCheckWarnings(mode) {
10288
- const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-MI5MZ7MB.js");
10713
+ const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-XRSSAXJP.js");
10289
10714
  const cwd = process.cwd();
10290
10715
  const crossResult = await runCrossCheck2({
10291
- specsDir: path64.join(cwd, "docs", "specs"),
10292
- plansDir: path64.join(cwd, "docs", "plans"),
10716
+ specsDir: path67.join(cwd, "docs", "specs"),
10717
+ plansDir: path67.join(cwd, "docs", "plans"),
10293
10718
  projectPath: cwd
10294
10719
  });
10295
10720
  if (!crossResult.ok || crossResult.value.warnings === 0) return;
@@ -10301,7 +10726,7 @@ async function printCrossCheckWarnings(mode) {
10301
10726
  ${crossResult.value.warnings} warnings`);
10302
10727
  }
10303
10728
  function createValidateCommand3() {
10304
- const command = new Command89("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
10729
+ const command = new Command92("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
10305
10730
  "--agent-configs",
10306
10731
  "Validate agent configs (CLAUDE.md, hooks, skills) via agnix or built-in fallback rules"
10307
10732
  ).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()));
@@ -10394,6 +10819,7 @@ var commandCreators = [
10394
10819
  createPulseCommand,
10395
10820
  createQueryCommand,
10396
10821
  createRecommendCommand,
10822
+ createRoadmapCommand,
10397
10823
  createScanCommand,
10398
10824
  createScanConfigCommand,
10399
10825
  createSetupCommand,
@@ -10403,6 +10829,7 @@ var commandCreators = [
10403
10829
  createSnapshotCommand,
10404
10830
  createStateCommand,
10405
10831
  createSyncAnalysesCommand,
10832
+ createSyncMainCommand,
10406
10833
  createTaintCommand,
10407
10834
  createTelemetryCommand,
10408
10835
  createTraceabilityCommand,
@@ -10415,7 +10842,7 @@ var commandCreators = [
10415
10842
 
10416
10843
  // src/index.ts
10417
10844
  function createProgram() {
10418
- const program = new Command90();
10845
+ const program = new Command93();
10419
10846
  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");
10420
10847
  for (const creator of commandCreators) {
10421
10848
  program.addCommand(creator());