@harness-engineering/cli 2.0.0 → 2.1.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 (95) hide show
  1. package/dist/agents/skills/claude-code/harness-compound/SKILL.md +153 -0
  2. package/dist/agents/skills/claude-code/harness-compound/skill.yaml +60 -0
  3. package/dist/agents/skills/claude-code/harness-knowledge-pipeline/SKILL.md +12 -1
  4. package/dist/agents/skills/claude-code/harness-observability/SKILL.md +2 -0
  5. package/dist/agents/skills/claude-code/harness-pulse/SKILL.md +138 -0
  6. package/dist/agents/skills/claude-code/harness-pulse/references/interview.md +77 -0
  7. package/dist/agents/skills/claude-code/harness-pulse/skill.yaml +61 -0
  8. package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +25 -1
  9. package/dist/agents/skills/codex/harness-compound/SKILL.md +153 -0
  10. package/dist/agents/skills/codex/harness-compound/skill.yaml +60 -0
  11. package/dist/agents/skills/codex/harness-knowledge-pipeline/SKILL.md +12 -1
  12. package/dist/agents/skills/codex/harness-observability/SKILL.md +2 -0
  13. package/dist/agents/skills/codex/harness-pulse/SKILL.md +138 -0
  14. package/dist/agents/skills/codex/harness-pulse/references/interview.md +77 -0
  15. package/dist/agents/skills/codex/harness-pulse/skill.yaml +61 -0
  16. package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +25 -1
  17. package/dist/agents/skills/cursor/harness-compound/SKILL.md +153 -0
  18. package/dist/agents/skills/cursor/harness-compound/skill.yaml +60 -0
  19. package/dist/agents/skills/cursor/harness-knowledge-pipeline/SKILL.md +12 -1
  20. package/dist/agents/skills/cursor/harness-observability/SKILL.md +2 -0
  21. package/dist/agents/skills/cursor/harness-pulse/SKILL.md +138 -0
  22. package/dist/agents/skills/cursor/harness-pulse/references/interview.md +77 -0
  23. package/dist/agents/skills/cursor/harness-pulse/skill.yaml +61 -0
  24. package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +25 -1
  25. package/dist/agents/skills/gemini-cli/harness-compound/SKILL.md +153 -0
  26. package/dist/agents/skills/gemini-cli/harness-compound/skill.yaml +60 -0
  27. package/dist/agents/skills/gemini-cli/harness-knowledge-pipeline/SKILL.md +12 -1
  28. package/dist/agents/skills/gemini-cli/harness-observability/SKILL.md +2 -0
  29. package/dist/agents/skills/gemini-cli/harness-pulse/SKILL.md +138 -0
  30. package/dist/agents/skills/gemini-cli/harness-pulse/references/interview.md +77 -0
  31. package/dist/agents/skills/gemini-cli/harness-pulse/skill.yaml +61 -0
  32. package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +25 -1
  33. package/dist/agents/skills/package.json +1 -0
  34. package/dist/agents/skills/tests/fixtures/harness-compound/bug-track-fixture/input.json +10 -0
  35. package/dist/agents/skills/tests/fixtures/harness-compound/duplicate-detection-fixture/docs/solutions/bug-track/integration-issues/stalled-lease-cleanup.md +28 -0
  36. package/dist/agents/skills/tests/fixtures/harness-compound/duplicate-detection-fixture/expected.json +4 -0
  37. package/dist/agents/skills/tests/fixtures/harness-compound/duplicate-detection-fixture/input.json +10 -0
  38. package/dist/agents/skills/tests/fixtures/harness-compound/knowledge-track-fixture/input.json +10 -0
  39. package/dist/agents/skills/tests/harness-compound.test.ts +86 -0
  40. package/dist/{agents-md-6SAMHE7H.js → agents-md-L4X4MOWT.js} +3 -3
  41. package/dist/{architecture-5YR52NSV.js → architecture-WJRIYQ45.js} +4 -4
  42. package/dist/{assess-project-5X7TYQFM.js → assess-project-PHC2HO3V.js} +1 -1
  43. package/dist/bin/harness-mcp.js +16 -15
  44. package/dist/bin/harness.js +26 -25
  45. package/dist/{check-phase-gate-PLV2VDOL.js → check-phase-gate-646KY67H.js} +5 -4
  46. package/dist/{chunk-ZYLBIDLE.js → chunk-224XKVLP.js} +1 -1
  47. package/dist/{chunk-ELJ2MXMO.js → chunk-2QPHCR22.js} +9 -9
  48. package/dist/{chunk-SITVRO7K.js → chunk-2ZURBWEV.js} +9 -9
  49. package/dist/{chunk-2IBXUG6J.js → chunk-36X7TRUI.js} +2 -2
  50. package/dist/{chunk-6L2BU4BP.js → chunk-4HKVZO7R.js} +1 -1
  51. package/dist/{chunk-74YADB7T.js → chunk-7XQYOXTB.js} +96 -94
  52. package/dist/{chunk-S2WB4LE7.js → chunk-BMM3GXV6.js} +384 -28
  53. package/dist/{chunk-BYS3TQOO.js → chunk-CPYL6LJR.js} +1 -1
  54. package/dist/{chunk-QDRBWVVY.js → chunk-E7W3YOXL.js} +2 -2
  55. package/dist/{chunk-MTPHNOJW.js → chunk-FNCJ3UCU.js} +507 -244
  56. package/dist/{chunk-RYDPFIJY.js → chunk-JPWICLXQ.js} +1 -1
  57. package/dist/{chunk-RFYF7TJS.js → chunk-K4WRQTEF.js} +1835 -805
  58. package/dist/{chunk-DXGI7DL3.js → chunk-KTWKW6KJ.js} +1 -1
  59. package/dist/{chunk-JNKALGRM.js → chunk-KV7A5OZT.js} +5 -5
  60. package/dist/{chunk-KJD4J54I.js → chunk-LO7ZLV7S.js} +6 -1
  61. package/dist/{chunk-XHOGGZS7.js → chunk-QTUPHTTK.js} +1 -1
  62. package/dist/{chunk-R2CBBZA6.js → chunk-SVC7THFK.js} +1 -1
  63. package/dist/{chunk-PFM3BVVU.js → chunk-TNZYQTEE.js} +1 -1
  64. package/dist/{chunk-HT7HYYGT.js → chunk-VJQLUS5I.js} +1 -1
  65. package/dist/{chunk-6GXSJGSW.js → chunk-VKDBM3RX.js} +3 -3
  66. package/dist/{chunk-JZST2WZS.js → chunk-W4AFGFFB.js} +3 -3
  67. package/dist/{chunk-YJE23GRZ.js → chunk-YG4ZBGEH.js} +39 -5
  68. package/dist/{chunk-5ME3WG3G.js → chunk-YLOAQZLA.js} +5 -5
  69. package/dist/{chunk-7JQ7HLM4.js → chunk-YLTRFZAT.js} +8 -8
  70. package/dist/{chunk-BFBZK6BC.js → chunk-YWD6WXXM.js} +6 -6
  71. package/dist/chunk-ZCZD7FHU.js +16 -0
  72. package/dist/{ci-workflow-7T2XKB3P.js → ci-workflow-TOS5X527.js} +3 -3
  73. package/dist/{dist-77VNTHWV.js → dist-6RT2AVYU.js} +78 -2
  74. package/dist/{dist-42AYXCAK.js → dist-D27LJR2T.js} +7 -1
  75. package/dist/{docs-MSIJ6SDO.js → docs-HOJMQYDZ.js} +5 -4
  76. package/dist/{engine-F4P5RBE4.js → engine-D6UYH6DB.js} +3 -3
  77. package/dist/{entropy-GSUTIORR.js → entropy-LZ4IDGZR.js} +3 -3
  78. package/dist/{feedback-NST6T4HI.js → feedback-WV7EQVK7.js} +1 -1
  79. package/dist/{generate-agent-definitions-BOUGQIPA.js → generate-agent-definitions-ZHFFS6YG.js} +4 -4
  80. package/dist/glob-helper-FZPPTGJN.js +62 -0
  81. package/dist/{graph-loader-IAUPGLRV.js → graph-loader-5MKHAJJF.js} +1 -1
  82. package/dist/index.d.ts +44 -6
  83. package/dist/index.js +26 -25
  84. package/dist/{loader-6QTJC7IN.js → loader-Z23JTXIZ.js} +3 -3
  85. package/dist/{mcp-QFBGTUX6.js → mcp-QFZDPFNP.js} +16 -15
  86. package/dist/{performance-B2NAAIE5.js → performance-7ATLHTQU.js} +5 -4
  87. package/dist/{review-pipeline-6EYMBS6B.js → review-pipeline-COBGGXHJ.js} +3 -3
  88. package/dist/{runtime-VFZK6BCZ.js → runtime-KCBNQUXK.js} +3 -3
  89. package/dist/{scan-DB6FNYGG.js → scan-BIJYHOE7.js} +2 -1
  90. package/dist/{security-HRNTYHPM.js → security-MAPRIFQT.js} +1 -1
  91. package/dist/templates/orchestrator/harness.orchestrator.md +9 -1
  92. package/dist/{validate-YEMAFWJE.js → validate-74XTQR7Q.js} +4 -4
  93. package/dist/{validate-cross-check-DGHTJFVH.js → validate-cross-check-MI5MZ7MB.js} +3 -3
  94. package/package.json +7 -6
  95. package/dist/glob-helper-VCQXK5XY.js +0 -54
@@ -13,13 +13,13 @@ import {
13
13
  NODE_STABILITY,
14
14
  init_dist as init_dist2,
15
15
  queryTraceability
16
- } from "./chunk-S2WB4LE7.js";
16
+ } from "./chunk-BMM3GXV6.js";
17
17
  import {
18
18
  __esm,
19
19
  __export
20
20
  } from "./chunk-KFQGP6VL.js";
21
21
 
22
- // ../core/dist/chunk-H73442AZ.mjs
22
+ // ../core/dist/chunk-CE225WRK.mjs
23
23
  import { z } from "zod";
24
24
  import { createHash } from "crypto";
25
25
  import { minimatch } from "minimatch";
@@ -69,17 +69,17 @@ function resolveFileToLayer(file, layers) {
69
69
  }
70
70
  return void 0;
71
71
  }
