@harness-engineering/cli 2.7.0 → 2.7.1

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 (52) hide show
  1. package/dist/agents/skills/claude-code/naming-craft/SKILL.md +74 -2
  2. package/dist/agents/skills/codex/naming-craft/SKILL.md +74 -2
  3. package/dist/agents/skills/cursor/naming-craft/SKILL.md +74 -2
  4. package/dist/agents/skills/gemini-cli/naming-craft/SKILL.md +74 -2
  5. package/dist/{agents-md-267R2NUJ.js → agents-md-FKMKH6ZF.js} +3 -3
  6. package/dist/{analyzer-VY6DJVOU-WYKV3TTW.js → analyzer-H3AHBFSL-KPOPJYRB.js} +7 -7
  7. package/dist/{architecture-ZTEHGIHD.js → architecture-LUR2I67H.js} +4 -4
  8. package/dist/{assess-project-OKDW3YSK.js → assess-project-OJWECOP2.js} +1 -1
  9. package/dist/bin/harness-mcp.js +14 -14
  10. package/dist/bin/harness.js +23 -23
  11. package/dist/{check-phase-gate-YJWFDW66.js → check-phase-gate-HS5KYLRO.js} +4 -4
  12. package/dist/{chunk-MQG7FHXX.js → chunk-7AF6C5GE.js} +3 -3
  13. package/dist/{chunk-4EGPFB7V.js → chunk-7PLIWP7U.js} +961 -256
  14. package/dist/{chunk-WOXR6I3R.js → chunk-B2VAYLYI.js} +1 -1
  15. package/dist/{chunk-67RP7MLR.js → chunk-CZPOPMMI.js} +2 -2
  16. package/dist/{chunk-OLTVDPA2.js → chunk-FC4JPM6W.js} +2 -2
  17. package/dist/{chunk-CXAHK5PJ.js → chunk-FEKBXX2J.js} +6 -6
  18. package/dist/{chunk-B4OLYXZ4.js → chunk-FXZI6NJ2.js} +39 -4
  19. package/dist/{chunk-6T5AYG5S.js → chunk-GGSNWH7P.js} +2 -2
  20. package/dist/{chunk-ZKA3TGYS.js → chunk-INBTDBV2.js} +1 -1
  21. package/dist/{chunk-HMMSWRWR.js → chunk-KN3EMDZ5.js} +2 -2
  22. package/dist/{chunk-OQE6ME2Z.js → chunk-LECXPXS3.js} +1 -1
  23. package/dist/{chunk-HLPY3RHE.js → chunk-LGYXR2KZ.js} +799 -515
  24. package/dist/{chunk-QUPC37UB.js → chunk-LYIPI2SJ.js} +3 -3
  25. package/dist/{chunk-S7GEONXL.js → chunk-N5NSSLMU.js} +1 -1
  26. package/dist/{chunk-P7EO7USC.js → chunk-NIVWM7OW.js} +5 -5
  27. package/dist/{chunk-PARV3G2F.js → chunk-O2ASYKA6.js} +1 -1
  28. package/dist/{chunk-XTIPZUPR.js → chunk-PTHX545Q.js} +1 -1
  29. package/dist/{chunk-B3B64OPD.js → chunk-RJ2WEES5.js} +1 -1
  30. package/dist/{chunk-TIZ3L6CU.js → chunk-VI4IS55S.js} +6 -6
  31. package/dist/{chunk-VG6UK6G6.js → chunk-VSIRUZQP.js} +1 -1
  32. package/dist/{chunk-IY2TZLY5.js → chunk-WZY5U6NS.js} +4 -4
  33. package/dist/{chunk-W3PDVZ4I.js → chunk-Y4T6ENKQ.js} +8 -8
  34. package/dist/{chunk-Z2GUITAS.js → chunk-Z3TMCCZB.js} +3 -3
  35. package/dist/{ci-workflow-YGTQTNVC.js → ci-workflow-MDSTHJOY.js} +3 -3
  36. package/dist/{dist-XIJWWQ5N.js → dist-72ID44UE.js} +2 -2
  37. package/dist/{docs-KCTLXK2G.js → docs-2RFOJ6XY.js} +4 -4
  38. package/dist/{engine-J64WPH5K.js → engine-BSFKOGPN.js} +3 -3
  39. package/dist/{entropy-M27JUL3V.js → entropy-3UX6644G.js} +3 -3
  40. package/dist/{feedback-W25QO3OL.js → feedback-CVCFYND4.js} +1 -1
  41. package/dist/{generate-agent-definitions-RNMU5U5R.js → generate-agent-definitions-HZ3XENWO.js} +4 -4
  42. package/dist/index.d.ts +425 -6
  43. package/dist/index.js +23 -23
  44. package/dist/{loader-HZKJ5ABV.js → loader-6RHWU5FH.js} +3 -3
  45. package/dist/{mcp-NEAPIDTT.js → mcp-OYR26JDI.js} +14 -14
  46. package/dist/{performance-3AVQUDRG.js → performance-JJMIRXCH.js} +4 -4
  47. package/dist/{review-pipeline-KA7SGUXJ.js → review-pipeline-BHQZIXWZ.js} +3 -3
  48. package/dist/{runtime-IP6FVV5M.js → runtime-DALTAVTN.js} +3 -3
  49. package/dist/{security-EAR4FJWI.js → security-RMLMYFPB.js} +1 -1
  50. package/dist/{validate-EVH3UXIC.js → validate-R7DZRDFK.js} +4 -4
  51. package/dist/{validate-cross-check-SNE3SQOB.js → validate-cross-check-AUUZFNVL.js} +3 -3
  52. package/package.json +4 -4
@@ -3,20 +3,20 @@ import {
3
3
  handleGetSecurityTrends,
4
4
  handleRunSecurityScan,
5
5
  runSecurityScanDefinition
6
- } from "./chunk-67RP7MLR.js";
6
+ } from "./chunk-CZPOPMMI.js";
7
7
  import {
8
8
  handleRunCodeReview,
9
9
  runCodeReviewDefinition,
10
10
  sortFindingsBySeverity
11
- } from "./chunk-HMMSWRWR.js";
11
+ } from "./chunk-KN3EMDZ5.js";
12
12
  import {
13
13
  assessProjectDefinition,
14
14
  handleAssessProject
15
- } from "./chunk-TIZ3L6CU.js";
15
+ } from "./chunk-VI4IS55S.js";
16
16
  import {
17
17
  detectEntropyDefinition,
18
18
  handleDetectEntropy
19
- } from "./chunk-QUPC37UB.js";
19
+ } from "./chunk-LYIPI2SJ.js";
20
20
  import {
21
21
  checkPerformanceDefinition,
22
22
  getCriticalPathsDefinition,
@@ -26,7 +26,7 @@ import {
26
26
  handleGetPerfBaselines,
27
27
  handleUpdatePerfBaselines,
28
28
  updatePerfBaselinesDefinition
29
- } from "./chunk-CXAHK5PJ.js";
29
+ } from "./chunk-FEKBXX2J.js";
30
30
  import {
31
31
  getBusinessKnowledgeResource
32
32
  } from "./chunk-IOW3MW2K.js";
@@ -37,7 +37,7 @@ import {
37
37
  handleCreateSelfReview,
38
38
  handleRequestPeerReview,
39
39
  requestPeerReviewDefinition
40
- } from "./chunk-Z2GUITAS.js";
40
+ } from "./chunk-Z3TMCCZB.js";
41
41
  import {
42
42
  GENERATED_HEADER_CLAUDE,
43
43
  GENERATED_HEADER_CODEX,
@@ -53,18 +53,18 @@ import {
53
53
  import {
54
54
  handleValidateProject,
55
55
  validateToolDefinition
56
- } from "./chunk-MQG7FHXX.js";
56
+ } from "./chunk-7AF6C5GE.js";
57
57
  import {
58
58
  checkDependenciesDefinition,
59
59
  handleCheckDependencies
60
- } from "./chunk-6T5AYG5S.js";
60
+ } from "./chunk-GGSNWH7P.js";
61
61
  import {
62
62
  resolveProjectConfig
63
- } from "./chunk-VG6UK6G6.js";
63
+ } from "./chunk-VSIRUZQP.js";
64
64
  import {
65
65
  checkDocsDefinition,
66
66
  handleCheckDocs
67
- } from "./chunk-P7EO7USC.js";
67
+ } from "./chunk-NIVWM7OW.js";
68
68
  import {
69
69
  resultToMcpResponse
70
70
  } from "./chunk-RC3OI5NK.js";
@@ -87,8 +87,10 @@ import {
87
87
  SkillMetadataSchema
88
88
  } from "./chunk-HIK6OEUF.js";
89
89
  import {
90
+ findConfigFile,
91
+ loadConfig,
90
92
  resolveConfig
91
- } from "./chunk-B4OLYXZ4.js";
93
+ } from "./chunk-FXZI6NJ2.js";
92
94
  import {
93
95
  logger
94
96
  } from "./chunk-EBJQ6N4M.js";
@@ -118,7 +120,7 @@ import {
118
120
  scanForInjection,
119
121
  serializeEnvelope,
120
122
  writeTaint
121
- } from "./chunk-IY2TZLY5.js";
123
+ } from "./chunk-WZY5U6NS.js";
122
124
  import {
123
125
  Err,
124
126
  INDEXED_FILE_KINDS,
@@ -571,7 +573,7 @@ init_dist2();
571
573
  init_dist();
572
574
  var searchSessionsDefinition = {
573
575
  name: "search_sessions",
574
- description: "Full-text search over archived + live session content (Hermes Phase 1, FTS5/BM25).",
576
+ description: "Full-text search over archived + live session content (FTS5/BM25).",
575
577
  inputSchema: {
576
578
  type: "object",
577
579
  properties: {
@@ -627,7 +629,7 @@ import * as fs2 from "fs";
627
629
  import * as path2 from "path";
628
630
  var summarizeSessionDefinition = {
629
631
  name: "summarize_session",
630
- description: "Generate or regenerate the LLM `llm-summary.md` for an archived session (Hermes Phase 1).",
632
+ description: "Generate or regenerate the LLM `llm-summary.md` for an archived session.",
631
633
  inputSchema: {
632
634
  type: "object",
633
635
  properties: {
@@ -714,7 +716,7 @@ init_dist2();
714
716
  init_dist();
715
717
  var insightsSummaryDefinition = {
716
718
  name: "insights_summary",
717
- description: "Composite report combining health, entropy, decay, attention, and impact (Hermes Phase 1).",
719
+ description: "Composite report combining health, entropy, decay, attention, and impact.",
718
720
  inputSchema: {
719
721
  type: "object",
720
722
  properties: {
@@ -735,7 +737,7 @@ async function handleInsightsSummary(input) {
735
737
  const skip = Array.isArray(input.skip) ? input.skip.filter(
736
738
  (k) => typeof k === "string" && INSIGHTS_KEYS.includes(k)
737
739
  ) : void 0;
738
- const { composeInsights } = await import("./dist-XIJWWQ5N.js");
740
+ const { composeInsights } = await import("./dist-72ID44UE.js");
739
741
  const report = await composeInsights(projectPath, {
740
742
  ...skip && skip.length > 0 && { skip }
741
743
  });
@@ -911,7 +913,7 @@ ${skippedMsg}`
911
913
  async function handleInitProject(input) {
912
914
  const i = input;
913
915
  try {
914
- const { TemplateEngine } = await import("./engine-J64WPH5K.js");
916
+ const { TemplateEngine } = await import("./engine-BSFKOGPN.js");
915
917
  const engine = new TemplateEngine(resolveTemplatesDir());
916
918
  const safePath = sanitizePath(i.path);
917
919
  const detected = tryDetectFramework(engine, safePath, i);
@@ -933,7 +935,7 @@ var listPersonasDefinition = {
933
935
  inputSchema: { type: "object", properties: {} }
934
936
  };
935
937
  async function handleListPersonas() {
936
- const { listPersonas } = await import("./loader-HZKJ5ABV.js");
938
+ const { listPersonas } = await import("./loader-6RHWU5FH.js");
937
939
  const result = listPersonas(resolvePersonasDir());
938
940
  return resultToMcpResponse(result);
939
941
  }
@@ -957,10 +959,10 @@ async function handleGeneratePersonaArtifacts(input) {
957
959
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.name)) {
958
960
  return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.name}`)));
959
961
  }
960
- const { loadPersona } = await import("./loader-HZKJ5ABV.js");
961
- const { generateRuntime } = await import("./runtime-IP6FVV5M.js");
962
- const { generateAgentsMd } = await import("./agents-md-267R2NUJ.js");
963
- const { generateCIWorkflow } = await import("./ci-workflow-YGTQTNVC.js");
962
+ const { loadPersona } = await import("./loader-6RHWU5FH.js");
963
+ const { generateRuntime } = await import("./runtime-DALTAVTN.js");
964
+ const { generateAgentsMd } = await import("./agents-md-FKMKH6ZF.js");
965
+ const { generateCIWorkflow } = await import("./ci-workflow-MDSTHJOY.js");
964
966
  const personasDir = resolvePersonasDir();
965
967
  const filePath = path4.join(personasDir, `${input.name}.yaml`);
966
968
  if (!filePath.startsWith(personasDir)) {
@@ -1015,7 +1017,7 @@ async function handleRunPersona(input) {
1015
1017
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.persona)) {
1016
1018
  return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.persona}`)));
1017
1019
  }
1018
- const { loadPersona } = await import("./loader-HZKJ5ABV.js");
1020
+ const { loadPersona } = await import("./loader-6RHWU5FH.js");
1019
1021
  const { runPersona } = await import("./runner-AAEF2TXY.js");
1020
1022
  const { executeSkill } = await import("./skill-executor-MOCUIAYS.js");
1021
1023
  const personasDir = resolvePersonasDir();
@@ -1460,7 +1462,7 @@ function loadOrGenerateProfile(projectRoot) {
1460
1462
  // src/mcp/tools/event-emitter.ts
1461
1463
  async function emitSkillEvent(projectPath, event) {
1462
1464
  try {
1463
- const { emitEvent } = await import("./dist-XIJWWQ5N.js");
1465
+ const { emitEvent } = await import("./dist-72ID44UE.js");
1464
1466
  await emitEvent(projectPath, event);
1465
1467
  } catch {
1466
1468
  }
@@ -1732,7 +1734,7 @@ async function autoSyncRoadmap(projectPath) {
1732
1734
  try {
1733
1735
  const roadmapFile = path11.join(projectPath, "docs", "roadmap.md");
1734
1736
  if (!fs10.existsSync(roadmapFile)) return;
1735
- const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges } = await import("./dist-XIJWWQ5N.js");
1737
+ const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges } = await import("./dist-72ID44UE.js");
1736
1738
  const raw = fs10.readFileSync(roadmapFile, "utf-8");
1737
1739
  const parseResult = parseRoadmap(raw);
1738
1740
  if (!parseResult.ok) return;
@@ -1762,7 +1764,7 @@ async function triggerExternalSync(projectPath, roadmapFile) {
1762
1764
  console.warn("[roadmap-sync] GITHUB_TOKEN not found \u2014 external sync skipped");
1763
1765
  return;
1764
1766
  }
1765
- const { fullSync, GitHubIssuesSyncAdapter } = await import("./dist-XIJWWQ5N.js");
1767
+ const { fullSync, GitHubIssuesSyncAdapter } = await import("./dist-72ID44UE.js");
1766
1768
  const adapter = new GitHubIssuesSyncAdapter({
1767
1769
  token,
1768
1770
  config: trackerConfig
@@ -1859,12 +1861,12 @@ var manageStateDefinition = {
1859
1861
  }
1860
1862
  };
1861
1863
  async function handleShow(projectPath, input) {
1862
- const { loadState } = await import("./dist-XIJWWQ5N.js");
1864
+ const { loadState } = await import("./dist-72ID44UE.js");
1863
1865
  return resultToMcpResponse(await loadState(projectPath, input.stream, input.session));
1864
1866
  }
1865
1867
  async function handleLearn(projectPath, input) {
1866
1868
  if (!input.learning) return mcpError("Error: learning is required for learn action");
1867
- const { appendLearning } = await import("./dist-XIJWWQ5N.js");
1869
+ const { appendLearning } = await import("./dist-72ID44UE.js");
1868
1870
  const result = await appendLearning(
1869
1871
  projectPath,
1870
1872
  input.learning,
@@ -1879,7 +1881,7 @@ async function handleLearn(projectPath, input) {
1879
1881
  async function handleFailure(projectPath, input) {
1880
1882
  if (!input.description) return mcpError("Error: description is required for failure action");
1881
1883
  if (!input.failureType) return mcpError("Error: failureType is required for failure action");
1882
- const { appendFailure } = await import("./dist-XIJWWQ5N.js");
1884
+ const { appendFailure } = await import("./dist-72ID44UE.js");
1883
1885
  const result = await appendFailure(
1884
1886
  projectPath,
1885
1887
  input.description,
@@ -1898,19 +1900,19 @@ async function handleFailure(projectPath, input) {
1898
1900
  return resultToMcpResponse(Ok({ recorded: true }));
1899
1901
  }
1900
1902
  async function handleArchive(projectPath, input) {
1901
- const { archiveFailures } = await import("./dist-XIJWWQ5N.js");
1903
+ const { archiveFailures } = await import("./dist-72ID44UE.js");
1902
1904
  const result = await archiveFailures(projectPath, input.stream, input.session);
1903
1905
  if (!result.ok) return resultToMcpResponse(result);
1904
1906
  return resultToMcpResponse(Ok({ archived: true }));
1905
1907
  }
1906
1908
  async function handleReset(projectPath, input) {
1907
- const { saveState, DEFAULT_STATE } = await import("./dist-XIJWWQ5N.js");
1909
+ const { saveState, DEFAULT_STATE } = await import("./dist-72ID44UE.js");
1908
1910
  const result = await saveState(projectPath, { ...DEFAULT_STATE }, input.stream, input.session);
1909
1911
  if (!result.ok) return resultToMcpResponse(result);
1910
1912
  return resultToMcpResponse(Ok({ reset: true }));
1911
1913
  }
1912
1914
  async function handleGate(projectPath, input) {
1913
- const { runMechanicalGate } = await import("./dist-XIJWWQ5N.js");
1915
+ const { runMechanicalGate } = await import("./dist-72ID44UE.js");
1914
1916
  const result = await runMechanicalGate(projectPath);
1915
1917
  if (result.ok) {
1916
1918
  await emitSkillEvent(projectPath, {
@@ -1930,7 +1932,7 @@ async function handleGate(projectPath, input) {
1930
1932
  }
1931
1933
  async function handleSaveHandoff(projectPath, input) {
1932
1934
  if (!input.handoff) return mcpError("Error: handoff is required for save-handoff action");
1933
- const { saveHandoff } = await import("./dist-XIJWWQ5N.js");
1935
+ const { saveHandoff } = await import("./dist-72ID44UE.js");
1934
1936
  const result = await saveHandoff(
1935
1937
  projectPath,
1936
1938
  input.handoff,
@@ -1952,7 +1954,7 @@ async function handleSaveHandoff(projectPath, input) {
1952
1954
  return resultToMcpResponse(Ok({ saved: true }));
1953
1955
  }
1954
1956
  async function handleLoadHandoff(projectPath, input) {
1955
- const { loadHandoff } = await import("./dist-XIJWWQ5N.js");
1957
+ const { loadHandoff } = await import("./dist-72ID44UE.js");
1956
1958
  return resultToMcpResponse(await loadHandoff(projectPath, input.stream, input.session));
1957
1959
  }
1958
1960
  async function handleAppendEntry(projectPath, input) {
@@ -1960,7 +1962,7 @@ async function handleAppendEntry(projectPath, input) {
1960
1962
  if (!input.authorSkill) return mcpError("Error: authorSkill is required for append_entry action");
1961
1963
  if (!input.content) return mcpError("Error: content is required for append_entry action");
1962
1964
  if (input.session) {
1963
- const { appendSessionEntry } = await import("./dist-XIJWWQ5N.js");
1965
+ const { appendSessionEntry } = await import("./dist-72ID44UE.js");
1964
1966
  const result = await appendSessionEntry(
1965
1967
  projectPath,
1966
1968
  input.session,
@@ -1973,7 +1975,7 @@ async function handleAppendEntry(projectPath, input) {
1973
1975
  if (input.section !== "decisions") {
1974
1976
  return mcpError("Error: session is required for non-decisions sections");
1975
1977
  }
1976
- const { loadState, saveState } = await import("./dist-XIJWWQ5N.js");
1978
+ const { loadState, saveState } = await import("./dist-72ID44UE.js");
1977
1979
  const lr = await loadState(projectPath, input.stream);
1978
1980
  if (!lr.ok) return resultToMcpResponse(lr);
1979
1981
  lr.value.decisions.push({
@@ -1991,7 +1993,7 @@ async function handleUpdateEntryStatus(projectPath, input) {
1991
1993
  if (!input.entryId) return mcpError("Error: entryId is required for update_entry_status action");
1992
1994
  if (!input.newStatus)
1993
1995
  return mcpError("Error: newStatus is required for update_entry_status action");
1994
- const { updateSessionEntryStatus } = await import("./dist-XIJWWQ5N.js");
1996
+ const { updateSessionEntryStatus } = await import("./dist-72ID44UE.js");
1995
1997
  const result = await updateSessionEntryStatus(
1996
1998
  projectPath,
1997
1999
  input.session,
@@ -2004,7 +2006,7 @@ async function handleUpdateEntryStatus(projectPath, input) {
2004
2006
  async function handleReadSection(projectPath, input) {
2005
2007
  if (!input.session) return mcpError("Error: session is required for read_section action");
2006
2008
  if (!input.section) return mcpError("Error: section is required for read_section action");
2007
- const { readSessionSection } = await import("./dist-XIJWWQ5N.js");
2009
+ const { readSessionSection } = await import("./dist-72ID44UE.js");
2008
2010
  const result = await readSessionSection(
2009
2011
  projectPath,
2010
2012
  input.session,
@@ -2014,13 +2016,13 @@ async function handleReadSection(projectPath, input) {
2014
2016
  }
2015
2017
  async function handleReadSections(projectPath, input) {
2016
2018
  if (!input.session) return mcpError("Error: session is required for read_sections action");
2017
- const { readSessionSections } = await import("./dist-XIJWWQ5N.js");
2019
+ const { readSessionSections } = await import("./dist-72ID44UE.js");
2018
2020
  const result = await readSessionSections(projectPath, input.session);
2019
2021
  return resultToMcpResponse(result);
2020
2022
  }
2021
2023
  async function handleArchiveSession(projectPath, input) {
2022
2024
  if (!input.session) return mcpError("Error: session is required for archive_session action");
2023
- const { archiveSession } = await import("./dist-XIJWWQ5N.js");
2025
+ const { archiveSession } = await import("./dist-72ID44UE.js");
2024
2026
  const { buildArchiveHooks } = await import("@harness-engineering/orchestrator");
2025
2027
  const hooks = buildArchiveHooks({ projectPath });
2026
2028
  const result = await archiveSession(projectPath, input.session, { hooks });
@@ -2102,7 +2104,7 @@ var listStreamsDefinition = {
2102
2104
  };
2103
2105
  async function handleListStreams(input) {
2104
2106
  try {
2105
- const { listStreams, loadStreamIndex } = await import("./dist-XIJWWQ5N.js");
2107
+ const { listStreams, loadStreamIndex } = await import("./dist-72ID44UE.js");
2106
2108
  const projectPath = sanitizePath(input.path);
2107
2109
  const indexResult = await loadStreamIndex(projectPath);
2108
2110
  const streamsResult = await listStreams(projectPath);
@@ -2140,7 +2142,7 @@ var checkPhaseGateDefinition = {
2140
2142
  };
2141
2143
  async function handleCheckPhaseGate(input) {
2142
2144
  try {
2143
- const { runCheckPhaseGate } = await import("./check-phase-gate-YJWFDW66.js");
2145
+ const { runCheckPhaseGate } = await import("./check-phase-gate-HS5KYLRO.js");
2144
2146
  const result = await runCheckPhaseGate({ cwd: sanitizePath(input.path) });
2145
2147
  if (result.ok) {
2146
2148
  return { content: [{ type: "text", text: JSON.stringify(result.value) }] };
@@ -2196,7 +2198,7 @@ async function handleValidateCrossCheck(input) {
2196
2198
  };
2197
2199
  }
2198
2200
  try {
2199
- const { runCrossCheck } = await import("./validate-cross-check-SNE3SQOB.js");
2201
+ const { runCrossCheck } = await import("./validate-cross-check-AUUZFNVL.js");
2200
2202
  const specsDir = path12.resolve(projectPath, input.specsDir ?? "docs/specs");
2201
2203
  if (!specsDir.startsWith(projectPath)) {
2202
2204
  return {
@@ -2705,11 +2707,11 @@ function resolveOutputDir(platform, opts) {
2705
2707
  }
2706
2708
  async function confirmDeletion(files) {
2707
2709
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
2708
- return new Promise((resolve4) => {
2710
+ return new Promise((resolve5) => {
2709
2711
  rl.question(`
2710
2712
  Remove ${files.length} orphaned command(s)? (y/N) `, (answer) => {
2711
2713
  rl.close();
2712
- resolve4(answer.toLowerCase() === "y");
2714
+ resolve5(answer.toLowerCase() === "y");
2713
2715
  });
2714
2716
  });
2715
2717
  }
@@ -3019,7 +3021,7 @@ async function handleGenerateSlashCommands(input) {
3019
3021
  // src/mcp/resources/state.ts
3020
3022
  async function getStateResource(projectRoot) {
3021
3023
  try {
3022
- const { loadState, migrateToStreams } = await import("./dist-XIJWWQ5N.js");
3024
+ const { loadState, migrateToStreams } = await import("./dist-72ID44UE.js");
3023
3025
  await migrateToStreams(projectRoot);
3024
3026
  const result = await loadState(projectRoot);
3025
3027
  if (result.ok) {
@@ -3630,8 +3632,8 @@ async function handleIngestSource(input) {
3630
3632
  const projectPath = sanitizePath(input.path);
3631
3633
  const graphDir = path16.join(projectPath, ".harness", "graph");
3632
3634
  const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-R3TOOPJ7.js");
3633
- const fs42 = await import("fs/promises");
3634
- await fs42.mkdir(graphDir, { recursive: true });
3635
+ const fs44 = await import("fs/promises");
3636
+ await fs44.mkdir(graphDir, { recursive: true });
3635
3637
  const store = new GraphStore();
3636
3638
  await store.load(graphDir);
3637
3639
  const results = [];
@@ -4039,7 +4041,7 @@ var generateAgentDefinitionsDefinition = {
4039
4041
  }
4040
4042
  };
4041
4043
  async function handleGenerateAgentDefinitions(input) {
4042
- const { generateAgentDefinitions } = await import("./generate-agent-definitions-RNMU5U5R.js");
4044
+ const { generateAgentDefinitions } = await import("./generate-agent-definitions-HZ3XENWO.js");
4043
4045
  const platforms = input.platform === "all" || !input.platform ? ["claude-code", "gemini-cli"] : [input.platform];
4044
4046
  const results = generateAgentDefinitions({
4045
4047
  platforms: [...platforms],
@@ -4533,7 +4535,7 @@ async function handleManageRoadmap(input) {
4533
4535
  return handleManageRoadmapFileLess(input, clientResult.value);
4534
4536
  }
4535
4537
  try {
4536
- const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges, assignFeature } = await import("./dist-XIJWWQ5N.js");
4538
+ const { parseRoadmap, serializeRoadmap, syncRoadmap, applySyncChanges, assignFeature } = await import("./dist-72ID44UE.js");
4537
4539
  const { Ok: Ok2 } = await import("./dist-E3SAAHCM.js");
4538
4540
  const projectPath = projectPathPre;
4539
4541
  const deps = {
@@ -4972,7 +4974,7 @@ async function handleTransition(validInput, projectPath, id) {
4972
4974
  const transition = transitionResult.data;
4973
4975
  const prompt = renderTransition(transition);
4974
4976
  try {
4975
- const { saveHandoff } = await import("./dist-XIJWWQ5N.js");
4977
+ const { saveHandoff } = await import("./dist-72ID44UE.js");
4976
4978
  await saveHandoff(
4977
4979
  projectPath,
4978
4980
  {
@@ -5053,7 +5055,7 @@ async function handleEmitInteraction(input) {
5053
5055
  }
5054
5056
  async function recordInteraction(projectPath, id, type, decision, stream) {
5055
5057
  try {
5056
- const { loadState, saveState } = await import("./dist-XIJWWQ5N.js");
5058
+ const { loadState, saveState } = await import("./dist-72ID44UE.js");
5057
5059
  const stateResult = await loadState(projectPath, stream);
5058
5060
  if (stateResult.ok) {
5059
5061
  const state = stateResult.value;
@@ -5214,10 +5216,10 @@ async function handleGatherContext(input) {
5214
5216
  input.include ?? ["state", "learnings", "handoff", "graph", "validation", "businessKnowledge"]
5215
5217
  );
5216
5218
  const errors = [];
5217
- const statePromise = includeSet.has("state") ? import("./dist-XIJWWQ5N.js").then(
5219
+ const statePromise = includeSet.has("state") ? import("./dist-72ID44UE.js").then(
5218
5220
  (core) => core.loadState(projectPath, void 0, input.session)
5219
5221
  ) : Promise.resolve(null);
5220
- const learningsPromise = includeSet.has("learnings") ? import("./dist-XIJWWQ5N.js").then(
5222
+ const learningsPromise = includeSet.has("learnings") ? import("./dist-72ID44UE.js").then(
5221
5223
  (core) => core.loadBudgetedLearnings(projectPath, {
5222
5224
  intent: input.intent,
5223
5225
  tokenBudget: input.learningsBudget ?? 1e3,
@@ -5226,7 +5228,7 @@ async function handleGatherContext(input) {
5226
5228
  ...input.depth !== void 0 && { depth: input.depth }
5227
5229
  })
5228
5230
  ) : Promise.resolve(null);
5229
- const handoffPromise = includeSet.has("handoff") ? import("./dist-XIJWWQ5N.js").then(
5231
+ const handoffPromise = includeSet.has("handoff") ? import("./dist-72ID44UE.js").then(
5230
5232
  (core) => core.loadHandoff(projectPath, void 0, input.session)
5231
5233
  ) : Promise.resolve(null);
5232
5234
  const graphPromise = includeSet.has("graph") ? (async () => {
@@ -5270,11 +5272,11 @@ async function handleGatherContext(input) {
5270
5272
  context: contextBlocks
5271
5273
  };
5272
5274
  })() : Promise.resolve(null);
5273
- const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-XIJWWQ5N.js").then(
5275
+ const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-72ID44UE.js").then(
5274
5276
  (core) => core.readSessionSections(projectPath, input.session)
5275
5277
  ) : Promise.resolve(null);
5276
5278
  const shouldIncludeEvents = input.includeEvents !== void 0 ? input.includeEvents : includeSet.has("events") || !!input.session && !input.include;
5277
- const eventsPromise = shouldIncludeEvents ? import("./dist-XIJWWQ5N.js").then(async (core) => {
5279
+ const eventsPromise = shouldIncludeEvents ? import("./dist-72ID44UE.js").then(async (core) => {
5278
5280
  const result = await core.loadEvents(projectPath, {
5279
5281
  session: input.session
5280
5282
  });
@@ -5282,7 +5284,7 @@ async function handleGatherContext(input) {
5282
5284
  return core.formatEventTimeline(result.value);
5283
5285
  }) : Promise.resolve(null);
5284
5286
  const validationPromise = includeSet.has("validation") ? (async () => {
5285
- const { handleValidateProject: handleValidateProject2 } = await import("./validate-EVH3UXIC.js");
5287
+ const { handleValidateProject: handleValidateProject2 } = await import("./validate-R7DZRDFK.js");
5286
5288
  const result = await handleValidateProject2({ path: projectPath });
5287
5289
  const first = result.content[0];
5288
5290
  return first ? JSON.parse(first.text) : null;
@@ -5385,7 +5387,7 @@ async function handleGatherContext(input) {
5385
5387
  };
5386
5388
  if (input.session) {
5387
5389
  try {
5388
- const core = await import("./dist-XIJWWQ5N.js");
5390
+ const core = await import("./dist-72ID44UE.js");
5389
5391
  core.updateSessionIndex(
5390
5392
  projectPath,
5391
5393
  input.session,
@@ -5537,7 +5539,7 @@ async function handleReviewChanges(input) {
5537
5539
  }
5538
5540
  }
5539
5541
  async function runQuickReview(projectPath, diff, diffLines, downgraded, offset, limit) {
5540
- const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-W25QO3OL.js");
5542
+ const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-CVCFYND4.js");
5541
5543
  const result = await handleAnalyzeDiff2({ diff, path: projectPath });
5542
5544
  const firstContent = result.content[0];
5543
5545
  if (!firstContent) throw new Error("Empty analyze_diff response");
@@ -5572,7 +5574,7 @@ function extractFileCount(diffParsed) {
5572
5574
  return files?.length ?? 0;
5573
5575
  }
5574
5576
  async function runStandardReview(projectPath, diff, diffLines, downgraded, offset, limit) {
5575
- const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-W25QO3OL.js");
5577
+ const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-CVCFYND4.js");
5576
5578
  const [diffResult, reviewResult] = await Promise.all([
5577
5579
  handleAnalyzeDiff2({ diff, path: projectPath }),
5578
5580
  handleCreateSelfReview2({ path: projectPath, diff })
@@ -5607,7 +5609,7 @@ async function runStandardReview(projectPath, diff, diffLines, downgraded, offse
5607
5609
  };
5608
5610
  }
5609
5611
  async function runDeepReview(projectPath, diff, diffLines, _downgraded, offset, limit) {
5610
- const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-KA7SGUXJ.js");
5612
+ const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-BHQZIXWZ.js");
5611
5613
  const result = await handleRunCodeReview2({
5612
5614
  path: projectPath,
5613
5615
  diff,
@@ -5901,7 +5903,7 @@ async function handleDetectStaleConstraints(input) {
5901
5903
  ]
5902
5904
  };
5903
5905
  }
5904
- const { detectStaleConstraints } = await import("./dist-XIJWWQ5N.js");
5906
+ const { detectStaleConstraints } = await import("./dist-72ID44UE.js");
5905
5907
  const result = detectStaleConstraints(
5906
5908
  store,
5907
5909
  windowDays,
@@ -5987,8 +5989,18 @@ function deriveSignals(checks, metrics) {
5987
5989
  return [...signals];
5988
5990
  }
5989
5991
  var DEFAULT_CHECK = { passed: true, issueCount: 0 };
5990
- function parseToolResult(result) {
5991
- return JSON.parse(result.content[0]?.text ?? "{}");
5992
+ function parseToolResult(result, toolName) {
5993
+ const text = result.content[0]?.text ?? "{}";
5994
+ if (result.isError) {
5995
+ logger.warn(`${toolName} reported an error: ${text}`);
5996
+ return {};
5997
+ }
5998
+ try {
5999
+ return JSON.parse(text);
6000
+ } catch {
6001
+ logger.warn(`${toolName} returned non-JSON output: ${text.slice(0, 120)}`);
6002
+ return {};
6003
+ }
5992
6004
  }
5993
6005
  function buildCheckMap(assessData) {
5994
6006
  const map = /* @__PURE__ */ new Map();
@@ -6021,10 +6033,10 @@ function countCriticalFindings(securityData) {
6021
6033
  return findings.filter((f) => f.severity === "error").length;
6022
6034
  }
6023
6035
  async function runHealthChecks(projectPath) {
6024
- const { handleAssessProject: handleAssessProject2 } = await import("./assess-project-OKDW3YSK.js");
6025
- const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-ZTEHGIHD.js");
6026
- const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-M27JUL3V.js");
6027
- const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-EAR4FJWI.js");
6036
+ const { handleAssessProject: handleAssessProject2 } = await import("./assess-project-OJWECOP2.js");
6037
+ const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-LUR2I67H.js");
6038
+ const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-3UX6644G.js");
6039
+ const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-RMLMYFPB.js");
6028
6040
  const [assessResult, depsResult, entropyResult, securityResult] = await Promise.all([
6029
6041
  handleAssessProject2({
6030
6042
  path: projectPath,
@@ -6034,11 +6046,13 @@ async function runHealthChecks(projectPath) {
6034
6046
  handleDetectEntropy2({ path: projectPath, type: "all" }),
6035
6047
  handleRunSecurityScan2({ path: projectPath })
6036
6048
  ]);
6037
- const assessData = parseToolResult(assessResult);
6049
+ const assessData = parseToolResult(assessResult, "assess_project");
6038
6050
  const checkMap = buildCheckMap(assessData);
6039
- const { circularDeps, layerViolations } = countViolations(parseToolResult(depsResult));
6040
- const entropyGranular = parseEntropyGranular(parseToolResult(entropyResult));
6041
- const criticalCount = countCriticalFindings(parseToolResult(securityResult));
6051
+ const { circularDeps, layerViolations } = countViolations(
6052
+ parseToolResult(depsResult, "check_dependencies")
6053
+ );
6054
+ const entropyGranular = parseEntropyGranular(parseToolResult(entropyResult, "detect_entropy"));
6055
+ const criticalCount = countCriticalFindings(parseToolResult(securityResult, "run_security_scan"));
6042
6056
  return assembleHealthChecks(
6043
6057
  checkMap,
6044
6058
  circularDeps,
@@ -6865,7 +6879,7 @@ async function handleGetDecayTrends(input) {
6865
6879
  };
6866
6880
  }
6867
6881
  try {
6868
- const core = await import("./dist-XIJWWQ5N.js");
6882
+ const core = await import("./dist-72ID44UE.js");
6869
6883
  const { TimelineManager } = core;
6870
6884
  const manager = new TimelineManager(projectPath);
6871
6885
  const timeline = manager.load();
@@ -7000,7 +7014,7 @@ async function handleCodeOutline(input) {
7000
7014
  };
7001
7015
  }
7002
7016
  try {
7003
- const { getOutline, formatOutline, EXTENSION_MAP } = await import("./dist-XIJWWQ5N.js");
7017
+ const { getOutline, formatOutline, EXTENSION_MAP } = await import("./dist-72ID44UE.js");
7004
7018
  const { stat } = await import("fs/promises");
7005
7019
  const stats = await stat(targetPath).catch(() => null);
7006
7020
  if (stats?.isFile()) {
@@ -7019,7 +7033,7 @@ async function handleCodeOutline(input) {
7019
7033
  })
7020
7034
  );
7021
7035
  fileStats.sort((a, b) => b.mtimeMs - a.mtimeMs);
7022
- const { paginate: paginate2 } = await import("./dist-XIJWWQ5N.js");
7036
+ const { paginate: paginate2 } = await import("./dist-72ID44UE.js");
7023
7037
  const paged = paginate2(fileStats, input.offset ?? 0, input.limit ?? 30);
7024
7038
  const results = [];
7025
7039
  for (const entry of paged.items) {
@@ -7092,7 +7106,7 @@ async function handleCodeSearch(input) {
7092
7106
  };
7093
7107
  }
7094
7108
  try {
7095
- const { searchSymbols } = await import("./dist-XIJWWQ5N.js");
7109
+ const { searchSymbols } = await import("./dist-72ID44UE.js");
7096
7110
  const result = await searchSymbols(input.query, directory, input.glob);
7097
7111
  const lines = [`Search: "${result.query}" \u2014 ${result.matches.length} matches`];
7098
7112
  for (const match of result.matches) {
@@ -7161,7 +7175,7 @@ async function handleCodeUnfold(input) {
7161
7175
  }
7162
7176
  try {
7163
7177
  if (input.symbol) {
7164
- const { unfoldSymbol } = await import("./dist-XIJWWQ5N.js");
7178
+ const { unfoldSymbol } = await import("./dist-72ID44UE.js");
7165
7179
  const result = await unfoldSymbol(filePath, input.symbol);
7166
7180
  const header = result.warning ? `${result.file}:${result.startLine}-${result.endLine} ${result.warning}
7167
7181
  ` : `${result.file}:${result.startLine}-${result.endLine}
@@ -7169,7 +7183,7 @@ async function handleCodeUnfold(input) {
7169
7183
  return { content: [{ type: "text", text: header + result.content }] };
7170
7184
  }
7171
7185
  if (input.startLine != null && input.endLine != null) {
7172
- const { unfoldRange } = await import("./dist-XIJWWQ5N.js");
7186
+ const { unfoldRange } = await import("./dist-72ID44UE.js");
7173
7187
  const result = await unfoldRange(filePath, input.startLine, input.endLine);
7174
7188
  const header = `${result.file}:${result.startLine}-${result.endLine}
7175
7189
  `;
@@ -7354,7 +7368,7 @@ async function handlePredictFailures(input) {
7354
7368
  };
7355
7369
  }
7356
7370
  try {
7357
- const core = await import("./dist-XIJWWQ5N.js");
7371
+ const core = await import("./dist-72ID44UE.js");
7358
7372
  const { TimelineManager, PredictionEngine, SpecImpactEstimator } = core;
7359
7373
  const manager = new TimelineManager(projectPath);
7360
7374
  const includeRoadmap = input.includeRoadmap !== false;
@@ -8463,7 +8477,7 @@ async function handleDetectConstraintEmergence(input) {
8463
8477
  }
8464
8478
  const nodePath = await import("path");
8465
8479
  const historyPath = nodePath.resolve(projectPath, ".harness/arch/violation-history.json");
8466
- const { ViolationHistoryManager, detectEmergentConstraints } = await import("./dist-XIJWWQ5N.js");
8480
+ const { ViolationHistoryManager, detectEmergentConstraints } = await import("./dist-72ID44UE.js");
8467
8481
  const manager = new ViolationHistoryManager(historyPath);
8468
8482
  const history = manager.load();
8469
8483
  const options = { windowWeeks, minOccurrences };
@@ -8551,7 +8565,7 @@ async function handleRunCIChecks(input) {
8551
8565
  };
8552
8566
  }
8553
8567
  try {
8554
- const { runCIChecks } = await import("./dist-XIJWWQ5N.js");
8568
+ const { runCIChecks } = await import("./dist-72ID44UE.js");
8555
8569
  const skip = input.checks ? VALID_CHECKS.filter((c) => !input.checks.includes(c)) : [];
8556
8570
  const result = await runCIChecks({
8557
8571
  projectRoot: projectPath,
@@ -8613,7 +8627,7 @@ async function handleGenerateBlueprint(input) {
8613
8627
  };
8614
8628
  }
8615
8629
  try {
8616
- const { ProjectScanner } = await import("./dist-XIJWWQ5N.js");
8630
+ const { ProjectScanner } = await import("./dist-72ID44UE.js");
8617
8631
  const scanner = new ProjectScanner(projectPath);
8618
8632
  const data = await scanner.scan();
8619
8633
  return {
@@ -8812,7 +8826,7 @@ async function handleEmitSkillProposal(input) {
8812
8826
  let createProposal;
8813
8827
  let ProposalConflictError;
8814
8828
  try {
8815
- const core = await import("./dist-XIJWWQ5N.js");
8829
+ const core = await import("./dist-72ID44UE.js");
8816
8830
  createProposal = core.createProposal;
8817
8831
  ProposalConflictError = core.ProposalConflictError;
8818
8832
  } catch (err2) {
@@ -9481,6 +9495,234 @@ var hierarchyClarityRubric = {
9481
9495
  }
9482
9496
  };
9483
9497
 
9498
+ // src/shared/craft/llm/in-session.ts
9499
+ var PromptDeferredError = class extends Error {
9500
+ promptId;
9501
+ constructor(promptId) {
9502
+ super(`In-session prompt ${promptId} deferred to calling agent`);
9503
+ this.name = "PromptDeferredError";
9504
+ this.promptId = promptId;
9505
+ }
9506
+ };
9507
+ var InSessionLlmProvider = class {
9508
+ providerId = "in-session";
9509
+ model = "host-chat";
9510
+ deferred = [];
9511
+ costs = [];
9512
+ counter = 0;
9513
+ async callText(prompt, opts) {
9514
+ const promptId = `p${(++this.counter).toString(36)}`;
9515
+ this.deferred.push({
9516
+ promptId,
9517
+ systemPrompt: opts?.systemPrompt,
9518
+ userPrompt: prompt
9519
+ });
9520
+ throw new PromptDeferredError(promptId);
9521
+ }
9522
+ async callVision(_prompt, _image) {
9523
+ throw new Error(
9524
+ "InSessionLlmProvider.callVision is not implemented \u2014 vision flows must use a real provider."
9525
+ );
9526
+ }
9527
+ recordCost(cost) {
9528
+ this.costs.push(cost);
9529
+ }
9530
+ getCosts() {
9531
+ return this.costs;
9532
+ }
9533
+ /** Read out the queue of deferred prompts (in the order callText was invoked). */
9534
+ getDeferred() {
9535
+ return this.deferred;
9536
+ }
9537
+ };
9538
+
9539
+ // src/shared/craft/llm/adapters.ts
9540
+ import { z as z2 } from "zod";
9541
+ var RAW_SCHEMA = z2.object({ raw: z2.string() });
9542
+ var RAW_INSTRUCTIONS = 'Return a JSON object with a single field "raw" whose string value is the fenced JSON block you would normally emit. Do not add prose outside the JSON object.';
9543
+ var AnalysisProviderAdapter = class {
9544
+ providerId;
9545
+ model;
9546
+ inner;
9547
+ costs = [];
9548
+ constructor(opts) {
9549
+ this.providerId = opts.providerId;
9550
+ this.model = opts.model;
9551
+ this.inner = opts.inner;
9552
+ }
9553
+ async callText(prompt, opts) {
9554
+ const wrappedSystem = [opts?.systemPrompt, RAW_INSTRUCTIONS].filter(Boolean).join("\n\n");
9555
+ const response = await this.inner.analyze({
9556
+ prompt,
9557
+ systemPrompt: wrappedSystem,
9558
+ responseSchema: RAW_SCHEMA
9559
+ });
9560
+ this.recordCost({
9561
+ provider: this.providerId,
9562
+ model: response.model || this.model,
9563
+ inputTokens: response.tokenUsage.inputTokens,
9564
+ outputTokens: response.tokenUsage.outputTokens,
9565
+ costUsd: 0
9566
+ });
9567
+ return response.result.raw;
9568
+ }
9569
+ async callVision(_prompt, _image) {
9570
+ throw new Error(
9571
+ `${this.providerId} adapter does not implement callVision \u2014 wire vision when needed.`
9572
+ );
9573
+ }
9574
+ recordCost(cost) {
9575
+ this.costs.push(cost);
9576
+ }
9577
+ getCosts() {
9578
+ return this.costs;
9579
+ }
9580
+ };
9581
+ function adaptClaudeCli(inner, model) {
9582
+ return new AnalysisProviderAdapter({
9583
+ providerId: "claude-cli",
9584
+ model: model ?? "claude",
9585
+ inner
9586
+ });
9587
+ }
9588
+ function adaptAnthropic(inner, model) {
9589
+ return new AnalysisProviderAdapter({
9590
+ providerId: "anthropic",
9591
+ model: model ?? "claude-sonnet-4-20250514",
9592
+ inner
9593
+ });
9594
+ }
9595
+ function adaptOpenAICompatible(inner, model) {
9596
+ return new AnalysisProviderAdapter({
9597
+ providerId: "openai-compatible",
9598
+ model: model ?? "unknown",
9599
+ inner
9600
+ });
9601
+ }
9602
+
9603
+ // src/shared/craft/llm/lazy-local-adapter.ts
9604
+ import { OpenAICompatibleAnalysisProvider } from "@harness-engineering/intelligence";
9605
+ import { defaultFetchModels } from "@harness-engineering/orchestrator";
9606
+ var LazyLocalAdapter = class {
9607
+ providerId;
9608
+ model;
9609
+ opts;
9610
+ costs = [];
9611
+ /** Cached resolution. Populated on first probe; subsequent calls reuse. */
9612
+ resolved = null;
9613
+ resolvePromise = null;
9614
+ constructor(opts, providerId = "local") {
9615
+ this.opts = opts;
9616
+ this.providerId = providerId;
9617
+ this.model = opts.configured[0] ?? "unresolved";
9618
+ }
9619
+ async callText(prompt, callOpts) {
9620
+ const { provider } = await this.resolve();
9621
+ return provider.callText(prompt, callOpts);
9622
+ }
9623
+ async callVision(_prompt, _image) {
9624
+ throw new Error(`${this.providerId}: callVision is not wired for local backends.`);
9625
+ }
9626
+ recordCost(cost) {
9627
+ this.costs.push(cost);
9628
+ }
9629
+ getCosts() {
9630
+ return this.costs;
9631
+ }
9632
+ /** Test/debug surface — read the resolved model id (null before first probe). */
9633
+ getResolvedModel() {
9634
+ return this.resolved?.modelId ?? null;
9635
+ }
9636
+ async resolve() {
9637
+ if (this.resolved !== null) return this.resolved;
9638
+ if (this.resolvePromise !== null) return this.resolvePromise;
9639
+ const fetcher = this.opts.fetchModels ?? defaultFetchModels;
9640
+ this.resolvePromise = (async () => {
9641
+ let detected;
9642
+ try {
9643
+ detected = await fetcher(this.opts.endpoint, this.opts.apiKey);
9644
+ } catch (err2) {
9645
+ const message = err2 instanceof Error ? err2.message : String(err2);
9646
+ throw new Error(
9647
+ `${this.providerId}: probe failed against ${this.opts.endpoint}: ${message}. Is the server running? (Ollama: \`ollama serve\`; LM Studio: enable the server.)`,
9648
+ { cause: err2 }
9649
+ );
9650
+ }
9651
+ const match = this.opts.configured.find((id) => detected.includes(id));
9652
+ if (match === void 0) {
9653
+ throw new Error(
9654
+ `${this.providerId}: no configured model is loaded at ${this.opts.endpoint}. Configured: [${this.opts.configured.join(", ")}]. Detected: [${detected.join(", ")}]. Load one of the configured models or update agent.backends.<name>.model.`
9655
+ );
9656
+ }
9657
+ const inner = new OpenAICompatibleAnalysisProvider({
9658
+ apiKey: this.opts.apiKey,
9659
+ baseUrl: this.opts.endpoint,
9660
+ defaultModel: match
9661
+ });
9662
+ const provider = new AnalysisProviderAdapter({
9663
+ providerId: this.providerId,
9664
+ model: match,
9665
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9666
+ inner
9667
+ });
9668
+ const resolved = { provider, modelId: match };
9669
+ this.resolved = resolved;
9670
+ return resolved;
9671
+ })().finally(() => {
9672
+ this.resolvePromise = null;
9673
+ });
9674
+ return this.resolvePromise;
9675
+ }
9676
+ };
9677
+
9678
+ // src/shared/craft/llm/provider.ts
9679
+ import {
9680
+ AnthropicAnalysisProvider,
9681
+ ClaudeCliAnalysisProvider,
9682
+ OpenAICompatibleAnalysisProvider as OpenAICompatibleAnalysisProvider2
9683
+ } from "@harness-engineering/intelligence";
9684
+
9685
+ // src/shared/craft/llm/orchestrator-md.ts
9686
+ import * as fs21 from "fs";
9687
+ import * as path24 from "path";
9688
+ import { parse as parse4 } from "yaml";
9689
+ var FILENAME = "harness.orchestrator.md";
9690
+ function findOrchestratorMd(startDir) {
9691
+ let cur = path24.resolve(startDir);
9692
+ const root = path24.parse(cur).root;
9693
+ while (cur !== root) {
9694
+ const candidate = path24.join(cur, FILENAME);
9695
+ if (fs21.existsSync(candidate)) return candidate;
9696
+ cur = path24.dirname(cur);
9697
+ }
9698
+ return null;
9699
+ }
9700
+ function readBackendsFromOrchestratorMd(startDir) {
9701
+ const file = findOrchestratorMd(startDir);
9702
+ if (file === null) return null;
9703
+ let raw;
9704
+ try {
9705
+ raw = fs21.readFileSync(file, "utf-8");
9706
+ } catch {
9707
+ return null;
9708
+ }
9709
+ const parts = raw.split("---");
9710
+ if (parts.length < 3) return null;
9711
+ const yamlContent = parts[1].trim();
9712
+ let parsed;
9713
+ try {
9714
+ parsed = parse4(yamlContent);
9715
+ } catch {
9716
+ return null;
9717
+ }
9718
+ if (parsed === null || typeof parsed !== "object") return null;
9719
+ const agent = parsed.agent;
9720
+ if (agent === null || typeof agent !== "object") return null;
9721
+ const backends = agent.backends;
9722
+ if (backends === null || typeof backends !== "object") return null;
9723
+ return backends;
9724
+ }
9725
+
9484
9726
  // src/shared/craft/llm/provider.ts
9485
9727
  var MockLlmProvider = class {
9486
9728
  constructor(responses = []) {
@@ -9528,8 +9770,206 @@ var MockLlmProvider = class {
9528
9770
  return this.costs;
9529
9771
  }
9530
9772
  };
9531
- function getProvider(_opts) {
9532
- return new MockLlmProvider();
9773
+ function hasEnvValue(raw) {
9774
+ return raw.length > 0;
9775
+ }
9776
+ function resolveCraftLlmConfig(opts = {}) {
9777
+ const projectRoot = opts.projectRoot ?? process.cwd();
9778
+ const fileConfig = readCraftConfigFromFile(projectRoot);
9779
+ const envRaw = (process.env.HARNESS_CRAFT_LLM ?? "").trim();
9780
+ if (hasEnvValue(envRaw)) {
9781
+ if (envRaw === "in-session" || envRaw === "mock") {
9782
+ return { mode: envRaw };
9783
+ }
9784
+ const def = fileConfig?.backends?.[envRaw];
9785
+ if (def !== void 0 && typeof def === "object" && def !== null) {
9786
+ const backendDef = def;
9787
+ const type = backendDef.type;
9788
+ if (typeof type === "string" && isBackendType(type)) {
9789
+ return { mode: type, backendName: envRaw, backendDef };
9790
+ }
9791
+ }
9792
+ }
9793
+ const backendName = fileConfig?.craft?.backend;
9794
+ if (fileConfig !== null && typeof backendName === "string" && backendName.length > 0) {
9795
+ const def = fileConfig.backends?.[backendName];
9796
+ if (def === void 0 || typeof def !== "object" || def === null) {
9797
+ throw new Error(
9798
+ `craft.llm.backend="${backendName}" references an entry that is missing from agent.backends.`
9799
+ );
9800
+ }
9801
+ const backendDef = def;
9802
+ const type = backendDef.type;
9803
+ if (typeof type !== "string" || !isBackendType(type)) {
9804
+ throw new Error(
9805
+ `agent.backends["${backendName}"] has unsupported type "${String(type)}" for craft skills.`
9806
+ );
9807
+ }
9808
+ return { mode: type, backendName, backendDef };
9809
+ }
9810
+ const mode2 = fileConfig?.craft?.mode;
9811
+ if (mode2 === "in-session" || mode2 === "mock") return { mode: mode2 };
9812
+ return { mode: "in-session" };
9813
+ }
9814
+ function resolveCraftLlmMode(envValue) {
9815
+ if (envValue !== void 0) {
9816
+ const trimmed = envValue.trim();
9817
+ if (trimmed === "in-session" || trimmed === "mock") return trimmed;
9818
+ }
9819
+ return resolveCraftLlmConfig().mode;
9820
+ }
9821
+ var BACKEND_TYPES = ["claude", "anthropic", "openai", "gemini", "local", "pi", "mock"];
9822
+ function isBackendType(t) {
9823
+ return BACKEND_TYPES.includes(t);
9824
+ }
9825
+ function readJsonCraftView(startDir) {
9826
+ const view = {};
9827
+ const found = findConfigFile(startDir);
9828
+ if (!found.ok) return view;
9829
+ const loaded = loadConfig(found.value);
9830
+ if (!loaded.ok) return view;
9831
+ const craft = loaded.value.craft?.llm;
9832
+ if (craft !== void 0) {
9833
+ view.craft = {};
9834
+ if (craft.backend !== void 0) view.craft.backend = craft.backend;
9835
+ if (craft.mode !== void 0) view.craft.mode = craft.mode;
9836
+ }
9837
+ const backends = loaded.value.agent?.backends;
9838
+ if (backends !== void 0) view.backends = backends;
9839
+ return view;
9840
+ }
9841
+ function readCraftConfigFromFile(startDir) {
9842
+ const view = readJsonCraftView(startDir);
9843
+ if (view.backends === void 0) {
9844
+ const fromMd = readBackendsFromOrchestratorMd(startDir);
9845
+ if (fromMd !== null) {
9846
+ view.backends = fromMd;
9847
+ view.backendsFromOrchestratorMd = true;
9848
+ warnOrchestratorMdFallback();
9849
+ }
9850
+ }
9851
+ return view.craft !== void 0 || view.backends !== void 0 ? view : null;
9852
+ }
9853
+ var warnedOrchestratorMd = false;
9854
+ function warnOrchestratorMdFallback() {
9855
+ if (warnedOrchestratorMd) return;
9856
+ warnedOrchestratorMd = true;
9857
+ if (process.env.HARNESS_SUPPRESS_BACKEND_MIGRATION_WARNING) return;
9858
+ console.warn(
9859
+ "[craft] agent.backends read from harness.orchestrator.md. Run `harness migrate backends` to copy them into harness.config.json (single source of truth). Suppress with HARNESS_SUPPRESS_BACKEND_MIGRATION_WARNING=1."
9860
+ );
9861
+ }
9862
+ function getProvider(opts) {
9863
+ if (opts?.mode === "in-session") return new InSessionLlmProvider();
9864
+ if (opts?.mode === "mock") return new MockLlmProvider();
9865
+ const resolved = resolveCraftLlmConfig(
9866
+ opts?.projectRoot !== void 0 ? { projectRoot: opts.projectRoot } : {}
9867
+ );
9868
+ return providerForResolution(resolved);
9869
+ }
9870
+ function providerForResolution(resolved) {
9871
+ switch (resolved.mode) {
9872
+ case "in-session":
9873
+ return new InSessionLlmProvider();
9874
+ case "mock":
9875
+ return new MockLlmProvider();
9876
+ case "claude":
9877
+ return buildClaudeProvider(resolved);
9878
+ case "anthropic":
9879
+ return buildAnthropicProvider(resolved);
9880
+ case "openai":
9881
+ case "local":
9882
+ case "pi":
9883
+ return buildOpenAICompatibleProvider(resolved);
9884
+ case "gemini":
9885
+ throw new Error(
9886
+ `agent.backends["${resolved.backendName}"]: 'gemini' backend is not yet wired into the craft adapter.`
9887
+ );
9888
+ }
9889
+ }
9890
+ function buildClaudeProvider(resolved) {
9891
+ const def = resolved.backendDef ?? {};
9892
+ const command = stringField(def, "command");
9893
+ return adaptClaudeCli(new ClaudeCliAnalysisProvider(command !== void 0 ? { command } : {}));
9894
+ }
9895
+ function buildAnthropicProvider(resolved) {
9896
+ const def = resolved.backendDef ?? {};
9897
+ const model = stringField(def, "model");
9898
+ if (model === void 0) {
9899
+ throw new Error(
9900
+ `agent.backends["${resolved.backendName}"]: 'anthropic' backend requires a 'model'.`
9901
+ );
9902
+ }
9903
+ const apiKey = stringField(def, "apiKey") ?? process.env.ANTHROPIC_API_KEY;
9904
+ if (!apiKey) {
9905
+ throw new Error(
9906
+ `agent.backends["${resolved.backendName}"]: 'anthropic' backend requires apiKey or ANTHROPIC_API_KEY.`
9907
+ );
9908
+ }
9909
+ return adaptAnthropic(new AnthropicAnalysisProvider({ apiKey, defaultModel: model }), model);
9910
+ }
9911
+ function pickConfiguredModels(modelField) {
9912
+ if (typeof modelField === "string") return [modelField];
9913
+ if (Array.isArray(modelField)) {
9914
+ return modelField.filter((m) => typeof m === "string");
9915
+ }
9916
+ return [];
9917
+ }
9918
+ function resolveOpenAICompatibleEndpoint(resolved) {
9919
+ const def = resolved.backendDef ?? {};
9920
+ const fallback = resolved.mode === "openai" ? "https://api.openai.com/v1" : void 0;
9921
+ const endpoint = stringField(def, "endpoint") ?? fallback;
9922
+ if (endpoint === void 0) {
9923
+ throw new Error(
9924
+ `agent.backends["${resolved.backendName}"]: '${resolved.mode}' backend requires 'endpoint'.`
9925
+ );
9926
+ }
9927
+ return endpoint;
9928
+ }
9929
+ function resolveOpenAICompatibleApiKey(resolved) {
9930
+ const def = resolved.backendDef ?? {};
9931
+ const fallback = resolved.mode === "openai" ? void 0 : "local";
9932
+ const apiKey = stringField(def, "apiKey") ?? process.env.OPENAI_API_KEY ?? fallback;
9933
+ if (!apiKey) {
9934
+ throw new Error(
9935
+ `agent.backends["${resolved.backendName}"]: 'openai' backend requires apiKey or OPENAI_API_KEY.`
9936
+ );
9937
+ }
9938
+ return apiKey;
9939
+ }
9940
+ function resolveOpenAICompatibleInputs(resolved) {
9941
+ const configured = pickConfiguredModels(resolved.backendDef?.model);
9942
+ if (configured.length === 0) {
9943
+ throw new Error(
9944
+ `agent.backends["${resolved.backendName}"]: '${resolved.mode}' backend requires 'model' (string or non-empty array of strings).`
9945
+ );
9946
+ }
9947
+ return {
9948
+ endpoint: resolveOpenAICompatibleEndpoint(resolved),
9949
+ apiKey: resolveOpenAICompatibleApiKey(resolved),
9950
+ configured
9951
+ };
9952
+ }
9953
+ function buildOpenAICompatibleProvider(resolved) {
9954
+ const { endpoint, apiKey, configured } = resolveOpenAICompatibleInputs(resolved);
9955
+ if (configured.length === 1) {
9956
+ return adaptOpenAICompatible(
9957
+ new OpenAICompatibleAnalysisProvider2({
9958
+ apiKey,
9959
+ baseUrl: endpoint,
9960
+ defaultModel: configured[0]
9961
+ }),
9962
+ configured[0]
9963
+ );
9964
+ }
9965
+ return new LazyLocalAdapter(
9966
+ { endpoint, apiKey, configured },
9967
+ resolved.mode === "pi" ? "pi" : "local"
9968
+ );
9969
+ }
9970
+ function stringField(obj, key) {
9971
+ const v = obj[key];
9972
+ return typeof v === "string" ? v : void 0;
9533
9973
  }
9534
9974
 
9535
9975
  // src/mcp/tools/design-craft.ts
@@ -9657,18 +10097,18 @@ async function handleDesignCraft(input) {
9657
10097
  }
9658
10098
 
9659
10099
  // src/drift/index.ts
9660
- import * as fs23 from "fs";
9661
- import * as path26 from "path";
10100
+ import * as fs24 from "fs";
10101
+ import * as path27 from "path";
9662
10102
 
9663
10103
  // src/drift/resolvers/tokens.ts
9664
- import * as fs21 from "fs";
9665
- import * as path24 from "path";
10104
+ import * as fs22 from "fs";
10105
+ import * as path25 from "path";
9666
10106
  function loadTokenSet(projectRoot) {
9667
- const tokenPath = path24.join(projectRoot, "design-system", "tokens.json");
9668
- if (!fs21.existsSync(tokenPath)) return null;
10107
+ const tokenPath = path25.join(projectRoot, "design-system", "tokens.json");
10108
+ if (!fs22.existsSync(tokenPath)) return null;
9669
10109
  let raw;
9670
10110
  try {
9671
- raw = fs21.readFileSync(tokenPath, "utf-8");
10111
+ raw = fs22.readFileSync(tokenPath, "utf-8");
9672
10112
  } catch {
9673
10113
  return null;
9674
10114
  }
@@ -9692,11 +10132,11 @@ function extractTokens(root) {
9692
10132
  return set;
9693
10133
  }
9694
10134
  function loadTokenPathIndex(projectRoot) {
9695
- const tokenPath = path24.join(projectRoot, "design-system", "tokens.json");
9696
- if (!fs21.existsSync(tokenPath)) return null;
10135
+ const tokenPath = path25.join(projectRoot, "design-system", "tokens.json");
10136
+ if (!fs22.existsSync(tokenPath)) return null;
9697
10137
  let raw;
9698
10138
  try {
9699
- raw = fs21.readFileSync(tokenPath, "utf-8");
10139
+ raw = fs22.readFileSync(tokenPath, "utf-8");
9700
10140
  } catch {
9701
10141
  return null;
9702
10142
  }
@@ -9746,9 +10186,9 @@ function walkForPaths(node, breadcrumb, idx) {
9746
10186
  }
9747
10187
  }
9748
10188
  }
9749
- function pushPath(map, key, path45) {
10189
+ function pushPath(map, key, path47) {
9750
10190
  const list = map.get(key) ?? [];
9751
- list.push(path45);
10191
+ list.push(path47);
9752
10192
  map.set(key, list);
9753
10193
  }
9754
10194
  function walk(node, breadcrumb, set) {
@@ -9795,8 +10235,8 @@ function parsePxValue(s) {
9795
10235
  }
9796
10236
 
9797
10237
  // src/drift/resolvers/component-registry.ts
9798
- import * as fs22 from "fs";
9799
- import * as path25 from "path";
10238
+ import * as fs23 from "fs";
10239
+ import * as path26 from "path";
9800
10240
  var HTML_PRIMITIVE_MAP = {
9801
10241
  Button: "button",
9802
10242
  Input: "input",
@@ -9805,11 +10245,11 @@ var HTML_PRIMITIVE_MAP = {
9805
10245
  Anchor: "a"
9806
10246
  };
9807
10247
  function loadComponentRegistry(projectRoot) {
9808
- const designMdPath = path25.join(projectRoot, "design-system", "DESIGN.md");
9809
- if (!fs22.existsSync(designMdPath)) return null;
10248
+ const designMdPath = path26.join(projectRoot, "design-system", "DESIGN.md");
10249
+ if (!fs23.existsSync(designMdPath)) return null;
9810
10250
  let raw;
9811
10251
  try {
9812
- raw = fs22.readFileSync(designMdPath, "utf-8");
10252
+ raw = fs23.readFileSync(designMdPath, "utf-8");
9813
10253
  } catch {
9814
10254
  return null;
9815
10255
  }
@@ -10107,7 +10547,7 @@ async function runDetectDrift(input) {
10107
10547
  for (const file of filesToScan) {
10108
10548
  let source;
10109
10549
  try {
10110
- source = fs23.readFileSync(file, "utf-8");
10550
+ source = fs24.readFileSync(file, "utf-8");
10111
10551
  } catch {
10112
10552
  continue;
10113
10553
  }
@@ -10142,7 +10582,7 @@ async function runDetectDrift(input) {
10142
10582
  }
10143
10583
  async function collectFiles(projectRoot, explicitFiles) {
10144
10584
  if (explicitFiles !== void 0 && explicitFiles.length > 0) {
10145
- return explicitFiles.map((f) => path26.isAbsolute(f) ? f : path26.join(projectRoot, f));
10585
+ return explicitFiles.map((f) => path27.isAbsolute(f) ? f : path27.join(projectRoot, f));
10146
10586
  }
10147
10587
  const out = [];
10148
10588
  walk2(projectRoot, out, 0);
@@ -10152,7 +10592,7 @@ function walk2(dir, out, depth) {
10152
10592
  if (depth > 8) return;
10153
10593
  let entries;
10154
10594
  try {
10155
- entries = fs23.readdirSync(dir, { withFileTypes: true });
10595
+ entries = fs24.readdirSync(dir, { withFileTypes: true });
10156
10596
  } catch {
10157
10597
  return;
10158
10598
  }
@@ -10160,7 +10600,7 @@ function walk2(dir, out, depth) {
10160
10600
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
10161
10601
  continue;
10162
10602
  }
10163
- const full = path26.join(dir, entry.name);
10603
+ const full = path27.join(dir, entry.name);
10164
10604
  if (entry.isDirectory()) {
10165
10605
  walk2(full, out, depth + 1);
10166
10606
  } else if (entry.isFile() && DEFAULT_GLOB_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
@@ -10228,8 +10668,8 @@ async function handleDetectDrift(input) {
10228
10668
  }
10229
10669
 
10230
10670
  // src/align/index.ts
10231
- import * as fs24 from "fs";
10232
- import * as path28 from "path";
10671
+ import * as fs25 from "fs";
10672
+ import * as path29 from "path";
10233
10673
 
10234
10674
  // src/align/classifier/token-import.ts
10235
10675
  var NAMED_IMPORT = /^\s*import\s*\{\s*tokens(?:\s+as\s+\w+)?\s*\}\s*from\s+['"][^'"]+['"];?\s*$/m;
@@ -10369,9 +10809,9 @@ function sourceLine(source, line) {
10369
10809
  }
10370
10810
 
10371
10811
  // src/align/codemods/common.ts
10372
- import * as path27 from "path";
10812
+ import * as path28 from "path";
10373
10813
  function renderTokenReference(file, tokenPath) {
10374
- const ext = path27.extname(file).toLowerCase();
10814
+ const ext = path28.extname(file).toLowerCase();
10375
10815
  if (ext === ".css" || ext === ".scss") {
10376
10816
  return `var(--${tokenPath.replace(/\./g, "-")})`;
10377
10817
  }
@@ -10563,10 +11003,10 @@ async function runAlignDesignSystem(input) {
10563
11003
  }
10564
11004
  async function loadFindings(projectRoot, input, mode2) {
10565
11005
  if (mode2 === "pipeline") {
10566
- const handoffPath = path28.join(projectRoot, HANDOFF_PATH);
10567
- if (!fs24.existsSync(handoffPath)) return [];
11006
+ const handoffPath = path29.join(projectRoot, HANDOFF_PATH);
11007
+ if (!fs25.existsSync(handoffPath)) return [];
10568
11008
  try {
10569
- const raw = fs24.readFileSync(handoffPath, "utf-8");
11009
+ const raw = fs25.readFileSync(handoffPath, "utf-8");
10570
11010
  const parsed = JSON.parse(raw);
10571
11011
  return parsed.pipeline?.driftFindings ?? [];
10572
11012
  } catch {
@@ -10591,7 +11031,7 @@ async function processFinding(finding, tokenPaths, sourceCache, dryRun) {
10591
11031
  }
10592
11032
  let source;
10593
11033
  try {
10594
- source = sourceCache.get(finding.file) ?? fs24.readFileSync(finding.file, "utf-8");
11034
+ source = sourceCache.get(finding.file) ?? fs25.readFileSync(finding.file, "utf-8");
10595
11035
  sourceCache.set(finding.file, source);
10596
11036
  } catch (err2) {
10597
11037
  return {
@@ -10619,7 +11059,7 @@ async function processFinding(finding, tokenPaths, sourceCache, dryRun) {
10619
11059
  }
10620
11060
  if (!dryRun) {
10621
11061
  try {
10622
- fs24.writeFileSync(finding.file, result.newSource, "utf-8");
11062
+ fs25.writeFileSync(finding.file, result.newSource, "utf-8");
10623
11063
  sourceCache.set(finding.file, result.newSource);
10624
11064
  } catch (err2) {
10625
11065
  return {
@@ -10680,19 +11120,19 @@ function aggregateOutput(outcomes, meta) {
10680
11120
  };
10681
11121
  }
10682
11122
  function writePipelineFixesApplied(projectRoot, outcomes) {
10683
- const handoffPath = path28.join(projectRoot, HANDOFF_PATH);
11123
+ const handoffPath = path29.join(projectRoot, HANDOFF_PATH);
10684
11124
  let handoff = {};
10685
- if (fs24.existsSync(handoffPath)) {
11125
+ if (fs25.existsSync(handoffPath)) {
10686
11126
  try {
10687
- handoff = JSON.parse(fs24.readFileSync(handoffPath, "utf-8"));
11127
+ handoff = JSON.parse(fs25.readFileSync(handoffPath, "utf-8"));
10688
11128
  } catch {
10689
11129
  handoff = {};
10690
11130
  }
10691
11131
  }
10692
11132
  handoff.pipeline = handoff.pipeline ?? {};
10693
11133
  handoff.pipeline.fixesApplied = outcomes;
10694
- fs24.mkdirSync(path28.dirname(handoffPath), { recursive: true });
10695
- fs24.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2) + "\n", "utf-8");
11134
+ fs25.mkdirSync(path29.dirname(handoffPath), { recursive: true });
11135
+ fs25.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2) + "\n", "utf-8");
10696
11136
  }
10697
11137
  function findingKey(finding) {
10698
11138
  return `${finding.code}@${finding.file}:${finding.line ?? "?"}`;
@@ -10764,18 +11204,18 @@ async function handleAlignDesignSystem(input) {
10764
11204
  }
10765
11205
 
10766
11206
  // src/brand/index.ts
10767
- import * as fs27 from "fs";
10768
- import * as path31 from "path";
11207
+ import * as fs28 from "fs";
11208
+ import * as path32 from "path";
10769
11209
 
10770
11210
  // src/brand/resolvers/design-md-brand.ts
10771
- import * as fs25 from "fs";
10772
- import * as path29 from "path";
11211
+ import * as fs26 from "fs";
11212
+ import * as path30 from "path";
10773
11213
  function loadBrandRules(projectRoot) {
10774
- const designMdPath = path29.join(projectRoot, "design-system", "DESIGN.md");
10775
- if (!fs25.existsSync(designMdPath)) return null;
11214
+ const designMdPath = path30.join(projectRoot, "design-system", "DESIGN.md");
11215
+ if (!fs26.existsSync(designMdPath)) return null;
10776
11216
  let raw;
10777
11217
  try {
10778
- raw = fs25.readFileSync(designMdPath, "utf-8");
11218
+ raw = fs26.readFileSync(designMdPath, "utf-8");
10779
11219
  } catch {
10780
11220
  return null;
10781
11221
  }
@@ -10886,14 +11326,14 @@ function parseAssets(block) {
10886
11326
  }
10887
11327
 
10888
11328
  // src/brand/resolvers/token-extensions.ts
10889
- import * as fs26 from "fs";
10890
- import * as path30 from "path";
11329
+ import * as fs27 from "fs";
11330
+ import * as path31 from "path";
10891
11331
  function loadBrandTokenIndex(projectRoot) {
10892
- const tokenPath = path30.join(projectRoot, "design-system", "tokens.json");
10893
- if (!fs26.existsSync(tokenPath)) return null;
11332
+ const tokenPath = path31.join(projectRoot, "design-system", "tokens.json");
11333
+ if (!fs27.existsSync(tokenPath)) return null;
10894
11334
  let raw;
10895
11335
  try {
10896
- raw = fs26.readFileSync(tokenPath, "utf-8");
11336
+ raw = fs27.readFileSync(tokenPath, "utf-8");
10897
11337
  } catch {
10898
11338
  return null;
10899
11339
  }
@@ -11142,7 +11582,7 @@ async function runAuditBrand(input) {
11142
11582
  for (const file of filesToScan) {
11143
11583
  let source;
11144
11584
  try {
11145
- source = fs27.readFileSync(file, "utf-8");
11585
+ source = fs28.readFileSync(file, "utf-8");
11146
11586
  } catch {
11147
11587
  continue;
11148
11588
  }
@@ -11184,7 +11624,7 @@ async function runAuditBrand(input) {
11184
11624
  }
11185
11625
  function collectFiles2(projectRoot, explicitFiles) {
11186
11626
  if (explicitFiles !== void 0 && explicitFiles.length > 0) {
11187
- return explicitFiles.map((f) => path31.isAbsolute(f) ? f : path31.join(projectRoot, f));
11627
+ return explicitFiles.map((f) => path32.isAbsolute(f) ? f : path32.join(projectRoot, f));
11188
11628
  }
11189
11629
  const out = [];
11190
11630
  walk4(projectRoot, out, 0);
@@ -11194,7 +11634,7 @@ function walk4(dir, out, depth) {
11194
11634
  if (depth > 8) return;
11195
11635
  let entries;
11196
11636
  try {
11197
- entries = fs27.readdirSync(dir, { withFileTypes: true });
11637
+ entries = fs28.readdirSync(dir, { withFileTypes: true });
11198
11638
  } catch {
11199
11639
  return;
11200
11640
  }
@@ -11202,7 +11642,7 @@ function walk4(dir, out, depth) {
11202
11642
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
11203
11643
  continue;
11204
11644
  }
11205
- const full = path31.join(dir, entry.name);
11645
+ const full = path32.join(dir, entry.name);
11206
11646
  if (entry.isDirectory()) {
11207
11647
  walk4(full, out, depth + 1);
11208
11648
  } else if (entry.isFile() && DEFAULT_GLOB_EXTENSIONS2.some((ext) => entry.name.endsWith(ext))) {
@@ -11320,15 +11760,15 @@ var VerifierRegistry = class {
11320
11760
  };
11321
11761
 
11322
11762
  // src/design-pipeline/phases/freshen.ts
11323
- import * as fs28 from "fs";
11324
- import * as path32 from "path";
11763
+ import * as fs29 from "fs";
11764
+ import * as path33 from "path";
11325
11765
  function runFreshen(input) {
11326
11766
  const { projectRoot, context } = input;
11327
- context.graphAvailable = fs28.existsSync(path32.join(projectRoot, ".harness", "graph"));
11328
- const designMdPath = path32.join(projectRoot, "design-system", "DESIGN.md");
11329
- const tokensJsonPath = path32.join(projectRoot, "design-system", "tokens.json");
11330
- context.inputs.designMdExists = fs28.existsSync(designMdPath);
11331
- context.inputs.tokensJsonExists = fs28.existsSync(tokensJsonPath);
11767
+ context.graphAvailable = fs29.existsSync(path33.join(projectRoot, ".harness", "graph"));
11768
+ const designMdPath = path33.join(projectRoot, "design-system", "DESIGN.md");
11769
+ const tokensJsonPath = path33.join(projectRoot, "design-system", "tokens.json");
11770
+ context.inputs.designMdExists = fs29.existsSync(designMdPath);
11771
+ context.inputs.tokensJsonExists = fs29.existsSync(tokensJsonPath);
11332
11772
  if (context.inputs.designMdExists) {
11333
11773
  const content = readFileSafe(designMdPath);
11334
11774
  context.inputs.componentRegistryExists = content !== null && /^##\s+component\s+registry\b/im.test(content);
@@ -11337,7 +11777,7 @@ function runFreshen(input) {
11337
11777
  }
11338
11778
  function readFileSafe(p) {
11339
11779
  try {
11340
- return fs28.readFileSync(p, "utf-8");
11780
+ return fs29.readFileSync(p, "utf-8");
11341
11781
  } catch {
11342
11782
  return null;
11343
11783
  }
@@ -11364,8 +11804,8 @@ async function runDetect(input) {
11364
11804
  }
11365
11805
 
11366
11806
  // src/design-pipeline/phases/fix.ts
11367
- import * as fs29 from "fs";
11368
- import * as path33 from "path";
11807
+ import * as fs30 from "fs";
11808
+ import * as path34 from "path";
11369
11809
  var MAX_ITERATIONS = 5;
11370
11810
  async function runFix(input) {
11371
11811
  const { projectRoot, context, mode: mode2, files, designStrictness } = input;
@@ -11414,11 +11854,11 @@ async function safelyRedetect(projectRoot, mode2, files, designStrictness) {
11414
11854
  }
11415
11855
  }
11416
11856
  function writePipelineHandoff(projectRoot, context) {
11417
- const handoffPath = path33.join(projectRoot, ".harness", "handoff.json");
11857
+ const handoffPath = path34.join(projectRoot, ".harness", "handoff.json");
11418
11858
  let handoff = {};
11419
- if (fs29.existsSync(handoffPath)) {
11859
+ if (fs30.existsSync(handoffPath)) {
11420
11860
  try {
11421
- handoff = JSON.parse(fs29.readFileSync(handoffPath, "utf-8"));
11861
+ handoff = JSON.parse(fs30.readFileSync(handoffPath, "utf-8"));
11422
11862
  } catch {
11423
11863
  handoff = {};
11424
11864
  }
@@ -11426,8 +11866,8 @@ function writePipelineHandoff(projectRoot, context) {
11426
11866
  handoff.pipeline = {
11427
11867
  driftFindings: context.driftFindings
11428
11868
  };
11429
- fs29.mkdirSync(path33.dirname(handoffPath), { recursive: true });
11430
- fs29.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2) + "\n");
11869
+ fs30.mkdirSync(path34.dirname(handoffPath), { recursive: true });
11870
+ fs30.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2) + "\n");
11431
11871
  }
11432
11872
 
11433
11873
  // src/design-pipeline/phases/audit.ts
@@ -11457,8 +11897,8 @@ async function runAudit2(input) {
11457
11897
  }
11458
11898
 
11459
11899
  // src/design-pipeline/phases/fill.ts
11460
- import * as fs30 from "fs";
11461
- import * as path34 from "path";
11900
+ import * as fs31 from "fs";
11901
+ import * as path35 from "path";
11462
11902
  var DESIGN_MD_STUB = `# Design System
11463
11903
 
11464
11904
  <!-- TODO: author this file. See harness-design skill for guidance. -->
@@ -11518,11 +11958,11 @@ async function runFill(input) {
11518
11958
  }
11519
11959
  function bootstrapMissingInputs(input) {
11520
11960
  const { projectRoot, context } = input;
11521
- const designMdPath = path34.join(projectRoot, "design-system", "DESIGN.md");
11522
- const tokensJsonPath = path34.join(projectRoot, "design-system", "tokens.json");
11523
- if (!fs30.existsSync(designMdPath)) {
11524
- fs30.mkdirSync(path34.dirname(designMdPath), { recursive: true });
11525
- fs30.writeFileSync(designMdPath, DESIGN_MD_STUB);
11961
+ const designMdPath = path35.join(projectRoot, "design-system", "DESIGN.md");
11962
+ const tokensJsonPath = path35.join(projectRoot, "design-system", "tokens.json");
11963
+ if (!fs31.existsSync(designMdPath)) {
11964
+ fs31.mkdirSync(path35.dirname(designMdPath), { recursive: true });
11965
+ fs31.writeFileSync(designMdPath, DESIGN_MD_STUB);
11526
11966
  context.bootstrapped.designMd = true;
11527
11967
  context.inputs.designMdExists = true;
11528
11968
  context.inputs.componentRegistryExists = true;
@@ -11542,16 +11982,16 @@ function bootstrapMissingInputs(input) {
11542
11982
  }
11543
11983
  }
11544
11984
  }
11545
- if (!fs30.existsSync(tokensJsonPath)) {
11546
- fs30.mkdirSync(path34.dirname(tokensJsonPath), { recursive: true });
11547
- fs30.writeFileSync(tokensJsonPath, TOKENS_JSON_STUB);
11985
+ if (!fs31.existsSync(tokensJsonPath)) {
11986
+ fs31.mkdirSync(path35.dirname(tokensJsonPath), { recursive: true });
11987
+ fs31.writeFileSync(tokensJsonPath, TOKENS_JSON_STUB);
11548
11988
  context.bootstrapped.tokensJson = true;
11549
11989
  context.inputs.tokensJsonExists = true;
11550
11990
  }
11551
11991
  }
11552
11992
  function readFileSafe2(p) {
11553
11993
  try {
11554
- return fs30.readFileSync(p, "utf-8");
11994
+ return fs31.readFileSync(p, "utf-8");
11555
11995
  } catch {
11556
11996
  return null;
11557
11997
  }
@@ -11586,10 +12026,10 @@ async function invokeCraftPolish(input) {
11586
12026
  function appendToFile(p, content) {
11587
12027
  let existing = "";
11588
12028
  try {
11589
- existing = fs30.readFileSync(p, "utf-8");
12029
+ existing = fs31.readFileSync(p, "utf-8");
11590
12030
  } catch {
11591
12031
  }
11592
- fs30.writeFileSync(p, existing + content);
12032
+ fs31.writeFileSync(p, existing + content);
11593
12033
  }
11594
12034
 
11595
12035
  // src/design-pipeline/phases/report.ts
@@ -11738,8 +12178,8 @@ async function handleDesignPipeline(input) {
11738
12178
  }
11739
12179
 
11740
12180
  // src/naming-craft/index.ts
11741
- import * as fs31 from "fs";
11742
- import * as path35 from "path";
12181
+ import * as fs33 from "fs";
12182
+ import * as path37 from "path";
11743
12183
  import { randomUUID as randomUUID3 } from "crypto";
11744
12184
 
11745
12185
  // src/naming-craft/extract/identifiers.ts
@@ -11971,12 +12411,14 @@ var SEED_RUBRICS = [
11971
12411
  ];
11972
12412
 
11973
12413
  // src/naming-craft/phases/critique.ts
12414
+ var CRITIQUE_SYSTEM_PROMPT = "You are a senior engineer critiquing identifier names against a single naming rubric. Respond ONLY with a fenced JSON block. If the rubric does not apply or the name is fine, return `null` (literally the word null inside the JSON block).";
11974
12415
  async function critiqueOne(input) {
11975
12416
  const { identifier, rubric, provider } = input;
11976
12417
  const prompt = buildPrompt(input);
11977
- const raw = await provider.callText(prompt, {
11978
- systemPrompt: "You are a senior engineer critiquing identifier names against a single naming rubric. Respond ONLY with a fenced JSON block. If the rubric does not apply or the name is fine, return `null` (literally the word null inside the JSON block)."
11979
- });
12418
+ const raw = await provider.callText(prompt, { systemPrompt: CRITIQUE_SYSTEM_PROMPT });
12419
+ return parseFindingFromRaw(raw, { identifier, rubric });
12420
+ }
12421
+ function parseFindingFromRaw(raw, ctx) {
11980
12422
  const parsed = parseFencedJson(raw);
11981
12423
  if (parsed === null) return null;
11982
12424
  if (typeof parsed !== "object") return null;
@@ -11985,23 +12427,22 @@ async function critiqueOne(input) {
11985
12427
  const confidence = parsed.confidence;
11986
12428
  if (!isTier2(tier) || !isImpact2(impact) || !isConfidence2(confidence)) return null;
11987
12429
  if (typeof parsed.message !== "string" || parsed.message.length === 0) return null;
11988
- const finding = {
11989
- code: rubric.id,
12430
+ return {
12431
+ code: ctx.rubric.id,
11990
12432
  phase: "critique",
11991
12433
  tier,
11992
12434
  impact,
11993
12435
  confidence,
11994
12436
  target: {
11995
- file: identifier.file,
11996
- line: identifier.line,
11997
- identifier: identifier.name,
11998
- kind: identifier.kind
12437
+ file: ctx.identifier.file,
12438
+ line: ctx.identifier.line,
12439
+ identifier: ctx.identifier.name,
12440
+ kind: ctx.identifier.kind
11999
12441
  },
12000
12442
  message: parsed.message,
12001
- cite: { rubricId: rubric.id, source: rubric.source },
12443
+ cite: { rubricId: ctx.rubric.id, source: ctx.rubric.source },
12002
12444
  derived: { priority: derivePriority(tier, impact, confidence) }
12003
12445
  };
12004
- return finding;
12005
12446
  }
12006
12447
  function buildPrompt(input) {
12007
12448
  const { identifier, rubric, convention } = input;
@@ -12061,23 +12502,74 @@ function isConfidence2(v) {
12061
12502
  return v === "high" || v === "medium" || v === "low";
12062
12503
  }
12063
12504
 
12505
+ // src/shared/craft/runs/store.ts
12506
+ import * as fs32 from "fs";
12507
+ import * as path36 from "path";
12508
+ var RUN_TTL_MS = 24 * 60 * 60 * 1e3;
12509
+ function runsDir(projectRoot) {
12510
+ return path36.join(projectRoot, ".harness", "craft", "runs");
12511
+ }
12512
+ function runPath(projectRoot, runId) {
12513
+ return path36.join(runsDir(projectRoot), `${runId}.json`);
12514
+ }
12515
+ function saveRunState(projectRoot, state) {
12516
+ const dir = runsDir(projectRoot);
12517
+ fs32.mkdirSync(dir, { recursive: true });
12518
+ const file = runPath(projectRoot, state.runId);
12519
+ fs32.writeFileSync(file, JSON.stringify(state, null, 2));
12520
+ return { runFile: file };
12521
+ }
12522
+ function loadRunState(projectRoot, runId) {
12523
+ const file = runPath(projectRoot, runId);
12524
+ if (!fs32.existsSync(file)) return null;
12525
+ try {
12526
+ const raw = fs32.readFileSync(file, "utf-8");
12527
+ return JSON.parse(raw);
12528
+ } catch {
12529
+ return null;
12530
+ }
12531
+ }
12532
+ function deleteRunState(projectRoot, runId) {
12533
+ const file = runPath(projectRoot, runId);
12534
+ try {
12535
+ fs32.unlinkSync(file);
12536
+ } catch {
12537
+ }
12538
+ }
12539
+ function pruneOldRuns(projectRoot, now = Date.now()) {
12540
+ const dir = runsDir(projectRoot);
12541
+ let entries;
12542
+ try {
12543
+ entries = fs32.readdirSync(dir, { withFileTypes: true });
12544
+ } catch {
12545
+ return;
12546
+ }
12547
+ for (const entry of entries) {
12548
+ if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
12549
+ const full = path36.join(dir, entry.name);
12550
+ try {
12551
+ const stat = fs32.statSync(full);
12552
+ if (now - stat.mtimeMs > RUN_TTL_MS) fs32.unlinkSync(full);
12553
+ } catch {
12554
+ }
12555
+ }
12556
+ }
12557
+
12064
12558
  // src/naming-craft/index.ts
12559
+ var DEFAULT_PROMPT_BUDGET = 100;
12065
12560
  var DEFAULT_MAX_FILES = 100;
12066
12561
  var DEFAULT_MAX_IDENTIFIERS_PER_FILE = 15;
12067
12562
  var EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"];
12068
- async function runNamingCraft(input) {
12069
- const startedAt = Date.now();
12563
+ function gatherProjectContext(input) {
12070
12564
  const projectRoot = sanitizePath(input.path);
12071
12565
  const maxFiles = input.maxFiles ?? DEFAULT_MAX_FILES;
12072
- const maxIdentifiersPerFile = input.maxIdentifiersPerFile ?? DEFAULT_MAX_IDENTIFIERS_PER_FILE;
12073
- const provider = input.__testProvider ?? getProvider();
12074
12566
  const files = collectFiles3(projectRoot, input.files).slice(0, maxFiles);
12075
12567
  const allIdentifiers = [];
12076
12568
  const perFile = /* @__PURE__ */ new Map();
12077
12569
  for (const file of files) {
12078
12570
  let source;
12079
12571
  try {
12080
- source = fs31.readFileSync(file, "utf-8");
12572
+ source = fs33.readFileSync(file, "utf-8");
12081
12573
  } catch {
12082
12574
  continue;
12083
12575
  }
@@ -12086,6 +12578,18 @@ async function runNamingCraft(input) {
12086
12578
  allIdentifiers.push(...ids);
12087
12579
  }
12088
12580
  const convention = sampleConventions(allIdentifiers, files);
12581
+ return { projectRoot, files, perFile, convention };
12582
+ }
12583
+ async function runNamingCraft(input) {
12584
+ const startedAt = Date.now();
12585
+ const maxIdentifiersPerFile = input.maxIdentifiersPerFile ?? DEFAULT_MAX_IDENTIFIERS_PER_FILE;
12586
+ const provider = input.__testProvider ?? getProvider();
12587
+ if (provider instanceof InSessionLlmProvider) {
12588
+ throw new Error(
12589
+ "runNamingCraft is the inline entry point; the in-session provider requires the two-step flow. Call collectNamingCraftPrompts(...) and then finalizeNamingCraft(...), or set HARNESS_CRAFT_LLM=mock for tests."
12590
+ );
12591
+ }
12592
+ const { perFile, convention } = gatherProjectContext(input);
12089
12593
  const rubrics = SEED_RUBRICS;
12090
12594
  const findings = [];
12091
12595
  for (const [, identifiers] of perFile) {
@@ -12120,9 +12624,109 @@ async function runNamingCraft(input) {
12120
12624
  }
12121
12625
  };
12122
12626
  }
12627
+ async function collectNamingCraftPrompts(input) {
12628
+ const maxIdentifiersPerFile = input.maxIdentifiersPerFile ?? DEFAULT_MAX_IDENTIFIERS_PER_FILE;
12629
+ const budget = input.promptBudget ?? DEFAULT_PROMPT_BUDGET;
12630
+ const { projectRoot, perFile, convention } = gatherProjectContext(input);
12631
+ const rubrics = SEED_RUBRICS;
12632
+ const runId = randomUUID3();
12633
+ const promptRecords = [];
12634
+ const pending = [];
12635
+ outer: for (const [, identifiers] of perFile) {
12636
+ const sample = sampleIdentifiers(identifiers, maxIdentifiersPerFile, input.kinds);
12637
+ for (const identifier of sample) {
12638
+ for (const rubric of rubrics) {
12639
+ if (!rubric.appliesTo.includes(identifier.kind)) continue;
12640
+ const promptId = `p${promptRecords.length + 1}`;
12641
+ const userPrompt = buildPrompt({ identifier, rubric, convention });
12642
+ promptRecords.push({ promptId, identifier, rubricId: rubric.id });
12643
+ pending.push({ promptId, systemPrompt: CRITIQUE_SYSTEM_PROMPT, userPrompt });
12644
+ if (pending.length > budget) break outer;
12645
+ }
12646
+ }
12647
+ }
12648
+ if (pending.length > budget) {
12649
+ return {
12650
+ status: "budget-exceeded",
12651
+ runId,
12652
+ pendingPrompts: [],
12653
+ projection: { promptCount: pending.length, budget },
12654
+ hint: `Projected at least ${pending.length} LLM prompts (budget: ${budget}). Re-invoke with smaller maxFiles / maxIdentifiersPerFile, or pass promptBudget to raise the ceiling.`
12655
+ };
12656
+ }
12657
+ const meta = {
12658
+ projectRoot,
12659
+ startedAt: Date.now(),
12660
+ convention,
12661
+ rubricsApplied: rubrics.map((r) => r.id),
12662
+ prompts: promptRecords
12663
+ };
12664
+ pruneOldRuns(projectRoot);
12665
+ const { runFile } = saveRunState(projectRoot, {
12666
+ v: 1,
12667
+ runId,
12668
+ skill: "naming-craft",
12669
+ createdAt: Date.now(),
12670
+ meta
12671
+ });
12672
+ return {
12673
+ status: "collected",
12674
+ runId,
12675
+ pendingPrompts: pending,
12676
+ projection: { promptCount: pending.length, budget },
12677
+ runFile
12678
+ };
12679
+ }
12680
+ async function finalizeNamingCraft(input) {
12681
+ const startedAt = Date.now();
12682
+ const projectRoot = sanitizePath(input.path);
12683
+ const state = loadRunState(projectRoot, input.runId);
12684
+ if (state === null) {
12685
+ throw new Error(
12686
+ `naming-craft: no persisted run found for runId=${input.runId} under ${projectRoot}. Run collectNamingCraftPrompts first, or ensure the path matches the project root used at collection time.`
12687
+ );
12688
+ }
12689
+ if (state.skill !== "naming-craft") {
12690
+ throw new Error(
12691
+ `naming-craft: runId=${input.runId} belongs to skill ${state.skill}, not naming-craft.`
12692
+ );
12693
+ }
12694
+ const rubricById = new Map(SEED_RUBRICS.map((r) => [r.id, r]));
12695
+ const promptById = new Map(state.meta.prompts.map((p) => [p.promptId, p]));
12696
+ const findings = [];
12697
+ for (const response of input.responses) {
12698
+ const promptRecord = promptById.get(response.promptId);
12699
+ if (promptRecord === void 0) continue;
12700
+ const rubric = rubricById.get(promptRecord.rubricId);
12701
+ if (rubric === void 0) continue;
12702
+ const finding = parseFindingFromRaw(response.raw, {
12703
+ identifier: promptRecord.identifier,
12704
+ rubric
12705
+ });
12706
+ if (finding !== null) findings.push(finding);
12707
+ }
12708
+ deleteRunState(projectRoot, input.runId);
12709
+ return {
12710
+ findings,
12711
+ summary: {
12712
+ phaseRun: ["critique"],
12713
+ mode: "fast",
12714
+ durationMs: Date.now() - startedAt,
12715
+ llmCalls: {
12716
+ provider: "in-session",
12717
+ model: "host-chat",
12718
+ count: input.responses.length,
12719
+ costUsd: 0
12720
+ },
12721
+ catalog: { rubricsApplied: state.meta.rubricsApplied },
12722
+ convention: state.meta.convention,
12723
+ runId: input.runId
12724
+ }
12725
+ };
12726
+ }
12123
12727
  function collectFiles3(projectRoot, explicitFiles) {
12124
12728
  if (explicitFiles !== void 0 && explicitFiles.length > 0) {
12125
- return explicitFiles.map((f) => path35.isAbsolute(f) ? f : path35.join(projectRoot, f));
12729
+ return explicitFiles.map((f) => path37.isAbsolute(f) ? f : path37.join(projectRoot, f));
12126
12730
  }
12127
12731
  const out = [];
12128
12732
  walk5(projectRoot, out, 0);
@@ -12132,7 +12736,7 @@ function walk5(dir, out, depth) {
12132
12736
  if (depth > 8) return;
12133
12737
  let entries;
12134
12738
  try {
12135
- entries = fs31.readdirSync(dir, { withFileTypes: true });
12739
+ entries = fs33.readdirSync(dir, { withFileTypes: true });
12136
12740
  } catch {
12137
12741
  return;
12138
12742
  }
@@ -12140,7 +12744,7 @@ function walk5(dir, out, depth) {
12140
12744
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
12141
12745
  continue;
12142
12746
  }
12143
- const full = path35.join(dir, entry.name);
12747
+ const full = path37.join(dir, entry.name);
12144
12748
  if (entry.isDirectory()) walk5(full, out, depth + 1);
12145
12749
  else if (entry.isFile() && EXTENSIONS.some((ext) => entry.name.endsWith(ext))) out.push(full);
12146
12750
  }
@@ -12179,7 +12783,7 @@ function sumCosts(provider) {
12179
12783
  // src/mcp/tools/naming-craft.ts
12180
12784
  var namingCraftDefinition = {
12181
12785
  name: "naming_craft",
12182
- description: "LLM-judgment critique of identifier names (variables, functions, types, files). First craft-pipeline ceiling skill; uses a curated rubric catalog seeded from Martin / Beck / Karlton. Emits 3-axis findings (tier x impact x confidence per ADR 0019).",
12786
+ description: "LLM-judgment critique of identifier names (variables, functions, types, files). First craft-pipeline ceiling skill; uses a curated rubric catalog seeded from Martin / Beck / Karlton. Emits 3-axis findings (tier x impact x confidence per ADR 0019). In-session mode (default in Claude Code) returns prompts for the calling agent to answer; call naming_craft_finalize with the responses to get findings.",
12183
12787
  inputSchema: {
12184
12788
  type: "object",
12185
12789
  properties: {
@@ -12198,11 +12802,52 @@ var namingCraftDefinition = {
12198
12802
  maxIdentifiersPerFile: {
12199
12803
  type: "number",
12200
12804
  description: "Cap per-file identifier sampling (default: 15)"
12805
+ },
12806
+ mode: {
12807
+ type: "string",
12808
+ enum: ["inline", "in-session"],
12809
+ description: "'in-session' (default): return prompts for the calling agent to answer, then call naming_craft_finalize. 'inline': run end-to-end via the configured provider (HARNESS_CRAFT_LLM)."
12810
+ },
12811
+ promptBudget: {
12812
+ type: "number",
12813
+ description: "Cap prompt count in in-session mode (default: 100)"
12201
12814
  }
12202
12815
  },
12203
12816
  required: ["path"]
12204
12817
  }
12205
12818
  };
12819
+ var namingCraftFinalizeDefinition = {
12820
+ name: "naming_craft_finalize",
12821
+ description: "Finalize a naming_craft in-session run by submitting the calling agent's responses to the prompts collected by naming_craft. Returns the standard NamingCraftOutput with findings.",
12822
+ inputSchema: {
12823
+ type: "object",
12824
+ properties: {
12825
+ path: {
12826
+ type: "string",
12827
+ description: "Project root path used in the collect call (must match)"
12828
+ },
12829
+ runId: { type: "string", description: "runId returned by the naming_craft collect call" },
12830
+ responses: {
12831
+ type: "array",
12832
+ description: "Per-prompt responses. `raw` is the fenced JSON block the calling agent produced.",
12833
+ items: {
12834
+ type: "object",
12835
+ properties: {
12836
+ promptId: { type: "string" },
12837
+ raw: { type: "string" }
12838
+ },
12839
+ required: ["promptId", "raw"]
12840
+ }
12841
+ }
12842
+ },
12843
+ required: ["path", "runId", "responses"]
12844
+ }
12845
+ };
12846
+ function effectiveMode(input) {
12847
+ if (input.mode !== void 0) return input.mode;
12848
+ const envMode = resolveCraftLlmMode();
12849
+ return envMode === "in-session" ? "in-session" : "inline";
12850
+ }
12206
12851
  async function handleNamingCraft(input) {
12207
12852
  if (typeof input?.path !== "string" || input.path.length === 0) {
12208
12853
  return {
@@ -12213,6 +12858,10 @@ async function handleNamingCraft(input) {
12213
12858
  };
12214
12859
  }
12215
12860
  try {
12861
+ if (effectiveMode(input) === "in-session") {
12862
+ const result2 = await collectNamingCraftPrompts(input);
12863
+ return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
12864
+ }
12216
12865
  const result = await runNamingCraft(input);
12217
12866
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
12218
12867
  } catch (err2) {
@@ -12225,34 +12874,86 @@ async function handleNamingCraft(input) {
12225
12874
  };
12226
12875
  }
12227
12876
  }
12877
+ async function handleNamingCraftFinalize(input) {
12878
+ if (typeof input?.path !== "string" || input.path.length === 0) {
12879
+ return {
12880
+ content: [
12881
+ {
12882
+ type: "text",
12883
+ text: JSON.stringify({ error: "naming_craft_finalize: `path` is required" })
12884
+ }
12885
+ ],
12886
+ isError: true
12887
+ };
12888
+ }
12889
+ if (typeof input?.runId !== "string" || input.runId.length === 0) {
12890
+ return {
12891
+ content: [
12892
+ {
12893
+ type: "text",
12894
+ text: JSON.stringify({ error: "naming_craft_finalize: `runId` is required" })
12895
+ }
12896
+ ],
12897
+ isError: true
12898
+ };
12899
+ }
12900
+ if (!Array.isArray(input?.responses)) {
12901
+ return {
12902
+ content: [
12903
+ {
12904
+ type: "text",
12905
+ text: JSON.stringify({
12906
+ error: "naming_craft_finalize: `responses` must be an array"
12907
+ })
12908
+ }
12909
+ ],
12910
+ isError: true
12911
+ };
12912
+ }
12913
+ try {
12914
+ const result = await finalizeNamingCraft(input);
12915
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
12916
+ } catch (err2) {
12917
+ const message = err2 instanceof Error ? err2.message : String(err2);
12918
+ return {
12919
+ content: [
12920
+ {
12921
+ type: "text",
12922
+ text: JSON.stringify({ error: `naming_craft_finalize failed: ${message}` })
12923
+ }
12924
+ ],
12925
+ isError: true
12926
+ };
12927
+ }
12928
+ }
12228
12929
 
12229
12930
  // src/spec-craft/index.ts
12230
- import * as fs33 from "fs";
12931
+ import * as fs35 from "fs";
12231
12932
  import { randomUUID as randomUUID4 } from "crypto";
12232
12933
 
12233
12934
  // src/spec-craft/extract/discover.ts
12234
- import * as fs32 from "fs";
12235
- import * as path36 from "path";
12935
+ import * as fs34 from "fs";
12936
+ import * as path38 from "path";
12236
12937
  function discoverSpecs(projectRoot, kindsFilter) {
12237
12938
  const wantProposal = kindsFilter === void 0 || kindsFilter.includes("proposal");
12238
12939
  const wantADR = kindsFilter === void 0 || kindsFilter.includes("adr");
12239
12940
  const out = [];
12240
12941
  if (wantProposal) {
12241
- const changesDir = path36.join(projectRoot, "docs", "changes");
12242
- if (fs32.existsSync(changesDir)) {
12243
- for (const entry of fs32.readdirSync(changesDir, { withFileTypes: true })) {
12942
+ const changesDir = path38.join(projectRoot, "docs", "changes");
12943
+ if (fs34.existsSync(changesDir)) {
12944
+ for (const entry of fs34.readdirSync(changesDir, { withFileTypes: true })) {
12244
12945
  if (!entry.isDirectory()) continue;
12245
12946
  if (entry.name.startsWith(".")) continue;
12246
- const topicDir = path36.join(changesDir, entry.name);
12247
- const direct = path36.join(topicDir, "proposal.md");
12248
- if (fs32.existsSync(direct)) {
12947
+ const topicDir = path38.join(changesDir, entry.name);
12948
+ const direct = path38.join(topicDir, "proposal.md");
12949
+ if (fs34.existsSync(direct)) {
12249
12950
  out.push({ file: direct, kind: "proposal" });
12250
12951
  }
12251
- for (const sub of fs32.readdirSync(topicDir, { withFileTypes: true })) {
12952
+ for (const sub of fs34.readdirSync(topicDir, { withFileTypes: true })) {
12252
12953
  if (!sub.isDirectory()) continue;
12253
12954
  if (sub.name.startsWith(".")) continue;
12254
- const subProposal = path36.join(topicDir, sub.name, "proposal.md");
12255
- if (fs32.existsSync(subProposal)) {
12955
+ const subProposal = path38.join(topicDir, sub.name, "proposal.md");
12956
+ if (fs34.existsSync(subProposal)) {
12256
12957
  out.push({ file: subProposal, kind: "proposal" });
12257
12958
  }
12258
12959
  }
@@ -12260,13 +12961,13 @@ function discoverSpecs(projectRoot, kindsFilter) {
12260
12961
  }
12261
12962
  }
12262
12963
  if (wantADR) {
12263
- const decisionsDir = path36.join(projectRoot, "docs", "knowledge", "decisions");
12264
- if (fs32.existsSync(decisionsDir)) {
12265
- for (const entry of fs32.readdirSync(decisionsDir, { withFileTypes: true })) {
12964
+ const decisionsDir = path38.join(projectRoot, "docs", "knowledge", "decisions");
12965
+ if (fs34.existsSync(decisionsDir)) {
12966
+ for (const entry of fs34.readdirSync(decisionsDir, { withFileTypes: true })) {
12266
12967
  if (!entry.isFile()) continue;
12267
12968
  if (!entry.name.endsWith(".md")) continue;
12268
12969
  if (entry.name.startsWith(".") || entry.name.toUpperCase() === "README.MD") continue;
12269
- out.push({ file: path36.join(decisionsDir, entry.name), kind: "adr" });
12970
+ out.push({ file: path38.join(decisionsDir, entry.name), kind: "adr" });
12270
12971
  }
12271
12972
  }
12272
12973
  }
@@ -12514,7 +13215,7 @@ async function runSpecCraft(input) {
12514
13215
  for (const spec of specs) {
12515
13216
  let source;
12516
13217
  try {
12517
- source = fs33.readFileSync(spec.file, "utf-8");
13218
+ source = fs35.readFileSync(spec.file, "utf-8");
12518
13219
  } catch {
12519
13220
  continue;
12520
13221
  }
@@ -12634,13 +13335,13 @@ async function handleSpecCraft(input) {
12634
13335
  }
12635
13336
 
12636
13337
  // src/copy-craft/index.ts
12637
- import * as fs35 from "fs";
12638
- import * as path39 from "path";
13338
+ import * as fs37 from "fs";
13339
+ import * as path41 from "path";
12639
13340
  import { randomUUID as randomUUID5 } from "crypto";
12640
13341
 
12641
13342
  // src/copy-craft/extract/source.ts
12642
13343
  import ts5 from "typescript";
12643
- import * as path37 from "path";
13344
+ import * as path39 from "path";
12644
13345
  var LOG_LEVELS = ["log", "info", "warn", "warning", "error", "debug", "trace", "fatal"];
12645
13346
  function extractFromSource(input) {
12646
13347
  if (!/\.(?:ts|tsx|js|jsx)$/i.test(input.file)) return [];
@@ -12780,7 +13481,7 @@ function isLikelyLogger(name) {
12780
13481
  }
12781
13482
  function fileMatchesCliPaths(file, cliPaths) {
12782
13483
  const paths = cliPaths ?? defaultCliOutputPaths();
12783
- const normalized = file.split(path37.sep).join("/");
13484
+ const normalized = file.split(path39.sep).join("/");
12784
13485
  return paths.some((p) => normalized.includes(p));
12785
13486
  }
12786
13487
  function defaultCliOutputPaths() {
@@ -12800,8 +13501,8 @@ function cleanCommentText(raw) {
12800
13501
 
12801
13502
  // src/copy-craft/extract/commits.ts
12802
13503
  import { spawnSync } from "child_process";
12803
- import * as fs34 from "fs";
12804
- import * as path38 from "path";
13504
+ import * as fs36 from "fs";
13505
+ import * as path40 from "path";
12805
13506
  var GIT_TIMEOUT_MS = 1e4;
12806
13507
  function extractCommits(input) {
12807
13508
  const { projectRoot, since = "1 month ago", limit = 100 } = input;
@@ -12840,8 +13541,8 @@ function extractCommits(input) {
12840
13541
  function isGitRepo(projectRoot) {
12841
13542
  let dir = projectRoot;
12842
13543
  for (let i = 0; i < 10; i++) {
12843
- if (fs34.existsSync(path38.join(dir, ".git"))) return true;
12844
- const parent = path38.dirname(dir);
13544
+ if (fs36.existsSync(path40.join(dir, ".git"))) return true;
13545
+ const parent = path40.dirname(dir);
12845
13546
  if (parent === dir) break;
12846
13547
  dir = parent;
12847
13548
  }
@@ -13147,7 +13848,7 @@ async function runCopyCraft(input) {
13147
13848
  for (const file of files) {
13148
13849
  let source;
13149
13850
  try {
13150
- source = fs35.readFileSync(file, "utf-8");
13851
+ source = fs37.readFileSync(file, "utf-8");
13151
13852
  } catch {
13152
13853
  continue;
13153
13854
  }
@@ -13231,7 +13932,7 @@ async function runCopyCraft(input) {
13231
13932
  }
13232
13933
  function collectSourceFiles(projectRoot, explicitFiles) {
13233
13934
  if (explicitFiles !== void 0 && explicitFiles.length > 0) {
13234
- return explicitFiles.map((f) => path39.isAbsolute(f) ? f : path39.join(projectRoot, f));
13935
+ return explicitFiles.map((f) => path41.isAbsolute(f) ? f : path41.join(projectRoot, f));
13235
13936
  }
13236
13937
  const out = [];
13237
13938
  walk6(projectRoot, out, 0);
@@ -13241,7 +13942,7 @@ function walk6(dir, out, depth) {
13241
13942
  if (depth > 8) return;
13242
13943
  let entries;
13243
13944
  try {
13244
- entries = fs35.readdirSync(dir, { withFileTypes: true });
13945
+ entries = fs37.readdirSync(dir, { withFileTypes: true });
13245
13946
  } catch {
13246
13947
  return;
13247
13948
  }
@@ -13249,7 +13950,7 @@ function walk6(dir, out, depth) {
13249
13950
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
13250
13951
  continue;
13251
13952
  }
13252
- const full = path39.join(dir, entry.name);
13953
+ const full = path41.join(dir, entry.name);
13253
13954
  if (entry.isDirectory()) walk6(full, out, depth + 1);
13254
13955
  else if (entry.isFile() && SOURCE_EXTENSIONS.some((ext) => entry.name.endsWith(ext)))
13255
13956
  out.push(full);
@@ -13319,8 +14020,8 @@ async function handleCopyCraft(input) {
13319
14020
  }
13320
14021
 
13321
14022
  // src/test-craft/index.ts
13322
- import * as fs37 from "fs";
13323
- import * as path41 from "path";
14023
+ import * as fs39 from "fs";
14024
+ import * as path43 from "path";
13324
14025
  import { randomUUID as randomUUID6 } from "crypto";
13325
14026
 
13326
14027
  // src/test-craft/extract/framework.ts
@@ -13426,25 +14127,25 @@ function extractCallbackText(node, fullSource) {
13426
14127
  }
13427
14128
 
13428
14129
  // src/test-craft/extract/source-pair.ts
13429
- import * as fs36 from "fs";
13430
- import * as path40 from "path";
14130
+ import * as fs38 from "fs";
14131
+ import * as path42 from "path";
13431
14132
  var MAX_SOURCE_CHARS = 2e3;
13432
14133
  function resolveSourceFile(testFile) {
13433
- const dir = path40.dirname(testFile);
14134
+ const dir = path42.dirname(testFile);
13434
14135
  const ext = /\.tsx$/.test(testFile) ? ".tsx" : ".ts";
13435
- const base = path40.basename(testFile).replace(/\.(?:test|spec)\.(?:tsx?|jsx?)$/, "");
14136
+ const base = path42.basename(testFile).replace(/\.(?:test|spec)\.(?:tsx?|jsx?)$/, "");
13436
14137
  const candidates = [
13437
14138
  // Sibling (most common in co-located setups)
13438
- path40.join(dir, base + ext),
14139
+ path42.join(dir, base + ext),
13439
14140
  // tests/ peer to src/
13440
- path40.join(dir, "..", "src", base + ext),
14141
+ path42.join(dir, "..", "src", base + ext),
13441
14142
  // tests/ one level deeper than src/
13442
- path40.join(dir, "..", "..", "src", base + ext)
14143
+ path42.join(dir, "..", "..", "src", base + ext)
13443
14144
  ];
13444
14145
  for (const candidate of candidates) {
13445
- if (fs36.existsSync(candidate)) {
14146
+ if (fs38.existsSync(candidate)) {
13446
14147
  try {
13447
- const raw = fs36.readFileSync(candidate, "utf-8");
14148
+ const raw = fs38.readFileSync(candidate, "utf-8");
13448
14149
  const content = raw.length > MAX_SOURCE_CHARS ? raw.slice(0, MAX_SOURCE_CHARS) + "\n[\u2026truncated for prompt cost\u2026]" : raw;
13449
14150
  return { file: candidate, content };
13450
14151
  } catch {
@@ -13680,7 +14381,7 @@ async function runTestCraft(input) {
13680
14381
  for (const file of files) {
13681
14382
  let source;
13682
14383
  try {
13683
- source = fs37.readFileSync(file, "utf-8");
14384
+ source = fs39.readFileSync(file, "utf-8");
13684
14385
  } catch {
13685
14386
  continue;
13686
14387
  }
@@ -13745,7 +14446,7 @@ async function runTestCraft(input) {
13745
14446
  }
13746
14447
  function collectTestFiles(projectRoot, explicitFiles) {
13747
14448
  if (explicitFiles !== void 0 && explicitFiles.length > 0) {
13748
- return explicitFiles.map((f) => path41.isAbsolute(f) ? f : path41.join(projectRoot, f));
14449
+ return explicitFiles.map((f) => path43.isAbsolute(f) ? f : path43.join(projectRoot, f));
13749
14450
  }
13750
14451
  const out = [];
13751
14452
  walk7(projectRoot, out, 0);
@@ -13755,7 +14456,7 @@ function walk7(dir, out, depth) {
13755
14456
  if (depth > 10) return;
13756
14457
  let entries;
13757
14458
  try {
13758
- entries = fs37.readdirSync(dir, { withFileTypes: true });
14459
+ entries = fs39.readdirSync(dir, { withFileTypes: true });
13759
14460
  } catch {
13760
14461
  return;
13761
14462
  }
@@ -13763,7 +14464,7 @@ function walk7(dir, out, depth) {
13763
14464
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
13764
14465
  continue;
13765
14466
  }
13766
- const full = path41.join(dir, entry.name);
14467
+ const full = path43.join(dir, entry.name);
13767
14468
  if (entry.isDirectory()) walk7(full, out, depth + 1);
13768
14469
  else if (entry.isFile() && TEST_FILE_EXTS.some((ext) => entry.name.endsWith(ext))) {
13769
14470
  out.push(full);
@@ -13836,18 +14537,18 @@ async function handleTestCraft(input) {
13836
14537
  }
13837
14538
 
13838
14539
  // src/knowledge-craft/index.ts
13839
- import * as fs39 from "fs";
13840
- import * as path43 from "path";
14540
+ import * as fs41 from "fs";
14541
+ import * as path45 from "path";
13841
14542
  import { randomUUID as randomUUID7 } from "crypto";
13842
14543
 
13843
14544
  // src/knowledge-craft/extract/discover.ts
13844
- import * as fs38 from "fs";
13845
- import * as path42 from "path";
14545
+ import * as fs40 from "fs";
14546
+ import * as path44 from "path";
13846
14547
  var KNOWLEDGE_ROOT = "docs/knowledge";
13847
14548
  var DEFAULT_EXCLUDED_DIRS = ["decisions"];
13848
14549
  function discoverKnowledgeEntries(projectRoot, extraExcludeDirs) {
13849
- const root = path42.join(projectRoot, KNOWLEDGE_ROOT);
13850
- if (!fs38.existsSync(root)) return [];
14550
+ const root = path44.join(projectRoot, KNOWLEDGE_ROOT);
14551
+ if (!fs40.existsSync(root)) return [];
13851
14552
  const exclude = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDED_DIRS, ...extraExcludeDirs ?? []]);
13852
14553
  const out = [];
13853
14554
  walk8(root, root, out, exclude);
@@ -13856,13 +14557,13 @@ function discoverKnowledgeEntries(projectRoot, extraExcludeDirs) {
13856
14557
  function walk8(dir, root, out, exclude) {
13857
14558
  let entries;
13858
14559
  try {
13859
- entries = fs38.readdirSync(dir, { withFileTypes: true });
14560
+ entries = fs40.readdirSync(dir, { withFileTypes: true });
13860
14561
  } catch {
13861
14562
  return;
13862
14563
  }
13863
14564
  for (const entry of entries) {
13864
14565
  if (entry.name.startsWith(".")) continue;
13865
- const full = path42.join(dir, entry.name);
14566
+ const full = path44.join(dir, entry.name);
13866
14567
  if (entry.isDirectory()) {
13867
14568
  if (exclude.has(entry.name)) continue;
13868
14569
  walk8(full, root, out, exclude);
@@ -13871,7 +14572,7 @@ function walk8(dir, root, out, exclude) {
13871
14572
  if (!entry.isFile()) continue;
13872
14573
  if (!entry.name.endsWith(".md")) continue;
13873
14574
  if (entry.name.toLowerCase() === "readme.md") continue;
13874
- const rel = path42.relative(root, full).replaceAll("\\", "/");
14575
+ const rel = path44.relative(root, full).replaceAll("\\", "/");
13875
14576
  out.push({ file: full, relative: rel });
13876
14577
  }
13877
14578
  }
@@ -14051,7 +14752,7 @@ async function runKnowledgeCraft(input) {
14051
14752
  for (const entry of entries) {
14052
14753
  let content;
14053
14754
  try {
14054
- content = fs39.readFileSync(entry.file, "utf-8");
14755
+ content = fs41.readFileSync(entry.file, "utf-8");
14055
14756
  } catch {
14056
14757
  filesSkipped++;
14057
14758
  continue;
@@ -14092,10 +14793,10 @@ async function runKnowledgeCraft(input) {
14092
14793
  }
14093
14794
  function collectEntries(projectRoot, input) {
14094
14795
  if (input.files !== void 0 && input.files.length > 0) {
14095
- const root = path43.join(projectRoot, KNOWLEDGE_ROOT);
14796
+ const root = path45.join(projectRoot, KNOWLEDGE_ROOT);
14096
14797
  return input.files.map((f) => ({
14097
14798
  file: f,
14098
- relative: path43.relative(root, f).replaceAll("\\", "/")
14799
+ relative: path45.relative(root, f).replaceAll("\\", "/")
14099
14800
  }));
14100
14801
  }
14101
14802
  return discoverKnowledgeEntries(projectRoot, input.excludeDirs);
@@ -14157,12 +14858,12 @@ async function handleKnowledgeCraft(input) {
14157
14858
  }
14158
14859
 
14159
14860
  // src/security-craft/index.ts
14160
- import * as fs41 from "fs";
14861
+ import * as fs43 from "fs";
14161
14862
  import { randomUUID as randomUUID8 } from "crypto";
14162
14863
 
14163
14864
  // src/security-craft/extract/discover.ts
14164
- import * as fs40 from "fs";
14165
- import * as path44 from "path";
14865
+ import * as fs42 from "fs";
14866
+ import * as path46 from "path";
14166
14867
  var SOURCE_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
14167
14868
  var EXCLUDED_DIRS = /* @__PURE__ */ new Set([
14168
14869
  "node_modules",
@@ -14182,12 +14883,12 @@ var EXCLUDED_DIRS = /* @__PURE__ */ new Set([
14182
14883
  ]);
14183
14884
  var TEST_FILE_PATTERN = /\.(test|spec)\.(ts|tsx|js|jsx|mjs|cjs)$/i;
14184
14885
  function discoverSourceFiles(projectRoot, packagesFilter) {
14185
- const packagesDir = path44.join(projectRoot, "packages");
14186
- if (!fs40.existsSync(packagesDir)) return [];
14886
+ const packagesDir = path46.join(projectRoot, "packages");
14887
+ if (!fs42.existsSync(packagesDir)) return [];
14187
14888
  const out = [];
14188
14889
  let entries;
14189
14890
  try {
14190
- entries = fs40.readdirSync(packagesDir, { withFileTypes: true });
14891
+ entries = fs42.readdirSync(packagesDir, { withFileTypes: true });
14191
14892
  } catch {
14192
14893
  return [];
14193
14894
  }
@@ -14195,8 +14896,8 @@ function discoverSourceFiles(projectRoot, packagesFilter) {
14195
14896
  if (!entry.isDirectory()) continue;
14196
14897
  if (entry.name.startsWith(".")) continue;
14197
14898
  if (packagesFilter !== void 0 && !packagesFilter.includes(entry.name)) continue;
14198
- const srcDir = path44.join(packagesDir, entry.name, "src");
14199
- if (!fs40.existsSync(srcDir)) continue;
14899
+ const srcDir = path46.join(packagesDir, entry.name, "src");
14900
+ if (!fs42.existsSync(srcDir)) continue;
14200
14901
  walk9(srcDir, out);
14201
14902
  }
14202
14903
  return out;
@@ -14204,13 +14905,13 @@ function discoverSourceFiles(projectRoot, packagesFilter) {
14204
14905
  function walk9(dir, out) {
14205
14906
  let entries;
14206
14907
  try {
14207
- entries = fs40.readdirSync(dir, { withFileTypes: true });
14908
+ entries = fs42.readdirSync(dir, { withFileTypes: true });
14208
14909
  } catch {
14209
14910
  return;
14210
14911
  }
14211
14912
  for (const entry of entries) {
14212
14913
  if (entry.name.startsWith(".")) continue;
14213
- const full = path44.join(dir, entry.name);
14914
+ const full = path46.join(dir, entry.name);
14214
14915
  if (entry.isDirectory()) {
14215
14916
  if (EXCLUDED_DIRS.has(entry.name)) continue;
14216
14917
  walk9(full, out);
@@ -14218,7 +14919,7 @@ function walk9(dir, out) {
14218
14919
  }
14219
14920
  if (!entry.isFile()) continue;
14220
14921
  if (TEST_FILE_PATTERN.test(entry.name)) continue;
14221
- const ext = path44.extname(entry.name);
14922
+ const ext = path46.extname(entry.name);
14222
14923
  if (!SOURCE_EXTENSIONS2.has(ext)) continue;
14223
14924
  out.push(full);
14224
14925
  }
@@ -14715,7 +15416,7 @@ async function runSecurityCraft(input) {
14715
15416
  for (const file of candidateFiles) {
14716
15417
  let source;
14717
15418
  try {
14718
- source = fs41.readFileSync(file, "utf-8");
15419
+ source = fs43.readFileSync(file, "utf-8");
14719
15420
  } catch {
14720
15421
  continue;
14721
15422
  }
@@ -14900,6 +15601,7 @@ var TOOL_DEFINITIONS = [
14900
15601
  auditBrandDefinition,
14901
15602
  designPipelineDefinition,
14902
15603
  namingCraftDefinition,
15604
+ namingCraftFinalizeDefinition,
14903
15605
  specCraftDefinition,
14904
15606
  copyCraftDefinition,
14905
15607
  testCraftDefinition,
@@ -14982,6 +15684,7 @@ var TOOL_HANDLERS = {
14982
15684
  audit_brand: handleAuditBrand,
14983
15685
  run_design_pipeline: handleDesignPipeline,
14984
15686
  naming_craft: handleNamingCraft,
15687
+ naming_craft_finalize: handleNamingCraftFinalize,
14985
15688
  spec_craft: handleSpecCraft,
14986
15689
  copy_craft: handleCopyCraft,
14987
15690
  test_craft: handleTestCraft,
@@ -15088,7 +15791,7 @@ async function appendUpdateNotification(result, resolvedRoot) {
15088
15791
  shouldRunCheck,
15089
15792
  readCheckState,
15090
15793
  spawnBackgroundCheck
15091
- } = await import("./dist-XIJWWQ5N.js");
15794
+ } = await import("./dist-72ID44UE.js");
15092
15795
  const { CLI_VERSION } = await import("./version-CUI434OP.js");
15093
15796
  const configInterval = readConfigInterval(resolvedRoot);
15094
15797
  const DEFAULT_INTERVAL = 864e5;
@@ -15186,6 +15889,8 @@ export {
15186
15889
  runDetectDrift,
15187
15890
  runAlignDesignSystem,
15188
15891
  runAudit,
15892
+ findOrchestratorMd,
15893
+ readBackendsFromOrchestratorMd,
15189
15894
  runDesignCraft,
15190
15895
  runAuditBrand,
15191
15896
  runCopyCraft,