72
- async function fileExists(path37) {
72
+ async function fileExists(path42) {
73
73
  try {
74
- await accessAsync(path37, constants.F_OK);
74
+ await accessAsync(path42, constants.F_OK);
75
75
  return true;
76
76
  } catch {
77
77
  return false;
78
78
  }
79
79
  }
80
- async function readFileContent(path37) {
80
+ async function readFileContent(path42) {
81
81
  try {
82
- const content = await readFileAsync(path37, "utf-8");
82
+ const content = await readFileAsync(path42, "utf-8");
83
83
  return Ok(content);
84
84
  } catch (error) {
85
85
  return Err(error);
@@ -115,20 +115,32 @@ function getExtensionsForLang(lang) {
115
115
  return [".ts", ".tsx", ".js", ".jsx"];
116
116
  }
117
117
  }
118
- function resolveImportPath(importSource, fromFile, _rootDir) {
118
+ async function resolveImportPath(importSource, fromFile, _rootDir) {
119
119
  if (!importSource.startsWith(".") && !importSource.startsWith("/")) {
120
120
  return null;
121
121
  }
122
122
  const fromDir = dirname(fromFile);
123
- let resolved = resolve(fromDir, importSource);
124
- const ext = extname(fromFile);
125
- const lang = detectLangFromExt(ext);
126
- const extensions = getExtensionsForLang(lang);
123
+ const resolved = resolve(fromDir, importSource);
124
+ const sourceExt = extname(resolved);
125
+ const fromLang = detectLangFromExt(extname(fromFile));
126
+ const fallbacks = JS_EXT_FALLBACKS[sourceExt];
127
+ if (fallbacks) {
128
+ const base = resolved.slice(0, -sourceExt.length);
129
+ for (const ext of fallbacks) {
130
+ const candidate = base + ext;
131
+ if (await fileExists(candidate)) return candidate.replace(/\\/g, "/");
132
+ }
133
+ for (const indexExt of [".ts", ".tsx", ".jsx"]) {
134
+ const indexPath2 = resolve(base, "index" + indexExt);
135
+ if (await fileExists(indexPath2)) return indexPath2.replace(/\\/g, "/");
136
+ }
137
+ }
127
138
  const hasKnownExt = Object.values(EXTENSION_BY_LANG).flat().some((e) => resolved.endsWith(e));
128
- if (!hasKnownExt) {
129
- resolved = resolved + extensions[0];
139
+ if (hasKnownExt) {
140
+ return resolved.replace(/\\/g, "/");
130
141
  }
131
- return resolved.replace(/\\/g, "/");
142
+ const extensions = getExtensionsForLang(fromLang);
143
+ return (resolved + extensions[0]).replace(/\\/g, "/");
132
144
  }
133
145
  function getImportType(imp) {
134
146
  if (imp.kind === "type") return "type-only";
@@ -157,7 +169,7 @@ async function buildDependencyGraph(files, parser, graphDependencyData) {
157
169
  continue;
158
170
  }
159
171
  for (const imp of importsResult.value) {
160
- const resolvedPath = resolveImportPath(imp.source, file, "");
172
+ const resolvedPath = await resolveImportPath(imp.source, file, "");
161
173
  if (resolvedPath) {
162
174
  edges.push({
163
175
  from: normalizedFile,
@@ -473,9 +485,9 @@ async function resolveWasmPath(grammarName) {
473
485
  const { createRequire } = await import("module");
474
486
  const require2 = createRequire(import.meta.url ?? __filename);
475
487
  const pkgPath = require2.resolve("tree-sitter-wasms/package.json");
476
- const path37 = await import("path");
477
- const pkgDir = path37.dirname(pkgPath);
478
- return path37.join(pkgDir, "out", `${grammarName}.wasm`);
488
+ const path42 = await import("path");
489
+ const pkgDir = path42.dirname(pkgPath);
490
+ return path42.join(pkgDir, "out", `${grammarName}.wasm`);
479
491
  }
480
492
  async function loadLanguage(lang) {
481
493
  const grammarName = GRAMMAR_MAP[lang];
@@ -1733,9 +1745,9 @@ async function toHaveMaxDepDepth(received, maxDepth) {
1733
1745
  message: () => pass ? `Expected dependency depth in '${received.scope}' to exceed ${maxDepth} but it was ${maxActual}` : `Module '${received.scope}' has dependency depth ${maxActual} (limit: ${maxDepth})`
1734
1746
  };
1735
1747
  }
1736
- var ArchMetricCategorySchema, ViolationSchema, MetricResultSchema, CategoryBaselineSchema, ArchBaselineSchema, CategoryRegressionSchema, ArchDiffResultSchema, ThresholdConfigSchema, ArchConfigSchema, ConstraintRuleSchema, ViolationSnapshotSchema, ViolationHistorySchema, EmergenceConfidenceSchema, EmergentConstraintSuggestionSchema, EmergenceResultSchema, accessAsync, readFileAsync, EXTENSION_BY_LANG, CircularDepsCollector, TypeScriptParser, EXTENSION_MAP, parserCache, initialized, GRAMMAR_MAP, TOP_LEVEL_TYPES, METHOD_TYPES, IDENTIFIER_TYPES, NAME_EXTRACTORS, pythonStrategy, goStrategy, RUST_USE_ARG_TYPES, RUST_PUB_ITEM_TYPES, rustStrategy, JAVA_IMPORT_TYPES, JAVA_EXPORT_TYPES, javaStrategy, STRATEGIES, TreeSitterParser, ParserRegistry, defaultRegistry, LayerViolationCollector, ArchBaselineManager, DEFAULT_THRESHOLDS, FUNCTION_PATTERNS, DECISION_PATTERNS, ComplexityCollector, DEFAULT_THRESHOLDS2, CouplingCollector, ForbiddenImportCollector, ModuleSizeCollector, DepDepthCollector, defaultCollectors, archMatchers;
1737
- var init_chunk_H73442AZ = __esm({
1738
- "../core/dist/chunk-H73442AZ.mjs"() {
1748
+ var ArchMetricCategorySchema, ViolationSchema, MetricResultSchema, CategoryBaselineSchema, ArchBaselineSchema, CategoryRegressionSchema, ArchDiffResultSchema, ThresholdConfigSchema, ArchConfigSchema, ConstraintRuleSchema, ViolationSnapshotSchema, ViolationHistorySchema, EmergenceConfidenceSchema, EmergentConstraintSuggestionSchema, EmergenceResultSchema, accessAsync, readFileAsync, EXTENSION_BY_LANG, JS_EXT_FALLBACKS, CircularDepsCollector, TypeScriptParser, EXTENSION_MAP, parserCache, initialized, GRAMMAR_MAP, TOP_LEVEL_TYPES, METHOD_TYPES, IDENTIFIER_TYPES, NAME_EXTRACTORS, pythonStrategy, goStrategy, RUST_USE_ARG_TYPES, RUST_PUB_ITEM_TYPES, rustStrategy, JAVA_IMPORT_TYPES, JAVA_EXPORT_TYPES, javaStrategy, STRATEGIES, TreeSitterParser, ParserRegistry, defaultRegistry, LayerViolationCollector, ArchBaselineManager, DEFAULT_THRESHOLDS, FUNCTION_PATTERNS, DECISION_PATTERNS, ComplexityCollector, DEFAULT_THRESHOLDS2, CouplingCollector, ForbiddenImportCollector, ModuleSizeCollector, DepDepthCollector, defaultCollectors, archMatchers;
1749
+ var init_chunk_CE225WRK = __esm({
1750
+ "../core/dist/chunk-CE225WRK.mjs"() {
1739
1751
  "use strict";
1740
1752
  init_dist();
1741
1753
  ArchMetricCategorySchema = z.enum([
@@ -1853,6 +1865,12 @@ var init_chunk_H73442AZ = __esm({
1853
1865
  rust: [".rs"],
1854
1866
  java: [".java"]
1855
1867
  };
1868
+ JS_EXT_FALLBACKS = {
1869
+ ".js": [".ts", ".tsx", ".jsx"],
1870
+ ".jsx": [".tsx"],
1871
+ ".mjs": [".mts"],
1872
+ ".cjs": [".cts"]
1873
+ };
1856
1874
  CircularDepsCollector = class {
1857
1875
  category = "circular-deps";
1858
1876
  getRules(_config, _rootDir) {
@@ -1908,11 +1926,11 @@ var init_chunk_H73442AZ = __esm({
1908
1926
  TypeScriptParser = class {
1909
1927
  name = "typescript";
1910
1928
  extensions = [".ts", ".tsx", ".mts", ".cts"];
1911
- async parseFile(path37) {
1912
- const contentResult = await readFileContent(path37);
1929
+ async parseFile(path42) {
1930
+ const contentResult = await readFileContent(path42);
1913
1931
  if (!contentResult.ok) {
1914
1932
  return Err(
1915
- createParseError("NOT_FOUND", `File not found: ${path37}`, { path: path37 }, [
1933
+ createParseError("NOT_FOUND", `File not found: ${path42}`, { path: path42 }, [
1916
1934
  "Check that the file exists",
1917
1935
  "Verify the path is correct"
1918
1936
  ])
@@ -1922,7 +1940,7 @@ var init_chunk_H73442AZ = __esm({
1922
1940
  const ast = parse(contentResult.value, {
1923
1941
  loc: true,
1924
1942
  range: true,
1925
- jsx: path37.endsWith(".tsx"),
1943
+ jsx: path42.endsWith(".tsx"),
1926
1944
  errorOnUnknownASTType: false
1927
1945
  });
1928
1946
  return Ok({
@@ -1933,7 +1951,7 @@ var init_chunk_H73442AZ = __esm({
1933
1951
  } catch (e) {
1934
1952
  const error = e;
1935
1953
  return Err(
1936
- createParseError("SYNTAX_ERROR", `Failed to parse ${path37}: ${error.message}`, { path: path37 }, [
1954
+ createParseError("SYNTAX_ERROR", `Failed to parse ${path42}: ${error.message}`, { path: path42 }, [
1937
1955
  "Check for syntax errors in the file",
1938
1956
  "Ensure valid TypeScript syntax"
1939
1957
  ])
@@ -2248,11 +2266,11 @@ var init_chunk_H73442AZ = __esm({
2248
2266
  this.extensions = extensions;
2249
2267
  this.strategy = strategy;
2250
2268
  }
2251
- async parseFile(path37) {
2252
- const contentResult = await readFileContent(path37);
2269
+ async parseFile(path42) {
2270
+ const contentResult = await readFileContent(path42);
2253
2271
  if (!contentResult.ok) {
2254
2272
  return Err(
2255
- createParseError("NOT_FOUND", `File not found: ${path37}`, { path: path37 }, [
2273
+ createParseError("NOT_FOUND", `File not found: ${path42}`, { path: path42 }, [
2256
2274
  "Check that the file exists"
2257
2275
  ])
2258
2276
  );
@@ -2268,7 +2286,7 @@ var init_chunk_H73442AZ = __esm({
2268
2286
  } catch (e) {
2269
2287
  const error = e;
2270
2288
  return Err(
2271
- createParseError("SYNTAX_ERROR", `Failed to parse ${path37}: ${error.message}`, { path: path37 }, [
2289
+ createParseError("SYNTAX_ERROR", `Failed to parse ${path42}: ${error.message}`, { path: path42 }, [
2272
2290
  "Check for syntax errors in the file"
2273
2291
  ])
2274
2292
  );
@@ -2439,6 +2457,25 @@ var init_chunk_H73442AZ = __esm({
2439
2457
  return null;
2440
2458
  }
2441
2459
  }
2460
+ /**
2461
+ * Refresh the on-disk baseline with new results.
2462
+ *
2463
+ * Categories present in `results` overwrite their on-disk entry; categories
2464
+ * absent from `results` are preserved as-is. This prevents silent data loss
2465
+ * when a collector returns no results (e.g. transient failure or a filtered
2466
+ * run) and the regenerated file is committed (issue #268).
2467
+ *
2468
+ * Use this from the `--update-baseline` flow instead of `capture()` + `save()`.
2469
+ */
2470
+ update(results, commitHash) {
2471
+ const fresh = this.capture(results, commitHash);
2472
+ const existing = this.load();
2473
+ if (existing) {
2474
+ fresh.metrics = { ...existing.metrics, ...fresh.metrics };
2475
+ }
2476
+ this.save(fresh);
2477
+ return fresh;
2478
+ }
2442
2479
  /**
2443
2480
  * Save an ArchBaseline to disk.
2444
2481
  * Creates parent directories if they do not exist.
@@ -2784,6 +2821,8 @@ var dist_exports = {};
2784
2821
  __export(dist_exports, {
2785
2822
  AGENT_DESCRIPTORS: () => AGENT_DESCRIPTORS,
2786
2823
  AGREEMENT_LINE_GAP: () => AGREEMENT_LINE_GAP,
2824
+ ALLOWED_FIELD_KEYS: () => ALLOWED_FIELD_KEYS,
2825
+ ALL_SOLUTION_CATEGORIES: () => ALL_SOLUTION_CATEGORIES,
2787
2826
  ARCHITECTURE_DESCRIPTOR: () => ARCHITECTURE_DESCRIPTOR,
2788
2827
  AdjustedForecastSchema: () => AdjustedForecastSchema,
2789
2828
  AgentActionEmitter: () => AgentActionEmitter,
@@ -2794,6 +2833,7 @@ __export(dist_exports, {
2794
2833
  ArchDiffResultSchema: () => ArchDiffResultSchema,
2795
2834
  ArchMetricCategorySchema: () => ArchMetricCategorySchema,
2796
2835
  BUG_DETECTION_DESCRIPTOR: () => BUG_DETECTION_DESCRIPTOR,
2836
+ BUG_TRACK_CATEGORIES: () => BUG_TRACK_CATEGORIES,
2797
2837
  BaselineManager: () => BaselineManager,
2798
2838
  BenchmarkRunner: () => BenchmarkRunner,
2799
2839
  BlueprintGenerator: () => BlueprintGenerator,
@@ -2811,6 +2851,7 @@ __export(dist_exports, {
2811
2851
  CircularDepsCollector: () => CircularDepsCollector,
2812
2852
  CompactionPipeline: () => CompactionPipeline,
2813
2853
  ComplexityCollector: () => ComplexityCollector,
2854
+ CompoundLockHeldError: () => CompoundLockHeldError,
2814
2855
  ConfidenceTierSchema: () => ConfidenceTierSchema,
2815
2856
  ConfirmationSchema: () => ConfirmationSchema,
2816
2857
  ConsoleSink: () => ConsoleSink,
@@ -2854,10 +2895,12 @@ __export(dist_exports, {
2854
2895
  HandoffSchema: () => HandoffSchema,
2855
2896
  HarnessStateSchema: () => HarnessStateSchema,
2856
2897
  InteractionTypeSchema: () => InteractionTypeSchema,
2898
+ KNOWLEDGE_TRACK_CATEGORIES: () => KNOWLEDGE_TRACK_CATEGORIES,
2857
2899
  LITELLM_PRICING_URL: () => LITELLM_PRICING_URL,
2858
2900
  LayerViolationCollector: () => LayerViolationCollector,
2859
2901
  LockfilePackageSchema: () => LockfilePackageSchema,
2860
2902
  LockfileSchema: () => LockfileSchema,
2903
+ MOCK_ADAPTER_NAME: () => MOCK_ADAPTER_NAME,
2861
2904
  ManifestSchema: () => ManifestSchema,
2862
2905
  MetricResultSchema: () => MetricResultSchema,
2863
2906
  ModuleSizeCollector: () => ModuleSizeCollector,
@@ -2866,6 +2909,9 @@ __export(dist_exports, {
2866
2909
  NoOpTelemetryAdapter: () => NoOpTelemetryAdapter,
2867
2910
  Ok: () => Ok,
2868
2911
  OpenAICacheAdapter: () => OpenAICacheAdapter,
2912
+ PII_FIELD_DENYLIST: () => PII_FIELD_DENYLIST,
2913
+ PII_LINE_RE: () => PII_LINE_RE,
2914
+ PII_TOKENS: () => PII_TOKENS,
2869
2915
  PatternConfigSchema: () => PatternConfigSchema,
2870
2916
  PredictionEngine: () => PredictionEngine,
2871
2917
  PredictionOptionsSchema: () => PredictionOptionsSchema,
@@ -2873,6 +2919,10 @@ __export(dist_exports, {
2873
2919
  PredictionResultSchema: () => PredictionResultSchema,
2874
2920
  PredictionWarningSchema: () => PredictionWarningSchema,
2875
2921
  ProjectScanner: () => ProjectScanner,
2922
+ PulseAdapterAlreadyRegisteredError: () => PulseAdapterAlreadyRegisteredError,
2923
+ PulseConfigSchema: () => PulseConfigSchema,
2924
+ PulseDbSourceSchema: () => PulseDbSourceSchema,
2925
+ PulseSourcesSchema: () => PulseSourcesSchema,
2876
2926
  QuestionSchema: () => QuestionSchema,
2877
2927
  REQUIRED_SECTIONS: () => REQUIRED_SECTIONS,
2878
2928
  RegressionDetector: () => RegressionDetector,
@@ -2897,6 +2947,7 @@ __export(dist_exports, {
2897
2947
  SharableLayerSchema: () => SharableLayerSchema,
2898
2948
  SharableSecurityRulesSchema: () => SharableSecurityRulesSchema,
2899
2949
  SkillEventSchema: () => SkillEventSchema,
2950
+ SolutionDocFrontmatterSchema: () => SolutionDocFrontmatterSchema,
2900
2951
  SpecImpactEstimateSchema: () => SpecImpactEstimateSchema,
2901
2952
  SpecImpactEstimator: () => SpecImpactEstimator,
2902
2953
  SpecImpactSignalsSchema: () => SpecImpactSignalsSchema,
@@ -2924,6 +2975,7 @@ __export(dist_exports, {
2924
2975
  ViolationHistorySchema: () => ViolationHistorySchema,
2925
2976
  ViolationSchema: () => ViolationSchema,
2926
2977
  ViolationSnapshotSchema: () => ViolationSnapshotSchema,
2978
+ acquireCompoundLock: () => acquireCompoundLock,
2927
2979
  addProvenance: () => addProvenance,
2928
2980
  agentConfigRules: () => agentConfigRules,
2929
2981
  aggregateAdoptionByDay: () => aggregateByDay2,
@@ -2946,6 +2998,9 @@ __export(dist_exports, {
2946
2998
  archiveLearnings: () => archiveLearnings,
2947
2999
  archiveSession: () => archiveSession,
2948
3000
  archiveStream: () => archiveStream,
3001
+ assembleCandidateReport: () => assembleCandidateReport,
3002
+ assembleReport: () => assembleReport,
3003
+ assertSanitized: () => assertSanitized,
2949
3004
  assignFeature: () => assignFeature,
2950
3005
  buildDependencyGraph: () => buildDependencyGraph,
2951
3006
  buildExclusionSet: () => buildExclusionSet,
@@ -2962,15 +3017,18 @@ __export(dist_exports, {
2962
3017
  clearEventHashCache: () => clearEventHashCache,
2963
3018
  clearFailuresCache: () => clearFailuresCache,
2964
3019
  clearLearningsCache: () => clearLearningsCache,
3020
+ clearPulseAdapters: () => clearPulseAdapters,
2965
3021
  clearTaint: () => clearTaint,
2966
3022
  clusterViolations: () => clusterViolations,
2967
3023
  collectEvents: () => collectEvents,
2968
3024
  computeContentHash: () => computeContentHash,
3025
+ computeHotspots: () => computeHotspots,
2969
3026
  computeLexicalSimilarity: () => computeLexicalSimilarity,
2970
3027
  computeLoadPlan: () => computeLoadPlan,
2971
3028
  computeOverallSeverity: () => computeOverallSeverity,
2972
3029
  computeScanExitCode: () => computeScanExitCode,
2973
3030
  computeTrustScores: () => computeTrustScores,
3031
+ computeWindow: () => computeWindow,
2974
3032
  configureFeedback: () => configureFeedback,
2975
3033
  constraintRuleId: () => constraintRuleId,
2976
3034
  contextBudget: () => contextBudget,
@@ -2986,6 +3044,7 @@ __export(dist_exports, {
2986
3044
  createRegionMap: () => createRegionMap,
2987
3045
  createSelfReview: () => createSelfReview,
2988
3046
  createStream: () => createStream,
3047
+ crossReferenceUndocumentedFixes: () => crossReferenceUndocumentedFixes,
2989
3048
  cryptoRules: () => cryptoRules,
2990
3049
  deduplicateCleanupFindings: () => deduplicateCleanupFindings,
2991
3050
  deduplicateFindings: () => deduplicateFindings,
@@ -3016,6 +3075,7 @@ __export(dist_exports, {
3016
3075
  extractBundle: () => extractBundle,
3017
3076
  extractDirectoryScope: () => extractDirectoryScope,
3018
3077
  extractFileReferences: () => extractFileReferences,
3078
+ extractHeadlines: () => extractHeadlines,
3019
3079
  extractIndexEntry: () => extractIndexEntry,
3020
3080
  extractLevel: () => extractLevel,
3021
3081
  extractMarkdownLinks: () => extractMarkdownLinks,
@@ -3027,6 +3087,7 @@ __export(dist_exports, {
3027
3087
  formatFindingBlock: () => formatFindingBlock,
3028
3088
  formatGitHubComment: () => formatGitHubComment,
3029
3089
  formatGitHubSummary: () => formatGitHubSummary,
3090
+ formatIsoWeek: () => formatIsoWeek,
3030
3091
  formatOutline: () => formatOutline,
3031
3092
  formatTerminalOutput: () => formatTerminalOutput,
3032
3093
  fullSync: () => fullSync,
@@ -3042,10 +3103,12 @@ __export(dist_exports, {
3042
3103
  getOutline: () => getOutline,
3043
3104
  getParser: () => getParser,
3044
3105
  getPhaseCategories: () => getPhaseCategories,
3106
+ getPulseAdapter: () => getPulseAdapter,
3045
3107
  getStreamForBranch: () => getStreamForBranch,
3046
3108
  getTaintFilePath: () => getTaintFilePath,
3047
3109
  getTrustLevel: () => getTrustLevel,
3048
3110
  getUpdateNotification: () => getUpdateNotification,
3111
+ gitScan: () => gitScan,
3049
3112
  goRules: () => goRules,
3050
3113
  injectionRules: () => injectionRules,
3051
3114
  insecureDefaultsRules: () => insecureDefaultsRules,
@@ -3053,9 +3116,12 @@ __export(dist_exports, {
3053
3116
  isErr: () => isErr,
3054
3117
  isOk: () => isOk,
3055
3118
  isRegression: () => isRegression,
3119
+ isSanitizedResult: () => isSanitizedResult,
3056
3120
  isSmallSuggestion: () => isSmallSuggestion,
3057
3121
  isUpdateCheckEnabled: () => isUpdateCheckEnabled,
3122
+ isoWeek: () => isoWeek,
3058
3123
  listActiveSessions: () => listActiveSessions,
3124
+ listPulseAdapters: () => listPulseAdapters,
3059
3125
  listStreams: () => listStreams,
3060
3126
  listTaintedSessions: () => listTaintedSessions,
3061
3127
  loadBudgetedLearnings: () => loadBudgetedLearnings,
@@ -3089,6 +3155,7 @@ __export(dist_exports, {
3089
3155
  parseFrontmatter: () => parseFrontmatter2,
3090
3156
  parseHarnessIgnore: () => parseHarnessIgnore,
3091
3157
  parseLiteLLMData: () => parseLiteLLMData,
3158
+ parseLookback: () => parseLookback,
3092
3159
  parseManifest: () => parseManifest,
3093
3160
  parseProtectedRegions: () => parseProtectedRegions,
3094
3161
  parseRoadmap: () => parseRoadmap,
@@ -3109,6 +3176,8 @@ __export(dist_exports, {
3109
3176
  readSessionSection: () => readSessionSection,
3110
3177
  readSessionSections: () => readSessionSections,
3111
3178
  readTaint: () => readTaint,
3179
+ registerMockAdapter: () => registerMockAdapter,
3180
+ registerPulseAdapter: () => registerPulseAdapter,
3112
3181
  removeContributions: () => removeContributions,
3113
3182
  removeProvenance: () => removeProvenance,
3114
3183
  requestMultiplePeerReviews: () => requestMultiplePeerReviews,
@@ -3134,6 +3203,7 @@ __export(dist_exports, {
3134
3203
  runMechanicalGate: () => runMechanicalGate,
3135
3204
  runMultiTurnPipeline: () => runMultiTurnPipeline,
3136
3205
  runPipeline: () => runPipeline,
3206
+ runPulse: () => runPulse,
3137
3207
  runReviewPipeline: () => runReviewPipeline,
3138
3208
  runSecurityAgent: () => runSecurityAgent,
3139
3209
  saveHandoff: () => saveHandoff,
@@ -3145,6 +3215,7 @@ __export(dist_exports, {
3145
3215
  searchSymbols: () => searchSymbols,
3146
3216
  secretRules: () => secretRules,
3147
3217
  securityFindingId: () => securityFindingId,
3218
+ seedFromStrategy: () => seedFromStrategy,
3148
3219
  send: () => send,
3149
3220
  serializeEnvelope: () => serializeEnvelope,
3150
3221
  serializeRoadmap: () => serializeRoadmap,
@@ -3154,6 +3225,7 @@ __export(dist_exports, {
3154
3225
  spawnBackgroundCheck: () => spawnBackgroundCheck,
3155
3226
  splitBundlesByStage: () => splitBundlesByStage,
3156
3227
  stageDomains: () => stageDomains,
3228
+ suggestCategory: () => suggestCategory,
3157
3229
  syncConstraintNodes: () => syncConstraintNodes,
3158
3230
  syncFromExternal: () => syncFromExternal,
3159
3231
  syncRoadmap: () => syncRoadmap,
@@ -3176,164 +3248,188 @@ __export(dist_exports, {
3176
3248
  validateFindings: () => validateFindings,
3177
3249
  validateKnowledgeMap: () => validateKnowledgeMap,
3178
3250
  validatePatternConfig: () => validatePatternConfig,
3251
+ validatePulseConfig: () => validatePulseConfig,
3252
+ validateSolutionsDir: () => validateSolutionsDir,
3179
3253
  violationId: () => violationId,
3180
3254
  weeksUntilThreshold: () => weeksUntilThreshold,
3181
3255
  weightedLinearRegression: () => weightedLinearRegression,
3182
3256
  writeConfig: () => writeConfig,
3183
3257
  writeLockfile: () => writeLockfile,
3258
+ writePulseConfig: () => writePulseConfig,
3184
3259
  writeSessionSummary: () => writeSessionSummary,
3185
3260
  writeTaint: () => writeTaint,
3186
3261
  xssRules: () => xssRules
3187
3262
  });
3263
+ import * as fs from "fs/promises";
3264
+ import * as path from "path";
3265
+ import { z as z2 } from "zod";
3266
+ import * as fs2 from "fs/promises";
3267
+ import * as path2 from "path";
3268
+ import matter from "gray-matter";
3269
+ import { z as z22 } from "zod";
3188
3270
  import { spawn } from "child_process";
3189
3271
  import { existsSync as existsSync2 } from "fs";
3190
- import { join as join4, isAbsolute } from "path";
3272
+ import { join as join32, isAbsolute } from "path";
3191
3273
  import { existsSync as existsSync22 } from "fs";
3192
- import { join as join22 } from "path";
3274
+ import { join as join42 } from "path";
3193
3275
  import { readFileSync as readFileSync2, statSync } from "fs";
3194
3276
  import { glob as glob2 } from "glob";
3195
3277
  import { existsSync as existsSync3 } from "fs";
3196
- import { isAbsolute as isAbsolute2, resolve as resolve3, join as join32 } from "path";
3278
+ import { isAbsolute as isAbsolute2, resolve as resolve3, join as join52 } from "path";
3197
3279
  import { glob as glob22 } from "glob";
3198
3280
  import { existsSync as existsSync4 } from "fs";
3199
- import { basename, dirname as dirname4, join as join42 } from "path";
3281
+ import { basename, dirname as dirname4, join as join6 } from "path";
3200
3282
  import { existsSync as existsSync5 } from "fs";
3201
- import { join as join5 } from "path";
3202
- import { existsSync as existsSync6 } from "fs";
3203
3283
  import { join as join7 } from "path";
3204
- import { join as join6, dirname as dirname22 } from "path";
3284
+ import { existsSync as existsSync6 } from "fs";
3285
+ import { join as join9 } from "path";
3286
+ import { join as join8, dirname as dirname22 } from "path";
3205
3287
  import { glob as glob3 } from "glob";
3206
3288
  import { existsSync as existsSync7 } from "fs";
3207
3289
  import { dirname as dirname32, resolve as resolve22, isAbsolute as isAbsolute3 } from "path";
3208
3290
  import { existsSync as existsSync8 } from "fs";
3209
- import { join as join8 } from "path";
3291
+ import { join as join10 } from "path";
3210
3292
  import { glob as glob4 } from "glob";
3211
3293
  import { existsSync as existsSync9 } from "fs";
3212
- import { join as join9 } from "path";
3294
+ import { join as join11 } from "path";
3213
3295
  import { existsSync as existsSync10 } from "fs";
3214
- import { join as join10 } from "path";
3296
+ import { join as join12 } from "path";
3215
3297
  import { minimatch as minimatch2 } from "minimatch";
3216
3298
  import { basename as basename2 } from "path";
3217
- import { join as join11, basename as basename3 } from "path";
3299
+ import { join as join13, basename as basename3 } from "path";
3218
3300
  import { basename as basename4, dirname as dirname42 } from "path";
3219
- import { z as z2 } from "zod";
3220
- import * as fs from "fs/promises";
3221
- import * as fs2 from "fs/promises";
3222
- import { join as join12, resolve as resolve32 } from "path";
3301
+ import { z as z3 } from "zod";
3302
+ import * as fs3 from "fs/promises";
3303
+ import * as fs4 from "fs/promises";
3304
+ import { join as join14, resolve as resolve32 } from "path";
3223
3305
  import { minimatch as minimatch22 } from "minimatch";
3224
3306
  import { dirname as dirname5, resolve as resolve4 } from "path";
3225
- import { dirname as dirname6, resolve as resolve5 } from "path";
3307
+ import { dirname as dirname6, extname as extname2, resolve as resolve5 } from "path";
3226
3308
  import { minimatch as minimatch3 } from "minimatch";
3227
3309
  import { readdirSync, statSync as statSync2 } from "fs";
3228
- import { join as join13 } from "path";
3229
- import * as fs3 from "fs";
3310
+ import { join as join15 } from "path";
3311
+ import * as fs5 from "fs";
3230
3312
  import { promisify as promisify2 } from "util";
3231
- import { dirname as dirname7, basename as basename5, join as join14 } from "path";
3232
- import { z as z22 } from "zod";
3313
+ import { dirname as dirname7, basename as basename5, join as join16 } from "path";
3314
+ import { z as z4 } from "zod";
3233
3315
  import { readFileSync as readFileSync22, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync11 } from "fs";
3234
- import { join as join15, dirname as dirname8 } from "path";
3316
+ import { join as join17, dirname as dirname8 } from "path";
3235
3317
  import { execFileSync } from "child_process";
3236
- import * as fs4 from "fs";
3237
- import * as path from "path";
3318
+ import * as fs6 from "fs";
3319
+ import * as path3 from "path";
3238
3320
  import { appendFileSync, writeFileSync as writeFileSync22, existsSync as existsSync12, mkdirSync as mkdirSync22 } from "fs";
3239
3321
  import { dirname as dirname9 } from "path";
3240
- import { z as z3 } from "zod";
3322
+ import { z as z5 } from "zod";
3241
3323
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync2, mkdirSync as mkdirSync3, existsSync as existsSync13 } from "fs";
3242
3324
  import { randomBytes as randomBytes2 } from "crypto";
3243
- import { join as join17, dirname as dirname10 } from "path";
3244
- import { z as z4 } from "zod";
3245
- import * as fs5 from "fs";
3246
- import * as path2 from "path";
3247
- import * as fs6 from "fs";
3248
- import * as path3 from "path";
3325
+ import { join as join19, dirname as dirname10 } from "path";
3326
+ import { z as z6 } from "zod";
3249
3327
  import * as fs7 from "fs";
3250
3328
  import * as path4 from "path";
3251
- import { z as z5 } from "zod";
3252
- import * as fs11 from "fs";
3253
- import * as path8 from "path";
3254
- import * as fs10 from "fs";
3255
- import * as path7 from "path";
3256
3329
  import * as fs8 from "fs";
3257
3330
  import * as path5 from "path";
3258
- import { execSync } from "child_process";
3259
- import { z as z6 } from "zod";
3260
3331
  import * as fs9 from "fs";
3261
3332
  import * as path6 from "path";
3262
- import * as fs12 from "fs";
3263
- import * as path9 from "path";
3264
- import * as crypto2 from "crypto";
3333
+ import { z as z7 } from "zod";
3265
3334
  import * as fs13 from "fs";
3266
3335
  import * as path10 from "path";
3336
+ import * as fs12 from "fs";
3337
+ import * as path9 from "path";
3338
+ import * as fs10 from "fs";
3339
+ import * as path7 from "path";
3340
+ import { execSync } from "child_process";
3341
+ import { z as z8 } from "zod";
3342
+ import * as fs11 from "fs";
3343
+ import * as path8 from "path";
3267
3344
  import * as fs14 from "fs";
3268
3345
  import * as path11 from "path";
3269
- import * as crypto3 from "crypto";
3346
+ import * as crypto2 from "crypto";
3270
3347
  import * as fs15 from "fs";
3271
3348
  import * as path12 from "path";
3272
3349
  import * as fs16 from "fs";
3273
3350
  import * as path13 from "path";
3351
+ import * as crypto3 from "crypto";
3274
3352
  import * as fs17 from "fs";
3275
3353
  import * as path14 from "path";
3276
3354
  import * as fs18 from "fs";
3277
3355
  import * as path15 from "path";
3278
3356
  import * as fs19 from "fs";
3279
3357
  import * as path16 from "path";
3280
- import { execSync as execSync2 } from "child_process";
3281
3358
  import * as fs20 from "fs";
3282
3359
  import * as path17 from "path";
3283
3360
  import * as fs21 from "fs";
3284
3361
  import * as path18 from "path";
3362
+ import { execSync as execSync2 } from "child_process";
3285
3363
  import * as fs22 from "fs";
3286
3364
  import * as path19 from "path";
3287
3365
  import * as fs23 from "fs";
3288
3366
  import * as path20 from "path";
3289
- import { z as z7 } from "zod";
3290
- import * as fs25 from "fs/promises";
3291
- import { minimatch as minimatch4 } from "minimatch";
3292
- import { z as z8 } from "zod";
3293
3367
  import * as fs24 from "fs";
3294
3368
  import * as path21 from "path";
3369
+ import * as fs25 from "fs";
3370
+ import * as path22 from "path";
3371
+ import { z as z9 } from "zod";
3372
+ import * as fs27 from "fs/promises";
3373
+ import { minimatch as minimatch4 } from "minimatch";
3374
+ import { z as z10 } from "zod";
3375
+ import * as fs26 from "fs";
3376
+ import * as path23 from "path";
3295
3377
  import { readFileSync as readFileSync222, writeFileSync as writeFileSync15, unlinkSync as unlinkSync2, mkdirSync as mkdirSync14, readdirSync as readdirSync3 } from "fs";
3296
- import { join as join362, dirname as dirname12 } from "path";
3378
+ import { join as join382, dirname as dirname12 } from "path";
3297
3379
  import { createHash as createHash32 } from "crypto";
3298
- import { z as z9 } from "zod";
3380
+ import { z as z11 } from "zod";
3299
3381
  import { readFileSync as readFileSync23, writeFileSync as writeFileSync16, renameSync as renameSync82, mkdirSync as mkdirSync15, existsSync as existsSync332 } from "fs";
3300
3382
  import { execSync as execSync3 } from "child_process";
3301
3383
  import { randomBytes as randomBytes22 } from "crypto";
3302
- import { join as join372, dirname as dirname13 } from "path";
3303
- import * as path22 from "path";
3304
- import * as path23 from "path";
3384
+ import { isAbsolute as isAbsolute4, join as join39, relative as relative32, dirname as dirname13 } from "path";
3305
3385
  import * as path24 from "path";
3306
3386
  import * as path25 from "path";
3307
- import * as fs26 from "fs";
3308
3387
  import * as path26 from "path";
3309
- import * as fs27 from "fs";
3310
3388
  import * as path27 from "path";
3311
3389
  import * as fs28 from "fs";
3312
- import { z as z10 } from "zod";
3313
- import * as fs29 from "fs/promises";
3314
3390
  import * as path28 from "path";
3315
- import * as fs30 from "fs/promises";
3391
+ import * as fs29 from "fs";
3316
3392
  import * as path29 from "path";
3317
- import * as ejs from "ejs";
3318
- import * as fs31 from "fs";
3393
+ import * as fs30 from "fs";
3394
+ import { z as z12 } from "zod";
3395
+ import * as fs31 from "fs/promises";
3319
3396
  import * as path30 from "path";
3320
- import * as os from "os";
3321
- import { spawn as spawn2 } from "child_process";
3322
3397
  import * as fs32 from "fs/promises";
3323
3398
  import * as path31 from "path";
3399
+ import * as ejs from "ejs";
3324
3400
  import * as fs33 from "fs";
3325
3401
  import * as path32 from "path";
3326
- import * as fs34 from "fs";
3402
+ import * as os from "os";
3403
+ import { spawn as spawn2 } from "child_process";
3404
+ import * as fs34 from "fs/promises";
3327
3405
  import * as path33 from "path";
3328
- import * as os2 from "os";
3329
3406
  import * as fs35 from "fs";
3330
3407
  import * as path34 from "path";
3408
+ import * as fs36 from "fs";
3409
+ import * as path35 from "path";
3410
+ import * as os2 from "os";
3331
3411
  import * as fs37 from "fs";
3332
3412
  import * as path36 from "path";
3413
+ import * as fs39 from "fs";
3414
+ import * as path38 from "path";
3333
3415
  import { execFileSync as execFileSync2 } from "child_process";
3334
- import * as fs36 from "fs";
3335
- import * as path35 from "path";
3416
+ import * as fs38 from "fs";
3417
+ import * as path37 from "path";
3336
3418
  import * as crypto4 from "crypto";
3419
+ import * as fs40 from "fs";
3420
+ import * as path39 from "path";
3421
+ import * as fs41 from "fs";
3422
+ import * as fs42 from "fs";
3423
+ import * as path40 from "path";
3424
+ import { readFileSync as readFileSync36 } from "fs";
3425
+ import { fileURLToPath } from "url";
3426
+ import { dirname as dirname18, join as join572 } from "path";
3427
+ import { execFile } from "child_process";
3428
+ import { promisify as promisify22 } from "util";
3429
+ import { execFile as execFile2 } from "child_process";
3430
+ import { promisify as promisify3 } from "util";
3431
+ import * as fs43 from "fs/promises";
3432
+ import * as path41 from "path";
3337
3433
  async function validateFileStructure(projectPath, conventions) {
3338
3434
  const missing = [];
3339
3435
  const unexpected = [];
@@ -3369,15 +3465,15 @@ function validateConfig(data, schema) {
3369
3465
  let message = "Configuration validation failed";
3370
3466
  const suggestions = [];
3371
3467
  if (firstError) {
3372
- const path37 = firstError.path.join(".");
3373
- const pathDisplay = path37 ? ` at "${path37}"` : "";
3468
+ const path42 = firstError.path.join(".");
3469
+ const pathDisplay = path42 ? ` at "${path42}"` : "";
3374
3470
  if (firstError.code === "invalid_type") {
3375
3471
  const received = firstError.received;
3376
3472
  const expected = firstError.expected;
3377
3473
  if (received === "undefined") {
3378
3474
  code = "MISSING_FIELD";
3379
3475
  message = `Missing required field${pathDisplay}: ${firstError.message}`;
3380
- suggestions.push(`Field "${path37}" is required and must be of type "${expected}"`);
3476
+ suggestions.push(`Field "${path42}" is required and must be of type "${expected}"`);
3381
3477
  } else {
3382
3478
  code = "INVALID_TYPE";
3383
3479
  message = `Invalid type${pathDisplay}: ${firstError.message}`;
@@ -3487,6 +3583,82 @@ function validateConventionalCommit(message) {
3487
3583
  issues: []
3488
3584
  });
3489
3585
  }
3586
+ async function validatePulseConfig(cwd) {
3587
+ const configPath = path.join(cwd, "harness.config.json");
3588
+ let raw;
3589
+ try {
3590
+ raw = await fs.readFile(configPath, "utf-8");
3591
+ } catch {
3592
+ return Ok({ present: false, valid: true });
3593
+ }
3594
+ let parsed;
3595
+ try {
3596
+ parsed = JSON.parse(raw);
3597
+ } catch (e) {
3598
+ return Err(
3599
+ createError(
3600
+ "VALIDATION_FAILED",
3601
+ `harness.config.json is not valid JSON: ${e.message}`,
3602
+ {},
3603
+ []
3604
+ )
3605
+ );
3606
+ }
3607
+ if (!("pulse" in parsed)) return Ok({ present: false, valid: true });
3608
+ const result = validateConfig(parsed.pulse, PulseConfigSchema);
3609
+ if (!result.ok) return Err(result.error);
3610
+ return Ok({ present: true, valid: true });
3611
+ }
3612
+ async function* walk2(dir) {
3613
+ let entries;
3614
+ try {
3615
+ entries = await fs2.readdir(dir, { withFileTypes: true });
3616
+ } catch {
3617
+ return;
3618
+ }
3619
+ for (const e of entries) {
3620
+ const p = path2.join(dir, e.name);
3621
+ if (e.isDirectory()) yield* walk2(p);
3622
+ else if (e.isFile() && e.name.endsWith(".md")) yield p;
3623
+ }
3624
+ }
3625
+ async function validateSolutionsDir(cwd) {
3626
+ const root = path2.join(cwd, "docs", "solutions");
3627
+ try {
3628
+ await fs2.stat(root);
3629
+ } catch {
3630
+ return Ok({ filesChecked: 0, issues: [] });
3631
+ }
3632
+ const issues = [];
3633
+ let count = 0;
3634
+ for (const [track, categories] of TRACK_CATEGORIES) {
3635
+ for (const category of categories) {
3636
+ const categoryDir = path2.join(root, track, category);
3637
+ for await (const file of walk2(categoryDir)) {
3638
+ count++;
3639
+ const raw = await fs2.readFile(file, "utf-8");
3640
+ const parsed = matter(raw);
3641
+ const result = validateConfig(parsed.data, SolutionDocFrontmatterSchema);
3642
+ if (!result.ok)
3643
+ issues.push({
3644
+ file: path2.relative(cwd, file).replaceAll("\\", "/"),
3645
+ message: result.error.message
3646
+ });
3647
+ }
3648
+ }
3649
+ }
3650
+ if (issues.length > 0) {
3651
+ return Err(
3652
+ createError(
3653
+ "VALIDATION_FAILED",
3654
+ `${issues.length} solution doc(s) failed frontmatter validation`,
3655
+ { issues },
3656
+ []
3657
+ )
3658
+ );
3659
+ }
3660
+ return Ok({ filesChecked: count, issues: [] });
3661
+ }
3490
3662
  function resolveAgnixBinary(explicit) {
3491
3663
  if (explicit) return existsSync2(explicit) ? explicit : null;
3492
3664
  const fromEnv = process.env[HARNESS_AGNIX_BIN];
@@ -3507,7 +3679,7 @@ function lookupOnPath() {
3507
3679
  function firstExistingIn(dir, candidates) {
3508
3680
  if (!dir) return null;
3509
3681
  for (const name of candidates) {
3510
- const candidate = isAbsolute(dir) ? join4(dir, name) : join4(process.cwd(), dir, name);
3682
+ const candidate = isAbsolute(dir) ? join32(dir, name) : join32(process.cwd(), dir, name);
3511
3683
  if (existsSync2(candidate)) return candidate;
3512
3684
  }
3513
3685
  return null;
@@ -3584,7 +3756,7 @@ function extractDiagnostics(parsed) {
3584
3756
  }
3585
3757
  function normalizeDiagnostic(diag, cwd) {
3586
3758
  const finding = {
3587
- file: normalizeFilePath(readFile10(diag), cwd),
3759
+ file: normalizeFilePath(readFile32(diag), cwd),
3588
3760
  ruleId: readRuleId(diag),
3589
3761
  severity: normalizeSeverity(readSeverity(diag)),
3590
3762
  message: diag.message ?? "agnix diagnostic"
@@ -3592,7 +3764,7 @@ function normalizeDiagnostic(diag, cwd) {
3592
3764
  attachOptionalFields(finding, diag);
3593
3765
  return finding;
3594
3766
  }
3595
- function readFile10(diag) {
3767
+ function readFile32(diag) {
3596
3768
  return diag.file ?? diag.path ?? "";
3597
3769
  }
3598
3770
  function readRuleId(diag) {
@@ -3635,16 +3807,16 @@ function makeFinding(input) {
3635
3807
  if (input.suggestion) finding.suggestion = input.suggestion;
3636
3808
  return finding;
3637
3809
  }
3638
- function readTextSafe(path37) {
3810
+ function readTextSafe(path42) {
3639
3811
  try {
3640
- return readFileSync2(path37, "utf-8");
3812
+ return readFileSync2(path42, "utf-8");
3641
3813
  } catch {
3642
3814
  return null;
3643
3815
  }
3644
3816
  }
3645
- function safeFileSize(path37) {
3817
+ function safeFileSize(path42) {
3646
3818
  try {
3647
- return statSync(path37).size;
3819
+ return statSync(path42).size;
3648
3820
  } catch {
3649
3821
  return null;
3650
3822
  }
@@ -3681,7 +3853,7 @@ function stripQuotes(value) {
3681
3853
  function runClaudeMdRules(cwd) {
3682
3854
  const findings = [];
3683
3855
  for (const name of CONTEXT_FILES) {
3684
- const abs = join22(cwd, name);
3856
+ const abs = join42(cwd, name);
3685
3857
  if (!existsSync22(abs)) continue;
3686
3858
  findings.push(...inspectContextFile(abs, name));
3687
3859
  }
@@ -3828,7 +4000,7 @@ function appendDescriptionFindings(out, rel, description) {
3828
4000
  function runHookRules(cwd) {
3829
4001
  const findings = [];
3830
4002
  for (const rel of SETTINGS_PATHS) {
3831
- const abs = join32(cwd, rel);
4003
+ const abs = join52(cwd, rel);
3832
4004
  if (!existsSync3(abs)) continue;
3833
4005
  const content = readTextSafe(abs);
3834
4006
  if (content === null) continue;
@@ -3944,7 +4116,7 @@ async function runSkillRules(cwd) {
3944
4116
  for (const abs of skillFiles) {
3945
4117
  const rel = relPath(cwd, abs);
3946
4118
  const dirName = basename(dirname4(abs));
3947
- const siblingYaml = join42(dirname4(abs), "skill.yaml");
4119
+ const siblingYaml = join6(dirname4(abs), "skill.yaml");
3948
4120
  if (existsSync4(siblingYaml)) {
3949
4121
  const yamlFields = parseFrontmatterFields(readTextSafe(siblingYaml) ?? "");
3950
4122
  findings.push(...checkSkillMetadata(relPath(cwd, siblingYaml), dirName, yamlFields));
@@ -4050,7 +4222,7 @@ function runMcpRules(cwd) {
4050
4222
  return findings;
4051
4223
  }
4052
4224
  function loadMcpServers(cwd, rel) {
4053
- const abs = join5(cwd, rel);
4225
+ const abs = join7(cwd, rel);
4054
4226
  if (!existsSync5(abs)) return null;
4055
4227
  const content = readTextSafe(abs);
4056
4228
  if (content === null) return null;
@@ -4189,27 +4361,27 @@ function extractSections(content) {
4189
4361
  }
4190
4362
  return sections.map((section) => buildAgentMapSection(section, lines));
4191
4363
  }
4192
- function isExternalLink(path37) {
4193
- return path37.startsWith("http://") || path37.startsWith("https://") || path37.startsWith("#") || path37.startsWith("mailto:");
4364
+ function isExternalLink(path42) {
4365
+ return path42.startsWith("http://") || path42.startsWith("https://") || path42.startsWith("#") || path42.startsWith("mailto:");
4194
4366
  }
4195
4367
  function resolveLinkPath(linkPath, baseDir) {
4196
- return linkPath.startsWith(".") ? join6(baseDir, linkPath) : linkPath;
4368
+ return linkPath.startsWith(".") ? join8(baseDir, linkPath) : linkPath;
4197
4369
  }
4198
- async function validateAgentsMap(path37 = "./AGENTS.md") {
4199
- const contentResult = await readFileContent(path37);
4370
+ async function validateAgentsMap(path42 = "./AGENTS.md") {
4371
+ const contentResult = await readFileContent(path42);
4200
4372
  if (!contentResult.ok) {
4201
4373
  return Err(
4202
4374
  createError(
4203
4375
  "PARSE_ERROR",
4204
4376
  `Failed to read AGENTS.md: ${contentResult.error.message}`,
4205
- { path: path37 },
4377
+ { path: path42 },
4206
4378
  ["Ensure the file exists", "Check file permissions"]
4207
4379
  )
4208
4380
  );
4209
4381
  }
4210
4382
  const content = contentResult.value;
4211
4383
  const sections = extractSections(content);
4212
- const baseDir = dirname22(path37);
4384
+ const baseDir = dirname22(path42);
4213
4385
  const sectionTitles = sections.map((s) => s.title);
4214
4386
  const missingSections = REQUIRED_SECTIONS.filter(
4215
4387
  (required) => !sectionTitles.some((title) => title.toLowerCase().includes(required.toLowerCase()))
@@ -4248,7 +4420,7 @@ async function validateAgentsMap(path37 = "./AGENTS.md") {
4248
4420
  });
4249
4421
  }
4250
4422
  async function runAgentsMdRules(cwd) {
4251
- const abs = join7(cwd, "AGENTS.md");
4423
+ const abs = join9(cwd, "AGENTS.md");
4252
4424
  if (!existsSync6(abs)) return [];
4253
4425
  const result = await validateAgentsMap(abs);
4254
4426
  if (result.ok) return [];
@@ -4305,7 +4477,7 @@ function extractLinkTargets(content) {
4305
4477
  function runSettingsJsonRules(cwd) {
4306
4478
  const findings = [];
4307
4479
  for (const rel of SETTINGS_FILES) {
4308
- const abs = join8(cwd, rel);
4480
+ const abs = join10(cwd, rel);
4309
4481
  if (!existsSync8(abs)) continue;
4310
4482
  const content = readTextSafe(abs);
4311
4483
  if (content === null) continue;
@@ -4381,15 +4553,15 @@ function stripQuotes2(value) {
4381
4553
  return value;
4382
4554
  }
4383
4555
  function skillExists(cwd, slug) {
4384
- if (existsSync9(join9(cwd, "agents", "skills", slug, "SKILL.md"))) return true;
4556
+ if (existsSync9(join11(cwd, "agents", "skills", slug, "SKILL.md"))) return true;
4385
4557
  for (const platform of ["claude-code", "gemini-cli", "codex", "cursor", "shared"]) {
4386
- if (existsSync9(join9(cwd, "agents", "skills", platform, slug, "SKILL.md"))) return true;
4558
+ if (existsSync9(join11(cwd, "agents", "skills", platform, slug, "SKILL.md"))) return true;
4387
4559
  }
4388
4560
  return false;
4389
4561
  }
4390
4562
  function runAgnixTomlRules(cwd) {
4391
4563
  const rel = ".agnix.toml";
4392
- const abs = join10(cwd, rel);
4564
+ const abs = join12(cwd, rel);
4393
4565
  if (!existsSync10(abs)) return [];
4394
4566
  const content = readTextSafe(abs);
4395
4567
  if (content === null) return [];
@@ -4649,8 +4821,8 @@ async function checkDocCoverage(domain, options = {}) {
4649
4821
  );
4650
4822
  }
4651
4823
  }
4652
- function suggestFix(path37, existingFiles) {
4653
- const targetName = basename3(path37).toLowerCase();
4824
+ function suggestFix(path42, existingFiles) {
4825
+ const targetName = basename3(path42).toLowerCase();
4654
4826
  const similar = existingFiles.find((file) => {
4655
4827
  const fileName = basename3(file).toLowerCase();
4656
4828
  return fileName.includes(targetName) || targetName.includes(fileName);
@@ -4658,10 +4830,10 @@ function suggestFix(path37, existingFiles) {
4658
4830
  if (similar) {
4659
4831
  return `Did you mean "${similar}"?`;
4660
4832
  }
4661
- return `Create the file "${path37}" or remove the link`;
4833
+ return `Create the file "${path42}" or remove the link`;
4662
4834
  }
4663
4835
  async function validateKnowledgeMap(rootDir = process.cwd()) {
4664
- const agentsPath = join11(rootDir, "AGENTS.md");
4836
+ const agentsPath = join13(rootDir, "AGENTS.md");
4665
4837
  const agentsResult = await validateAgentsMap(agentsPath);
4666
4838
  if (!agentsResult.ok) {
4667
4839
  return Err(agentsResult.error);
@@ -5016,8 +5188,8 @@ function createBoundaryValidator(schema, name) {
5016
5188
  return Ok(result.data);
5017
5189
  }
5018
5190
  const suggestions = result.error.issues.map((issue) => {
5019
- const path37 = issue.path.join(".");
5020
- return path37 ? `${path37}: ${issue.message}` : issue.message;
5191
+ const path42 = issue.path.join(".");
5192
+ return path42 ? `${path42}: ${issue.message}` : issue.message;
5021
5193
  });
5022
5194
  return Err(
5023
5195
  createError(
@@ -5063,7 +5235,7 @@ function validateBoundaries(boundaries, data) {
5063
5235
  async function writeConfig(filePath, content) {
5064
5236
  try {
5065
5237
  const json = JSON.stringify(content, null, 2) + "\n";
5066
- await fs.writeFile(filePath, json, "utf-8");
5238
+ await fs3.writeFile(filePath, json, "utf-8");
5067
5239
  return Ok(void 0);
5068
5240
  } catch (error) {
5069
5241
  return Err(error instanceof Error ? error : new Error(String(error)));
@@ -5337,7 +5509,7 @@ function deepMergeConstraints(localConfig, bundleConstraints, _existingContribut
5337
5509
  async function readLockfile(lockfilePath) {
5338
5510
  let raw;
5339
5511
  try {
5340
- raw = await fs2.readFile(lockfilePath, "utf-8");
5512
+ raw = await fs4.readFile(lockfilePath, "utf-8");
5341
5513
  } catch (err) {
5342
5514
  if (isNodeError(err) && err.code === "ENOENT") {
5343
5515
  return { ok: true, value: null };
@@ -5640,7 +5812,7 @@ async function resolveEntryPoints(rootDir, explicitEntries) {
5640
5812
  if (explicitEntries && explicitEntries.length > 0) {
5641
5813
  return Ok(explicitEntries.map((e) => resolve32(rootDir, e)));
5642
5814
  }
5643
- const pkgPath = join12(rootDir, "package.json");
5815
+ const pkgPath = join14(rootDir, "package.json");
5644
5816
  if (await fileExists(pkgPath)) {
5645
5817
  const pkgContent = await readFileContent(pkgPath);
5646
5818
  if (pkgContent.ok) {
@@ -5654,7 +5826,7 @@ async function resolveEntryPoints(rootDir, explicitEntries) {
5654
5826
  }
5655
5827
  const conventions = ["src/index.ts", "src/main.ts", "index.ts", "main.ts"];
5656
5828
  for (const conv of conventions) {
5657
- const convPath = join12(rootDir, conv);
5829
+ const convPath = join14(rootDir, conv);
5658
5830
  if (await fileExists(convPath)) {
5659
5831
  return Ok([convPath]);
5660
5832
  }
@@ -5721,22 +5893,22 @@ function extractInlineRefs(content) {
5721
5893
  }
5722
5894
  return refs;
5723
5895
  }
5724
- async function parseDocumentationFile(path37) {
5725
- const contentResult = await readFileContent(path37);
5896
+ async function parseDocumentationFile(path42) {
5897
+ const contentResult = await readFileContent(path42);
5726
5898
  if (!contentResult.ok) {
5727
5899
  return Err(
5728
5900
  createEntropyError(
5729
5901
  "PARSE_ERROR",
5730
- `Failed to read documentation file: ${path37}`,
5731
- { file: path37 },
5902
+ `Failed to read documentation file: ${path42}`,
5903
+ { file: path42 },
5732
5904
  ["Check that the file exists"]
5733
5905
  )
5734
5906
  );
5735
5907
  }
5736
5908
  const content = contentResult.value;
5737
- const type = path37.endsWith(".md") ? "markdown" : "text";
5909
+ const type = path42.endsWith(".md") ? "markdown" : "text";
5738
5910
  return Ok({
5739
- path: path37,
5911
+ path: path42,
5740
5912
  type,
5741
5913
  content,
5742
5914
  codeBlocks: extractCodeBlocks(content),
@@ -6108,19 +6280,30 @@ function resolveImportToFile(importSource, fromFile, snapshot, fileIndex) {
6108
6280
  }
6109
6281
  const hasFile = fileIndex ? (p) => fileIndex.has(p) : (p) => snapshot.files.some((f) => f.path === p);
6110
6282
  const fromDir = dirname6(fromFile);
6111
- let resolved = resolve5(fromDir, importSource);
6112
- if (!resolved.endsWith(".ts") && !resolved.endsWith(".tsx")) {
6113
- const withTs = resolved + ".ts";
6114
- if (hasFile(withTs)) {
6115
- return withTs;
6283
+ const resolved = resolve5(fromDir, importSource);
6284
+ const sourceExt = extname2(resolved);
6285
+ const fallbacks = JS_EXT_FALLBACKS2[sourceExt];
6286
+ if (fallbacks) {
6287
+ const base = resolved.slice(0, -sourceExt.length);
6288
+ for (const ext of fallbacks) {
6289
+ const candidate = base + ext;
6290
+ if (hasFile(candidate)) return candidate;
6116
6291
  }
6117
- const withIndex = resolve5(resolved, "index.ts");
6118
- if (hasFile(withIndex)) {
6119
- return withIndex;
6292
+ for (const indexExt of [".ts", ".tsx", ".jsx"]) {
6293
+ const indexPath2 = resolve5(base, "index" + indexExt);
6294
+ if (hasFile(indexPath2)) return indexPath2;
6120
6295
  }
6121
6296
  }
6122
- if (hasFile(resolved)) {
6123
- return resolved;
6297
+ if (hasFile(resolved)) return resolved;
6298
+ if (!sourceExt) {
6299
+ for (const ext of [".ts", ".tsx"]) {
6300
+ const candidate = resolved + ext;
6301
+ if (hasFile(candidate)) return candidate;
6302
+ }
6303
+ for (const indexExt of [".ts", ".tsx"]) {
6304
+ const indexPath2 = resolve5(resolved, "index" + indexExt);
6305
+ if (hasFile(indexPath2)) return indexPath2;
6306
+ }
6124
6307
  }
6125
6308
  return null;
6126
6309
  }
@@ -6635,13 +6818,13 @@ function dirSize(dirPath) {
6635
6818
  }
6636
6819
  for (const entry of entries) {
6637
6820
  if (entry === "node_modules" || entry === ".git") continue;
6638
- const fullPath = join13(dirPath, entry);
6821
+ const fullPath = join15(dirPath, entry);
6639
6822
  try {
6640
- const stat = statSync2(fullPath);
6641
- if (stat.isDirectory()) {
6823
+ const stat2 = statSync2(fullPath);
6824
+ if (stat2.isDirectory()) {
6642
6825
  total += dirSize(fullPath);
6643
- } else if (stat.isFile()) {
6644
- total += stat.size;
6826
+ } else if (stat2.isFile()) {
6827
+ total += stat2.size;
6645
6828
  }
6646
6829
  } catch {
6647
6830
  continue;
@@ -6655,7 +6838,7 @@ async function detectSizeBudgetViolations(rootDir, config) {
6655
6838
  let packagesChecked = 0;
6656
6839
  for (const [pkgPath, budget] of Object.entries(budgets)) {
6657
6840
  packagesChecked++;
6658
- const distPath = join13(rootDir, pkgPath, "dist");
6841
+ const distPath = join15(rootDir, pkgPath, "dist");
6659
6842
  const currentSize = dirSize(distPath);
6660
6843
  if (budget.warn) {
6661
6844
  const budgetBytes = parseSize(budget.warn);
@@ -6899,7 +7082,7 @@ function previewFix(fix) {
6899
7082
  }
6900
7083
  }
6901
7084
  async function createBackup(filePath, backupDir) {
6902
- const backupPath = join14(backupDir, `${Date.now()}-${basename5(filePath)}`);
7085
+ const backupPath = join16(backupDir, `${Date.now()}-${basename5(filePath)}`);
6903
7086
  try {
6904
7087
  await mkdir22(dirname7(backupPath), { recursive: true });
6905
7088
  await copyFile2(filePath, backupPath);
@@ -6925,7 +7108,7 @@ async function applyDeleteFile(fix, config) {
6925
7108
  }
6926
7109
  async function applyDeleteLines(fix) {
6927
7110
  if (fix.line !== void 0) {
6928
- const content = await readFile42(fix.file, "utf-8");
7111
+ const content = await readFile62(fix.file, "utf-8");
6929
7112
  const lines = content.split("\n");
6930
7113
  lines.splice(fix.line - 1, 1);
6931
7114
  await writeFile32(fix.file, lines.join("\n"));
@@ -6933,13 +7116,13 @@ async function applyDeleteLines(fix) {
6933
7116
  }
6934
7117
  async function applyReplace(fix) {
6935
7118
  if (fix.oldContent && fix.newContent !== void 0) {
6936
- const content = await readFile42(fix.file, "utf-8");
7119
+ const content = await readFile62(fix.file, "utf-8");
6937
7120
  await writeFile32(fix.file, content.replace(fix.oldContent, fix.newContent));
6938
7121
  }
6939
7122
  }
6940
7123
  async function applyInsert(fix) {
6941
7124
  if (fix.line !== void 0 && fix.newContent) {
6942
- const content = await readFile42(fix.file, "utf-8");
7125
+ const content = await readFile62(fix.file, "utf-8");
6943
7126
  const lines = content.split("\n");
6944
7127
  lines.splice(fix.line - 1, 0, fix.newContent);
6945
7128
  await writeFile32(fix.file, lines.join("\n"));
@@ -7274,12 +7457,12 @@ function parseDiffHeader(part) {
7274
7457
  return headerMatch[2];
7275
7458
  }
7276
7459
  function parseDiffPart(part) {
7277
- const path37 = parseDiffHeader(part);
7278
- if (!path37) return null;
7460
+ const path42 = parseDiffHeader(part);
7461
+ if (!path42) return null;
7279
7462
  const additionRegex = /^\+(?!\+\+)/gm;
7280
7463
  const deletionRegex = /^-(?!--)/gm;
7281
7464
  return {
7282
- path: path37,
7465
+ path: path42,
7283
7466
  status: detectFileStatus(part),
7284
7467
  additions: (part.match(additionRegex) || []).length,
7285
7468
  deletions: (part.match(deletionRegex) || []).length
@@ -8064,10 +8247,10 @@ function detectEmergentConstraints(history, options) {
8064
8247
  return { suggestions, totalViolationsAnalyzed, windowWeeks, minOccurrences };
8065
8248
  }
8066
8249
  function streamsDir(projectPath) {
8067
- return path5.join(projectPath, HARNESS_DIR, STREAMS_DIR);
8250
+ return path7.join(projectPath, HARNESS_DIR, STREAMS_DIR);
8068
8251
  }
8069
8252
  function indexPath(projectPath) {
8070
- return path5.join(streamsDir(projectPath), INDEX_FILE);
8253
+ return path7.join(streamsDir(projectPath), INDEX_FILE);
8071
8254
  }
8072
8255
  function validateStreamName(name) {
8073
8256
  if (!STREAM_NAME_REGEX.test(name)) {
@@ -8081,11 +8264,11 @@ function validateStreamName(name) {
8081
8264
  }
8082
8265
  async function loadStreamIndex(projectPath) {
8083
8266
  const idxPath = indexPath(projectPath);
8084
- if (!fs8.existsSync(idxPath)) {
8267
+ if (!fs10.existsSync(idxPath)) {
8085
8268
  return Ok({ ...DEFAULT_STREAM_INDEX, streams: {} });
8086
8269
  }
8087
8270
  try {
8088
- const raw = fs8.readFileSync(idxPath, "utf-8");
8271
+ const raw = fs10.readFileSync(idxPath, "utf-8");
8089
8272
  const parsed = JSON.parse(raw);
8090
8273
  const result = StreamIndexSchema.safeParse(parsed);
8091
8274
  if (!result.success) {
@@ -8103,8 +8286,8 @@ async function loadStreamIndex(projectPath) {
8103
8286
  async function saveStreamIndex(projectPath, index) {
8104
8287
  const dir = streamsDir(projectPath);
8105
8288
  try {
8106
- fs8.mkdirSync(dir, { recursive: true });
8107
- fs8.writeFileSync(indexPath(projectPath), JSON.stringify(index, null, 2));
8289
+ fs10.mkdirSync(dir, { recursive: true });
8290
+ fs10.writeFileSync(indexPath(projectPath), JSON.stringify(index, null, 2));
8108
8291
  return Ok(void 0);
8109
8292
  } catch (error) {
8110
8293
  return Err(
@@ -8143,18 +8326,18 @@ async function resolveStreamPath(projectPath, options) {
8143
8326
  )
8144
8327
  );
8145
8328
  }
8146
- return Ok(path5.join(streamsDir(projectPath), options.stream));
8329
+ return Ok(path7.join(streamsDir(projectPath), options.stream));
8147
8330
  }
8148
8331
  const branch = getCurrentBranch(projectPath);
8149
8332
  if (branch && branch !== "main" && branch !== "master") {
8150
8333
  for (const [name, info] of Object.entries(index.streams)) {
8151
8334
  if (info.branch === branch) {
8152
- return Ok(path5.join(streamsDir(projectPath), name));
8335
+ return Ok(path7.join(streamsDir(projectPath), name));
8153
8336
  }
8154
8337
  }
8155
8338
  }
8156
8339
  if (index.activeStream && index.streams[index.activeStream]) {
8157
- return Ok(path5.join(streamsDir(projectPath), index.activeStream));
8340
+ return Ok(path7.join(streamsDir(projectPath), index.activeStream));
8158
8341
  }
8159
8342
  return Err(
8160
8343
  new Error(
@@ -8182,9 +8365,9 @@ async function createStream(projectPath, name, branch) {
8182
8365
  if (index.streams[name]) {
8183
8366
  return Err(new Error(`Stream '${name}' already exists`));
8184
8367
  }
8185
- const streamPath = path5.join(streamsDir(projectPath), name);
8368
+ const streamPath = path7.join(streamsDir(projectPath), name);
8186
8369
  try {
8187
- fs8.mkdirSync(streamPath, { recursive: true });
8370
+ fs10.mkdirSync(streamPath, { recursive: true });
8188
8371
  } catch (error) {
8189
8372
  return Err(
8190
8373
  new Error(
@@ -8225,12 +8408,12 @@ async function archiveStream(projectPath, name) {
8225
8408
  if (!index.streams[name]) {
8226
8409
  return Err(new Error(`Stream '${name}' not found`));
8227
8410
  }
8228
- const streamPath = path5.join(streamsDir(projectPath), name);
8229
- const archiveDir = path5.join(projectPath, HARNESS_DIR, "archive", "streams");
8411
+ const streamPath = path7.join(streamsDir(projectPath), name);
8412
+ const archiveDir = path7.join(projectPath, HARNESS_DIR, "archive", "streams");
8230
8413
  try {
8231
- fs8.mkdirSync(archiveDir, { recursive: true });
8414
+ fs10.mkdirSync(archiveDir, { recursive: true });
8232
8415
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
8233
- fs8.renameSync(streamPath, path5.join(archiveDir, `${name}-${date}`));
8416
+ fs10.renameSync(streamPath, path7.join(archiveDir, `${name}-${date}`));
8234
8417
  } catch (error) {
8235
8418
  return Err(
8236
8419
  new Error(
@@ -8251,19 +8434,19 @@ function getStreamForBranch(index, branch) {
8251
8434
  return null;
8252
8435
  }
8253
8436
  async function migrateToStreams(projectPath) {
8254
- const harnessDir = path5.join(projectPath, HARNESS_DIR);
8255
- if (fs8.existsSync(indexPath(projectPath))) {
8437
+ const harnessDir = path7.join(projectPath, HARNESS_DIR);
8438
+ if (fs10.existsSync(indexPath(projectPath))) {
8256
8439
  return Ok(void 0);
8257
8440
  }
8258
- const filesToMove = STATE_FILES.filter((f) => fs8.existsSync(path5.join(harnessDir, f)));
8441
+ const filesToMove = STATE_FILES.filter((f) => fs10.existsSync(path7.join(harnessDir, f)));
8259
8442
  if (filesToMove.length === 0) {
8260
8443
  return Ok(void 0);
8261
8444
  }
8262
- const defaultDir = path5.join(streamsDir(projectPath), "default");
8445
+ const defaultDir = path7.join(streamsDir(projectPath), "default");
8263
8446
  try {
8264
- fs8.mkdirSync(defaultDir, { recursive: true });
8447
+ fs10.mkdirSync(defaultDir, { recursive: true });
8265
8448
  for (const file of filesToMove) {
8266
- fs8.renameSync(path5.join(harnessDir, file), path5.join(defaultDir, file));
8449
+ fs10.renameSync(path7.join(harnessDir, file), path7.join(defaultDir, file));
8267
8450
  }
8268
8451
  } catch (error) {
8269
8452
  return Err(
@@ -8293,26 +8476,26 @@ function resolveSessionDir(projectPath, sessionSlug, options) {
8293
8476
  new Error(`Invalid session slug '${sessionSlug}': must not contain path traversal characters`)
8294
8477
  );
8295
8478
  }
8296
- const sessionDir = path6.join(projectPath, HARNESS_DIR, SESSIONS_DIR, sessionSlug);
8479
+ const sessionDir = path8.join(projectPath, HARNESS_DIR, SESSIONS_DIR, sessionSlug);
8297
8480
  if (options?.create) {
8298
- fs9.mkdirSync(sessionDir, { recursive: true });
8481
+ fs11.mkdirSync(sessionDir, { recursive: true });
8299
8482
  }
8300
8483
  return Ok(sessionDir);
8301
8484
  }
8302
8485
  function updateSessionIndex(projectPath, sessionSlug, description) {
8303
- const sessionsDir = path6.join(projectPath, HARNESS_DIR, SESSIONS_DIR);
8304
- fs9.mkdirSync(sessionsDir, { recursive: true });
8305
- const indexPath2 = path6.join(sessionsDir, SESSION_INDEX_FILE);
8486
+ const sessionsDir = path8.join(projectPath, HARNESS_DIR, SESSIONS_DIR);
8487
+ fs11.mkdirSync(sessionsDir, { recursive: true });
8488
+ const indexPath2 = path8.join(sessionsDir, SESSION_INDEX_FILE);
8306
8489
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
8307
8490
  const newLine = `- [${sessionSlug}](${sessionSlug}/summary.md) \u2014 ${description} (${date})`;
8308
- if (!fs9.existsSync(indexPath2)) {
8309
- fs9.writeFileSync(indexPath2, `## Active Sessions
8491
+ if (!fs11.existsSync(indexPath2)) {
8492
+ fs11.writeFileSync(indexPath2, `## Active Sessions
8310
8493
 
8311
8494
  ${newLine}
8312
8495
  `);
8313
8496
  return;
8314
8497
  }
8315
- const content = fs9.readFileSync(indexPath2, "utf-8");
8498
+ const content = fs11.readFileSync(indexPath2, "utf-8");
8316
8499
  const lines = content.split("\n");
8317
8500
  const slugPattern = `- [${sessionSlug}]`;
8318
8501
  const existingIdx = lines.findIndex((l) => l.startsWith(slugPattern));
@@ -8322,7 +8505,7 @@ ${newLine}
8322
8505
  const lastNonEmpty = lines.reduce((last, line, i) => line.trim() !== "" ? i : last, 0);
8323
8506
  lines.splice(lastNonEmpty + 1, 0, newLine);
8324
8507
  }
8325
- fs9.writeFileSync(indexPath2, lines.join("\n"));
8508
+ fs11.writeFileSync(indexPath2, lines.join("\n"));
8326
8509
  }
8327
8510
  function evictIfNeeded(map) {
8328
8511
  if (map.size > MAX_CACHE_ENTRIES) {
@@ -8335,8 +8518,8 @@ async function getStateDir(projectPath, stream, session) {
8335
8518
  const sessionResult = resolveSessionDir(projectPath, session, { create: true });
8336
8519
  return sessionResult;
8337
8520
  }
8338
- const streamsIndexPath = path7.join(projectPath, HARNESS_DIR, "streams", INDEX_FILE);
8339
- const hasStreams = fs10.existsSync(streamsIndexPath);
8521
+ const streamsIndexPath = path9.join(projectPath, HARNESS_DIR, "streams", INDEX_FILE);
8522
+ const hasStreams = fs12.existsSync(streamsIndexPath);
8340
8523
  if (stream || hasStreams) {
8341
8524
  const result = await resolveStreamPath(projectPath, stream ? { stream } : void 0);
8342
8525
  if (result.ok) {
@@ -8346,18 +8529,18 @@ async function getStateDir(projectPath, stream, session) {
8346
8529
  return result;
8347
8530
  }
8348
8531
  }
8349
- return Ok(path7.join(projectPath, HARNESS_DIR));
8532
+ return Ok(path9.join(projectPath, HARNESS_DIR));
8350
8533
  }
8351
8534
  async function loadState(projectPath, stream, session) {
8352
8535
  try {
8353
8536
  const dirResult = await getStateDir(projectPath, stream, session);
8354
8537
  if (!dirResult.ok) return dirResult;
8355
8538
  const stateDir = dirResult.value;
8356
- const statePath = path8.join(stateDir, STATE_FILE);
8357
- if (!fs11.existsSync(statePath)) {
8539
+ const statePath = path10.join(stateDir, STATE_FILE);
8540
+ if (!fs13.existsSync(statePath)) {
8358
8541
  return Ok({ ...DEFAULT_STATE });
8359
8542
  }
8360
- const raw = fs11.readFileSync(statePath, "utf-8");
8543
+ const raw = fs13.readFileSync(statePath, "utf-8");
8361
8544
  const parsed = JSON.parse(raw);
8362
8545
  const result = HarnessStateSchema.safeParse(parsed);
8363
8546
  if (!result.success) {
@@ -8375,11 +8558,11 @@ async function saveState(projectPath, state, stream, session) {
8375
8558
  const dirResult = await getStateDir(projectPath, stream, session);
8376
8559
  if (!dirResult.ok) return dirResult;
8377
8560
  const stateDir = dirResult.value;
8378
- const statePath = path8.join(stateDir, STATE_FILE);
8379
- fs11.mkdirSync(stateDir, { recursive: true });
8561
+ const statePath = path10.join(stateDir, STATE_FILE);
8562
+ fs13.mkdirSync(stateDir, { recursive: true });
8380
8563
  const tmpPath = statePath + ".tmp";
8381
- fs11.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
8382
- fs11.renameSync(tmpPath, statePath);
8564
+ fs13.writeFileSync(tmpPath, JSON.stringify(state, null, 2));
8565
+ fs13.renameSync(tmpPath, statePath);
8383
8566
  return Ok(void 0);
8384
8567
  } catch (error) {
8385
8568
  return Err(
@@ -8465,10 +8648,10 @@ function computeContentHash(text) {
8465
8648
  return crypto2.createHash("sha256").update(text).digest("hex").slice(0, 16);
8466
8649
  }
8467
8650
  function loadContentHashes(stateDir) {
8468
- const hashesPath = path9.join(stateDir, CONTENT_HASHES_FILE);
8469
- if (!fs12.existsSync(hashesPath)) return {};
8651
+ const hashesPath = path11.join(stateDir, CONTENT_HASHES_FILE);
8652
+ if (!fs14.existsSync(hashesPath)) return {};
8470
8653
  try {
8471
- const raw = fs12.readFileSync(hashesPath, "utf-8");
8654
+ const raw = fs14.readFileSync(hashesPath, "utf-8");
8472
8655
  const parsed = JSON.parse(raw);
8473
8656
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
8474
8657
  return parsed;
@@ -8477,15 +8660,15 @@ function loadContentHashes(stateDir) {
8477
8660
  }
8478
8661
  }
8479
8662
  function saveContentHashes(stateDir, index) {
8480
- const hashesPath = path9.join(stateDir, CONTENT_HASHES_FILE);
8663
+ const hashesPath = path11.join(stateDir, CONTENT_HASHES_FILE);
8481
8664
  const tmpPath = hashesPath + ".tmp";
8482
- fs12.writeFileSync(tmpPath, JSON.stringify(index, null, 2) + "\n");
8483
- fs12.renameSync(tmpPath, hashesPath);
8665
+ fs14.writeFileSync(tmpPath, JSON.stringify(index, null, 2) + "\n");
8666
+ fs14.renameSync(tmpPath, hashesPath);
8484
8667
  }
8485
8668
  function rebuildContentHashes(stateDir, learningsFile) {
8486
- const learningsPath = path9.join(stateDir, learningsFile);
8487
- if (!fs12.existsSync(learningsPath)) return {};
8488
- const content = fs12.readFileSync(learningsPath, "utf-8");
8669
+ const learningsPath = path11.join(stateDir, learningsFile);
8670
+ if (!fs14.existsSync(learningsPath)) return {};
8671
+ const content = fs14.readFileSync(learningsPath, "utf-8");
8489
8672
  const lines = content.split("\n");
8490
8673
  const index = {};
8491
8674
  for (let i = 0; i < lines.length; i++) {
@@ -8544,18 +8727,18 @@ async function loadRelevantLearnings(projectPath, skillName, stream, session) {
8544
8727
  const dirResult = await getStateDir(projectPath, stream, session);
8545
8728
  if (!dirResult.ok) return dirResult;
8546
8729
  const stateDir = dirResult.value;
8547
- const learningsPath = path10.join(stateDir, LEARNINGS_FILE);
8548
- if (!fs13.existsSync(learningsPath)) {
8730
+ const learningsPath = path12.join(stateDir, LEARNINGS_FILE);
8731
+ if (!fs15.existsSync(learningsPath)) {
8549
8732
  return Ok([]);
8550
8733
  }
8551
- const stats = fs13.statSync(learningsPath);
8734
+ const stats = fs15.statSync(learningsPath);
8552
8735
  const cacheKey = learningsPath;
8553
8736
  const cached = learningsCacheMap.get(cacheKey);
8554
8737
  let entries;
8555
8738
  if (cached && cached.mtimeMs === stats.mtimeMs) {
8556
8739
  entries = cached.entries;
8557
8740
  } else {
8558
- const content = fs13.readFileSync(learningsPath, "utf-8");
8741
+ const content = fs15.readFileSync(learningsPath, "utf-8");
8559
8742
  const lines = content.split("\n");
8560
8743
  entries = [];
8561
8744
  let currentBlock = [];
@@ -8696,11 +8879,11 @@ function sleep(ms) {
8696
8879
  async function acquireFileLock(lockPath) {
8697
8880
  for (let attempt = 0; attempt < LOCK_RETRIES; attempt++) {
8698
8881
  try {
8699
- const fd = fs14.openSync(
8882
+ const fd = fs16.openSync(
8700
8883
  lockPath,
8701
- fs14.constants.O_CREAT | fs14.constants.O_EXCL | fs14.constants.O_WRONLY
8884
+ fs16.constants.O_CREAT | fs16.constants.O_EXCL | fs16.constants.O_WRONLY
8702
8885
  );
8703
- fs14.closeSync(fd);
8886
+ fs16.closeSync(fd);
8704
8887
  return;
8705
8888
  } catch (err) {
8706
8889
  const isExist = err instanceof Error && "code" in err && err.code === "EEXIST";
@@ -8714,20 +8897,20 @@ async function acquireFileLock(lockPath) {
8714
8897
  }
8715
8898
  function releaseFileLock(lockPath) {
8716
8899
  try {
8717
- fs14.unlinkSync(lockPath);
8900
+ fs16.unlinkSync(lockPath);
8718
8901
  } catch {
8719
8902
  }
8720
8903
  }
8721
8904
  function loadOrRebuildHashes(stateDir, learningsPath) {
8722
- const hashesPath = path11.join(stateDir, CONTENT_HASHES_FILE);
8723
- if (fs14.existsSync(hashesPath)) {
8905
+ const hashesPath = path13.join(stateDir, CONTENT_HASHES_FILE);
8906
+ if (fs16.existsSync(hashesPath)) {
8724
8907
  const hashes = loadContentHashes(stateDir);
8725
- if (Object.keys(hashes).length === 0 && fs14.existsSync(learningsPath)) {
8908
+ if (Object.keys(hashes).length === 0 && fs16.existsSync(learningsPath)) {
8726
8909
  return rebuildContentHashes(stateDir, LEARNINGS_FILE);
8727
8910
  }
8728
8911
  return hashes;
8729
8912
  }
8730
- if (fs14.existsSync(learningsPath)) {
8913
+ if (fs16.existsSync(learningsPath)) {
8731
8914
  return rebuildContentHashes(stateDir, LEARNINGS_FILE);
8732
8915
  }
8733
8916
  return {};
@@ -8751,8 +8934,8 @@ async function appendLearning(projectPath, learning, skillName, outcome, stream,
8751
8934
  const dirResult = await getStateDir(projectPath, stream, session);
8752
8935
  if (!dirResult.ok) return dirResult;
8753
8936
  const stateDir = dirResult.value;
8754
- const learningsPath = path11.join(stateDir, LEARNINGS_FILE);
8755
- fs14.mkdirSync(stateDir, { recursive: true });
8937
+ const learningsPath = path13.join(stateDir, LEARNINGS_FILE);
8938
+ fs16.mkdirSync(stateDir, { recursive: true });
8756
8939
  const lockPath = learningsPath + ".lock";
8757
8940
  await acquireFileLock(lockPath);
8758
8941
  try {
@@ -8782,17 +8965,17 @@ ${bulletLine}
8782
8965
  `;
8783
8966
  let overlapResult;
8784
8967
  let existingLineCount;
8785
- if (!fs14.existsSync(learningsPath)) {
8786
- fs14.writeFileSync(learningsPath, `# Learnings
8968
+ if (!fs16.existsSync(learningsPath)) {
8969
+ fs16.writeFileSync(learningsPath, `# Learnings
8787
8970
  ${entry}`);
8788
8971
  existingLineCount = 1;
8789
8972
  } else {
8790
- const existingContent = fs14.readFileSync(learningsPath, "utf-8");
8973
+ const existingContent = fs16.readFileSync(learningsPath, "utf-8");
8791
8974
  const existingEntries = existingContent.split("\n").filter((line) => /^- \*\*\d{4}-\d{2}-\d{2}/.test(line));
8792
8975
  const overlap = checkOverlap(bulletLine, existingEntries);
8793
8976
  if (overlap.score >= 0.7) overlapResult = overlap;
8794
8977
  existingLineCount = existingContent.split("\n").length;
8795
- fs14.appendFileSync(learningsPath, entry);
8978
+ fs16.appendFileSync(learningsPath, entry);
8796
8979
  }
8797
8980
  const bulletLineNum = existingLineCount + 2;
8798
8981
  contentHashes[contentHash] = { date: timestamp ?? "", line: bulletLineNum };
@@ -8897,11 +9080,11 @@ async function loadIndexEntries(projectPath, skillName, stream, session) {
8897
9080
  const dirResult = await getStateDir(projectPath, stream, session);
8898
9081
  if (!dirResult.ok) return dirResult;
8899
9082
  const stateDir = dirResult.value;
8900
- const learningsPath = path11.join(stateDir, LEARNINGS_FILE);
8901
- if (!fs14.existsSync(learningsPath)) {
9083
+ const learningsPath = path13.join(stateDir, LEARNINGS_FILE);
9084
+ if (!fs16.existsSync(learningsPath)) {
8902
9085
  return Ok([]);
8903
9086
  }
8904
- const content = fs14.readFileSync(learningsPath, "utf-8");
9087
+ const content = fs16.readFileSync(learningsPath, "utf-8");
8905
9088
  const lines = content.split("\n");
8906
9089
  const indexEntries = [];
8907
9090
  let pendingFrontmatter = null;
@@ -8943,16 +9126,16 @@ async function archiveLearnings(projectPath, entries, stream) {
8943
9126
  const dirResult = await getStateDir(projectPath, stream);
8944
9127
  if (!dirResult.ok) return dirResult;
8945
9128
  const stateDir = dirResult.value;
8946
- const archiveDir = path12.join(stateDir, "learnings-archive");
8947
- fs15.mkdirSync(archiveDir, { recursive: true });
9129
+ const archiveDir = path14.join(stateDir, "learnings-archive");
9130
+ fs17.mkdirSync(archiveDir, { recursive: true });
8948
9131
  const now = /* @__PURE__ */ new Date();
8949
9132
  const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
8950
- const archivePath = path12.join(archiveDir, `${yearMonth}.md`);
9133
+ const archivePath = path14.join(archiveDir, `${yearMonth}.md`);
8951
9134
  const archiveContent = entries.join("\n\n") + "\n";
8952
- if (fs15.existsSync(archivePath)) {
8953
- fs15.appendFileSync(archivePath, "\n" + archiveContent);
9135
+ if (fs17.existsSync(archivePath)) {
9136
+ fs17.appendFileSync(archivePath, "\n" + archiveContent);
8954
9137
  } else {
8955
- fs15.writeFileSync(archivePath, `# Learnings Archive
9138
+ fs17.writeFileSync(archivePath, `# Learnings Archive
8956
9139
 
8957
9140
  ${archiveContent}`);
8958
9141
  }
@@ -8970,8 +9153,8 @@ async function pruneLearnings(projectPath, stream) {
8970
9153
  const dirResult = await getStateDir(projectPath, stream);
8971
9154
  if (!dirResult.ok) return dirResult;
8972
9155
  const stateDir = dirResult.value;
8973
- const learningsPath = path12.join(stateDir, LEARNINGS_FILE);
8974
- if (!fs15.existsSync(learningsPath)) {
9156
+ const learningsPath = path14.join(stateDir, LEARNINGS_FILE);
9157
+ if (!fs17.existsSync(learningsPath)) {
8975
9158
  return Ok({ kept: 0, archived: 0, patterns: [] });
8976
9159
  }
8977
9160
  const loadResult = await loadRelevantLearnings(projectPath, void 0, stream);
@@ -9002,7 +9185,7 @@ async function pruneLearnings(projectPath, stream) {
9002
9185
  if (!archiveResult.ok) return archiveResult;
9003
9186
  }
9004
9187
  const newContent = "# Learnings\n\n" + toKeep.join("\n\n") + "\n";
9005
- fs15.writeFileSync(learningsPath, newContent);
9188
+ fs17.writeFileSync(learningsPath, newContent);
9006
9189
  invalidateLearningsCacheEntry(learningsPath);
9007
9190
  return Ok({
9008
9191
  kept: toKeep.length,
@@ -9046,19 +9229,19 @@ async function promoteSessionLearnings(projectPath, sessionSlug, stream) {
9046
9229
  const dirResult = await getStateDir(projectPath, stream);
9047
9230
  if (!dirResult.ok) return dirResult;
9048
9231
  const stateDir = dirResult.value;
9049
- const globalPath = path12.join(stateDir, LEARNINGS_FILE);
9050
- const existingGlobal = fs15.existsSync(globalPath) ? fs15.readFileSync(globalPath, "utf-8") : "";
9232
+ const globalPath = path14.join(stateDir, LEARNINGS_FILE);
9233
+ const existingGlobal = fs17.existsSync(globalPath) ? fs17.readFileSync(globalPath, "utf-8") : "";
9051
9234
  const newEntries = toPromote.filter((entry) => !existingGlobal.includes(entry.trim()));
9052
9235
  if (newEntries.length === 0) {
9053
9236
  return Ok({ promoted: 0, skipped: skipped + toPromote.length });
9054
9237
  }
9055
9238
  const promotedContent = newEntries.join("\n\n") + "\n";
9056
9239
  if (!existingGlobal) {
9057
- fs15.writeFileSync(globalPath, `# Learnings
9240
+ fs17.writeFileSync(globalPath, `# Learnings
9058
9241
 
9059
9242
  ${promotedContent}`);
9060
9243
  } else {
9061
- fs15.appendFileSync(globalPath, "\n\n" + promotedContent);
9244
+ fs17.appendFileSync(globalPath, "\n\n" + promotedContent);
9062
9245
  }
9063
9246
  invalidateLearningsCacheEntry(globalPath);
9064
9247
  return Ok({
@@ -9094,13 +9277,13 @@ async function detectStaleLearnings(projectPath, stream, session) {
9094
9277
  freshCount++;
9095
9278
  continue;
9096
9279
  }
9097
- const resolvedRoot = path13.resolve(projectPath);
9280
+ const resolvedRoot = path15.resolve(projectPath);
9098
9281
  const missing = refs.filter((ref) => {
9099
- const absPath = path13.resolve(projectPath, ref);
9100
- if (!absPath.startsWith(resolvedRoot + path13.sep) && absPath !== resolvedRoot) {
9282
+ const absPath = path15.resolve(projectPath, ref);
9283
+ if (!absPath.startsWith(resolvedRoot + path15.sep) && absPath !== resolvedRoot) {
9101
9284
  return false;
9102
9285
  }
9103
- return !fs16.existsSync(absPath);
9286
+ return !fs18.existsSync(absPath);
9104
9287
  });
9105
9288
  if (missing.length > 0) {
9106
9289
  const idx = extractIndexEntry(entry);
@@ -9135,17 +9318,17 @@ async function appendFailure(projectPath, description, skillName, type, stream,
9135
9318
  const dirResult = await getStateDir(projectPath, stream, session);
9136
9319
  if (!dirResult.ok) return dirResult;
9137
9320
  const stateDir = dirResult.value;
9138
- const failuresPath = path14.join(stateDir, FAILURES_FILE);
9139
- fs17.mkdirSync(stateDir, { recursive: true });
9321
+ const failuresPath = path16.join(stateDir, FAILURES_FILE);
9322
+ fs19.mkdirSync(stateDir, { recursive: true });
9140
9323
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9141
9324
  const entry = `
9142
9325
  - **${timestamp} [skill:${skillName}] [type:${type}]:** ${description}
9143
9326
  `;
9144
- if (!fs17.existsSync(failuresPath)) {
9145
- fs17.writeFileSync(failuresPath, `# Failures
9327
+ if (!fs19.existsSync(failuresPath)) {
9328
+ fs19.writeFileSync(failuresPath, `# Failures
9146
9329
  ${entry}`);
9147
9330
  } else {
9148
- fs17.appendFileSync(failuresPath, entry);
9331
+ fs19.appendFileSync(failuresPath, entry);
9149
9332
  }
9150
9333
  failuresCacheMap.delete(failuresPath);
9151
9334
  return Ok(void 0);
@@ -9162,17 +9345,17 @@ async function loadFailures(projectPath, stream, session) {
9162
9345
  const dirResult = await getStateDir(projectPath, stream, session);
9163
9346
  if (!dirResult.ok) return dirResult;
9164
9347
  const stateDir = dirResult.value;
9165
- const failuresPath = path14.join(stateDir, FAILURES_FILE);
9166
- if (!fs17.existsSync(failuresPath)) {
9348
+ const failuresPath = path16.join(stateDir, FAILURES_FILE);
9349
+ if (!fs19.existsSync(failuresPath)) {
9167
9350
  return Ok([]);
9168
9351
  }
9169
- const stats = fs17.statSync(failuresPath);
9352
+ const stats = fs19.statSync(failuresPath);
9170
9353
  const cacheKey = failuresPath;
9171
9354
  const cached = failuresCacheMap.get(cacheKey);
9172
9355
  if (cached && cached.mtimeMs === stats.mtimeMs) {
9173
9356
  return Ok(cached.entries);
9174
9357
  }
9175
- const content = fs17.readFileSync(failuresPath, "utf-8");
9358
+ const content = fs19.readFileSync(failuresPath, "utf-8");
9176
9359
  const entries = [];
9177
9360
  for (const line of content.split("\n")) {
9178
9361
  const match = line.match(FAILURE_LINE_REGEX);
@@ -9201,20 +9384,20 @@ async function archiveFailures(projectPath, stream, session) {
9201
9384
  const dirResult = await getStateDir(projectPath, stream, session);
9202
9385
  if (!dirResult.ok) return dirResult;
9203
9386
  const stateDir = dirResult.value;
9204
- const failuresPath = path14.join(stateDir, FAILURES_FILE);
9205
- if (!fs17.existsSync(failuresPath)) {
9387
+ const failuresPath = path16.join(stateDir, FAILURES_FILE);
9388
+ if (!fs19.existsSync(failuresPath)) {
9206
9389
  return Ok(void 0);
9207
9390
  }
9208
- const archiveDir = path14.join(stateDir, "archive");
9209
- fs17.mkdirSync(archiveDir, { recursive: true });
9391
+ const archiveDir = path16.join(stateDir, "archive");
9392
+ fs19.mkdirSync(archiveDir, { recursive: true });
9210
9393
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9211
9394
  let archiveName = `failures-${date}.md`;
9212
9395
  let counter = 2;
9213
- while (fs17.existsSync(path14.join(archiveDir, archiveName))) {
9396
+ while (fs19.existsSync(path16.join(archiveDir, archiveName))) {
9214
9397
  archiveName = `failures-${date}-${counter}.md`;
9215
9398
  counter++;
9216
9399
  }
9217
- fs17.renameSync(failuresPath, path14.join(archiveDir, archiveName));
9400
+ fs19.renameSync(failuresPath, path16.join(archiveDir, archiveName));
9218
9401
  failuresCacheMap.delete(failuresPath);
9219
9402
  return Ok(void 0);
9220
9403
  } catch (error) {
@@ -9230,11 +9413,11 @@ async function saveHandoff(projectPath, handoff, stream, session) {
9230
9413
  const dirResult = await getStateDir(projectPath, stream, session);
9231
9414
  if (!dirResult.ok) return dirResult;
9232
9415
  const stateDir = dirResult.value;
9233
- const handoffPath = path15.join(stateDir, HANDOFF_FILE);
9234
- fs18.mkdirSync(stateDir, { recursive: true });
9416
+ const handoffPath = path17.join(stateDir, HANDOFF_FILE);
9417
+ fs20.mkdirSync(stateDir, { recursive: true });
9235
9418
  const tmpPath = handoffPath + ".tmp";
9236
- fs18.writeFileSync(tmpPath, JSON.stringify(handoff, null, 2));
9237
- fs18.renameSync(tmpPath, handoffPath);
9419
+ fs20.writeFileSync(tmpPath, JSON.stringify(handoff, null, 2));
9420
+ fs20.renameSync(tmpPath, handoffPath);
9238
9421
  return Ok(void 0);
9239
9422
  } catch (error) {
9240
9423
  return Err(
@@ -9247,11 +9430,11 @@ async function loadHandoff(projectPath, stream, session) {
9247
9430
  const dirResult = await getStateDir(projectPath, stream, session);
9248
9431
  if (!dirResult.ok) return dirResult;
9249
9432
  const stateDir = dirResult.value;
9250
- const handoffPath = path15.join(stateDir, HANDOFF_FILE);
9251
- if (!fs18.existsSync(handoffPath)) {
9433
+ const handoffPath = path17.join(stateDir, HANDOFF_FILE);
9434
+ if (!fs20.existsSync(handoffPath)) {
9252
9435
  return Ok(null);
9253
9436
  }
9254
- const raw = fs18.readFileSync(handoffPath, "utf-8");
9437
+ const raw = fs20.readFileSync(handoffPath, "utf-8");
9255
9438
  const parsed = JSON.parse(raw);
9256
9439
  const result = HandoffSchema.safeParse(parsed);
9257
9440
  if (!result.success) {
@@ -9265,28 +9448,28 @@ async function loadHandoff(projectPath, stream, session) {
9265
9448
  }
9266
9449
  }
9267
9450
  function loadChecksFromConfig(gateConfigPath) {
9268
- if (!fs19.existsSync(gateConfigPath)) return [];
9269
- const raw = JSON.parse(fs19.readFileSync(gateConfigPath, "utf-8"));
9451
+ if (!fs21.existsSync(gateConfigPath)) return [];
9452
+ const raw = JSON.parse(fs21.readFileSync(gateConfigPath, "utf-8"));
9270
9453
  const config = GateConfigSchema.safeParse(raw);
9271
9454
  if (config.success && config.data.checks) return config.data.checks;
9272
9455
  return [];
9273
9456
  }
9274
9457
  function discoverChecksFromProject(projectPath) {
9275
9458
  const checks = [];
9276
- const packageJsonPath = path16.join(projectPath, "package.json");
9277
- if (fs19.existsSync(packageJsonPath)) {
9278
- const pkg = JSON.parse(fs19.readFileSync(packageJsonPath, "utf-8"));
9459
+ const packageJsonPath = path18.join(projectPath, "package.json");
9460
+ if (fs21.existsSync(packageJsonPath)) {
9461
+ const pkg = JSON.parse(fs21.readFileSync(packageJsonPath, "utf-8"));
9279
9462
  const scripts = pkg.scripts || {};
9280
9463
  if (scripts.test) checks.push({ name: "test", command: "npm test" });
9281
9464
  if (scripts.lint) checks.push({ name: "lint", command: "npm run lint" });
9282
9465
  if (scripts.typecheck) checks.push({ name: "typecheck", command: "npm run typecheck" });
9283
9466
  if (scripts.build) checks.push({ name: "build", command: "npm run build" });
9284
9467
  }
9285
- if (fs19.existsSync(path16.join(projectPath, "go.mod"))) {
9468
+ if (fs21.existsSync(path18.join(projectPath, "go.mod"))) {
9286
9469
  checks.push({ name: "test", command: "go test ./..." });
9287
9470
  checks.push({ name: "build", command: "go build ./..." });
9288
9471
  }
9289
- if (fs19.existsSync(path16.join(projectPath, "pyproject.toml")) || fs19.existsSync(path16.join(projectPath, "setup.py"))) {
9472
+ if (fs21.existsSync(path18.join(projectPath, "pyproject.toml")) || fs21.existsSync(path18.join(projectPath, "setup.py"))) {
9290
9473
  checks.push({ name: "test", command: "python -m pytest" });
9291
9474
  }
9292
9475
  return checks;
@@ -9326,8 +9509,8 @@ function executeCheck(check, projectPath) {
9326
9509
  }
9327
9510
  }
9328
9511
  async function runMechanicalGate(projectPath) {
9329
- const harnessDir = path16.join(projectPath, HARNESS_DIR);
9330
- const gateConfigPath = path16.join(harnessDir, GATE_CONFIG_FILE);
9512
+ const harnessDir = path18.join(projectPath, HARNESS_DIR);
9513
+ const gateConfigPath = path18.join(harnessDir, GATE_CONFIG_FILE);
9331
9514
  try {
9332
9515
  let checks = loadChecksFromConfig(gateConfigPath);
9333
9516
  if (checks.length === 0) {
@@ -9383,9 +9566,9 @@ function writeSessionSummary(projectPath, sessionSlug, data) {
9383
9566
  const dirResult = resolveSessionDir(projectPath, sessionSlug, { create: true });
9384
9567
  if (!dirResult.ok) return dirResult;
9385
9568
  const sessionDir = dirResult.value;
9386
- const summaryPath = path17.join(sessionDir, SUMMARY_FILE);
9569
+ const summaryPath = path19.join(sessionDir, SUMMARY_FILE);
9387
9570
  const content = formatSummary(data);
9388
- fs20.writeFileSync(summaryPath, content);
9571
+ fs22.writeFileSync(summaryPath, content);
9389
9572
  const description = deriveIndexDescription(data);
9390
9573
  updateSessionIndex(projectPath, sessionSlug, description);
9391
9574
  return Ok(void 0);
@@ -9402,11 +9585,11 @@ function loadSessionSummary(projectPath, sessionSlug) {
9402
9585
  const dirResult = resolveSessionDir(projectPath, sessionSlug);
9403
9586
  if (!dirResult.ok) return dirResult;
9404
9587
  const sessionDir = dirResult.value;
9405
- const summaryPath = path17.join(sessionDir, SUMMARY_FILE);
9406
- if (!fs20.existsSync(summaryPath)) {
9588
+ const summaryPath = path19.join(sessionDir, SUMMARY_FILE);
9589
+ if (!fs22.existsSync(summaryPath)) {
9407
9590
  return Ok(null);
9408
9591
  }
9409
- const content = fs20.readFileSync(summaryPath, "utf-8");
9592
+ const content = fs22.readFileSync(summaryPath, "utf-8");
9410
9593
  return Ok(content);
9411
9594
  } catch (error) {
9412
9595
  return Err(
@@ -9418,11 +9601,11 @@ function loadSessionSummary(projectPath, sessionSlug) {
9418
9601
  }
9419
9602
  function listActiveSessions(projectPath) {
9420
9603
  try {
9421
- const indexPath2 = path17.join(projectPath, HARNESS_DIR, SESSIONS_DIR, SESSION_INDEX_FILE);
9422
- if (!fs20.existsSync(indexPath2)) {
9604
+ const indexPath2 = path19.join(projectPath, HARNESS_DIR, SESSIONS_DIR, SESSION_INDEX_FILE);
9605
+ if (!fs22.existsSync(indexPath2)) {
9423
9606
  return Ok(null);
9424
9607
  }
9425
- const content = fs20.readFileSync(indexPath2, "utf-8");
9608
+ const content = fs22.readFileSync(indexPath2, "utf-8");
9426
9609
  return Ok(content);
9427
9610
  } catch (error) {
9428
9611
  return Err(
@@ -9443,12 +9626,12 @@ async function loadSessionState(projectPath, sessionSlug) {
9443
9626
  const dirResult = resolveSessionDir(projectPath, sessionSlug);
9444
9627
  if (!dirResult.ok) return dirResult;
9445
9628
  const sessionDir = dirResult.value;
9446
- const filePath = path18.join(sessionDir, SESSION_STATE_FILE);
9447
- if (!fs21.existsSync(filePath)) {
9629
+ const filePath = path20.join(sessionDir, SESSION_STATE_FILE);
9630
+ if (!fs23.existsSync(filePath)) {
9448
9631
  return Ok(emptySections());
9449
9632
  }
9450
9633
  try {
9451
- const raw = fs21.readFileSync(filePath, "utf-8");
9634
+ const raw = fs23.readFileSync(filePath, "utf-8");
9452
9635
  const parsed = JSON.parse(raw);
9453
9636
  const sections = emptySections();
9454
9637
  for (const name of SESSION_SECTION_NAMES) {
@@ -9469,9 +9652,9 @@ async function saveSessionState(projectPath, sessionSlug, sections) {
9469
9652
  const dirResult = resolveSessionDir(projectPath, sessionSlug, { create: true });
9470
9653
  if (!dirResult.ok) return dirResult;
9471
9654
  const sessionDir = dirResult.value;
9472
- const filePath = path18.join(sessionDir, SESSION_STATE_FILE);
9655
+ const filePath = path20.join(sessionDir, SESSION_STATE_FILE);
9473
9656
  try {
9474
- fs21.writeFileSync(filePath, JSON.stringify(sections, null, 2));
9657
+ fs23.writeFileSync(filePath, JSON.stringify(sections, null, 2));
9475
9658
  return Ok(void 0);
9476
9659
  } catch (error) {
9477
9660
  return Err(
@@ -9527,26 +9710,26 @@ async function archiveSession(projectPath, sessionSlug) {
9527
9710
  const dirResult = resolveSessionDir(projectPath, sessionSlug);
9528
9711
  if (!dirResult.ok) return dirResult;
9529
9712
  const sessionDir = dirResult.value;
9530
- if (!fs22.existsSync(sessionDir)) {
9713
+ if (!fs24.existsSync(sessionDir)) {
9531
9714
  return Err(new Error(`Session '${sessionSlug}' not found at ${sessionDir}`));
9532
9715
  }
9533
- const archiveBase = path19.join(projectPath, HARNESS_DIR, ARCHIVE_DIR, "sessions");
9716
+ const archiveBase = path21.join(projectPath, HARNESS_DIR, ARCHIVE_DIR, "sessions");
9534
9717
  try {
9535
- fs22.mkdirSync(archiveBase, { recursive: true });
9718
+ fs24.mkdirSync(archiveBase, { recursive: true });
9536
9719
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9537
9720
  let archiveName = `${sessionSlug}-${date}`;
9538
9721
  let counter = 1;
9539
- while (fs22.existsSync(path19.join(archiveBase, archiveName))) {
9722
+ while (fs24.existsSync(path21.join(archiveBase, archiveName))) {
9540
9723
  archiveName = `${sessionSlug}-${date}-${counter}`;
9541
9724
  counter++;
9542
9725
  }
9543
- const dest = path19.join(archiveBase, archiveName);
9726
+ const dest = path21.join(archiveBase, archiveName);
9544
9727
  try {
9545
- fs22.renameSync(sessionDir, dest);
9728
+ fs24.renameSync(sessionDir, dest);
9546
9729
  } catch (renameErr) {
9547
9730
  if (renameErr instanceof Error && "code" in renameErr && renameErr.code === "EXDEV") {
9548
- fs22.cpSync(sessionDir, dest, { recursive: true });
9549
- fs22.rmSync(sessionDir, { recursive: true });
9731
+ fs24.cpSync(sessionDir, dest, { recursive: true });
9732
+ fs24.rmSync(sessionDir, { recursive: true });
9550
9733
  } else {
9551
9734
  throw renameErr;
9552
9735
  }
@@ -9568,8 +9751,8 @@ function loadKnownHashes(eventsPath) {
9568
9751
  const cached = knownHashesCache.get(eventsPath);
9569
9752
  if (cached) return cached;
9570
9753
  const hashes = /* @__PURE__ */ new Set();
9571
- if (fs23.existsSync(eventsPath)) {
9572
- const content = fs23.readFileSync(eventsPath, "utf-8");
9754
+ if (fs25.existsSync(eventsPath)) {
9755
+ const content = fs25.readFileSync(eventsPath, "utf-8");
9573
9756
  const lines = content.split("\n").filter((line) => line.trim() !== "");
9574
9757
  for (const line of lines) {
9575
9758
  try {
@@ -9592,8 +9775,8 @@ async function emitEvent(projectPath, event, options) {
9592
9775
  const dirResult = await getStateDir(projectPath, options?.stream, options?.session);
9593
9776
  if (!dirResult.ok) return dirResult;
9594
9777
  const stateDir = dirResult.value;
9595
- const eventsPath = path20.join(stateDir, EVENTS_FILE);
9596
- fs23.mkdirSync(stateDir, { recursive: true });
9778
+ const eventsPath = path22.join(stateDir, EVENTS_FILE);
9779
+ fs25.mkdirSync(stateDir, { recursive: true });
9597
9780
  const contentHash = computeEventHash(event, options?.session);
9598
9781
  const knownHashes = loadKnownHashes(eventsPath);
9599
9782
  if (knownHashes.has(contentHash)) {
@@ -9607,7 +9790,7 @@ async function emitEvent(projectPath, event, options) {
9607
9790
  if (options?.session) {
9608
9791
  fullEvent.session = options.session;
9609
9792
  }
9610
- fs23.appendFileSync(eventsPath, JSON.stringify(fullEvent) + "\n");
9793
+ fs25.appendFileSync(eventsPath, JSON.stringify(fullEvent) + "\n");
9611
9794
  knownHashes.add(contentHash);
9612
9795
  return Ok({ written: true });
9613
9796
  } catch (error) {
@@ -9621,11 +9804,11 @@ async function loadEvents(projectPath, options) {
9621
9804
  const dirResult = await getStateDir(projectPath, options?.stream, options?.session);
9622
9805
  if (!dirResult.ok) return dirResult;
9623
9806
  const stateDir = dirResult.value;
9624
- const eventsPath = path20.join(stateDir, EVENTS_FILE);
9625
- if (!fs23.existsSync(eventsPath)) {
9807
+ const eventsPath = path22.join(stateDir, EVENTS_FILE);
9808
+ if (!fs25.existsSync(eventsPath)) {
9626
9809
  return Ok([]);
9627
9810
  }
9628
- const content = fs23.readFileSync(eventsPath, "utf-8");
9811
+ const content = fs25.readFileSync(eventsPath, "utf-8");
9629
9812
  const lines = content.split("\n").filter((line) => line.trim() !== "");
9630
9813
  const events = [];
9631
9814
  for (const line of lines) {
@@ -9874,11 +10057,11 @@ function nodeSubStacks(allDeps) {
9874
10057
  return found;
9875
10058
  }
9876
10059
  function detectNodeStacks(projectRoot) {
9877
- const pkgJsonPath = path21.join(projectRoot, "package.json");
9878
- if (!fs24.existsSync(pkgJsonPath)) return [];
10060
+ const pkgJsonPath = path23.join(projectRoot, "package.json");
10061
+ if (!fs26.existsSync(pkgJsonPath)) return [];
9879
10062
  const stacks = ["node"];
9880
10063
  try {
9881
- const pkgJson = JSON.parse(fs24.readFileSync(pkgJsonPath, "utf-8"));
10064
+ const pkgJson = JSON.parse(fs26.readFileSync(pkgJsonPath, "utf-8"));
9882
10065
  const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };
9883
10066
  stacks.push(...nodeSubStacks(allDeps));
9884
10067
  } catch {
@@ -9887,10 +10070,10 @@ function detectNodeStacks(projectRoot) {
9887
10070
  }
9888
10071
  function detectStack(projectRoot) {
9889
10072
  const stacks = [...detectNodeStacks(projectRoot)];
9890
- if (fs24.existsSync(path21.join(projectRoot, "go.mod"))) {
10073
+ if (fs26.existsSync(path23.join(projectRoot, "go.mod"))) {
9891
10074
  stacks.push("go");
9892
10075
  }
9893
- const hasPython = fs24.existsSync(path21.join(projectRoot, "requirements.txt")) || fs24.existsSync(path21.join(projectRoot, "pyproject.toml"));
10076
+ const hasPython = fs26.existsSync(path23.join(projectRoot, "requirements.txt")) || fs26.existsSync(path23.join(projectRoot, "pyproject.toml"));
9894
10077
  if (hasPython) {
9895
10078
  stacks.push("python");
9896
10079
  }
@@ -9933,7 +10116,7 @@ function getInjectionPatterns() {
9933
10116
  }
9934
10117
  function getTaintFilePath(projectRoot, sessionId) {
9935
10118
  const id = sessionId || DEFAULT_SESSION_ID;
9936
- return join362(projectRoot, ".harness", `session-taint-${id}.json`);
10119
+ return join382(projectRoot, ".harness", `session-taint-${id}.json`);
9937
10120
  }
9938
10121
  function readTaint(projectRoot, sessionId) {
9939
10122
  const filePath = getTaintFilePath(projectRoot, sessionId);
@@ -10015,14 +10198,14 @@ function clearTaint(projectRoot, sessionId) {
10015
10198
  return 0;
10016
10199
  }
10017
10200
  }
10018
- const harnessDir = join362(projectRoot, ".harness");
10201
+ const harnessDir = join382(projectRoot, ".harness");
10019
10202
  let count = 0;
10020
10203
  try {
10021
10204
  const files = readdirSync3(harnessDir);
10022
10205
  for (const file of files) {
10023
10206
  if (file.startsWith("session-taint-") && file.endsWith(".json")) {
10024
10207
  try {
10025
- unlinkSync2(join362(harnessDir, file));
10208
+ unlinkSync2(join382(harnessDir, file));
10026
10209
  count++;
10027
10210
  } catch {
10028
10211
  }
@@ -10033,7 +10216,7 @@ function clearTaint(projectRoot, sessionId) {
10033
10216
  return count;
10034
10217
  }
10035
10218
  function listTaintedSessions(projectRoot) {
10036
- const harnessDir = join362(projectRoot, ".harness");
10219
+ const harnessDir = join382(projectRoot, ".harness");
10037
10220
  const sessions = [];
10038
10221
  try {
10039
10222
  const files = readdirSync3(harnessDir);
@@ -10105,7 +10288,7 @@ function securityFindingId(finding) {
10105
10288
  }
10106
10289
  async function runValidateCheck(projectRoot, config) {
10107
10290
  const issues = [];
10108
- const agentsPath = path22.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
10291
+ const agentsPath = path24.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
10109
10292
  const result = await validateAgentsMap(agentsPath);
10110
10293
  if (!result.ok) {
10111
10294
  issues.push({ severity: "error", message: result.error.message });
@@ -10162,7 +10345,7 @@ async function runDepsCheck(projectRoot, config) {
10162
10345
  }
10163
10346
  async function runDocsCheck(projectRoot, config) {
10164
10347
  const issues = [];
10165
- const docsDir = path22.join(projectRoot, config.docsDir ?? "docs");
10348
+ const docsDir = path24.join(projectRoot, config.docsDir ?? "docs");
10166
10349
  const entropyConfig = config.entropy || {};
10167
10350
  const result = await checkDocCoverage("project", {
10168
10351
  docsDir,
@@ -10347,7 +10530,7 @@ async function runTraceabilityCheck(projectRoot, config) {
10347
10530
  const issues = [];
10348
10531
  const traceConfig = config.traceability || {};
10349
10532
  if (traceConfig.enabled === false) return issues;
10350
- const graphDir = path22.join(projectRoot, ".harness", "graph");
10533
+ const graphDir = path24.join(projectRoot, ".harness", "graph");
10351
10534
  const store = new GraphStore();
10352
10535
  const loaded = await store.load(graphDir);
10353
10536
  if (!loaded) {
@@ -10525,7 +10708,7 @@ async function runMechanicalChecks(options) {
10525
10708
  };
10526
10709
  if (!skip.includes("validate")) {
10527
10710
  try {
10528
- const agentsPath = path23.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
10711
+ const agentsPath = path25.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
10529
10712
  const result = await validateAgentsMap(agentsPath);
10530
10713
  if (!result.ok) {
10531
10714
  statuses.validate = "fail";
@@ -10562,7 +10745,7 @@ async function runMechanicalChecks(options) {
10562
10745
  statuses.validate = "fail";
10563
10746
  findings.push({
10564
10747
  tool: "validate",
10565
- file: path23.join(projectRoot, "AGENTS.md"),
10748
+ file: path25.join(projectRoot, "AGENTS.md"),
10566
10749
  message: err instanceof Error ? err.message : String(err),
10567
10750
  severity: "error"
10568
10751
  });
@@ -10626,7 +10809,7 @@ async function runMechanicalChecks(options) {
10626
10809
  (async () => {
10627
10810
  const localFindings = [];
10628
10811
  try {
10629
- const docsDir = path23.join(projectRoot, config.docsDir ?? "docs");
10812
+ const docsDir = path25.join(projectRoot, config.docsDir ?? "docs");
10630
10813
  const result = await checkDocCoverage("project", { docsDir });
10631
10814
  if (!result.ok) {
10632
10815
  statuses["check-docs"] = "warn";
@@ -10653,7 +10836,7 @@ async function runMechanicalChecks(options) {
10653
10836
  statuses["check-docs"] = "warn";
10654
10837
  localFindings.push({
10655
10838
  tool: "check-docs",
10656
- file: path23.join(projectRoot, "docs"),
10839
+ file: path25.join(projectRoot, "docs"),
10657
10840
  message: err instanceof Error ? err.message : String(err),
10658
10841
  severity: "warning"
10659
10842
  });
@@ -10750,18 +10933,18 @@ function computeContextBudget(diffLines) {
10750
10933
  return diffLines;
10751
10934
  }
10752
10935
  function isWithinProject(absPath, projectRoot) {
10753
- const resolvedRoot = path24.resolve(projectRoot) + path24.sep;
10754
- const resolvedPath = path24.resolve(absPath);
10755
- return resolvedPath.startsWith(resolvedRoot) || resolvedPath === path24.resolve(projectRoot);
10936
+ const resolvedRoot = path26.resolve(projectRoot) + path26.sep;
10937
+ const resolvedPath = path26.resolve(absPath);
10938
+ return resolvedPath.startsWith(resolvedRoot) || resolvedPath === path26.resolve(projectRoot);
10756
10939
  }
10757
10940
  async function readContextFile(projectRoot, filePath, reason) {
10758
- const absPath = path24.isAbsolute(filePath) ? filePath : path24.join(projectRoot, filePath);
10941
+ const absPath = path26.isAbsolute(filePath) ? filePath : path26.join(projectRoot, filePath);
10759
10942
  if (!isWithinProject(absPath, projectRoot)) return null;
10760
10943
  const result = await readFileContent(absPath);
10761
10944
  if (!result.ok) return null;
10762
10945
  const content = result.value;
10763
10946
  const lines = content.split("\n").length;
10764
- const relPath2 = path24.isAbsolute(filePath) ? relativePosix(projectRoot, filePath) : filePath;
10947
+ const relPath2 = path26.isAbsolute(filePath) ? relativePosix(projectRoot, filePath) : filePath;
10765
10948
  return { path: relPath2, content, reason, lines };
10766
10949
  }
10767
10950
  function extractImportSources2(content) {
@@ -10776,18 +10959,24 @@ function extractImportSources2(content) {
10776
10959
  }
10777
10960
  async function resolveImportPath2(projectRoot, fromFile, importSource) {
10778
10961
  if (!importSource.startsWith(".")) return null;
10779
- const fromDir = path24.dirname(path24.join(projectRoot, fromFile));
10780
- const basePath = path24.resolve(fromDir, importSource);
10962
+ const fromDir = path26.dirname(path26.join(projectRoot, fromFile));
10963
+ const basePath = path26.resolve(fromDir, importSource);
10781
10964
  if (!isWithinProject(basePath, projectRoot)) return null;
10782
10965
  const relBase = relativePosix(projectRoot, basePath);
10783
- const candidates = [
10784
- relBase + ".ts",
10785
- relBase + ".tsx",
10786
- relBase + ".mts",
10787
- path24.join(relBase, "index.ts")
10788
- ];
10966
+ const sourceExt = path26.extname(relBase);
10967
+ const candidates = [];
10968
+ const fallbacks = JS_EXT_FALLBACKS22[sourceExt];
10969
+ if (fallbacks) {
10970
+ const stripped = relBase.slice(0, -sourceExt.length);
10971
+ for (const ext of fallbacks) candidates.push(stripped + ext);
10972
+ candidates.push(path26.join(stripped, "index.ts"));
10973
+ candidates.push(path26.join(stripped, "index.tsx"));
10974
+ candidates.push(path26.join(stripped, "index.jsx"));
10975
+ }
10976
+ candidates.push(relBase + ".ts", relBase + ".tsx", relBase + ".mts");
10977
+ candidates.push(path26.join(relBase, "index.ts"));
10789
10978
  for (const candidate of candidates) {
10790
- const absCandidate = path24.join(projectRoot, candidate);
10979
+ const absCandidate = path26.join(projectRoot, candidate);
10791
10980
  if (await fileExists(absCandidate)) {
10792
10981
  return candidate;
10793
10982
  }
@@ -10795,7 +10984,7 @@ async function resolveImportPath2(projectRoot, fromFile, importSource) {
10795
10984
  return null;
10796
10985
  }
10797
10986
  async function findTestFiles(projectRoot, sourceFile) {
10798
- const baseName = path24.basename(sourceFile, path24.extname(sourceFile));
10987
+ const baseName = path26.basename(sourceFile, path26.extname(sourceFile));
10799
10988
  const pattern = `**/${baseName}.{test,spec}.{ts,tsx,mts}`;
10800
10989
  const results = await findFiles(pattern, projectRoot);
10801
10990
  return results.map((f) => relativePosix(projectRoot, f));
@@ -11563,7 +11752,7 @@ function normalizePath(filePath, projectRoot) {
11563
11752
  let normalized = filePath;
11564
11753
  normalized = normalized.replace(/\\/g, "/");
11565
11754
  const normalizedRoot = projectRoot.replace(/\\/g, "/");
11566
- if (path25.isAbsolute(normalized)) {
11755
+ if (path27.isAbsolute(normalized)) {
11567
11756
  const root = normalizedRoot.endsWith("/") ? normalizedRoot : normalizedRoot + "/";
11568
11757
  if (normalized.startsWith(root)) {
11569
11758
  normalized = normalized.slice(root.length);
@@ -11575,12 +11764,12 @@ function normalizePath(filePath, projectRoot) {
11575
11764
  return normalized;
11576
11765
  }
11577
11766
  function resolveImportPath22(currentFile, importPath) {
11578
- const dir = path25.dirname(currentFile);
11579
- let resolved = path25.join(dir, importPath).replace(/\\/g, "/");
11767
+ const dir = path27.dirname(currentFile);
11768
+ let resolved = path27.join(dir, importPath).replace(/\\/g, "/");
11580
11769
  if (!resolved.match(/\.(ts|tsx|js|jsx)$/)) {
11581
11770
  resolved += ".ts";
11582
11771
  }
11583
- return path25.normalize(resolved).replace(/\\/g, "/");
11772
+ return path27.normalize(resolved).replace(/\\/g, "/");
11584
11773
  }
11585
11774
  function enqueueImports(content, current, visited, queue, maxDepth) {
11586
11775
  const importRegex = /import\s+.*?from\s+['"]([^'"]+)['"]/g;
@@ -11612,7 +11801,7 @@ function isMechanicallyExcluded(finding, exclusionSet, projectRoot) {
11612
11801
  const normalizedFile = normalizePath(finding.file, projectRoot);
11613
11802
  if (exclusionSet.isExcluded(normalizedFile, finding.lineRange)) return true;
11614
11803
  if (exclusionSet.isExcluded(finding.file, finding.lineRange)) return true;
11615
- const absoluteFile = path25.isAbsolute(finding.file) ? finding.file : path25.join(projectRoot, finding.file).replace(/\\/g, "/");
11804
+ const absoluteFile = path27.isAbsolute(finding.file) ? finding.file : path27.join(projectRoot, finding.file).replace(/\\/g, "/");
11616
11805
  return exclusionSet.isExcluded(absoluteFile, finding.lineRange);
11617
11806
  }
11618
11807
  async function validateWithGraph(crossFileRefs, graph) {
@@ -12620,7 +12809,7 @@ function isRegression(from, to) {
12620
12809
  }
12621
12810
  function collectAutopilotStatuses(autopilotPath, featurePlans, allTaskStatuses) {
12622
12811
  try {
12623
- const raw = fs26.readFileSync(autopilotPath, "utf-8");
12812
+ const raw = fs28.readFileSync(autopilotPath, "utf-8");
12624
12813
  const autopilot = JSON.parse(raw);
12625
12814
  if (!autopilot.phases) return;
12626
12815
  const linkedPhases = autopilot.phases.filter(
@@ -12652,10 +12841,10 @@ function inferStatus(feature, projectPath, allFeatures) {
12652
12841
  const featuresWithPlans = allFeatures.filter((f) => f.plans.length > 0);
12653
12842
  const useRootState = featuresWithPlans.length <= 1;
12654
12843
  if (useRootState) {
12655
- const rootStatePath = path26.join(projectPath, ".harness", "state.json");
12656
- if (fs26.existsSync(rootStatePath)) {
12844
+ const rootStatePath = path28.join(projectPath, ".harness", "state.json");
12845
+ if (fs28.existsSync(rootStatePath)) {
12657
12846
  try {
12658
- const raw = fs26.readFileSync(rootStatePath, "utf-8");
12847
+ const raw = fs28.readFileSync(rootStatePath, "utf-8");
12659
12848
  const state = JSON.parse(raw);
12660
12849
  if (state.progress) {
12661
12850
  for (const status of Object.values(state.progress)) {
@@ -12666,14 +12855,14 @@ function inferStatus(feature, projectPath, allFeatures) {
12666
12855
  }
12667
12856
  }
12668
12857
  }
12669
- const sessionsDir = path26.join(projectPath, ".harness", "sessions");
12670
- if (fs26.existsSync(sessionsDir)) {
12858
+ const sessionsDir = path28.join(projectPath, ".harness", "sessions");
12859
+ if (fs28.existsSync(sessionsDir)) {
12671
12860
  try {
12672
- const sessionDirs = fs26.readdirSync(sessionsDir, { withFileTypes: true });
12861
+ const sessionDirs = fs28.readdirSync(sessionsDir, { withFileTypes: true });
12673
12862
  for (const entry of sessionDirs) {
12674
12863
  if (!entry.isDirectory()) continue;
12675
- const autopilotPath = path26.join(sessionsDir, entry.name, "autopilot-state.json");
12676
- if (!fs26.existsSync(autopilotPath)) continue;
12864
+ const autopilotPath = path28.join(sessionsDir, entry.name, "autopilot-state.json");
12865
+ if (!fs28.existsSync(autopilotPath)) continue;
12677
12866
  collectAutopilotStatuses(autopilotPath, feature.plans, allTaskStatuses);
12678
12867
  }
12679
12868
  } catch {
@@ -12788,9 +12977,9 @@ function isValidTrackerShape(tracker) {
12788
12977
  }
12789
12978
  function loadTrackerSyncConfig(projectRoot) {
12790
12979
  try {
12791
- const configPath = path27.join(projectRoot, "harness.config.json");
12792
- if (!fs27.existsSync(configPath)) return null;
12793
- const raw = fs27.readFileSync(configPath, "utf-8");
12980
+ const configPath = path29.join(projectRoot, "harness.config.json");
12981
+ if (!fs29.existsSync(configPath)) return null;
12982
+ const raw = fs29.readFileSync(configPath, "utf-8");
12794
12983
  const config = JSON.parse(raw);
12795
12984
  const tracker = config.roadmap?.tracker;
12796
12985
  if (!isValidTrackerShape(tracker)) return null;
@@ -12817,14 +13006,14 @@ function buildDedupIndex(tickets, config) {
12817
13006
  }
12818
13007
  return index;
12819
13008
  }
12820
- async function resolveExternalId(feature, milestone, adapter, dedupIndex, result) {
13009
+ async function resolveExternalId(feature, milestone, adapter2, dedupIndex, result) {
12821
13010
  if (feature.externalId) return true;
12822
13011
  const existing = dedupIndex.get(feature.name.toLowerCase());
12823
13012
  if (existing) {
12824
13013
  feature.externalId = existing.externalId;
12825
13014
  return true;
12826
13015
  }
12827
- const createResult = await adapter.createTicket(feature, milestone);
13016
+ const createResult = await adapter2.createTicket(feature, milestone);
12828
13017
  if (createResult.ok) {
12829
13018
  feature.externalId = createResult.value.externalId;
12830
13019
  result.created.push(createResult.value);
@@ -12833,7 +13022,7 @@ async function resolveExternalId(feature, milestone, adapter, dedupIndex, result
12833
13022
  }
12834
13023
  return false;
12835
13024
  }
12836
- async function syncToExternal(roadmap, adapter, config, prefetchedTickets) {
13025
+ async function syncToExternal(roadmap, adapter2, config, prefetchedTickets) {
12837
13026
  const result = emptySyncResult();
12838
13027
  const dedupIndex = buildDedupIndex(prefetchedTickets, config);
12839
13028
  for (const milestone of roadmap.milestones) {
@@ -12841,12 +13030,12 @@ async function syncToExternal(roadmap, adapter, config, prefetchedTickets) {
12841
13030
  const shouldUpdate = await resolveExternalId(
12842
13031
  feature,
12843
13032
  milestone.name,
12844
- adapter,
13033
+ adapter2,
12845
13034
  dedupIndex,
12846
13035
  result
12847
13036
  );
12848
13037
  if (!shouldUpdate) continue;
12849
- const updateResult = await adapter.updateTicket(feature.externalId, feature, milestone.name);
13038
+ const updateResult = await adapter2.updateTicket(feature.externalId, feature, milestone.name);
12850
13039
  if (updateResult.ok) {
12851
13040
  result.updated.push(feature.externalId);
12852
13041
  } else {
@@ -12872,7 +13061,7 @@ function applyTicketToFeature(ticketState, feature, config, forceSync, result) {
12872
13061
  if (!forceSync && feature.status === "blocked" && newStatus === "planned") return;
12873
13062
  feature.status = newStatus;
12874
13063
  }
12875
- async function syncFromExternal(roadmap, adapter, config, options, prefetchedTickets) {
13064
+ async function syncFromExternal(roadmap, adapter2, config, options, prefetchedTickets) {
12876
13065
  const result = emptySyncResult();
12877
13066
  const forceSync = options?.forceSync ?? false;
12878
13067
  const featureByExternalId = /* @__PURE__ */ new Map();
@@ -12888,7 +13077,7 @@ async function syncFromExternal(roadmap, adapter, config, options, prefetchedTic
12888
13077
  if (prefetchedTickets) {
12889
13078
  tickets = prefetchedTickets;
12890
13079
  } else {
12891
- const fetchResult = await adapter.fetchAllTickets();
13080
+ const fetchResult = await adapter2.fetchAllTickets();
12892
13081
  if (!fetchResult.ok) {
12893
13082
  result.errors.push({ featureOrId: "*", error: fetchResult.error });
12894
13083
  return result;
@@ -12902,7 +13091,7 @@ async function syncFromExternal(roadmap, adapter, config, options, prefetchedTic
12902
13091
  }
12903
13092
  return result;
12904
13093
  }
12905
- async function fullSync(roadmapPath, adapter, config, options) {
13094
+ async function fullSync(roadmapPath, adapter2, config, options) {
12906
13095
  const previousSync = syncMutex;
12907
13096
  let releaseMutex;
12908
13097
  syncMutex = new Promise((resolve8) => {
@@ -12910,7 +13099,7 @@ async function fullSync(roadmapPath, adapter, config, options) {
12910
13099
  });
12911
13100
  await previousSync;
12912
13101
  try {
12913
- const raw = fs28.readFileSync(roadmapPath, "utf-8");
13102
+ const raw = fs30.readFileSync(roadmapPath, "utf-8");
12914
13103
  const parseResult = parseRoadmap(raw);
12915
13104
  if (!parseResult.ok) {
12916
13105
  return {
@@ -12919,11 +13108,11 @@ async function fullSync(roadmapPath, adapter, config, options) {
12919
13108
  };
12920
13109
  }
12921
13110
  const roadmap = parseResult.value;
12922
- const fetchResult = await adapter.fetchAllTickets();
13111
+ const fetchResult = await adapter2.fetchAllTickets();
12923
13112
  const tickets = fetchResult.ok ? fetchResult.value : void 0;
12924
- const pushResult = await syncToExternal(roadmap, adapter, config, tickets);
12925
- const pullResult = await syncFromExternal(roadmap, adapter, config, options);
12926
- fs28.writeFileSync(roadmapPath, serializeRoadmap(roadmap), "utf-8");
13113
+ const pushResult = await syncToExternal(roadmap, adapter2, config, tickets);
13114
+ const pullResult = await syncFromExternal(roadmap, adapter2, config, options);
13115
+ fs30.writeFileSync(roadmapPath, serializeRoadmap(roadmap), "utf-8");
12927
13116
  return {
12928
13117
  created: pushResult.created,
12929
13118
  updated: pushResult.updated,
@@ -13045,7 +13234,7 @@ function assignFeature(roadmap, feature, assignee, date) {
13045
13234
  }
13046
13235
  function getStatePath() {
13047
13236
  const home = process.env["HOME"] || os.homedir();
13048
- return path30.join(home, ".harness", "update-check.json");
13237
+ return path32.join(home, ".harness", "update-check.json");
13049
13238
  }
13050
13239
  function isUpdateCheckEnabled(configInterval) {
13051
13240
  if (process.env["HARNESS_NO_UPDATE_CHECK"] === "1") return false;
@@ -13058,7 +13247,7 @@ function shouldRunCheck(state, intervalMs) {
13058
13247
  }
13059
13248
  function readCheckState() {
13060
13249
  try {
13061
- const raw = fs31.readFileSync(getStatePath(), "utf-8");
13250
+ const raw = fs33.readFileSync(getStatePath(), "utf-8");
13062
13251
  const parsed = JSON.parse(raw);
13063
13252
  if (typeof parsed === "object" && parsed !== null && "lastCheckTime" in parsed && typeof parsed.lastCheckTime === "number" && "currentVersion" in parsed && typeof parsed.currentVersion === "string") {
13064
13253
  const state = parsed;
@@ -13075,7 +13264,7 @@ function readCheckState() {
13075
13264
  }
13076
13265
  function spawnBackgroundCheck(currentVersion) {
13077
13266
  const statePath = getStatePath();
13078
- const stateDir = path30.dirname(statePath);
13267
+ const stateDir = path32.dirname(statePath);
13079
13268
  const script = `
13080
13269
  const { execSync } = require('child_process');
13081
13270
  const fs = require('fs');
@@ -13318,14 +13507,14 @@ function getModelPrice(model, dataset) {
13318
13507
  return pricing;
13319
13508
  }
13320
13509
  function getCachePath(projectRoot) {
13321
- return path31.join(projectRoot, ".harness", "cache", "pricing.json");
13510
+ return path33.join(projectRoot, ".harness", "cache", "pricing.json");
13322
13511
  }
13323
13512
  function getStalenessMarkerPath(projectRoot) {
13324
- return path31.join(projectRoot, ".harness", "cache", "staleness-marker.json");
13513
+ return path33.join(projectRoot, ".harness", "cache", "staleness-marker.json");
13325
13514
  }
13326
13515
  async function readDiskCache(projectRoot) {
13327
13516
  try {
13328
- const raw = await fs32.readFile(getCachePath(projectRoot), "utf-8");
13517
+ const raw = await fs34.readFile(getCachePath(projectRoot), "utf-8");
13329
13518
  return JSON.parse(raw);
13330
13519
  } catch {
13331
13520
  return null;
@@ -13333,8 +13522,8 @@ async function readDiskCache(projectRoot) {
13333
13522
  }
13334
13523
  async function writeDiskCache(projectRoot, data) {
13335
13524
  const cachePath = getCachePath(projectRoot);
13336
- await fs32.mkdir(path31.dirname(cachePath), { recursive: true });
13337
- await fs32.writeFile(cachePath, JSON.stringify(data, null, 2));
13525
+ await fs34.mkdir(path33.dirname(cachePath), { recursive: true });
13526
+ await fs34.writeFile(cachePath, JSON.stringify(data, null, 2));
13338
13527
  }
13339
13528
  async function fetchFromNetwork() {
13340
13529
  try {
@@ -13361,7 +13550,7 @@ function loadFallbackDataset() {
13361
13550
  async function checkAndWarnStaleness(projectRoot) {
13362
13551
  const markerPath = getStalenessMarkerPath(projectRoot);
13363
13552
  try {
13364
- const raw = await fs32.readFile(markerPath, "utf-8");
13553
+ const raw = await fs34.readFile(markerPath, "utf-8");
13365
13554
  const marker = JSON.parse(raw);
13366
13555
  const firstUse = new Date(marker.firstFallbackUse).getTime();
13367
13556
  const now = Date.now();
@@ -13373,8 +13562,8 @@ async function checkAndWarnStaleness(projectRoot) {
13373
13562
  }
13374
13563
  } catch {
13375
13564
  try {
13376
- await fs32.mkdir(path31.dirname(markerPath), { recursive: true });
13377
- await fs32.writeFile(
13565
+ await fs34.mkdir(path33.dirname(markerPath), { recursive: true });
13566
+ await fs34.writeFile(
13378
13567
  markerPath,
13379
13568
  JSON.stringify({ firstFallbackUse: (/* @__PURE__ */ new Date()).toISOString() })
13380
13569
  );
@@ -13384,7 +13573,7 @@ async function checkAndWarnStaleness(projectRoot) {
13384
13573
  }
13385
13574
  async function clearStalenessMarker(projectRoot) {
13386
13575
  try {
13387
- await fs32.unlink(getStalenessMarkerPath(projectRoot));
13576
+ await fs34.unlink(getStalenessMarkerPath(projectRoot));
13388
13577
  } catch {
13389
13578
  }
13390
13579
  }
@@ -13621,10 +13810,10 @@ function parseLine(line, lineNumber) {
13621
13810
  return record;
13622
13811
  }
13623
13812
  function readCostRecords(projectRoot) {
13624
- const costsFile = path32.join(projectRoot, ".harness", "metrics", "costs.jsonl");
13813
+ const costsFile = path34.join(projectRoot, ".harness", "metrics", "costs.jsonl");
13625
13814
  let raw;
13626
13815
  try {
13627
- raw = fs33.readFileSync(costsFile, "utf-8");
13816
+ raw = fs35.readFileSync(costsFile, "utf-8");
13628
13817
  } catch {
13629
13818
  return [];
13630
13819
  }
@@ -13674,7 +13863,7 @@ function parseCCLine(line, filePath, lineNumber) {
13674
13863
  entry = JSON.parse(line);
13675
13864
  } catch {
13676
13865
  console.warn(
13677
- `[harness usage] Skipping malformed CC JSONL line ${lineNumber} in ${path33.basename(filePath)}`
13866
+ `[harness usage] Skipping malformed CC JSONL line ${lineNumber} in ${path35.basename(filePath)}`
13678
13867
  );
13679
13868
  return null;
13680
13869
  }
@@ -13688,7 +13877,7 @@ function parseCCLine(line, filePath, lineNumber) {
13688
13877
  function readCCFile(filePath) {
13689
13878
  let raw;
13690
13879
  try {
13691
- raw = fs34.readFileSync(filePath, "utf-8");
13880
+ raw = fs36.readFileSync(filePath, "utf-8");
13692
13881
  } catch {
13693
13882
  return [];
13694
13883
  }
@@ -13710,10 +13899,10 @@ function readCCFile(filePath) {
13710
13899
  }
13711
13900
  function parseCCRecords() {
13712
13901
  const homeDir = process.env.HOME ?? os2.homedir();
13713
- const projectsDir = path33.join(homeDir, ".claude", "projects");
13902
+ const projectsDir = path35.join(homeDir, ".claude", "projects");
13714
13903
  let projectDirs;
13715
13904
  try {
13716
- projectDirs = fs34.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path33.join(projectsDir, d.name));
13905
+ projectDirs = fs36.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path35.join(projectsDir, d.name));
13717
13906
  } catch {
13718
13907
  return [];
13719
13908
  }
@@ -13721,7 +13910,7 @@ function parseCCRecords() {
13721
13910
  for (const dir of projectDirs) {
13722
13911
  let files;
13723
13912
  try {
13724
- files = fs34.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path33.join(dir, f));
13913
+ files = fs36.readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => path35.join(dir, f));
13725
13914
  } catch {
13726
13915
  continue;
13727
13916
  }
@@ -13749,10 +13938,10 @@ function parseLine2(line, lineNumber) {
13749
13938
  }
13750
13939
  }
13751
13940
  function readAdoptionRecords(projectRoot) {
13752
- const adoptionFile = path34.join(projectRoot, ".harness", "metrics", "adoption.jsonl");
13941
+ const adoptionFile = path36.join(projectRoot, ".harness", "metrics", "adoption.jsonl");
13753
13942
  let raw;
13754
13943
  try {
13755
- raw = fs35.readFileSync(adoptionFile, "utf-8");
13944
+ raw = fs37.readFileSync(adoptionFile, "utf-8");
13756
13945
  } catch {
13757
13946
  return [];
13758
13947
  }
@@ -13900,25 +14089,25 @@ function resolveStability(contentType) {
13900
14089
  return STABILITY_LOOKUP[contentType] ?? "ephemeral";
13901
14090
  }
13902
14091
  function getOrCreateInstallId(projectRoot) {
13903
- const harnessDir = path35.join(projectRoot, ".harness");
13904
- const installIdFile = path35.join(harnessDir, ".install-id");
14092
+ const harnessDir = path37.join(projectRoot, ".harness");
14093
+ const installIdFile = path37.join(harnessDir, ".install-id");
13905
14094
  const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
13906
14095
  try {
13907
- const existing = fs36.readFileSync(installIdFile, "utf-8").trim();
14096
+ const existing = fs38.readFileSync(installIdFile, "utf-8").trim();
13908
14097
  if (UUID_V4_RE.test(existing)) {
13909
14098
  return existing;
13910
14099
  }
13911
14100
  } catch {
13912
14101
  }
13913
14102
  const id = crypto4.randomUUID();
13914
- fs36.mkdirSync(harnessDir, { recursive: true });
13915
- fs36.writeFileSync(installIdFile, id, { encoding: "utf-8", mode: 384 });
14103
+ fs38.mkdirSync(harnessDir, { recursive: true });
14104
+ fs38.writeFileSync(installIdFile, id, { encoding: "utf-8", mode: 384 });
13916
14105
  return id;
13917
14106
  }
13918
14107
  function parseIdentityFromTelemetryFile(filePath) {
13919
14108
  const identity = {};
13920
14109
  try {
13921
- const raw = fs37.readFileSync(filePath, "utf-8");
14110
+ const raw = fs39.readFileSync(filePath, "utf-8");
13922
14111
  const parsed = JSON.parse(raw);
13923
14112
  const src = parsed?.identity;
13924
14113
  if (!src || typeof src !== "object") return identity;
@@ -13931,7 +14120,7 @@ function parseIdentityFromTelemetryFile(filePath) {
13931
14120
  }
13932
14121
  function readProjectNameFallback(configPath) {
13933
14122
  try {
13934
- const raw = fs37.readFileSync(configPath, "utf-8");
14123
+ const raw = fs39.readFileSync(configPath, "utf-8");
13935
14124
  const config = JSON.parse(raw);
13936
14125
  return typeof config?.name === "string" ? config.name : void 0;
13937
14126
  } catch {
@@ -13952,10 +14141,10 @@ function readGitAliasFallback(cwd) {
13952
14141
  }
13953
14142
  }
13954
14143
  function readIdentity(projectRoot) {
13955
- const filePath = path36.join(projectRoot, ".harness", "telemetry.json");
14144
+ const filePath = path38.join(projectRoot, ".harness", "telemetry.json");
13956
14145
  const identity = parseIdentityFromTelemetryFile(filePath);
13957
14146
  if (!identity.project) {
13958
- const fallbackProject = readProjectNameFallback(path36.join(projectRoot, "harness.config.json"));
14147
+ const fallbackProject = readProjectNameFallback(path38.join(projectRoot, "harness.config.json"));
13959
14148
  if (fallbackProject) identity.project = fallbackProject;
13960
14149
  }
13961
14150
  if (!identity.alias) {
@@ -14025,10 +14214,560 @@ async function send(events, apiKey) {
14025
14214
  }
14026
14215
  }
14027
14216
  }
14028
- var VALID_TYPES, CONVENTIONAL_PATTERN, DEFAULT_AGNIX_TIMEOUT_MS, HARNESS_AGNIX_DISABLE, HARNESS_AGNIX_BIN, CLAUDE_MD_WARN_BYTES, CLAUDE_MD_ERROR_BYTES, CONTEXT_FILES, MIN_DESCRIPTION_LENGTH, SETTINGS_PATHS, KNOWN_HOOK_EVENTS, MCP_SETTINGS_FILES, REQUIRED_SECTIONS, SETTINGS_FILES, KNOWN_AGNIX_TOOLS, DEFAULT_SECTIONS, DEFAULT_RATIOS, NODE_TYPE_TO_CATEGORY, SECTION_LEVEL_MAP, DEFAULT_LEVEL, DEFAULT_BUDGET, DEFAULT_LOADER_CONFIG, LEVEL_FRACTIONS, PHASE_PRIORITIES, ManifestSchema, BundleConstraintsSchema, BundleSchema, ContributionsSchema, LockfilePackageSchema, LockfileSchema, SharableLayerSchema, SharableForbiddenImportSchema, SharableBoundaryConfigSchema, SharableSecurityRulesSchema, VALID_SCOPES, LINE_PATTERN, START_PATTERN, END_PATTERN, CODE_BLOCK_LANGUAGES, DEFAULT_DRIFT_CONFIG, FILE_TYPES, EXPORT_TYPES, CONVENTION_DESCRIPTIONS, RULE_CHECKERS, EntropyAnalyzer, readFile42, writeFile32, unlink22, mkdir22, copyFile2, DEFAULT_FIX_CONFIG, EXPORT_TYPE_KEYWORD, ALWAYS_UNSAFE_TYPES, idCounter, DEAD_CODE_FIX_ACTIONS, MustExportRuleSchema, MustExportDefaultRuleSchema, NoExportRuleSchema, MustImportRuleSchema, NoImportRuleSchema, NamingRuleSchema, MaxExportsRuleSchema, MaxLinesRuleSchema, RequireJSDocRuleSchema, RuleSchema, ConfigPatternSchema, PatternConfigSchema, DriftConfigSchema, DeadCodeConfigSchema, EntropyConfigSchema, BaselineManager, BenchmarkRunner, RegressionDetector, SKIP_DIRS, SOURCE_EXTENSIONS, FUNCTION_DECL_RE, CONST_DECL_RE, CriticalPathResolver, NoOpTelemetryAdapter, NoOpExecutor, ConsoleSink, feedbackConfig, ChecklistBuilder, AgentActionEmitter, globalEmitter, FileSink, NoOpSink, CategorySnapshotSchema, TimelineSnapshotSchema, TimelineFileSchema, TrendLineSchema, TrendResultSchema, DEFAULT_STABILITY_THRESHOLDS, ALL_CATEGORIES, TimelineManager, ConfidenceTierSchema, RegressionResultSchema, DirectionSchema, CategoryForecastSchema, SpecImpactSignalsSchema, SpecImpactEstimateSchema, ContributingFeatureSchema, AdjustedForecastSchema, PredictionWarningSchema, StabilityForecastSchema, PredictionResultSchema, PredictionOptionsSchema, VALID_STATUSES, EM_DASH, VALID_PRIORITIES, ALL_CATEGORIES2, DIRECTION_THRESHOLD, PredictionEngine, DEFAULT_COEFFICIENTS, SpecImpactEstimator, EMPTY_HISTORY, ViolationHistoryManager, NORMALIZERS, MAX_SAMPLES, DEFAULT_WINDOW_WEEKS, DEFAULT_MIN_OCCURRENCES, FailureEntrySchema, HandoffSchema, GateCheckSchema, GateResultSchema, GateConfigSchema, HarnessStateSchema, DEFAULT_STATE, StreamInfoSchema, StreamIndexSchema, DEFAULT_STREAM_INDEX, HARNESS_DIR, STATE_FILE, LEARNINGS_FILE, FAILURES_FILE, HANDOFF_FILE, GATE_CONFIG_FILE, INDEX_FILE, SESSIONS_DIR, SESSION_INDEX_FILE, SUMMARY_FILE, SESSION_STATE_FILE, ARCHIVE_DIR, CONTENT_HASHES_FILE, EVENTS_FILE, STREAMS_DIR, STREAM_NAME_REGEX, branchCache, BRANCH_CACHE_TTL_MS, STATE_FILES, MAX_CACHE_ENTRIES, learningsCacheMap, WEIGHTS, LOCK_RETRIES, LOCK_BACKOFFS, PROMOTABLE_OUTCOMES, failuresCacheMap, FAILURE_LINE_REGEX, SAFE_GATE_COMMAND, SkillEventSchema, knownHashesCache, EVENT_FORMATTERS, RuleRegistry, DEFAULT_SECURITY_CONFIG, RuleOverrideSchema, SecurityConfigSchema, secretRules, injectionRules, xssRules, cryptoRules, pathTraversalRules, networkRules, deserializationRules, agentConfigRules, mcpRules, insecureDefaultsRules, sharpEdgesRules, nodeRules, expressRules, reactRules, goRules, SecurityScanner, hiddenUnicodePatterns, reRolingPatterns, permissionEscalationPatterns, encodedPayloadPatterns, indirectInjectionPatterns, contextManipulationPatterns, socialEngineeringPatterns, suspiciousPatterns, ALL_PATTERNS, DESTRUCTIVE_BASH, TAINT_DURATION_MS, DEFAULT_SESSION_ID, SecurityCategorySnapshotSchema, SupplyChainSnapshotSchema, SecurityTimelineSnapshotSchema, FindingLifecycleSchema, SecurityTimelineFileSchema, DirectionSchema2, SecurityTrendLineSchema, TrendAttributionSchema, SecurityTrendResultSchema, TimeToFixStatsSchema, TimeToFixResultSchema, EMPTY_SUPPLY_CHAIN, SecurityTimelineManager, ALL_CHECKS, STATUS_ICONS, CINotifier, ExclusionSet, PREFIX_PATTERNS, TEST_FILE_PATTERN, MD_FILE_PATTERN, ALL_DOMAINS, SECURITY_PATTERNS, SEVERITY_RANK, SEVERITY_ORDER, SEVERITY_LABELS, VALIDATED_BY_RANK, VALIDATION_SCORES, DOMAIN_BASELINES, FACTOR_WEIGHTS, EVIDENCE_SATURATION, CORROBORATED_AGREEMENT, STANDALONE_AGREEMENT, AGREEMENT_LINE_GAP, COMPLIANCE_DESCRIPTOR, EXPORT_RE, BUG_DETECTION_DESCRIPTOR, SECURITY_DESCRIPTOR, EVAL_PATTERN, SECRET_PATTERNS, SQL_CONCAT_PATTERN, SHELL_EXEC_PATTERN, ARCHITECTURE_DESCRIPTOR, LARGE_FILE_THRESHOLD, VIOLATION_FILE_RE, LEARNINGS_DESCRIPTOR, RELEVANCE_THRESHOLD, AGENT_DESCRIPTORS, AGENT_RUNNERS, DOWNGRADE_MAP, DEFAULT_PROVIDER_TIERS, SMALL_SUGGESTION_LINE_LIMIT, FILE_LINE_RANGE_PATTERN, FILE_LINE_PATTERN, FILE_ONLY_PATTERN, SECURITY_SENSITIVE_PATH, MIGRATION_PATH, TEST_PATH, CONFIG_PATH, STAGE_DOMAINS, EM_DASH2, STATUS_RANK, RETRY_DEFAULTS, GitHubIssuesSyncAdapter, syncMutex, PRIORITY_RANK, POSITION_WEIGHT, DEPENDENTS_WEIGHT, AFFINITY_WEIGHT, InteractionTypeSchema, QuestionSchema, ConfirmationSchema, TransitionSchema, EmitInteractionInputSchema, ProjectScanner, SHELL_TEMPLATE, STYLES, SCRIPTS, MockLLMService, llmService, ContentPipeline, BlueprintGenerator, TOKENS_PER_MILLION, fallback_default, LITELLM_PRICING_URL, CACHE_TTL_MS, STALENESS_WARNING_DAYS, MICRODOLLARS_PER_DOLLAR, TOKENS_PER_MILLION2, StructuralStrategy, DEFAULT_TOKEN_BUDGET, CHARS_PER_TOKEN, TRUNCATION_MARKER, TruncationStrategy, CompactionPipeline, STABILITY_LOOKUP, TIER_ORDER, AnthropicCacheAdapter, TIER_ORDER2, OpenAICacheAdapter, TIER_ORDER3, CACHED_CONTENT_MARKER, GeminiCacheAdapter, VERSION, POSTHOG_BATCH_URL, MAX_ATTEMPTS, TIMEOUT_MS;
14217
+ function acquireCompoundLock(category, opts = {}) {
14218
+ if (!KNOWN_CATEGORIES.has(category)) {
14219
+ throw new Error(
14220
+ `Unknown category "${category}". Must be one of: ${[...KNOWN_CATEGORIES].join(", ")}`
14221
+ );
14222
+ }
14223
+ const cwd = opts.cwd ?? process.cwd();
14224
+ const lockDir = path39.join(cwd, ".harness", "locks");
14225
+ fs40.mkdirSync(lockDir, { recursive: true });
14226
+ const lockPath = path39.join(lockDir, `compound-${category}.lock`);
14227
+ let fd;
14228
+ try {
14229
+ fd = fs40.openSync(lockPath, "wx");
14230
+ } catch (e) {
14231
+ const err = e;
14232
+ if (err.code === "EEXIST") {
14233
+ const holderPid = readHolderPid(lockPath);
14234
+ throw new CompoundLockHeldError(category, holderPid, lockPath);
14235
+ }
14236
+ throw err;
14237
+ }
14238
+ fs40.writeSync(fd, String(process.pid));
14239
+ fs40.closeSync(fd);
14240
+ let released = false;
14241
+ const release = () => {
14242
+ if (released) return;
14243
+ released = true;
14244
+ try {
14245
+ fs40.unlinkSync(lockPath);
14246
+ } catch {
14247
+ }
14248
+ process.removeListener("exit", onExit);
14249
+ process.removeListener("SIGINT", onSignal);
14250
+ process.removeListener("SIGTERM", onSignal);
14251
+ process.removeListener("uncaughtException", onUncaught);
14252
+ };
14253
+ const onExit = () => release();
14254
+ const onSignal = (sig) => {
14255
+ release();
14256
+ process.kill(process.pid, sig);
14257
+ };
14258
+ const onUncaught = (err) => {
14259
+ release();
14260
+ console.error(err && err.stack ? err.stack : err);
14261
+ process.exit(1);
14262
+ };
14263
+ process.once("exit", onExit);
14264
+ process.once("SIGINT", onSignal);
14265
+ process.once("SIGTERM", onSignal);
14266
+ process.once("uncaughtException", onUncaught);
14267
+ return { category, lockPath, release };
14268
+ }
14269
+ function readHolderPid(lockPath) {
14270
+ try {
14271
+ const raw = fs40.readFileSync(lockPath, "utf-8").trim();
14272
+ const n = Number.parseInt(raw, 10);
14273
+ return Number.isFinite(n) ? n : -1;
14274
+ } catch {
14275
+ return -1;
14276
+ }
14277
+ }
14278
+ function isSanitizedResult(value) {
14279
+ if (!value || typeof value !== "object") return false;
14280
+ const v = value;
14281
+ if (!v.fields || typeof v.fields !== "object") return false;
14282
+ for (const k of Object.keys(v.fields)) {
14283
+ if (!ALLOWED_SET.has(k)) return false;
14284
+ if (PII_FIELD_DENYLIST.test(k)) return false;
14285
+ }
14286
+ if (!v.distributions || typeof v.distributions !== "object") return false;
14287
+ return true;
14288
+ }
14289
+ function assertSanitized(value) {
14290
+ if (!isSanitizedResult(value)) {
14291
+ throw new Error("PII boundary violated: result is not a SanitizedResult");
14292
+ }
14293
+ }
14294
+ function writePulseConfig(config, opts) {
14295
+ PulseConfigSchema.parse(config);
14296
+ if (!fs41.existsSync(opts.configPath)) {
14297
+ throw new Error(`harness.config.json not found at ${opts.configPath}`);
14298
+ }
14299
+ const raw = fs41.readFileSync(opts.configPath, "utf-8");
14300
+ let parsed;
14301
+ try {
14302
+ parsed = JSON.parse(raw);
14303
+ } catch (e) {
14304
+ throw new Error(`Invalid JSON in ${opts.configPath}: ${e.message}`, { cause: e });
14305
+ }
14306
+ const bakPath = `${opts.configPath}.bak`;
14307
+ if (!opts.skipBackup && !fs41.existsSync(bakPath)) {
14308
+ fs41.writeFileSync(bakPath, raw, "utf-8");
14309
+ }
14310
+ parsed.pulse = config;
14311
+ const serialized = JSON.stringify(parsed, null, 2) + "\n";
14312
+ const tmpPath = `${opts.configPath}.tmp-${process.pid}`;
14313
+ fs41.writeFileSync(tmpPath, serialized, "utf-8");
14314
+ try {
14315
+ fs41.renameSync(tmpPath, opts.configPath);
14316
+ } catch (e) {
14317
+ try {
14318
+ fs41.unlinkSync(tmpPath);
14319
+ } catch {
14320
+ }
14321
+ throw e;
14322
+ }
14323
+ }
14324
+ function seedFromStrategy(opts = {}) {
14325
+ const cwd = opts.cwd ?? process.cwd();
14326
+ const strategyPath = path40.join(cwd, "STRATEGY.md");
14327
+ const warnings = [];
14328
+ if (!fs42.existsSync(strategyPath)) {
14329
+ return { name: null, keyMetrics: [], warnings: ["STRATEGY.md not found"] };
14330
+ }
14331
+ const raw = fs42.readFileSync(strategyPath, "utf-8");
14332
+ let name = null;
14333
+ const fmMatch = /^---\s*\n([\s\S]*?)\n---\s*\n/.exec(raw);
14334
+ const fm = fmMatch?.[1];
14335
+ if (fm !== void 0) {
14336
+ const nameMatch = /^name:\s*['"]?([^'"\n]+)['"]?\s*$/m.exec(fm);
14337
+ const nameCapture = nameMatch?.[1];
14338
+ if (nameCapture !== void 0) {
14339
+ name = nameCapture.trim();
14340
+ }
14341
+ }
14342
+ if (name === null) {
14343
+ const h1 = /^#\s+(.+)$/m.exec(raw);
14344
+ const h1Capture = h1?.[1];
14345
+ if (h1Capture !== void 0) {
14346
+ name = h1Capture.trim();
14347
+ warnings.push("STRATEGY.md frontmatter missing name; used H1 fallback");
14348
+ }
14349
+ }
14350
+ const keyMetrics = [];
14351
+ const headerMatch = /^##\s+Key metrics\s*$/m.exec(raw);
14352
+ if (headerMatch && headerMatch.index !== void 0) {
14353
+ const startIdx = headerMatch.index + headerMatch[0].length;
14354
+ const after = raw.slice(startIdx);
14355
+ const stopMatch = /^(#{1,3})\s+/m.exec(after);
14356
+ const block = stopMatch ? after.slice(0, stopMatch.index) : after;
14357
+ for (const line of block.split("\n")) {
14358
+ const m = /^[-*]\s+(.+)$/.exec(line.trim());
14359
+ const capture = m?.[1];
14360
+ if (capture !== void 0) keyMetrics.push(capture.trim());
14361
+ }
14362
+ } else {
14363
+ warnings.push("STRATEGY.md is missing a `## Key metrics` section");
14364
+ }
14365
+ return { name, keyMetrics, warnings };
14366
+ }
14367
+ function registerPulseAdapter(name, adapter2) {
14368
+ if (!adapter2 || typeof adapter2 !== "object") {
14369
+ throw new TypeError(`Pulse adapter "${name}" must be an object with query and sanitize.`);
14370
+ }
14371
+ if (typeof adapter2.query !== "function") {
14372
+ throw new TypeError(`Pulse adapter "${name}" is missing required field: query`);
14373
+ }
14374
+ if (typeof adapter2.sanitize !== "function") {
14375
+ throw new TypeError(`Pulse adapter "${name}" is missing required field: sanitize`);
14376
+ }
14377
+ if (REGISTRY.has(name)) {
14378
+ throw new PulseAdapterAlreadyRegisteredError(name);
14379
+ }
14380
+ REGISTRY.set(name, adapter2);
14381
+ }
14382
+ function getPulseAdapter(name) {
14383
+ return REGISTRY.get(name);
14384
+ }
14385
+ function listPulseAdapters() {
14386
+ return [...REGISTRY.keys()].sort();
14387
+ }
14388
+ function clearPulseAdapters() {
14389
+ REGISTRY.clear();
14390
+ }
14391
+ function registerMockAdapter() {
14392
+ if (listPulseAdapters().includes(MOCK_ADAPTER_NAME)) return;
14393
+ registerPulseAdapter(MOCK_ADAPTER_NAME, adapter);
14394
+ }
14395
+ function parseLookback(input) {
14396
+ const match = LOOKBACK_RE.exec(input);
14397
+ if (!match) {
14398
+ throw new Error(`Invalid lookback "${input}": expected format like "24h" or "7d"`);
14399
+ }
14400
+ const n = Number(match[1]);
14401
+ const unit = match[2];
14402
+ return unit === "h" ? n * 60 * 60 * 1e3 : n * 24 * 60 * 60 * 1e3;
14403
+ }
14404
+ function computeWindow(now, lookback, bufferMinutes = 15) {
14405
+ const lookbackMs = parseLookback(lookback);
14406
+ const bufferMs = bufferMinutes * 60 * 1e3;
14407
+ const end = new Date(now.getTime() - bufferMs);
14408
+ const start = new Date(end.getTime() - lookbackMs);
14409
+ return { start, end };
14410
+ }
14411
+ async function querySource(name, window) {
14412
+ const adapter2 = getPulseAdapter(name);
14413
+ if (!adapter2) {
14414
+ return {
14415
+ ok: false,
14416
+ skipKind: "no-adapter",
14417
+ reason: `no adapter registered for "${name}"`
14418
+ };
14419
+ }
14420
+ let sanitized;
14421
+ try {
14422
+ const raw = await adapter2.query(window);
14423
+ sanitized = adapter2.sanitize(raw);
14424
+ } catch (err) {
14425
+ return {
14426
+ ok: false,
14427
+ skipKind: "query-failure",
14428
+ reason: err instanceof Error ? err.message : String(err)
14429
+ };
14430
+ }
14431
+ try {
14432
+ assertSanitized(sanitized);
14433
+ } catch (err) {
14434
+ return {
14435
+ ok: false,
14436
+ skipKind: "pii-violation",
14437
+ reason: err instanceof Error ? err.message : String(err)
14438
+ };
14439
+ }
14440
+ return { ok: true, result: sanitized };
14441
+ }
14442
+ async function runPulse(config, window) {
14443
+ const startedAt = Date.now();
14444
+ const sources = [];
14445
+ const sourcesQueried = [];
14446
+ const sourcesSkipped = [];
14447
+ const parallelSlots = [
14448
+ ["analytics", config.sources.analytics],
14449
+ ["tracing", config.sources.tracing],
14450
+ ["payments", config.sources.payments]
14451
+ ];
14452
+ const parallelEntries = parallelSlots.filter(
14453
+ (slot) => slot[1] != null
14454
+ );
14455
+ const parallelResults = await Promise.all(
14456
+ parallelEntries.map(([kind, n]) => querySource(n, window).then((r) => [kind, n, r]))
14457
+ );
14458
+ for (const [kind, name, r] of parallelResults) {
14459
+ if (r.ok) {
14460
+ sources.push({ kind, name, result: r.result });
14461
+ sourcesQueried.push(name);
14462
+ } else {
14463
+ sourcesSkipped.push({ name, kind, skipKind: r.skipKind, reason: r.reason });
14464
+ }
14465
+ }
14466
+ if (config.sources.db.enabled && config.sources.db.source) {
14467
+ const name = config.sources.db.source;
14468
+ const r = await querySource(name, window);
14469
+ if (r.ok) {
14470
+ sources.push({ kind: "db", name, result: r.result });
14471
+ sourcesQueried.push(name);
14472
+ } else {
14473
+ sourcesSkipped.push({ name, kind: "db", skipKind: r.skipKind, reason: r.reason });
14474
+ }
14475
+ }
14476
+ return { sources, sourcesQueried, sourcesSkipped, durationMs: Date.now() - startedAt };
14477
+ }
14478
+ function loadTemplate() {
14479
+ try {
14480
+ const url = import.meta?.url;
14481
+ if (!url) return INLINE_TEMPLATE;
14482
+ const here = dirname18(fileURLToPath(url));
14483
+ return readFileSync36(join572(here, "template.md"), "utf-8");
14484
+ } catch {
14485
+ return INLINE_TEMPLATE;
14486
+ }
14487
+ }
14488
+ function totalCount(s) {
14489
+ const c = s.fields.count;
14490
+ return typeof c === "number" ? c : 0;
14491
+ }
14492
+ function buildHeadlines(r) {
14493
+ const total = r.sources.reduce((sum, s) => sum + totalCount(s.result), 0);
14494
+ return [
14495
+ `- ${r.sourcesQueried.length} source(s) queried in ${r.durationMs}ms`,
14496
+ `- ${total} total events recorded`,
14497
+ `- ${r.sourcesSkipped.length} source(s) skipped`
14498
+ ].join("\n");
14499
+ }
14500
+ function buildUsage(r) {
14501
+ if (r.sources.length === 0) return "_(none)_";
14502
+ return r.sources.map((s) => {
14503
+ const name = s.result.fields.event_name ?? "unknown";
14504
+ const count = totalCount(s.result);
14505
+ return `- ${name}: count=${count}`;
14506
+ }).join("\n");
14507
+ }
14508
+ function buildSystemPerformance(r) {
14509
+ const tracing = r.sources.find((s) => s.kind === "tracing") ?? null;
14510
+ if (!tracing) return "_(no tracing source configured)_";
14511
+ const dist = tracing.result.distributions;
14512
+ const lines = Object.entries(dist).map(([k, v]) => `- ${k}: ${JSON.stringify(v)}`);
14513
+ return lines.length > 0 ? lines.join("\n") : "_(no distributions)_";
14514
+ }
14515
+ function buildFollowups(r) {
14516
+ if (r.sourcesSkipped.length === 0) return "_(none)_";
14517
+ return r.sourcesSkipped.map((s) => `- ${s.name} skipped: ${s.reason}`).join("\n");
14518
+ }
14519
+ function finalPiiSweep(text) {
14520
+ return text.split("\n").filter((l) => {
14521
+ if (l.startsWith("# ") || l.startsWith("## ")) return true;
14522
+ return !PII_LINE_RE.test(l);
14523
+ }).join("\n");
14524
+ }
14525
+ function truncateSection(lines, startIdx, endIdx) {
14526
+ const head = lines.slice(0, startIdx + 1);
14527
+ const section = lines.slice(startIdx + 1, endIdx);
14528
+ const tail = lines.slice(endIdx);
14529
+ let truncated = false;
14530
+ while (head.length + section.length + tail.length + (truncated ? 0 : 1) > MAX_LINES && section.length > 0) {
14531
+ section.pop();
14532
+ truncated = true;
14533
+ }
14534
+ if (truncated) section.push(TRUNCATION_MARKER2);
14535
+ return [...head, ...section, ...tail];
14536
+ }
14537
+ function truncateToFit(text) {
14538
+ let lines = text.split("\n");
14539
+ if (lines.length <= MAX_LINES) return text;
14540
+ const sections = [
14541
+ { header: "## Followups" },
14542
+ { header: "## System performance" },
14543
+ { header: "## Usage" }
14544
+ ];
14545
+ for (const { header } of sections) {
14546
+ if (lines.length <= MAX_LINES) break;
14547
+ const startIdx = lines.findIndex((l) => l === header || l.startsWith(`${header} `));
14548
+ if (startIdx < 0) continue;
14549
+ let endIdx = lines.length;
14550
+ for (let i = startIdx + 1; i < lines.length; i++) {
14551
+ const line = lines[i];
14552
+ if (line !== void 0 && line.startsWith("## ")) {
14553
+ endIdx = i;
14554
+ break;
14555
+ }
14556
+ }
14557
+ lines = truncateSection(lines, startIdx, endIdx);
14558
+ }
14559
+ if (lines.length > MAX_LINES) lines = lines.slice(0, MAX_LINES);
14560
+ return lines.join("\n");
14561
+ }
14562
+ function assembleReport(result, productName, windowLabel) {
14563
+ const template = loadTemplate();
14564
+ const filled = template.replace("{{productName}}", productName).replace("{{windowLabel}}", windowLabel).replace("{{headlines}}", buildHeadlines(result)).replace("{{usage}}", buildUsage(result)).replace("{{systemPerformance}}", buildSystemPerformance(result)).replace("{{followups}}", buildFollowups(result));
14565
+ const swept = finalPiiSweep(filled);
14566
+ return truncateToFit(swept);
14567
+ }
14568
+ function extractHeadlines(report) {
14569
+ const lines = report.split("\n");
14570
+ const headlinesIdx = lines.findIndex((l) => l === "## Headlines" || l.startsWith("## Headlines"));
14571
+ if (headlinesIdx < 0) return lines.slice(0, 5).join("\n");
14572
+ let endIdx = lines.length;
14573
+ for (let i = headlinesIdx + 1; i < lines.length; i++) {
14574
+ const line = lines[i];
14575
+ if (line !== void 0 && line.startsWith("## ")) {
14576
+ endIdx = i;
14577
+ break;
14578
+ }
14579
+ }
14580
+ while (endIdx > headlinesIdx + 1 && lines[endIdx - 1] === "") endIdx--;
14581
+ return lines.slice(0, endIdx).join("\n");
14582
+ }
14583
+ function isoWeek(date) {
14584
+ const d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
14585
+ const dayNum = d.getUTCDay() || 7;
14586
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
14587
+ const year = d.getUTCFullYear();
14588
+ const yearStart = new Date(Date.UTC(year, 0, 1));
14589
+ const week = Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
14590
+ return { year, week };
14591
+ }
14592
+ function formatIsoWeek(w) {
14593
+ return `${w.year}-W${String(w.week).padStart(2, "0")}`;
14594
+ }
14595
+ function normalizeSince(since) {
14596
+ const m = /^(\d+)(h|d|w|mo)$/i.exec(since.trim());
14597
+ if (!m) {
14598
+ throw new Error(
14599
+ `Invalid lookback "${since}": expected format like "24h", "7d", "4w", or "3mo"`
14600
+ );
14601
+ }
14602
+ const n = m[1];
14603
+ const unit = m[2]?.toLowerCase();
14604
+ switch (unit) {
14605
+ case "h":
14606
+ return `${n} hours ago`;
14607
+ case "d":
14608
+ return `${n} days ago`;
14609
+ case "w":
14610
+ return `${n} weeks ago`;
14611
+ case "mo":
14612
+ return `${n} months ago`;
14613
+ default:
14614
+ throw new Error(`Invalid lookback "${since}"`);
14615
+ }
14616
+ }
14617
+ async function readCommits(opts) {
14618
+ let stdout;
14619
+ try {
14620
+ const r = await execFileAsync(
14621
+ "git",
14622
+ ["log", `--since=${normalizeSince(opts.since)}`, "--name-only", "--format=%x1e%H%x1f%s"],
14623
+ { cwd: opts.cwd, maxBuffer: 16 * 1024 * 1024 }
14624
+ );
14625
+ stdout = r.stdout;
14626
+ } catch (err) {
14627
+ const msg = err instanceof Error ? err.message : String(err);
14628
+ if (EMPTY_REPO_RE.test(msg)) {
14629
+ process.stderr.write(`gitScan: empty repo or non-repo at ${opts.cwd}; returning []
14630
+ `);
14631
+ return [];
14632
+ }
14633
+ throw err;
14634
+ }
14635
+ const records = stdout.split("").filter((r) => r.trim().length > 0);
14636
+ return records.map((rec) => {
14637
+ const [header, ...fileLines] = rec.split("\n");
14638
+ const [sha, subject] = (header ?? "").split("");
14639
+ const files = fileLines.map((l) => l.trim()).filter((l) => l.length > 0);
14640
+ return { sha: sha ?? "", subject: subject ?? "", files };
14641
+ });
14642
+ }
14643
+ async function gitScan(opts) {
14644
+ const all = await readCommits(opts);
14645
+ const fixes = all.filter((c) => FIX_RE.test(c.subject));
14646
+ return fixes.map((c) => {
14647
+ const overlap = all.filter(
14648
+ (other) => other.sha !== c.sha && other.files.some((f) => c.files.includes(f))
14649
+ ).length;
14650
+ return {
14651
+ sha: c.sha,
14652
+ subject: c.subject,
14653
+ filesChanged: c.files.length,
14654
+ branchIterations: overlap
14655
+ };
14656
+ });
14657
+ }
14658
+ async function computeHotspots(opts) {
14659
+ let stdout;
14660
+ try {
14661
+ const r = await execFileAsync2(
14662
+ "git",
14663
+ ["log", `--since=${normalizeSince(opts.since)}`, "--name-only", "--format="],
14664
+ { cwd: opts.cwd, maxBuffer: 16 * 1024 * 1024 }
14665
+ );
14666
+ stdout = r.stdout;
14667
+ } catch {
14668
+ return [];
14669
+ }
14670
+ const counts = /* @__PURE__ */ new Map();
14671
+ for (const line of stdout.split("\n")) {
14672
+ const path42 = line.trim();
14673
+ if (path42.length === 0) continue;
14674
+ counts.set(path42, (counts.get(path42) ?? 0) + 1);
14675
+ }
14676
+ return [...counts.entries()].filter(([, c]) => c > opts.threshold).map(([path42, churn]) => ({ path: path42, churn })).sort((a, b) => b.churn - a.churn);
14677
+ }
14678
+ function tokenize(text) {
14679
+ return new Set(
14680
+ text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((t) => t.length > 2 && !STOPWORDS.has(t))
14681
+ );
14682
+ }
14683
+ async function* walk22(dir) {
14684
+ let entries;
14685
+ try {
14686
+ entries = await fs43.readdir(dir, { withFileTypes: true });
14687
+ } catch {
14688
+ return;
14689
+ }
14690
+ for (const e of entries) {
14691
+ const p = path41.join(dir, e.name);
14692
+ if (e.isDirectory()) yield* walk22(p);
14693
+ else if (e.isFile() && e.name.endsWith(".md")) yield p;
14694
+ }
14695
+ }
14696
+ async function readDocumentedTokens(solutionsDir) {
14697
+ const docs = [];
14698
+ for (const [track, categories] of TRACK_CATEGORIES2) {
14699
+ for (const category of categories) {
14700
+ const dir = path41.join(solutionsDir, track, category);
14701
+ for await (const file of walk22(dir)) {
14702
+ const raw = await fs43.readFile(file, "utf-8");
14703
+ const m = /^#\s+(.+)$/m.exec(raw);
14704
+ const title = m?.[1] ?? path41.basename(file, ".md");
14705
+ docs.push(tokenize(title));
14706
+ }
14707
+ }
14708
+ }
14709
+ return docs;
14710
+ }
14711
+ function jaccard(a, b) {
14712
+ if (a.size === 0 || b.size === 0) return 0;
14713
+ let inter = 0;
14714
+ for (const t of a) if (b.has(t)) inter++;
14715
+ const union = a.size + b.size - inter;
14716
+ return union === 0 ? 0 : inter / union;
14717
+ }
14718
+ async function crossReferenceUndocumentedFixes(commits, solutionsDir) {
14719
+ const documented = await readDocumentedTokens(solutionsDir);
14720
+ const OVERLAP_THRESHOLD = 0.4;
14721
+ return commits.filter((c) => {
14722
+ const tokens = tokenize(c.subject);
14723
+ return !documented.some((d) => jaccard(tokens, d) >= OVERLAP_THRESHOLD);
14724
+ });
14725
+ }
14726
+ function suggestCategory(subject) {
14727
+ for (const [re, cat] of KEYWORD_TO_CATEGORY) if (re.test(subject)) return cat;
14728
+ return "bug-track/logic-errors";
14729
+ }
14730
+ function descriptor(subject) {
14731
+ return subject.replace(/^fix(\([^)]+\))?:\s*/i, "").trim();
14732
+ }
14733
+ function assembleCandidateReport(input) {
14734
+ const week = formatIsoWeek(input.isoWeek);
14735
+ const lines = [];
14736
+ lines.push(`# Compound candidates \u2014 week ${week}`, "");
14737
+ lines.push(`## Undocumented fixes (from \`git log\` past ${input.lookback})`, "");
14738
+ if (input.undocumentedFixes.length === 0) {
14739
+ lines.push("_(none this week)_", "");
14740
+ } else {
14741
+ for (const c of input.undocumentedFixes) {
14742
+ const d = descriptor(c.subject);
14743
+ const cat = suggestCategory(c.subject);
14744
+ lines.push(
14745
+ `- **${c.subject}** (commit ${c.sha.slice(0, 7)}, ${c.filesChanged} file(s), ${c.branchIterations} related commits)`
14746
+ );
14747
+ lines.push(` - Suggested category: ${cat}`);
14748
+ lines.push(` - Run: \`/harness:compound "${d}"\``);
14749
+ }
14750
+ lines.push("");
14751
+ }
14752
+ lines.push("## Pattern candidates (from churn + hotspot analysis)", "");
14753
+ if (input.hotspotCandidates.length === 0) {
14754
+ lines.push("_(none this week)_", "");
14755
+ } else {
14756
+ for (const h of input.hotspotCandidates) {
14757
+ lines.push(
14758
+ `- File \`${h.path}\` has ${h.churn} commits in ${input.lookback}; no docs/solutions/ entry`
14759
+ );
14760
+ lines.push(" - Suggested category: knowledge-track/architecture-patterns");
14761
+ lines.push(` - Run: \`/harness:compound "${h.path} pattern"\``);
14762
+ }
14763
+ lines.push("");
14764
+ }
14765
+ return lines.join("\n");
14766
+ }
14767
+ var VALID_TYPES, CONVENTIONAL_PATTERN, LOOKBACK_PATTERN, PulseDbSourceSchema, PulseSourcesSchema, PulseConfigSchema, BUG_TRACK_CATEGORIES, KNOWLEDGE_TRACK_CATEGORIES, ALL_SOLUTION_CATEGORIES, ISO_DATE, BugTrackSchema, KnowledgeTrackSchema, BaseFrontmatter, SolutionDocFrontmatterSchema, TRACK_CATEGORIES, DEFAULT_AGNIX_TIMEOUT_MS, HARNESS_AGNIX_DISABLE, HARNESS_AGNIX_BIN, CLAUDE_MD_WARN_BYTES, CLAUDE_MD_ERROR_BYTES, CONTEXT_FILES, MIN_DESCRIPTION_LENGTH, SETTINGS_PATHS, KNOWN_HOOK_EVENTS, MCP_SETTINGS_FILES, REQUIRED_SECTIONS, SETTINGS_FILES, KNOWN_AGNIX_TOOLS, DEFAULT_SECTIONS, DEFAULT_RATIOS, NODE_TYPE_TO_CATEGORY, SECTION_LEVEL_MAP, DEFAULT_LEVEL, DEFAULT_BUDGET, DEFAULT_LOADER_CONFIG, LEVEL_FRACTIONS, PHASE_PRIORITIES, ManifestSchema, BundleConstraintsSchema, BundleSchema, ContributionsSchema, LockfilePackageSchema, LockfileSchema, SharableLayerSchema, SharableForbiddenImportSchema, SharableBoundaryConfigSchema, SharableSecurityRulesSchema, VALID_SCOPES, LINE_PATTERN, START_PATTERN, END_PATTERN, CODE_BLOCK_LANGUAGES, DEFAULT_DRIFT_CONFIG, JS_EXT_FALLBACKS2, FILE_TYPES, EXPORT_TYPES, CONVENTION_DESCRIPTIONS, RULE_CHECKERS, EntropyAnalyzer, readFile62, writeFile32, unlink22, mkdir22, copyFile2, DEFAULT_FIX_CONFIG, EXPORT_TYPE_KEYWORD, ALWAYS_UNSAFE_TYPES, idCounter, DEAD_CODE_FIX_ACTIONS, MustExportRuleSchema, MustExportDefaultRuleSchema, NoExportRuleSchema, MustImportRuleSchema, NoImportRuleSchema, NamingRuleSchema, MaxExportsRuleSchema, MaxLinesRuleSchema, RequireJSDocRuleSchema, RuleSchema, ConfigPatternSchema, PatternConfigSchema, DriftConfigSchema, DeadCodeConfigSchema, EntropyConfigSchema, BaselineManager, BenchmarkRunner, RegressionDetector, SKIP_DIRS, SOURCE_EXTENSIONS, FUNCTION_DECL_RE, CONST_DECL_RE, CriticalPathResolver, NoOpTelemetryAdapter, NoOpExecutor, ConsoleSink, feedbackConfig, ChecklistBuilder, AgentActionEmitter, globalEmitter, FileSink, NoOpSink, CategorySnapshotSchema, TimelineSnapshotSchema, TimelineFileSchema, TrendLineSchema, TrendResultSchema, DEFAULT_STABILITY_THRESHOLDS, ALL_CATEGORIES, TimelineManager, ConfidenceTierSchema, RegressionResultSchema, DirectionSchema, CategoryForecastSchema, SpecImpactSignalsSchema, SpecImpactEstimateSchema, ContributingFeatureSchema, AdjustedForecastSchema, PredictionWarningSchema, StabilityForecastSchema, PredictionResultSchema, PredictionOptionsSchema, VALID_STATUSES, EM_DASH, VALID_PRIORITIES, ALL_CATEGORIES2, DIRECTION_THRESHOLD, PredictionEngine, DEFAULT_COEFFICIENTS, SpecImpactEstimator, EMPTY_HISTORY, ViolationHistoryManager, NORMALIZERS, MAX_SAMPLES, DEFAULT_WINDOW_WEEKS, DEFAULT_MIN_OCCURRENCES, FailureEntrySchema, HandoffSchema, GateCheckSchema, GateResultSchema, GateConfigSchema, HarnessStateSchema, DEFAULT_STATE, StreamInfoSchema, StreamIndexSchema, DEFAULT_STREAM_INDEX, HARNESS_DIR, STATE_FILE, LEARNINGS_FILE, FAILURES_FILE, HANDOFF_FILE, GATE_CONFIG_FILE, INDEX_FILE, SESSIONS_DIR, SESSION_INDEX_FILE, SUMMARY_FILE, SESSION_STATE_FILE, ARCHIVE_DIR, CONTENT_HASHES_FILE, EVENTS_FILE, STREAMS_DIR, STREAM_NAME_REGEX, branchCache, BRANCH_CACHE_TTL_MS, STATE_FILES, MAX_CACHE_ENTRIES, learningsCacheMap, WEIGHTS, LOCK_RETRIES, LOCK_BACKOFFS, PROMOTABLE_OUTCOMES, failuresCacheMap, FAILURE_LINE_REGEX, SAFE_GATE_COMMAND, SkillEventSchema, knownHashesCache, EVENT_FORMATTERS, RuleRegistry, DEFAULT_SECURITY_CONFIG, RuleOverrideSchema, SecurityConfigSchema, secretRules, injectionRules, xssRules, cryptoRules, pathTraversalRules, networkRules, deserializationRules, agentConfigRules, mcpRules, insecureDefaultsRules, sharpEdgesRules, nodeRules, expressRules, reactRules, goRules, SecurityScanner, hiddenUnicodePatterns, reRolingPatterns, permissionEscalationPatterns, encodedPayloadPatterns, indirectInjectionPatterns, contextManipulationPatterns, socialEngineeringPatterns, suspiciousPatterns, ALL_PATTERNS, DESTRUCTIVE_BASH, TAINT_DURATION_MS, DEFAULT_SESSION_ID, SecurityCategorySnapshotSchema, SupplyChainSnapshotSchema, SecurityTimelineSnapshotSchema, FindingLifecycleSchema, SecurityTimelineFileSchema, DirectionSchema2, SecurityTrendLineSchema, TrendAttributionSchema, SecurityTrendResultSchema, TimeToFixStatsSchema, TimeToFixResultSchema, EMPTY_SUPPLY_CHAIN, SecurityTimelineManager, ALL_CHECKS, STATUS_ICONS, CINotifier, ExclusionSet, PREFIX_PATTERNS, TEST_FILE_PATTERN, MD_FILE_PATTERN, ALL_DOMAINS, SECURITY_PATTERNS, JS_EXT_FALLBACKS22, SEVERITY_RANK, SEVERITY_ORDER, SEVERITY_LABELS, VALIDATED_BY_RANK, VALIDATION_SCORES, DOMAIN_BASELINES, FACTOR_WEIGHTS, EVIDENCE_SATURATION, CORROBORATED_AGREEMENT, STANDALONE_AGREEMENT, AGREEMENT_LINE_GAP, COMPLIANCE_DESCRIPTOR, EXPORT_RE, BUG_DETECTION_DESCRIPTOR, SECURITY_DESCRIPTOR, EVAL_PATTERN, SECRET_PATTERNS, SQL_CONCAT_PATTERN, SHELL_EXEC_PATTERN, ARCHITECTURE_DESCRIPTOR, LARGE_FILE_THRESHOLD, VIOLATION_FILE_RE, LEARNINGS_DESCRIPTOR, RELEVANCE_THRESHOLD, AGENT_DESCRIPTORS, AGENT_RUNNERS, DOWNGRADE_MAP, DEFAULT_PROVIDER_TIERS, SMALL_SUGGESTION_LINE_LIMIT, FILE_LINE_RANGE_PATTERN, FILE_LINE_PATTERN, FILE_ONLY_PATTERN, SECURITY_SENSITIVE_PATH, MIGRATION_PATH, TEST_PATH, CONFIG_PATH, STAGE_DOMAINS, EM_DASH2, STATUS_RANK, RETRY_DEFAULTS, GitHubIssuesSyncAdapter, syncMutex, PRIORITY_RANK, POSITION_WEIGHT, DEPENDENTS_WEIGHT, AFFINITY_WEIGHT, InteractionTypeSchema, QuestionSchema, ConfirmationSchema, TransitionSchema, EmitInteractionInputSchema, ProjectScanner, SHELL_TEMPLATE, STYLES, SCRIPTS, MockLLMService, llmService, ContentPipeline, BlueprintGenerator, TOKENS_PER_MILLION, fallback_default, LITELLM_PRICING_URL, CACHE_TTL_MS, STALENESS_WARNING_DAYS, MICRODOLLARS_PER_DOLLAR, TOKENS_PER_MILLION2, StructuralStrategy, DEFAULT_TOKEN_BUDGET, CHARS_PER_TOKEN, TRUNCATION_MARKER, TruncationStrategy, CompactionPipeline, STABILITY_LOOKUP, TIER_ORDER, AnthropicCacheAdapter, TIER_ORDER2, OpenAICacheAdapter, TIER_ORDER3, CACHED_CONTENT_MARKER, GeminiCacheAdapter, VERSION, POSTHOG_BATCH_URL, MAX_ATTEMPTS, TIMEOUT_MS, CompoundLockHeldError, KNOWN_CATEGORIES, ALLOWED_FIELD_KEYS, PII_TOKENS, PII_FIELD_DENYLIST, PII_LINE_RE, ALLOWED_SET, PulseAdapterAlreadyRegisteredError, REGISTRY, MOCK_ADAPTER_NAME, ALLOWED_FIELD_SET, adapter, LOOKBACK_RE, MAX_LINES, INLINE_TEMPLATE, TRUNCATION_MARKER2, execFileAsync, FIX_RE, EMPTY_REPO_RE, execFileAsync2, TRACK_CATEGORIES2, STOPWORDS, KEYWORD_TO_CATEGORY;
14029
14768
  var init_dist3 = __esm({
14030
14769
  "../core/dist/index.mjs"() {
14031
- init_chunk_H73442AZ();
14770
+ init_chunk_CE225WRK();
14032
14771
  init_dist();
14033
14772
  init_dist();
14034
14773
  init_dist();
@@ -14050,6 +14789,76 @@ var init_dist3 = __esm({
14050
14789
  "revert"
14051
14790
  ];
14052
14791
  CONVENTIONAL_PATTERN = /^(\w+)(\(([^)]+)\))?(!)?: (.+)$/;
14792
+ LOOKBACK_PATTERN = /^\d+(h|d|w)$/;
14793
+ PulseDbSourceSchema = z2.object({
14794
+ enabled: z2.boolean(),
14795
+ connectionEnv: z2.string().optional()
14796
+ });
14797
+ PulseSourcesSchema = z2.object({
14798
+ analytics: z2.string().nullable(),
14799
+ tracing: z2.string().nullable(),
14800
+ payments: z2.string().nullable(),
14801
+ db: PulseDbSourceSchema
14802
+ });
14803
+ PulseConfigSchema = z2.object({
14804
+ enabled: z2.boolean(),
14805
+ lookbackDefault: z2.string().regex(LOOKBACK_PATTERN, 'lookback must be like "24h", "7d", or "1w"'),
14806
+ primaryEvent: z2.string(),
14807
+ valueEvent: z2.string(),
14808
+ completionEvents: z2.array(z2.string()),
14809
+ qualityScoring: z2.boolean(),
14810
+ qualityDimension: z2.string().nullable(),
14811
+ sources: PulseSourcesSchema,
14812
+ metricSourceOverrides: z2.record(z2.string(), z2.string()),
14813
+ pendingMetrics: z2.array(z2.string()),
14814
+ excludedMetrics: z2.array(z2.string())
14815
+ });
14816
+ BUG_TRACK_CATEGORIES = [
14817
+ "build-errors",
14818
+ "test-failures",
14819
+ "runtime-errors",
14820
+ "performance-issues",
14821
+ "database-issues",
14822
+ "security-issues",
14823
+ "ui-bugs",
14824
+ "integration-issues",
14825
+ "logic-errors"
14826
+ ];
14827
+ KNOWLEDGE_TRACK_CATEGORIES = [
14828
+ "architecture-patterns",
14829
+ "design-patterns",
14830
+ "tooling-decisions",
14831
+ "conventions",
14832
+ "dx",
14833
+ "best-practices"
14834
+ ];
14835
+ ALL_SOLUTION_CATEGORIES = [
14836
+ ...BUG_TRACK_CATEGORIES,
14837
+ ...KNOWLEDGE_TRACK_CATEGORIES
14838
+ ];
14839
+ ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
14840
+ BugTrackSchema = z22.object({
14841
+ track: z22.literal("bug-track"),
14842
+ category: z22.enum(BUG_TRACK_CATEGORIES)
14843
+ });
14844
+ KnowledgeTrackSchema = z22.object({
14845
+ track: z22.literal("knowledge-track"),
14846
+ category: z22.enum(KNOWLEDGE_TRACK_CATEGORIES)
14847
+ });
14848
+ BaseFrontmatter = z22.object({
14849
+ module: z22.string().min(1),
14850
+ tags: z22.array(z22.string()),
14851
+ problem_type: z22.string().min(1),
14852
+ last_updated: z22.string().regex(ISO_DATE, "last_updated must be ISO date YYYY-MM-DD")
14853
+ });
14854
+ SolutionDocFrontmatterSchema = z22.discriminatedUnion("track", [
14855
+ BaseFrontmatter.merge(BugTrackSchema),
14856
+ BaseFrontmatter.merge(KnowledgeTrackSchema)
14857
+ ]);
14858
+ TRACK_CATEGORIES = [
14859
+ ["bug-track", BUG_TRACK_CATEGORIES],
14860
+ ["knowledge-track", KNOWLEDGE_TRACK_CATEGORIES]
14861
+ ];
14053
14862
  DEFAULT_AGNIX_TIMEOUT_MS = 3e4;
14054
14863
  HARNESS_AGNIX_DISABLE = "HARNESS_AGNIX_DISABLE";
14055
14864
  HARNESS_AGNIX_BIN = "HARNESS_AGNIX_BIN";
@@ -14196,81 +15005,81 @@ var init_dist3 = __esm({
14196
15005
  { category: "config", patterns: ["harness.config.json", "package.json"], priority: 5 }
14197
15006
  ]
14198
15007
  };
14199
- ManifestSchema = z2.object({
14200
- name: z2.string(),
14201
- version: z2.string(),
14202
- description: z2.string().optional(),
14203
- include: z2.array(z2.string()).min(1),
14204
- minHarnessVersion: z2.string().optional(),
14205
- keywords: z2.array(z2.string()).optional().default([]),
14206
- layers: z2.record(z2.array(z2.string())).optional(),
14207
- boundaries: z2.array(
14208
- z2.object({
14209
- name: z2.string(),
14210
- layer: z2.string(),
14211
- direction: z2.enum(["input", "output"]),
14212
- schema: z2.string()
15008
+ ManifestSchema = z3.object({
15009
+ name: z3.string(),
15010
+ version: z3.string(),
15011
+ description: z3.string().optional(),
15012
+ include: z3.array(z3.string()).min(1),
15013
+ minHarnessVersion: z3.string().optional(),
15014
+ keywords: z3.array(z3.string()).optional().default([]),
15015
+ layers: z3.record(z3.array(z3.string())).optional(),
15016
+ boundaries: z3.array(
15017
+ z3.object({
15018
+ name: z3.string(),
15019
+ layer: z3.string(),
15020
+ direction: z3.enum(["input", "output"]),
15021
+ schema: z3.string()
14213
15022
  })
14214
15023
  ).optional()
14215
15024
  });
14216
- BundleConstraintsSchema = z2.object({
14217
- layers: z2.array(
14218
- z2.object({
14219
- name: z2.string(),
14220
- pattern: z2.string(),
14221
- allowedDependencies: z2.array(z2.string())
15025
+ BundleConstraintsSchema = z3.object({
15026
+ layers: z3.array(
15027
+ z3.object({
15028
+ name: z3.string(),
15029
+ pattern: z3.string(),
15030
+ allowedDependencies: z3.array(z3.string())
14222
15031
  })
14223
15032
  ).optional(),
14224
- forbiddenImports: z2.array(
14225
- z2.object({
14226
- from: z2.string(),
14227
- disallow: z2.array(z2.string()),
14228
- message: z2.string().optional()
15033
+ forbiddenImports: z3.array(
15034
+ z3.object({
15035
+ from: z3.string(),
15036
+ disallow: z3.array(z3.string()),
15037
+ message: z3.string().optional()
14229
15038
  })
14230
15039
  ).optional(),
14231
- boundaries: z2.object({
14232
- requireSchema: z2.array(z2.string()).optional()
15040
+ boundaries: z3.object({
15041
+ requireSchema: z3.array(z3.string()).optional()
14233
15042
  }).optional(),
14234
- architecture: z2.object({
14235
- thresholds: z2.record(z2.unknown()).optional(),
14236
- modules: z2.record(z2.record(z2.unknown())).optional()
15043
+ architecture: z3.object({
15044
+ thresholds: z3.record(z3.unknown()).optional(),
15045
+ modules: z3.record(z3.record(z3.unknown())).optional()
14237
15046
  }).optional(),
14238
- security: z2.object({
14239
- rules: z2.record(z2.string()).optional()
15047
+ security: z3.object({
15048
+ rules: z3.record(z3.string()).optional()
14240
15049
  }).optional()
14241
15050
  });
14242
- BundleSchema = z2.object({
14243
- name: z2.string(),
14244
- version: z2.string(),
14245
- description: z2.string().optional(),
14246
- minHarnessVersion: z2.string().optional(),
15051
+ BundleSchema = z3.object({
15052
+ name: z3.string(),
15053
+ version: z3.string(),
15054
+ description: z3.string().optional(),
15055
+ minHarnessVersion: z3.string().optional(),
14247
15056
  manifest: ManifestSchema,
14248
15057
  constraints: BundleConstraintsSchema,
14249
- contributions: z2.record(z2.unknown()).optional()
15058
+ contributions: z3.record(z3.unknown()).optional()
14250
15059
  });
14251
- ContributionsSchema = z2.record(z2.unknown());
14252
- LockfilePackageSchema = z2.object({
14253
- version: z2.string(),
14254
- source: z2.string(),
14255
- installedAt: z2.string(),
14256
- contributions: z2.record(z2.unknown()).optional().nullable(),
14257
- resolved: z2.string().optional(),
14258
- integrity: z2.string().optional(),
14259
- provenance: z2.array(z2.string()).optional()
15060
+ ContributionsSchema = z3.record(z3.unknown());
15061
+ LockfilePackageSchema = z3.object({
15062
+ version: z3.string(),
15063
+ source: z3.string(),
15064
+ installedAt: z3.string(),
15065
+ contributions: z3.record(z3.unknown()).optional().nullable(),
15066
+ resolved: z3.string().optional(),
15067
+ integrity: z3.string().optional(),
15068
+ provenance: z3.array(z3.string()).optional()
14260
15069
  });
14261
- LockfileSchema = z2.object({
14262
- version: z2.literal(1).optional(),
15070
+ LockfileSchema = z3.object({
15071
+ version: z3.literal(1).optional(),
14263
15072
  // Used by some tests
14264
- lockfileVersion: z2.literal(1).optional(),
15073
+ lockfileVersion: z3.literal(1).optional(),
14265
15074
  // Standard field
14266
- packages: z2.record(LockfilePackageSchema)
15075
+ packages: z3.record(LockfilePackageSchema)
14267
15076
  }).refine((data) => data.version !== void 0 || data.lockfileVersion !== void 0, {
14268
15077
  message: "Either 'version' or 'lockfileVersion' must be present and equal to 1"
14269
15078
  });
14270
- SharableLayerSchema = z2.unknown();
14271
- SharableForbiddenImportSchema = z2.unknown();
14272
- SharableBoundaryConfigSchema = z2.unknown();
14273
- SharableSecurityRulesSchema = z2.unknown();
15079
+ SharableLayerSchema = z3.unknown();
15080
+ SharableForbiddenImportSchema = z3.unknown();
15081
+ SharableBoundaryConfigSchema = z3.unknown();
15082
+ SharableSecurityRulesSchema = z3.unknown();
14274
15083
  VALID_SCOPES = /* @__PURE__ */ new Set([
14275
15084
  "entropy",
14276
15085
  "architecture",
@@ -14288,6 +15097,12 @@ var init_dist3 = __esm({
14288
15097
  checkStructure: true,
14289
15098
  ignorePatterns: []
14290
15099
  };
15100
+ JS_EXT_FALLBACKS2 = {
15101
+ ".js": [".ts", ".tsx", ".jsx"],
15102
+ ".jsx": [".tsx"],
15103
+ ".mjs": [".mts"],
15104
+ ".cjs": [".cts"]
15105
+ };
14291
15106
  FILE_TYPES = /* @__PURE__ */ new Set(["file", "module"]);
14292
15107
  EXPORT_TYPES = /* @__PURE__ */ new Set(["function", "class", "method", "interface", "variable"]);
14293
15108
  CONVENTION_DESCRIPTIONS = {
@@ -14541,11 +15356,11 @@ var init_dist3 = __esm({
14541
15356
  return detectPatternViolations(snapshotResult.value, config);
14542
15357
  }
14543
15358
  };
14544
- readFile42 = promisify2(fs3.readFile);
14545
- writeFile32 = promisify2(fs3.writeFile);
14546
- unlink22 = promisify2(fs3.unlink);
14547
- mkdir22 = promisify2(fs3.mkdir);
14548
- copyFile2 = promisify2(fs3.copyFile);
15359
+ readFile62 = promisify2(fs5.readFile);
15360
+ writeFile32 = promisify2(fs5.writeFile);
15361
+ unlink22 = promisify2(fs5.unlink);
15362
+ mkdir22 = promisify2(fs5.mkdir);
15363
+ copyFile2 = promisify2(fs5.copyFile);
14549
15364
  DEFAULT_FIX_CONFIG = {
14550
15365
  dryRun: false,
14551
15366
  fixTypes: ["unused-imports", "dead-files"],
@@ -14573,45 +15388,45 @@ var init_dist3 = __esm({
14573
15388
  "commented-code": "Delete commented block",
14574
15389
  "unused-import": "Remove import"
14575
15390
  };
14576
- MustExportRuleSchema = z22.object({
14577
- type: z22.literal("must-export"),
14578
- names: z22.array(z22.string())
15391
+ MustExportRuleSchema = z4.object({
15392
+ type: z4.literal("must-export"),
15393
+ names: z4.array(z4.string())
14579
15394
  });
14580
- MustExportDefaultRuleSchema = z22.object({
14581
- type: z22.literal("must-export-default"),
14582
- kind: z22.enum(["class", "function", "object"]).optional()
15395
+ MustExportDefaultRuleSchema = z4.object({
15396
+ type: z4.literal("must-export-default"),
15397
+ kind: z4.enum(["class", "function", "object"]).optional()
14583
15398
  });
14584
- NoExportRuleSchema = z22.object({
14585
- type: z22.literal("no-export"),
14586
- names: z22.array(z22.string())
15399
+ NoExportRuleSchema = z4.object({
15400
+ type: z4.literal("no-export"),
15401
+ names: z4.array(z4.string())
14587
15402
  });
14588
- MustImportRuleSchema = z22.object({
14589
- type: z22.literal("must-import"),
14590
- from: z22.string(),
14591
- names: z22.array(z22.string()).optional()
15403
+ MustImportRuleSchema = z4.object({
15404
+ type: z4.literal("must-import"),
15405
+ from: z4.string(),
15406
+ names: z4.array(z4.string()).optional()
14592
15407
  });
14593
- NoImportRuleSchema = z22.object({
14594
- type: z22.literal("no-import"),
14595
- from: z22.string()
15408
+ NoImportRuleSchema = z4.object({
15409
+ type: z4.literal("no-import"),
15410
+ from: z4.string()
14596
15411
  });
14597
- NamingRuleSchema = z22.object({
14598
- type: z22.literal("naming"),
14599
- match: z22.string(),
14600
- convention: z22.enum(["camelCase", "PascalCase", "UPPER_SNAKE", "kebab-case"])
15412
+ NamingRuleSchema = z4.object({
15413
+ type: z4.literal("naming"),
15414
+ match: z4.string(),
15415
+ convention: z4.enum(["camelCase", "PascalCase", "UPPER_SNAKE", "kebab-case"])
14601
15416
  });
14602
- MaxExportsRuleSchema = z22.object({
14603
- type: z22.literal("max-exports"),
14604
- count: z22.number().positive()
15417
+ MaxExportsRuleSchema = z4.object({
15418
+ type: z4.literal("max-exports"),
15419
+ count: z4.number().positive()
14605
15420
  });
14606
- MaxLinesRuleSchema = z22.object({
14607
- type: z22.literal("max-lines"),
14608
- count: z22.number().positive()
15421
+ MaxLinesRuleSchema = z4.object({
15422
+ type: z4.literal("max-lines"),
15423
+ count: z4.number().positive()
14609
15424
  });
14610
- RequireJSDocRuleSchema = z22.object({
14611
- type: z22.literal("require-jsdoc"),
14612
- for: z22.array(z22.enum(["function", "class", "export"]))
15425
+ RequireJSDocRuleSchema = z4.object({
15426
+ type: z4.literal("require-jsdoc"),
15427
+ for: z4.array(z4.enum(["function", "class", "export"]))
14613
15428
  });
14614
- RuleSchema = z22.discriminatedUnion("type", [
15429
+ RuleSchema = z4.discriminatedUnion("type", [
14615
15430
  MustExportRuleSchema,
14616
15431
  MustExportDefaultRuleSchema,
14617
15432
  NoExportRuleSchema,
@@ -14622,52 +15437,52 @@ var init_dist3 = __esm({
14622
15437
  MaxLinesRuleSchema,
14623
15438
  RequireJSDocRuleSchema
14624
15439
  ]);
14625
- ConfigPatternSchema = z22.object({
14626
- name: z22.string().min(1),
14627
- description: z22.string(),
14628
- severity: z22.enum(["error", "warning"]),
14629
- files: z22.array(z22.string()),
15440
+ ConfigPatternSchema = z4.object({
15441
+ name: z4.string().min(1),
15442
+ description: z4.string(),
15443
+ severity: z4.enum(["error", "warning"]),
15444
+ files: z4.array(z4.string()),
14630
15445
  rule: RuleSchema,
14631
- message: z22.string().optional()
15446
+ message: z4.string().optional()
14632
15447
  });
14633
- PatternConfigSchema = z22.object({
14634
- patterns: z22.array(ConfigPatternSchema),
14635
- customPatterns: z22.array(z22.any()).optional(),
15448
+ PatternConfigSchema = z4.object({
15449
+ patterns: z4.array(ConfigPatternSchema),
15450
+ customPatterns: z4.array(z4.any()).optional(),
14636
15451
  // Code patterns are functions, can't validate
14637
- ignoreFiles: z22.array(z22.string()).optional()
15452
+ ignoreFiles: z4.array(z4.string()).optional()
14638
15453
  });
14639
- DriftConfigSchema = z22.object({
14640
- docPaths: z22.array(z22.string()).optional(),
14641
- checkApiSignatures: z22.boolean().optional(),
14642
- checkExamples: z22.boolean().optional(),
14643
- checkStructure: z22.boolean().optional(),
14644
- ignorePatterns: z22.array(z22.string()).optional()
15454
+ DriftConfigSchema = z4.object({
15455
+ docPaths: z4.array(z4.string()).optional(),
15456
+ checkApiSignatures: z4.boolean().optional(),
15457
+ checkExamples: z4.boolean().optional(),
15458
+ checkStructure: z4.boolean().optional(),
15459
+ ignorePatterns: z4.array(z4.string()).optional()
14645
15460
  });
14646
- DeadCodeConfigSchema = z22.object({
14647
- entryPoints: z22.array(z22.string()).optional(),
14648
- includeTypes: z22.boolean().optional(),
14649
- includeInternals: z22.boolean().optional(),
14650
- ignorePatterns: z22.array(z22.string()).optional(),
14651
- treatDynamicImportsAs: z22.enum(["used", "unknown"]).optional()
15461
+ DeadCodeConfigSchema = z4.object({
15462
+ entryPoints: z4.array(z4.string()).optional(),
15463
+ includeTypes: z4.boolean().optional(),
15464
+ includeInternals: z4.boolean().optional(),
15465
+ ignorePatterns: z4.array(z4.string()).optional(),
15466
+ treatDynamicImportsAs: z4.enum(["used", "unknown"]).optional()
14652
15467
  });
14653
- EntropyConfigSchema = z22.object({
14654
- rootDir: z22.string(),
14655
- parser: z22.any().optional(),
15468
+ EntropyConfigSchema = z4.object({
15469
+ rootDir: z4.string(),
15470
+ parser: z4.any().optional(),
14656
15471
  // LanguageParser instance, can't validate
14657
- entryPoints: z22.array(z22.string()).optional(),
14658
- analyze: z22.object({
14659
- drift: z22.union([z22.boolean(), DriftConfigSchema]).optional(),
14660
- deadCode: z22.union([z22.boolean(), DeadCodeConfigSchema]).optional(),
14661
- patterns: z22.union([z22.boolean(), PatternConfigSchema]).optional()
15472
+ entryPoints: z4.array(z4.string()).optional(),
15473
+ analyze: z4.object({
15474
+ drift: z4.union([z4.boolean(), DriftConfigSchema]).optional(),
15475
+ deadCode: z4.union([z4.boolean(), DeadCodeConfigSchema]).optional(),
15476
+ patterns: z4.union([z4.boolean(), PatternConfigSchema]).optional()
14662
15477
  }),
14663
- include: z22.array(z22.string()).optional(),
14664
- exclude: z22.array(z22.string()).optional(),
14665
- docPaths: z22.array(z22.string()).optional()
15478
+ include: z4.array(z4.string()).optional(),
15479
+ exclude: z4.array(z4.string()).optional(),
15480
+ docPaths: z4.array(z4.string()).optional()
14666
15481
  });
14667
15482
  BaselineManager = class {
14668
15483
  baselinesPath;
14669
15484
  constructor(projectRoot) {
14670
- this.baselinesPath = join15(projectRoot, ".harness", "perf", "baselines.json");
15485
+ this.baselinesPath = join17(projectRoot, ".harness", "perf", "baselines.json");
14671
15486
  }
14672
15487
  /**
14673
15488
  * Load the baselines file from disk.
@@ -14942,16 +15757,16 @@ var init_dist3 = __esm({
14942
15757
  walkDir(dir, entries) {
14943
15758
  let items;
14944
15759
  try {
14945
- items = fs4.readdirSync(dir, { withFileTypes: true });
15760
+ items = fs6.readdirSync(dir, { withFileTypes: true });
14946
15761
  } catch {
14947
15762
  return;
14948
15763
  }
14949
15764
  for (const item of items) {
14950
15765
  if (item.isDirectory()) {
14951
15766
  if (SKIP_DIRS.has(item.name)) continue;
14952
- this.walkDir(path.join(dir, item.name), entries);
14953
- } else if (item.isFile() && SOURCE_EXTENSIONS.has(path.extname(item.name))) {
14954
- this.scanFile(path.join(dir, item.name), entries);
15767
+ this.walkDir(path3.join(dir, item.name), entries);
15768
+ } else if (item.isFile() && SOURCE_EXTENSIONS.has(path3.extname(item.name))) {
15769
+ this.scanFile(path3.join(dir, item.name), entries);
14955
15770
  }
14956
15771
  }
14957
15772
  }
@@ -14966,12 +15781,12 @@ var init_dist3 = __esm({
14966
15781
  scanFile(filePath, entries) {
14967
15782
  let content;
14968
15783
  try {
14969
- content = fs4.readFileSync(filePath, "utf-8");
15784
+ content = fs6.readFileSync(filePath, "utf-8");
14970
15785
  } catch {
14971
15786
  return;
14972
15787
  }
14973
15788
  const lines = content.split("\n");
14974
- const relativePath = path.relative(this.projectRoot, filePath).replace(/\\/g, "/");
15789
+ const relativePath = path3.relative(this.projectRoot, filePath).replace(/\\/g, "/");
14975
15790
  for (let i = 0; i < lines.length; i++) {
14976
15791
  if (!lines[i].includes("@perf-critical")) continue;
14977
15792
  const fnName = this.resolveFunctionName(lines, i + 1);
@@ -15370,46 +16185,46 @@ var init_dist3 = __esm({
15370
16185
  return Ok(void 0);
15371
16186
  }
15372
16187
  };
15373
- CategorySnapshotSchema = z3.object({
16188
+ CategorySnapshotSchema = z5.object({
15374
16189
  /** Aggregate metric value (e.g., violation count, avg complexity) */
15375
- value: z3.number(),
16190
+ value: z5.number(),
15376
16191
  /** Count of violations in this category */
15377
- violationCount: z3.number()
16192
+ violationCount: z5.number()
15378
16193
  });
15379
- TimelineSnapshotSchema = z3.object({
16194
+ TimelineSnapshotSchema = z5.object({
15380
16195
  /** ISO 8601 timestamp of capture */
15381
- capturedAt: z3.string().datetime(),
16196
+ capturedAt: z5.string().datetime(),
15382
16197
  /** Git commit hash at capture time */
15383
- commitHash: z3.string(),
16198
+ commitHash: z5.string(),
15384
16199
  /** Composite stability score (0-100, higher is healthier) */
15385
- stabilityScore: z3.number().min(0).max(100),
16200
+ stabilityScore: z5.number().min(0).max(100),
15386
16201
  /** Per-category metric aggregates */
15387
- metrics: z3.record(ArchMetricCategorySchema, CategorySnapshotSchema)
16202
+ metrics: z5.record(ArchMetricCategorySchema, CategorySnapshotSchema)
15388
16203
  });
15389
- TimelineFileSchema = z3.object({
15390
- version: z3.literal(1),
15391
- snapshots: z3.array(TimelineSnapshotSchema)
16204
+ TimelineFileSchema = z5.object({
16205
+ version: z5.literal(1),
16206
+ snapshots: z5.array(TimelineSnapshotSchema)
15392
16207
  });
15393
- TrendLineSchema = z3.object({
16208
+ TrendLineSchema = z5.object({
15394
16209
  /** Current value */
15395
- current: z3.number(),
16210
+ current: z5.number(),
15396
16211
  /** Previous value (from comparison snapshot) */
15397
- previous: z3.number(),
16212
+ previous: z5.number(),
15398
16213
  /** Absolute delta (current - previous) */
15399
- delta: z3.number(),
16214
+ delta: z5.number(),
15400
16215
  /** Direction indicator */
15401
- direction: z3.enum(["improving", "stable", "declining"])
16216
+ direction: z5.enum(["improving", "stable", "declining"])
15402
16217
  });
15403
- TrendResultSchema = z3.object({
16218
+ TrendResultSchema = z5.object({
15404
16219
  /** Overall stability trend */
15405
16220
  stability: TrendLineSchema,
15406
16221
  /** Per-category trends */
15407
- categories: z3.record(ArchMetricCategorySchema, TrendLineSchema),
16222
+ categories: z5.record(ArchMetricCategorySchema, TrendLineSchema),
15408
16223
  /** Number of snapshots analyzed */
15409
- snapshotCount: z3.number(),
16224
+ snapshotCount: z5.number(),
15410
16225
  /** Time range covered */
15411
- from: z3.string(),
15412
- to: z3.string()
16226
+ from: z5.string(),
16227
+ to: z5.string()
15413
16228
  });
15414
16229
  DEFAULT_STABILITY_THRESHOLDS = {
15415
16230
  "circular-deps": 5,
@@ -15424,7 +16239,7 @@ var init_dist3 = __esm({
15424
16239
  TimelineManager = class {
15425
16240
  timelinePath;
15426
16241
  constructor(rootDir) {
15427
- this.timelinePath = join17(rootDir, ".harness", "arch", "timeline.json");
16242
+ this.timelinePath = join19(rootDir, ".harness", "arch", "timeline.json");
15428
16243
  }
15429
16244
  /**
15430
16245
  * Load timeline from disk.
@@ -15608,80 +16423,80 @@ var init_dist3 = __esm({
15608
16423
  };
15609
16424
  }
15610
16425
  };
15611
- ConfidenceTierSchema = z4.enum(["high", "medium", "low"]);
15612
- RegressionResultSchema = z4.object({
15613
- slope: z4.number(),
15614
- intercept: z4.number(),
15615
- rSquared: z4.number().min(0).max(1),
15616
- dataPoints: z4.number().int().min(0)
16426
+ ConfidenceTierSchema = z6.enum(["high", "medium", "low"]);
16427
+ RegressionResultSchema = z6.object({
16428
+ slope: z6.number(),
16429
+ intercept: z6.number(),
16430
+ rSquared: z6.number().min(0).max(1),
16431
+ dataPoints: z6.number().int().min(0)
15617
16432
  });
15618
- DirectionSchema = z4.enum(["improving", "stable", "declining"]);
15619
- CategoryForecastSchema = z4.object({
16433
+ DirectionSchema = z6.enum(["improving", "stable", "declining"]);
16434
+ CategoryForecastSchema = z6.object({
15620
16435
  category: ArchMetricCategorySchema,
15621
- current: z4.number(),
15622
- threshold: z4.number(),
15623
- projectedValue4w: z4.number(),
15624
- projectedValue8w: z4.number(),
15625
- projectedValue12w: z4.number(),
15626
- thresholdCrossingWeeks: z4.number().nullable(),
16436
+ current: z6.number(),
16437
+ threshold: z6.number(),
16438
+ projectedValue4w: z6.number(),
16439
+ projectedValue8w: z6.number(),
16440
+ projectedValue12w: z6.number(),
16441
+ thresholdCrossingWeeks: z6.number().nullable(),
15627
16442
  confidence: ConfidenceTierSchema,
15628
16443
  regression: RegressionResultSchema,
15629
16444
  direction: DirectionSchema
15630
16445
  });
15631
- SpecImpactSignalsSchema = z4.object({
15632
- newFileCount: z4.number().int().min(0),
15633
- affectedLayers: z4.array(z4.string()),
15634
- newDependencies: z4.number().int().min(0),
15635
- phaseCount: z4.number().int().min(0)
16446
+ SpecImpactSignalsSchema = z6.object({
16447
+ newFileCount: z6.number().int().min(0),
16448
+ affectedLayers: z6.array(z6.string()),
16449
+ newDependencies: z6.number().int().min(0),
16450
+ phaseCount: z6.number().int().min(0)
15636
16451
  });
15637
- SpecImpactEstimateSchema = z4.object({
15638
- specPath: z4.string(),
15639
- featureName: z4.string(),
16452
+ SpecImpactEstimateSchema = z6.object({
16453
+ specPath: z6.string(),
16454
+ featureName: z6.string(),
15640
16455
  signals: SpecImpactSignalsSchema,
15641
- deltas: z4.record(ArchMetricCategorySchema, z4.number()).optional()
16456
+ deltas: z6.record(ArchMetricCategorySchema, z6.number()).optional()
15642
16457
  });
15643
- ContributingFeatureSchema = z4.object({
15644
- name: z4.string(),
15645
- specPath: z4.string(),
15646
- delta: z4.number()
16458
+ ContributingFeatureSchema = z6.object({
16459
+ name: z6.string(),
16460
+ specPath: z6.string(),
16461
+ delta: z6.number()
15647
16462
  });
15648
- AdjustedForecastSchema = z4.object({
16463
+ AdjustedForecastSchema = z6.object({
15649
16464
  baseline: CategoryForecastSchema,
15650
16465
  adjusted: CategoryForecastSchema,
15651
- contributingFeatures: z4.array(ContributingFeatureSchema)
16466
+ contributingFeatures: z6.array(ContributingFeatureSchema)
15652
16467
  });
15653
- PredictionWarningSchema = z4.object({
15654
- severity: z4.enum(["critical", "warning", "info"]),
16468
+ PredictionWarningSchema = z6.object({
16469
+ severity: z6.enum(["critical", "warning", "info"]),
15655
16470
  category: ArchMetricCategorySchema,
15656
- message: z4.string(),
15657
- weeksUntil: z4.number(),
16471
+ message: z6.string(),
16472
+ weeksUntil: z6.number(),
15658
16473
  confidence: ConfidenceTierSchema,
15659
- contributingFeatures: z4.array(z4.string())
16474
+ contributingFeatures: z6.array(z6.string())
15660
16475
  });
15661
- StabilityForecastSchema = z4.object({
15662
- current: z4.number(),
15663
- projected4w: z4.number(),
15664
- projected8w: z4.number(),
15665
- projected12w: z4.number(),
16476
+ StabilityForecastSchema = z6.object({
16477
+ current: z6.number(),
16478
+ projected4w: z6.number(),
16479
+ projected8w: z6.number(),
16480
+ projected12w: z6.number(),
15666
16481
  confidence: ConfidenceTierSchema,
15667
16482
  direction: DirectionSchema
15668
16483
  });
15669
- PredictionResultSchema = z4.object({
15670
- generatedAt: z4.string(),
15671
- snapshotsUsed: z4.number().int().min(0),
15672
- timelineRange: z4.object({
15673
- from: z4.string(),
15674
- to: z4.string()
16484
+ PredictionResultSchema = z6.object({
16485
+ generatedAt: z6.string(),
16486
+ snapshotsUsed: z6.number().int().min(0),
16487
+ timelineRange: z6.object({
16488
+ from: z6.string(),
16489
+ to: z6.string()
15675
16490
  }),
15676
16491
  stabilityForecast: StabilityForecastSchema,
15677
- categories: z4.record(ArchMetricCategorySchema, AdjustedForecastSchema),
15678
- warnings: z4.array(PredictionWarningSchema)
16492
+ categories: z6.record(ArchMetricCategorySchema, AdjustedForecastSchema),
16493
+ warnings: z6.array(PredictionWarningSchema)
15679
16494
  });
15680
- PredictionOptionsSchema = z4.object({
15681
- horizon: z4.number().int().min(1).default(12),
15682
- includeRoadmap: z4.boolean().default(true),
15683
- categories: z4.array(ArchMetricCategorySchema).optional(),
15684
- thresholds: z4.record(ArchMetricCategorySchema, z4.number()).optional()
16495
+ PredictionOptionsSchema = z6.object({
16496
+ horizon: z6.number().int().min(1).default(12),
16497
+ includeRoadmap: z6.boolean().default(true),
16498
+ categories: z6.array(ArchMetricCategorySchema).optional(),
16499
+ thresholds: z6.record(ArchMetricCategorySchema, z6.number()).optional()
15685
16500
  });
15686
16501
  VALID_STATUSES = /* @__PURE__ */ new Set([
15687
16502
  "backlog",
@@ -16014,8 +16829,8 @@ var init_dist3 = __esm({
16014
16829
  return null;
16015
16830
  }
16016
16831
  try {
16017
- const roadmapPath = path2.join(this.rootDir, "roadmap.md");
16018
- const raw = fs5.readFileSync(roadmapPath, "utf-8");
16832
+ const roadmapPath = path4.join(this.rootDir, "roadmap.md");
16833
+ const raw = fs7.readFileSync(roadmapPath, "utf-8");
16019
16834
  const parseResult = parseRoadmap(raw);
16020
16835
  if (!parseResult.ok) return null;
16021
16836
  const features = parseResult.value.milestones.flatMap(
@@ -16050,8 +16865,8 @@ var init_dist3 = __esm({
16050
16865
  * @param specPath - Relative path from rootDir to the spec file.
16051
16866
  */
16052
16867
  estimate(specPath) {
16053
- const absolutePath = path3.join(this.rootDir, specPath);
16054
- const content = fs6.readFileSync(absolutePath, "utf-8");
16868
+ const absolutePath = path5.join(this.rootDir, specPath);
16869
+ const content = fs8.readFileSync(absolutePath, "utf-8");
16055
16870
  const newFileCount = this.extractNewFileCount(content);
16056
16871
  const affectedLayers = this.extractAffectedLayers(content);
16057
16872
  const newDependencies = this.extractNewDependencies(content);
@@ -16063,7 +16878,7 @@ var init_dist3 = __esm({
16063
16878
  phaseCount
16064
16879
  );
16065
16880
  const h1Match = content.match(/^#\s+(.+)$/m);
16066
- const featureName = h1Match ? h1Match[1].trim() : path3.basename(specPath, ".md");
16881
+ const featureName = h1Match ? h1Match[1].trim() : path5.basename(specPath, ".md");
16067
16882
  return {
16068
16883
  specPath,
16069
16884
  featureName,
@@ -16084,8 +16899,8 @@ var init_dist3 = __esm({
16084
16899
  const results = [];
16085
16900
  for (const feature of features) {
16086
16901
  if (!feature.spec) continue;
16087
- const absolutePath = path3.join(this.rootDir, feature.spec);
16088
- if (!fs6.existsSync(absolutePath)) continue;
16902
+ const absolutePath = path5.join(this.rootDir, feature.spec);
16903
+ if (!fs8.existsSync(absolutePath)) continue;
16089
16904
  const estimate = this.estimate(feature.spec);
16090
16905
  results.push({ ...estimate, featureName: feature.name });
16091
16906
  }
@@ -16113,8 +16928,8 @@ var init_dist3 = __esm({
16113
16928
  }
16114
16929
  let count = 0;
16115
16930
  for (const fp of filePaths) {
16116
- const absolute = path3.join(this.rootDir, fp);
16117
- if (!fs6.existsSync(absolute)) {
16931
+ const absolute = path5.join(this.rootDir, fp);
16932
+ if (!fs8.existsSync(absolute)) {
16118
16933
  count++;
16119
16934
  }
16120
16935
  }
@@ -16184,8 +16999,8 @@ var init_dist3 = __esm({
16184
16999
  // --- Private: Config Loading ---
16185
17000
  loadLayerNames() {
16186
17001
  try {
16187
- const configPath = path3.join(this.rootDir, "harness.config.json");
16188
- const raw = fs6.readFileSync(configPath, "utf-8");
17002
+ const configPath = path5.join(this.rootDir, "harness.config.json");
17003
+ const raw = fs8.readFileSync(configPath, "utf-8");
16189
17004
  const config = JSON.parse(raw);
16190
17005
  return (config.layers ?? []).map((l) => l.name);
16191
17006
  } catch {
@@ -16204,8 +17019,8 @@ var init_dist3 = __esm({
16204
17019
  historyPath;
16205
17020
  /** Load history from disk, returning empty history if file doesn't exist. */
16206
17021
  load() {
16207
- if (!fs7.existsSync(this.historyPath)) return { ...EMPTY_HISTORY, snapshots: [] };
16208
- const raw = fs7.readFileSync(this.historyPath, "utf-8");
17022
+ if (!fs9.existsSync(this.historyPath)) return { ...EMPTY_HISTORY, snapshots: [] };
17023
+ const raw = fs9.readFileSync(this.historyPath, "utf-8");
16209
17024
  return JSON.parse(raw);
16210
17025
  }
16211
17026
  /** Append a timestamped snapshot of current violations. */
@@ -16219,18 +17034,18 @@ var init_dist3 = __esm({
16219
17034
  }
16220
17035
  /** Prune snapshots older than retentionDays. */
16221
17036
  prune(retentionDays) {
16222
- if (!fs7.existsSync(this.historyPath)) return;
17037
+ if (!fs9.existsSync(this.historyPath)) return;
16223
17038
  const history = this.load();
16224
17039
  const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
16225
17040
  history.snapshots = history.snapshots.filter((s) => new Date(s.timestamp).getTime() >= cutoff);
16226
17041
  this.write(history);
16227
17042
  }
16228
17043
  write(history) {
16229
- const dir = path4.dirname(this.historyPath);
16230
- if (!fs7.existsSync(dir)) {
16231
- fs7.mkdirSync(dir, { recursive: true });
17044
+ const dir = path6.dirname(this.historyPath);
17045
+ if (!fs9.existsSync(dir)) {
17046
+ fs9.mkdirSync(dir, { recursive: true });
16232
17047
  }
16233
- fs7.writeFileSync(this.historyPath, JSON.stringify(history, null, 2), "utf-8");
17048
+ fs9.writeFileSync(this.historyPath, JSON.stringify(history, null, 2), "utf-8");
16234
17049
  }
16235
17050
  };
16236
17051
  NORMALIZERS = {
@@ -16245,81 +17060,81 @@ var init_dist3 = __esm({
16245
17060
  MAX_SAMPLES = 5;
16246
17061
  DEFAULT_WINDOW_WEEKS = 4;
16247
17062
  DEFAULT_MIN_OCCURRENCES = 3;
16248
- FailureEntrySchema = z5.object({
16249
- date: z5.string(),
16250
- skill: z5.string(),
16251
- type: z5.string(),
16252
- description: z5.string()
17063
+ FailureEntrySchema = z7.object({
17064
+ date: z7.string(),
17065
+ skill: z7.string(),
17066
+ type: z7.string(),
17067
+ description: z7.string()
16253
17068
  });
16254
- HandoffSchema = z5.object({
16255
- timestamp: z5.string(),
16256
- fromSkill: z5.string(),
16257
- phase: z5.string(),
16258
- summary: z5.string(),
16259
- completed: z5.array(z5.string()).default([]),
16260
- pending: z5.array(z5.string()).default([]),
16261
- concerns: z5.array(z5.string()).default([]),
16262
- decisions: z5.array(
16263
- z5.object({
16264
- what: z5.string(),
16265
- why: z5.string()
17069
+ HandoffSchema = z7.object({
17070
+ timestamp: z7.string(),
17071
+ fromSkill: z7.string(),
17072
+ phase: z7.string(),
17073
+ summary: z7.string(),
17074
+ completed: z7.array(z7.string()).default([]),
17075
+ pending: z7.array(z7.string()).default([]),
17076
+ concerns: z7.array(z7.string()).default([]),
17077
+ decisions: z7.array(
17078
+ z7.object({
17079
+ what: z7.string(),
17080
+ why: z7.string()
16266
17081
  })
16267
17082
  ).default([]),
16268
- blockers: z5.array(z5.string()).default([]),
16269
- contextKeywords: z5.array(z5.string()).default([]),
16270
- recommendedSkills: z5.object({
16271
- apply: z5.array(z5.string()),
16272
- reference: z5.array(z5.string()),
16273
- consider: z5.array(z5.string()),
16274
- skillsPath: z5.string()
17083
+ blockers: z7.array(z7.string()).default([]),
17084
+ contextKeywords: z7.array(z7.string()).default([]),
17085
+ recommendedSkills: z7.object({
17086
+ apply: z7.array(z7.string()),
17087
+ reference: z7.array(z7.string()),
17088
+ consider: z7.array(z7.string()),
17089
+ skillsPath: z7.string()
16275
17090
  }).optional()
16276
17091
  });
16277
- GateCheckSchema = z5.object({
16278
- name: z5.string(),
16279
- passed: z5.boolean(),
16280
- command: z5.string(),
16281
- output: z5.string().optional(),
16282
- duration: z5.number().optional()
17092
+ GateCheckSchema = z7.object({
17093
+ name: z7.string(),
17094
+ passed: z7.boolean(),
17095
+ command: z7.string(),
17096
+ output: z7.string().optional(),
17097
+ duration: z7.number().optional()
16283
17098
  });
16284
- GateResultSchema = z5.object({
16285
- passed: z5.boolean(),
16286
- checks: z5.array(GateCheckSchema)
17099
+ GateResultSchema = z7.object({
17100
+ passed: z7.boolean(),
17101
+ checks: z7.array(GateCheckSchema)
16287
17102
  });
16288
- GateConfigSchema = z5.object({
16289
- checks: z5.array(
16290
- z5.object({
16291
- name: z5.string(),
16292
- command: z5.string()
17103
+ GateConfigSchema = z7.object({
17104
+ checks: z7.array(
17105
+ z7.object({
17106
+ name: z7.string(),
17107
+ command: z7.string()
16293
17108
  })
16294
17109
  ).optional(),
16295
- trace: z5.boolean().optional()
17110
+ trace: z7.boolean().optional()
16296
17111
  });
16297
- HarnessStateSchema = z5.object({
16298
- schemaVersion: z5.literal(1),
16299
- position: z5.object({
16300
- phase: z5.string().optional(),
16301
- task: z5.string().optional()
17112
+ HarnessStateSchema = z7.object({
17113
+ schemaVersion: z7.literal(1),
17114
+ position: z7.object({
17115
+ phase: z7.string().optional(),
17116
+ task: z7.string().optional()
16302
17117
  }).default({}),
16303
- decisions: z5.array(
16304
- z5.object({
16305
- date: z5.string(),
16306
- decision: z5.string(),
16307
- context: z5.string()
17118
+ decisions: z7.array(
17119
+ z7.object({
17120
+ date: z7.string(),
17121
+ decision: z7.string(),
17122
+ context: z7.string()
16308
17123
  })
16309
17124
  ).default([]),
16310
- blockers: z5.array(
16311
- z5.object({
16312
- id: z5.string(),
16313
- description: z5.string(),
16314
- status: z5.enum(["open", "resolved"])
17125
+ blockers: z7.array(
17126
+ z7.object({
17127
+ id: z7.string(),
17128
+ description: z7.string(),
17129
+ status: z7.enum(["open", "resolved"])
16315
17130
  })
16316
17131
  ).default([]),
16317
- progress: z5.record(z5.enum(["pending", "in_progress", "complete"])).default({}),
16318
- lastSession: z5.object({
16319
- date: z5.string(),
16320
- summary: z5.string(),
16321
- lastSkill: z5.string().optional(),
16322
- pendingTasks: z5.array(z5.string()).optional()
17132
+ progress: z7.record(z7.enum(["pending", "in_progress", "complete"])).default({}),
17133
+ lastSession: z7.object({
17134
+ date: z7.string(),
17135
+ summary: z7.string(),
17136
+ lastSkill: z7.string().optional(),
17137
+ pendingTasks: z7.array(z7.string()).optional()
16323
17138
  }).optional()
16324
17139
  });
16325
17140
  DEFAULT_STATE = {
@@ -16329,16 +17144,16 @@ var init_dist3 = __esm({
16329
17144
  blockers: [],
16330
17145
  progress: {}
16331
17146
  };
16332
- StreamInfoSchema = z6.object({
16333
- name: z6.string(),
16334
- branch: z6.string().optional(),
16335
- createdAt: z6.string(),
16336
- lastActiveAt: z6.string()
17147
+ StreamInfoSchema = z8.object({
17148
+ name: z8.string(),
17149
+ branch: z8.string().optional(),
17150
+ createdAt: z8.string(),
17151
+ lastActiveAt: z8.string()
16337
17152
  });
16338
- StreamIndexSchema = z6.object({
16339
- schemaVersion: z6.literal(1),
16340
- activeStream: z6.string().nullable(),
16341
- streams: z6.record(StreamInfoSchema)
17153
+ StreamIndexSchema = z8.object({
17154
+ schemaVersion: z8.literal(1),
17155
+ activeStream: z8.string().nullable(),
17156
+ streams: z8.record(StreamInfoSchema)
16342
17157
  });
16343
17158
  DEFAULT_STREAM_INDEX = {
16344
17159
  schemaVersion: 1,
@@ -16379,15 +17194,15 @@ var init_dist3 = __esm({
16379
17194
  failuresCacheMap = /* @__PURE__ */ new Map();
16380
17195
  FAILURE_LINE_REGEX = /^- \*\*(\d{4}-\d{2}-\d{2}) \[skill:([^\]]+)\] \[type:([^\]]+)\]:\*\* (.+)$/;
16381
17196
  SAFE_GATE_COMMAND = /^(?:npm|pnpm|yarn)\s+(?:test|run\s+[\w.-]+|run-script\s+[\w.-]+)$|^go\s+(?:test|build|vet|fmt)\s+[\w./ -]+$|^(?:python|python3)\s+-m\s+[\w.-]+$|^make\s+[\w.-]+$|^cargo\s+(?:test|build|check|clippy)(?:\s+[\w./ -]+)?$|^(?:gradle|mvn)\s+[\w:.-]+$/;
16382
- SkillEventSchema = z7.object({
16383
- timestamp: z7.string(),
16384
- skill: z7.string(),
16385
- session: z7.string().optional(),
16386
- type: z7.enum(["phase_transition", "decision", "gate_result", "handoff", "error", "checkpoint"]),
16387
- summary: z7.string(),
16388
- data: z7.record(z7.unknown()).optional(),
16389
- refs: z7.array(z7.string()).optional(),
16390
- contentHash: z7.string().optional()
17197
+ SkillEventSchema = z9.object({
17198
+ timestamp: z9.string(),
17199
+ skill: z9.string(),
17200
+ session: z9.string().optional(),
17201
+ type: z9.enum(["phase_transition", "decision", "gate_result", "handoff", "error", "checkpoint"]),
17202
+ summary: z9.string(),
17203
+ data: z9.record(z9.unknown()).optional(),
17204
+ refs: z9.array(z9.string()).optional(),
17205
+ contentHash: z9.string().optional()
16391
17206
  });
16392
17207
  knownHashesCache = /* @__PURE__ */ new Map();
16393
17208
  EVENT_FORMATTERS = {
@@ -16430,19 +17245,19 @@ var init_dist3 = __esm({
16430
17245
  rules: {},
16431
17246
  exclude: ["**/node_modules/**", "**/dist/**", "**/*.test.ts", "**/fixtures/**"]
16432
17247
  };
16433
- RuleOverrideSchema = z8.enum(["off", "error", "warning", "info"]);
16434
- SecurityConfigSchema = z8.object({
16435
- enabled: z8.boolean().default(true),
16436
- strict: z8.boolean().default(false),
16437
- rules: z8.record(z8.string(), RuleOverrideSchema).optional().default({}),
16438
- exclude: z8.array(z8.string()).optional().default(["**/node_modules/**", "**/dist/**", "**/*.test.ts", "**/fixtures/**"]),
16439
- external: z8.object({
16440
- semgrep: z8.object({
16441
- enabled: z8.union([z8.literal("auto"), z8.boolean()]).default("auto"),
16442
- rulesets: z8.array(z8.string()).optional()
17248
+ RuleOverrideSchema = z10.enum(["off", "error", "warning", "info"]);
17249
+ SecurityConfigSchema = z10.object({
17250
+ enabled: z10.boolean().default(true),
17251
+ strict: z10.boolean().default(false),
17252
+ rules: z10.record(z10.string(), RuleOverrideSchema).optional().default({}),
17253
+ exclude: z10.array(z10.string()).optional().default(["**/node_modules/**", "**/dist/**", "**/*.test.ts", "**/fixtures/**"]),
17254
+ external: z10.object({
17255
+ semgrep: z10.object({
17256
+ enabled: z10.union([z10.literal("auto"), z10.boolean()]).default("auto"),
17257
+ rulesets: z10.array(z10.string()).optional()
16443
17258
  }).optional(),
16444
- gitleaks: z8.object({
16445
- enabled: z8.union([z8.literal("auto"), z8.boolean()]).default("auto")
17259
+ gitleaks: z10.object({
17260
+ enabled: z10.union([z10.literal("auto"), z10.boolean()]).default("auto")
16446
17261
  }).optional()
16447
17262
  }).optional()
16448
17263
  });
@@ -17232,7 +18047,7 @@ var init_dist3 = __esm({
17232
18047
  }
17233
18048
  async scanFile(filePath) {
17234
18049
  if (!this.config.enabled) return [];
17235
- const content = await fs25.readFile(filePath, "utf-8");
18050
+ const content = await fs27.readFile(filePath, "utf-8");
17236
18051
  return this.scanContentForFile(content, filePath, 1);
17237
18052
  }
17238
18053
  scanContentForFile(content, filePath, startLine = 1) {
@@ -17541,88 +18356,88 @@ var init_dist3 = __esm({
17541
18356
  ];
17542
18357
  TAINT_DURATION_MS = 30 * 60 * 1e3;
17543
18358
  DEFAULT_SESSION_ID = "default";
17544
- SecurityCategorySnapshotSchema = z9.object({
17545
- findingCount: z9.number(),
17546
- errorCount: z9.number(),
17547
- warningCount: z9.number(),
17548
- infoCount: z9.number()
18359
+ SecurityCategorySnapshotSchema = z11.object({
18360
+ findingCount: z11.number(),
18361
+ errorCount: z11.number(),
18362
+ warningCount: z11.number(),
18363
+ infoCount: z11.number()
17549
18364
  });
17550
- SupplyChainSnapshotSchema = z9.object({
17551
- critical: z9.number(),
17552
- high: z9.number(),
17553
- moderate: z9.number(),
17554
- low: z9.number(),
17555
- info: z9.number(),
17556
- total: z9.number()
18365
+ SupplyChainSnapshotSchema = z11.object({
18366
+ critical: z11.number(),
18367
+ high: z11.number(),
18368
+ moderate: z11.number(),
18369
+ low: z11.number(),
18370
+ info: z11.number(),
18371
+ total: z11.number()
17557
18372
  });
17558
- SecurityTimelineSnapshotSchema = z9.object({
17559
- capturedAt: z9.string().datetime(),
17560
- commitHash: z9.string(),
17561
- securityScore: z9.number().min(0).max(100),
17562
- totalFindings: z9.number(),
17563
- bySeverity: z9.object({
17564
- error: z9.number(),
17565
- warning: z9.number(),
17566
- info: z9.number()
18373
+ SecurityTimelineSnapshotSchema = z11.object({
18374
+ capturedAt: z11.string().datetime(),
18375
+ commitHash: z11.string(),
18376
+ securityScore: z11.number().min(0).max(100),
18377
+ totalFindings: z11.number(),
18378
+ bySeverity: z11.object({
18379
+ error: z11.number(),
18380
+ warning: z11.number(),
18381
+ info: z11.number()
17567
18382
  }),
17568
- byCategory: z9.record(z9.string(), SecurityCategorySnapshotSchema),
18383
+ byCategory: z11.record(z11.string(), SecurityCategorySnapshotSchema),
17569
18384
  supplyChain: SupplyChainSnapshotSchema,
17570
- suppressionCount: z9.number(),
17571
- findingIds: z9.array(z9.string())
18385
+ suppressionCount: z11.number(),
18386
+ findingIds: z11.array(z11.string())
17572
18387
  });
17573
- FindingLifecycleSchema = z9.object({
17574
- findingId: z9.string(),
17575
- ruleId: z9.string(),
17576
- category: z9.string(),
17577
- severity: z9.string(),
17578
- file: z9.string(),
17579
- firstSeenAt: z9.string().datetime(),
17580
- firstSeenCommit: z9.string(),
17581
- resolvedAt: z9.string().datetime().nullable(),
17582
- resolvedCommit: z9.string().nullable()
18388
+ FindingLifecycleSchema = z11.object({
18389
+ findingId: z11.string(),
18390
+ ruleId: z11.string(),
18391
+ category: z11.string(),
18392
+ severity: z11.string(),
18393
+ file: z11.string(),
18394
+ firstSeenAt: z11.string().datetime(),
18395
+ firstSeenCommit: z11.string(),
18396
+ resolvedAt: z11.string().datetime().nullable(),
18397
+ resolvedCommit: z11.string().nullable()
17583
18398
  });
17584
- SecurityTimelineFileSchema = z9.object({
17585
- version: z9.literal(1),
17586
- snapshots: z9.array(SecurityTimelineSnapshotSchema),
17587
- findingLifecycles: z9.array(FindingLifecycleSchema)
18399
+ SecurityTimelineFileSchema = z11.object({
18400
+ version: z11.literal(1),
18401
+ snapshots: z11.array(SecurityTimelineSnapshotSchema),
18402
+ findingLifecycles: z11.array(FindingLifecycleSchema)
17588
18403
  });
17589
- DirectionSchema2 = z9.enum(["improving", "stable", "declining"]);
17590
- SecurityTrendLineSchema = z9.object({
17591
- current: z9.number(),
17592
- previous: z9.number(),
17593
- delta: z9.number(),
18404
+ DirectionSchema2 = z11.enum(["improving", "stable", "declining"]);
18405
+ SecurityTrendLineSchema = z11.object({
18406
+ current: z11.number(),
18407
+ previous: z11.number(),
18408
+ delta: z11.number(),
17594
18409
  direction: DirectionSchema2
17595
18410
  });
17596
- TrendAttributionSchema = z9.object({
17597
- category: z9.string(),
17598
- delta: z9.number(),
18411
+ TrendAttributionSchema = z11.object({
18412
+ category: z11.string(),
18413
+ delta: z11.number(),
17599
18414
  direction: DirectionSchema2,
17600
- description: z9.string()
18415
+ description: z11.string()
17601
18416
  });
17602
- SecurityTrendResultSchema = z9.object({
18417
+ SecurityTrendResultSchema = z11.object({
17603
18418
  score: SecurityTrendLineSchema,
17604
18419
  totalFindings: SecurityTrendLineSchema,
17605
- bySeverity: z9.object({
18420
+ bySeverity: z11.object({
17606
18421
  error: SecurityTrendLineSchema,
17607
18422
  warning: SecurityTrendLineSchema,
17608
18423
  info: SecurityTrendLineSchema
17609
18424
  }),
17610
18425
  supplyChain: SecurityTrendLineSchema,
17611
- snapshotCount: z9.number(),
17612
- from: z9.string(),
17613
- to: z9.string(),
17614
- attribution: z9.array(TrendAttributionSchema)
18426
+ snapshotCount: z11.number(),
18427
+ from: z11.string(),
18428
+ to: z11.string(),
18429
+ attribution: z11.array(TrendAttributionSchema)
17615
18430
  });
17616
- TimeToFixStatsSchema = z9.object({
17617
- mean: z9.number(),
17618
- median: z9.number(),
17619
- count: z9.number()
18431
+ TimeToFixStatsSchema = z11.object({
18432
+ mean: z11.number(),
18433
+ median: z11.number(),
18434
+ count: z11.number()
17620
18435
  });
17621
- TimeToFixResultSchema = z9.object({
18436
+ TimeToFixResultSchema = z11.object({
17622
18437
  overall: TimeToFixStatsSchema,
17623
- byCategory: z9.record(z9.string(), TimeToFixStatsSchema),
17624
- openFindings: z9.number(),
17625
- oldestOpenDays: z9.number().nullable()
18438
+ byCategory: z11.record(z11.string(), TimeToFixStatsSchema),
18439
+ openFindings: z11.number(),
18440
+ oldestOpenDays: z11.number().nullable()
17626
18441
  });
17627
18442
  EMPTY_SUPPLY_CHAIN = {
17628
18443
  critical: 0,
@@ -17637,11 +18452,15 @@ var init_dist3 = __esm({
17637
18452
  timelinePath;
17638
18453
  constructor(rootDir) {
17639
18454
  this.rootDir = rootDir;
17640
- this.timelinePath = join372(rootDir, ".harness", "security", "timeline.json");
18455
+ this.timelinePath = join39(rootDir, ".harness", "security", "timeline.json");
17641
18456
  }
17642
18457
  /**
17643
18458
  * Load timeline from disk.
17644
18459
  * Returns empty SecurityTimelineFile if file does not exist or is invalid.
18460
+ * Lifecycle entries with absolute paths under rootDir are migrated to repo-relative
18461
+ * form on read (older versions persisted whatever the scanner emitted, which leaked
18462
+ * machine paths into committed timeline.json). Migrated files are re-saved so the
18463
+ * fixup is one-shot.
17645
18464
  */
17646
18465
  load() {
17647
18466
  if (!existsSync332(this.timelinePath)) {
@@ -17658,6 +18477,15 @@ var init_dist3 = __esm({
17658
18477
  );
17659
18478
  return { version: 1, snapshots: [], findingLifecycles: [] };
17660
18479
  }
18480
+ let mutated = false;
18481
+ for (const lc of parsed.data.findingLifecycles) {
18482
+ const next = this.toRepoRelativePath(lc.file);
18483
+ if (next !== lc.file) {
18484
+ lc.file = next;
18485
+ mutated = true;
18486
+ }
18487
+ }
18488
+ if (mutated) this.save(parsed.data);
17661
18489
  return parsed.data;
17662
18490
  } catch (error) {
17663
18491
  console.error(`Error loading security timeline from ${this.timelinePath}:`, error);
@@ -17682,16 +18510,17 @@ var init_dist3 = __esm({
17682
18510
  * appends to timeline (or replaces if same commitHash), and saves.
17683
18511
  */
17684
18512
  capture(scanResult, commitHash, supplyChain) {
17685
- const byCategory = this.aggregateByCategory(scanResult.findings);
17686
- const bySeverity = this.aggregateBySeverity(scanResult.findings);
17687
- const findingIds = scanResult.findings.map((f) => securityFindingId(f));
18513
+ const normalized = scanResult.findings.map((f) => this.normalizeFindingPath(f));
18514
+ const byCategory = this.aggregateByCategory(normalized);
18515
+ const bySeverity = this.aggregateBySeverity(normalized);
18516
+ const findingIds = normalized.map((f) => securityFindingId(f));
17688
18517
  const supply = supplyChain ?? EMPTY_SUPPLY_CHAIN;
17689
18518
  const snapshot = {
17690
18519
  capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
17691
18520
  commitHash,
17692
18521
  securityScore: 0,
17693
18522
  // computed below
17694
- totalFindings: scanResult.findings.length,
18523
+ totalFindings: normalized.length,
17695
18524
  bySeverity,
17696
18525
  byCategory,
17697
18526
  supplyChain: supply,
@@ -17754,13 +18583,14 @@ var init_dist3 = __esm({
17754
18583
  */
17755
18584
  updateLifecycles(currentFindings, commitHash) {
17756
18585
  const timeline = this.load();
17757
- const currentIds = new Set(currentFindings.map((f) => securityFindingId(f)));
18586
+ const normalized = currentFindings.map((f) => this.normalizeFindingPath(f));
18587
+ const currentIds = new Set(normalized.map((f) => securityFindingId(f)));
17758
18588
  const now = (/* @__PURE__ */ new Date()).toISOString();
17759
18589
  const lifecycleMap = /* @__PURE__ */ new Map();
17760
18590
  for (const lc of timeline.findingLifecycles) {
17761
18591
  lifecycleMap.set(lc.findingId, lc);
17762
18592
  }
17763
- for (const finding of currentFindings) {
18593
+ for (const finding of normalized) {
17764
18594
  const id = securityFindingId(finding);
17765
18595
  this.upsertLifecycle(lifecycleMap, id, finding, now, commitHash);
17766
18596
  }
@@ -17875,6 +18705,23 @@ var init_dist3 = __esm({
17875
18705
  return Math.round(Math.max(0, Math.min(100, 100 - penalty)));
17876
18706
  }
17877
18707
  // --- Private helpers ---
18708
+ /**
18709
+ * Convert a path to repo-relative form using forward slashes. Absolute paths under
18710
+ * rootDir are stripped; already-relative paths are normalized to forward slashes;
18711
+ * paths that escape rootDir (relative starts with `..`) are returned unchanged so we
18712
+ * never silently misattribute a finding outside the project.
18713
+ */
18714
+ toRepoRelativePath(filePath) {
18715
+ if (!filePath) return filePath;
18716
+ if (!isAbsolute4(filePath)) return filePath.replaceAll("\\", "/");
18717
+ const rel = relative32(this.rootDir, filePath).replaceAll("\\", "/");
18718
+ if (rel === "" || rel.startsWith("../") || rel === "..") return filePath;
18719
+ return rel;
18720
+ }
18721
+ normalizeFindingPath(finding) {
18722
+ const next = this.toRepoRelativePath(finding.file);
18723
+ return next === finding.file ? finding : { ...finding, file: next };
18724
+ }
17878
18725
  upsertLifecycle(map, id, finding, now, commitHash) {
17879
18726
  if (!map.has(id)) {
17880
18727
  map.set(id, {
@@ -18015,8 +18862,8 @@ var init_dist3 = __esm({
18015
18862
  skip: "\u23ED\uFE0F"
18016
18863
  };
18017
18864
  CINotifier = class {
18018
- constructor(adapter, repo) {
18019
- this.adapter = adapter;
18865
+ constructor(adapter2, repo) {
18866
+ this.adapter = adapter2;
18020
18867
  this.repo = repo;
18021
18868
  }
18022
18869
  adapter;
@@ -18110,6 +18957,12 @@ var init_dist3 = __esm({
18110
18957
  MD_FILE_PATTERN = /\.md$/;
18111
18958
  ALL_DOMAINS = ["compliance", "bug", "security", "architecture", "learnings"];
18112
18959
  SECURITY_PATTERNS = /auth|crypto|password|secret|token|session|cookie|hash|encrypt|decrypt|sql|shell|exec|eval/i;
18960
+ JS_EXT_FALLBACKS22 = {
18961
+ ".js": [".ts", ".tsx", ".jsx"],
18962
+ ".jsx": [".tsx"],
18963
+ ".mjs": [".mts"],
18964
+ ".cjs": [".cts"]
18965
+ };
18113
18966
  SEVERITY_RANK = {
18114
18967
  suggestion: 0,
18115
18968
  important: 1,
@@ -18667,28 +19520,28 @@ var init_dist3 = __esm({
18667
19520
  POSITION_WEIGHT = 0.5;
18668
19521
  DEPENDENTS_WEIGHT = 0.3;
18669
19522
  AFFINITY_WEIGHT = 0.2;
18670
- InteractionTypeSchema = z10.enum(["question", "confirmation", "transition"]);
18671
- QuestionSchema = z10.object({
18672
- text: z10.string(),
18673
- options: z10.array(z10.string()).optional(),
18674
- default: z10.string().optional()
19523
+ InteractionTypeSchema = z12.enum(["question", "confirmation", "transition"]);
19524
+ QuestionSchema = z12.object({
19525
+ text: z12.string(),
19526
+ options: z12.array(z12.string()).optional(),
19527
+ default: z12.string().optional()
18675
19528
  });
18676
- ConfirmationSchema = z10.object({
18677
- text: z10.string(),
18678
- context: z10.string()
19529
+ ConfirmationSchema = z12.object({
19530
+ text: z12.string(),
19531
+ context: z12.string()
18679
19532
  });
18680
- TransitionSchema = z10.object({
18681
- completedPhase: z10.string(),
18682
- suggestedNext: z10.string(),
18683
- reason: z10.string(),
18684
- artifacts: z10.array(z10.string()),
18685
- requiresConfirmation: z10.boolean(),
18686
- summary: z10.string()
19533
+ TransitionSchema = z12.object({
19534
+ completedPhase: z12.string(),
19535
+ suggestedNext: z12.string(),
19536
+ reason: z12.string(),
19537
+ artifacts: z12.array(z12.string()),
19538
+ requiresConfirmation: z12.boolean(),
19539
+ summary: z12.string()
18687
19540
  });
18688
- EmitInteractionInputSchema = z10.object({
18689
- path: z10.string(),
19541
+ EmitInteractionInputSchema = z12.object({
19542
+ path: z12.string(),
18690
19543
  type: InteractionTypeSchema,
18691
- stream: z10.string().optional(),
19544
+ stream: z12.string().optional(),
18692
19545
  question: QuestionSchema.optional(),
18693
19546
  confirmation: ConfirmationSchema.optional(),
18694
19547
  transition: TransitionSchema.optional()
@@ -18699,10 +19552,10 @@ var init_dist3 = __esm({
18699
19552
  }
18700
19553
  rootDir;
18701
19554
  async scan() {
18702
- let projectName = path28.basename(this.rootDir);
19555
+ let projectName = path30.basename(this.rootDir);
18703
19556
  try {
18704
- const pkgPath = path28.join(this.rootDir, "package.json");
18705
- const pkgRaw = await fs29.readFile(pkgPath, "utf-8");
19557
+ const pkgPath = path30.join(this.rootDir, "package.json");
19558
+ const pkgRaw = await fs31.readFile(pkgPath, "utf-8");
18706
19559
  const pkg = JSON.parse(pkgRaw);
18707
19560
  if (pkg.name) projectName = pkg.name;
18708
19561
  } catch {
@@ -18815,8 +19668,8 @@ console.log('Blueprint player initialized.');
18815
19668
  styles: STYLES,
18816
19669
  scripts: SCRIPTS
18817
19670
  });
18818
- await fs30.mkdir(options.outputDir, { recursive: true });
18819
- await fs30.writeFile(path29.join(options.outputDir, "index.html"), html);
19671
+ await fs32.mkdir(options.outputDir, { recursive: true });
19672
+ await fs32.writeFile(path31.join(options.outputDir, "index.html"), html);
18820
19673
  }
18821
19674
  };
18822
19675
  TOKENS_PER_MILLION = 1e6;
@@ -19039,6 +19892,145 @@ console.log('Blueprint player initialized.');
19039
19892
  POSTHOG_BATCH_URL = "https://app.posthog.com/batch";
19040
19893
  MAX_ATTEMPTS = 3;
19041
19894
  TIMEOUT_MS = 5e3;
19895
+ CompoundLockHeldError = class extends Error {
19896
+ constructor(category, holderPid, lockPath) {
19897
+ super(
19898
+ `Compound lock for category "${category}" is held by pid ${holderPid} (lock file: ${lockPath}). If the holder is no longer running (e.g. it was SIGKILL'd), the lock is stale; recover with: rm ${lockPath}`
19899
+ );
19900
+ this.category = category;
19901
+ this.holderPid = holderPid;
19902
+ this.lockPath = lockPath;
19903
+ this.name = "CompoundLockHeldError";
19904
+ }
19905
+ category;
19906
+ holderPid;
19907
+ lockPath;
19908
+ };
19909
+ KNOWN_CATEGORIES = new Set(ALL_SOLUTION_CATEGORIES);
19910
+ ALLOWED_FIELD_KEYS = [
19911
+ "event_name",
19912
+ "count",
19913
+ "timestamp_bucket",
19914
+ "error_signature",
19915
+ "latency_ms",
19916
+ "category"
19917
+ ];
19918
+ PII_TOKENS = [
19919
+ "email",
19920
+ "user_id",
19921
+ "session_id",
19922
+ "ip",
19923
+ "name",
19924
+ "phone",
19925
+ "address",
19926
+ "message",
19927
+ "content",
19928
+ "payload"
19929
+ ];
19930
+ PII_FIELD_DENYLIST = new RegExp(`^(?:${PII_TOKENS.join("|")})$`, "i");
19931
+ PII_LINE_RE = new RegExp(`\\b(?:${PII_TOKENS.join("|")})\\b`, "i");
19932
+ ALLOWED_SET = new Set(ALLOWED_FIELD_KEYS);
19933
+ PulseAdapterAlreadyRegisteredError = class extends Error {
19934
+ constructor(adapterName) {
19935
+ super(`Pulse adapter "${adapterName}" is already registered.`);
19936
+ this.adapterName = adapterName;
19937
+ this.name = "PulseAdapterAlreadyRegisteredError";
19938
+ }
19939
+ adapterName;
19940
+ };
19941
+ REGISTRY = /* @__PURE__ */ new Map();
19942
+ MOCK_ADAPTER_NAME = "mock";
19943
+ ALLOWED_FIELD_SET = new Set(ALLOWED_FIELD_KEYS);
19944
+ adapter = {
19945
+ async query(_window, _eventNames) {
19946
+ return {
19947
+ event_name: "mock.event",
19948
+ count: 42,
19949
+ timestamp_bucket: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
19950
+ latency_ms: 123
19951
+ };
19952
+ },
19953
+ sanitize(raw) {
19954
+ const fields = {};
19955
+ if (raw && typeof raw === "object") {
19956
+ for (const [key, value] of Object.entries(raw)) {
19957
+ if (PII_FIELD_DENYLIST.test(key)) continue;
19958
+ if (!ALLOWED_FIELD_SET.has(key)) continue;
19959
+ fields[key] = value;
19960
+ }
19961
+ }
19962
+ return { fields, distributions: {} };
19963
+ }
19964
+ };
19965
+ registerMockAdapter();
19966
+ LOOKBACK_RE = /^(\d+)(h|d)$/;
19967
+ MAX_LINES = 40;
19968
+ INLINE_TEMPLATE = `# {{productName}} Pulse \u2014 {{windowLabel}}
19969
+
19970
+ ## Headlines
19971
+
19972
+ {{headlines}}
19973
+
19974
+ ## Usage
19975
+
19976
+ {{usage}}
19977
+
19978
+ ## System performance
19979
+
19980
+ {{systemPerformance}}
19981
+
19982
+ ## Followups
19983
+
19984
+ {{followups}}
19985
+ `;
19986
+ TRUNCATION_MARKER2 = "_(truncated to fit single-page constraint)_";
19987
+ execFileAsync = promisify22(execFile);
19988
+ FIX_RE = /^fix(\([^)]+\))?:/i;
19989
+ EMPTY_REPO_RE = /(does not have any commits yet|not a git repository)/i;
19990
+ execFileAsync2 = promisify3(execFile2);
19991
+ TRACK_CATEGORIES2 = [
19992
+ ["bug-track", BUG_TRACK_CATEGORIES],
19993
+ ["knowledge-track", KNOWLEDGE_TRACK_CATEGORIES]
19994
+ ];
19995
+ STOPWORDS = /* @__PURE__ */ new Set([
19996
+ "fix",
19997
+ "the",
19998
+ "a",
19999
+ "an",
20000
+ "in",
20001
+ "on",
20002
+ "of",
20003
+ "and",
20004
+ "or",
20005
+ "to",
20006
+ "for",
20007
+ "with",
20008
+ "is",
20009
+ "be",
20010
+ "when",
20011
+ "if",
20012
+ "this",
20013
+ "that",
20014
+ "edge",
20015
+ "case",
20016
+ "handle"
20017
+ ]);
20018
+ KEYWORD_TO_CATEGORY = [
20019
+ [/\b(test|flaky|spec)\b/i, "bug-track/test-failures"],
20020
+ [/\b(perf|slow|latency|throughput|timeout|deadlock|n\+1|oom)\b/i, "bug-track/performance-issues"],
20021
+ [
20022
+ /\b(security|sqli|injection|xss|csrf|jwt|oauth|auth(?:n|z|entication)?|crypt(?:o|ographic|ography)?|encrypt(?:ion)?|decrypt(?:ion)?|password|token|session|tls|ssl)\b/i,
20023
+ "bug-track/security-issues"
20024
+ ],
20025
+ [/\b(ui|css|color|contrast|layout|render)\b/i, "bug-track/ui-bugs"],
20026
+ [/\b(build|compile|tsc|webpack|tsup)\b/i, "bug-track/build-errors"],
20027
+ [
20028
+ /\b(db|database|sql|postgres|mysql|query|migration|transaction|deadlock)\b/i,
20029
+ "bug-track/database-issues"
20030
+ ],
20031
+ [/\b(runtime|crash|exception|panic)\b/i, "bug-track/runtime-errors"],
20032
+ [/\(orchestrator\)|\bintegrat|\blease\b|\brace\b|\bconcurren/i, "bug-track/integration-issues"]
20033
+ ];
19042
20034
  }
19043
20035
  });
19044
20036
 
@@ -19095,6 +20087,15 @@ export {
19095
20087
  validateFileStructure,
19096
20088
  validateConfig,
19097
20089
  validateCommitMessage,
20090
+ PulseDbSourceSchema,
20091
+ PulseSourcesSchema,
20092
+ PulseConfigSchema,
20093
+ validatePulseConfig,
20094
+ BUG_TRACK_CATEGORIES,
20095
+ KNOWLEDGE_TRACK_CATEGORIES,
20096
+ ALL_SOLUTION_CATEGORIES,
20097
+ SolutionDocFrontmatterSchema,
20098
+ validateSolutionsDir,
19098
20099
  REQUIRED_SECTIONS,
19099
20100
  extractMarkdownLinks,
19100
20101
  extractSections,
@@ -19438,6 +20439,35 @@ export {
19438
20439
  VERSION,
19439
20440
  collectEvents,
19440
20441
  send,
20442
+ CompoundLockHeldError,
20443
+ acquireCompoundLock,
20444
+ ALLOWED_FIELD_KEYS,
20445
+ PII_TOKENS,
20446
+ PII_FIELD_DENYLIST,
20447
+ PII_LINE_RE,
20448
+ isSanitizedResult,
20449
+ assertSanitized,
20450
+ writePulseConfig,
20451
+ seedFromStrategy,
20452
+ PulseAdapterAlreadyRegisteredError,
20453
+ registerPulseAdapter,
20454
+ getPulseAdapter,
20455
+ listPulseAdapters,
20456
+ clearPulseAdapters,
20457
+ MOCK_ADAPTER_NAME,
20458
+ registerMockAdapter,
20459
+ parseLookback,
20460
+ computeWindow,
20461
+ runPulse,
20462
+ assembleReport,
20463
+ extractHeadlines,
20464
+ isoWeek,
20465
+ formatIsoWeek,
20466
+ gitScan,
20467
+ computeHotspots,
20468
+ crossReferenceUndocumentedFixes,
20469
+ suggestCategory,
20470
+ assembleCandidateReport,
19441
20471
  dist_exports,
19442
20472
  init_dist3 as init_dist
19443
20473
  };