@harness-engineering/core 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -106,6 +106,7 @@ __export(index_exports, {
106
106
  ViolationSchema: () => ViolationSchema,
107
107
  addProvenance: () => addProvenance,
108
108
  analyzeDiff: () => analyzeDiff,
109
+ analyzeLearningPatterns: () => analyzeLearningPatterns,
109
110
  appendFailure: () => appendFailure,
110
111
  appendLearning: () => appendLearning,
111
112
  applyFixes: () => applyFixes,
@@ -114,6 +115,7 @@ __export(index_exports, {
114
115
  archModule: () => archModule,
115
116
  architecture: () => architecture,
116
117
  archiveFailures: () => archiveFailures,
118
+ archiveLearnings: () => archiveLearnings,
117
119
  archiveStream: () => archiveStream,
118
120
  buildDependencyGraph: () => buildDependencyGraph,
119
121
  buildExclusionSet: () => buildExclusionSet,
@@ -121,6 +123,8 @@ __export(index_exports, {
121
123
  checkDocCoverage: () => checkDocCoverage,
122
124
  checkEligibility: () => checkEligibility,
123
125
  classifyFinding: () => classifyFinding,
126
+ clearFailuresCache: () => clearFailuresCache,
127
+ clearLearningsCache: () => clearLearningsCache,
124
128
  configureFeedback: () => configureFeedback,
125
129
  constraintRuleId: () => constraintRuleId,
126
130
  contextBudget: () => contextBudget,
@@ -176,16 +180,20 @@ __export(index_exports, {
176
180
  injectionRules: () => injectionRules,
177
181
  isSmallSuggestion: () => isSmallSuggestion,
178
182
  isUpdateCheckEnabled: () => isUpdateCheckEnabled,
183
+ listActiveSessions: () => listActiveSessions,
179
184
  listStreams: () => listStreams,
185
+ loadBudgetedLearnings: () => loadBudgetedLearnings,
180
186
  loadFailures: () => loadFailures,
181
187
  loadHandoff: () => loadHandoff,
182
188
  loadRelevantLearnings: () => loadRelevantLearnings,
189
+ loadSessionSummary: () => loadSessionSummary,
183
190
  loadState: () => loadState,
184
191
  loadStreamIndex: () => loadStreamIndex,
185
192
  logAgentAction: () => logAgentAction,
186
193
  migrateToStreams: () => migrateToStreams,
187
194
  networkRules: () => networkRules,
188
195
  nodeRules: () => nodeRules,
196
+ parseDateFromEntry: () => parseDateFromEntry,
189
197
  parseDiff: () => parseDiff,
190
198
  parseManifest: () => parseManifest,
191
199
  parseRoadmap: () => parseRoadmap,
@@ -193,9 +201,11 @@ __export(index_exports, {
193
201
  parseSize: () => parseSize,
194
202
  pathTraversalRules: () => pathTraversalRules,
195
203
  previewFix: () => previewFix,
204
+ pruneLearnings: () => pruneLearnings,
196
205
  reactRules: () => reactRules,
197
206
  readCheckState: () => readCheckState,
198
207
  readLockfile: () => readLockfile,
208
+ removeContributions: () => removeContributions,
199
209
  removeProvenance: () => removeProvenance,
200
210
  requestMultiplePeerReviews: () => requestMultiplePeerReviews,
201
211
  requestPeerReview: () => requestPeerReview,
@@ -203,6 +213,7 @@ __export(index_exports, {
203
213
  resolveFileToLayer: () => resolveFileToLayer,
204
214
  resolveModelTier: () => resolveModelTier,
205
215
  resolveRuleSeverity: () => resolveRuleSeverity,
216
+ resolveSessionDir: () => resolveSessionDir,
206
217
  resolveStreamPath: () => resolveStreamPath,
207
218
  resolveThresholds: () => resolveThresholds,
208
219
  runAll: () => runAll,
@@ -229,6 +240,7 @@ __export(index_exports, {
229
240
  syncRoadmap: () => syncRoadmap,
230
241
  touchStream: () => touchStream,
231
242
  trackAction: () => trackAction,
243
+ updateSessionIndex: () => updateSessionIndex,
232
244
  validateAgentsMap: () => validateAgentsMap,
233
245
  validateBoundaries: () => validateBoundaries,
234
246
  validateCommitMessage: () => validateCommitMessage,
@@ -241,6 +253,7 @@ __export(index_exports, {
241
253
  violationId: () => violationId,
242
254
  writeConfig: () => writeConfig,
243
255
  writeLockfile: () => writeLockfile,
256
+ writeSessionSummary: () => writeSessionSummary,
244
257
  xssRules: () => xssRules
245
258
  });
246
259
  module.exports = __toCommonJS(index_exports);
@@ -263,17 +276,17 @@ var import_util = require("util");
263
276
  var import_glob = require("glob");
264
277
  var accessAsync = (0, import_util.promisify)(import_fs.access);
265
278
  var readFileAsync = (0, import_util.promisify)(import_fs.readFile);
266
- async function fileExists(path13) {
279
+ async function fileExists(path20) {
267
280
  try {
268
- await accessAsync(path13, import_fs.constants.F_OK);
281
+ await accessAsync(path20, import_fs.constants.F_OK);
269
282
  return true;
270
283
  } catch {
271
284
  return false;
272
285
  }
273
286
  }
274
- async function readFileContent(path13) {
287
+ async function readFileContent(path20) {
275
288
  try {
276
- const content = await readFileAsync(path13, "utf-8");
289
+ const content = await readFileAsync(path20, "utf-8");
277
290
  return (0, import_types.Ok)(content);
278
291
  } catch (error) {
279
292
  return (0, import_types.Err)(error);
@@ -321,15 +334,15 @@ function validateConfig(data, schema) {
321
334
  let message = "Configuration validation failed";
322
335
  const suggestions = [];
323
336
  if (firstError) {
324
- const path13 = firstError.path.join(".");
325
- const pathDisplay = path13 ? ` at "${path13}"` : "";
337
+ const path20 = firstError.path.join(".");
338
+ const pathDisplay = path20 ? ` at "${path20}"` : "";
326
339
  if (firstError.code === "invalid_type") {
327
340
  const received = firstError.received;
328
341
  const expected = firstError.expected;
329
342
  if (received === "undefined") {
330
343
  code = "MISSING_FIELD";
331
344
  message = `Missing required field${pathDisplay}: ${firstError.message}`;
332
- suggestions.push(`Field "${path13}" is required and must be of type "${expected}"`);
345
+ suggestions.push(`Field "${path20}" is required and must be of type "${expected}"`);
333
346
  } else {
334
347
  code = "INVALID_TYPE";
335
348
  message = `Invalid type${pathDisplay}: ${firstError.message}`;
@@ -542,30 +555,27 @@ function extractSections(content) {
542
555
  return result;
543
556
  });
544
557
  }
545
- function isExternalLink(path13) {
546
- return path13.startsWith("http://") || path13.startsWith("https://") || path13.startsWith("#") || path13.startsWith("mailto:");
558
+ function isExternalLink(path20) {
559
+ return path20.startsWith("http://") || path20.startsWith("https://") || path20.startsWith("#") || path20.startsWith("mailto:");
547
560
  }
548
561
  function resolveLinkPath(linkPath, baseDir) {
549
562
  return linkPath.startsWith(".") ? (0, import_path.join)(baseDir, linkPath) : linkPath;
550
563
  }
551
- async function validateAgentsMap(path13 = "./AGENTS.md") {
552
- console.warn(
553
- "[harness] validateAgentsMap() is deprecated. Use graph-based validation via Assembler.checkCoverage() from @harness-engineering/graph"
554
- );
555
- const contentResult = await readFileContent(path13);
564
+ async function validateAgentsMap(path20 = "./AGENTS.md") {
565
+ const contentResult = await readFileContent(path20);
556
566
  if (!contentResult.ok) {
557
567
  return (0, import_types.Err)(
558
568
  createError(
559
569
  "PARSE_ERROR",
560
570
  `Failed to read AGENTS.md: ${contentResult.error.message}`,
561
- { path: path13 },
571
+ { path: path20 },
562
572
  ["Ensure the file exists", "Check file permissions"]
563
573
  )
564
574
  );
565
575
  }
566
576
  const content = contentResult.value;
567
577
  const sections = extractSections(content);
568
- const baseDir = (0, import_path.dirname)(path13);
578
+ const baseDir = (0, import_path.dirname)(path20);
569
579
  const sectionTitles = sections.map((s) => s.title);
570
580
  const missingSections = REQUIRED_SECTIONS.filter(
571
581
  (required) => !sectionTitles.some((title) => title.toLowerCase().includes(required.toLowerCase()))
@@ -706,8 +716,8 @@ async function checkDocCoverage(domain, options = {}) {
706
716
 
707
717
  // src/context/knowledge-map.ts
708
718
  var import_path3 = require("path");
709
- function suggestFix(path13, existingFiles) {
710
- const targetName = (0, import_path3.basename)(path13).toLowerCase();
719
+ function suggestFix(path20, existingFiles) {
720
+ const targetName = (0, import_path3.basename)(path20).toLowerCase();
711
721
  const similar = existingFiles.find((file) => {
712
722
  const fileName = (0, import_path3.basename)(file).toLowerCase();
713
723
  return fileName.includes(targetName) || targetName.includes(fileName);
@@ -715,12 +725,9 @@ function suggestFix(path13, existingFiles) {
715
725
  if (similar) {
716
726
  return `Did you mean "${similar}"?`;
717
727
  }
718
- return `Create the file "${path13}" or remove the link`;
728
+ return `Create the file "${path20}" or remove the link`;
719
729
  }
720
730
  async function validateKnowledgeMap(rootDir = process.cwd()) {
721
- console.warn(
722
- "[harness] validateKnowledgeMap() is deprecated. Use graph-based validation via Assembler.checkCoverage() from @harness-engineering/graph"
723
- );
724
731
  const agentsPath = (0, import_path3.join)(rootDir, "AGENTS.md");
725
732
  const agentsResult = await validateAgentsMap(agentsPath);
726
733
  if (!agentsResult.ok) {
@@ -1318,8 +1325,8 @@ function createBoundaryValidator(schema, name) {
1318
1325
  return (0, import_types.Ok)(result.data);
1319
1326
  }
1320
1327
  const suggestions = result.error.issues.map((issue) => {
1321
- const path13 = issue.path.join(".");
1322
- return path13 ? `${path13}: ${issue.message}` : issue.message;
1328
+ const path20 = issue.path.join(".");
1329
+ return path20 ? `${path20}: ${issue.message}` : issue.message;
1323
1330
  });
1324
1331
  return (0, import_types.Err)(
1325
1332
  createError(
@@ -1626,8 +1633,6 @@ function deepMergeConstraints(localConfig, bundleConstraints, _existingContribut
1626
1633
  }
1627
1634
  if (bundleConstraints.architecture) {
1628
1635
  const localArch = localConfig.architecture ?? {
1629
- enabled: true,
1630
- baselinePath: ".harness/arch/baselines.json",
1631
1636
  thresholds: {},
1632
1637
  modules: {}
1633
1638
  };
@@ -1750,7 +1755,7 @@ async function readLockfile(lockfilePath) {
1750
1755
  return { ok: true, value: result.data };
1751
1756
  }
1752
1757
  async function writeLockfile(lockfilePath, lockfile) {
1753
- await writeConfig(lockfilePath, lockfile);
1758
+ return writeConfig(lockfilePath, lockfile);
1754
1759
  }
1755
1760
  function addProvenance(lockfile, packageName, entry) {
1756
1761
  return {
@@ -1779,6 +1784,77 @@ function isNodeError(err) {
1779
1784
  return err instanceof Error && "code" in err;
1780
1785
  }
1781
1786
 
1787
+ // src/constraints/sharing/remove.ts
1788
+ function removeContributions(config, contributions) {
1789
+ const result = { ...config };
1790
+ const layerNames = contributions.layers;
1791
+ if (layerNames && layerNames.length > 0 && Array.isArray(result.layers)) {
1792
+ const nameSet = new Set(layerNames);
1793
+ result.layers = result.layers.filter((l) => !nameSet.has(l.name));
1794
+ }
1795
+ const fromKeys = contributions.forbiddenImports;
1796
+ if (fromKeys && fromKeys.length > 0 && Array.isArray(result.forbiddenImports)) {
1797
+ const fromSet = new Set(fromKeys);
1798
+ result.forbiddenImports = result.forbiddenImports.filter(
1799
+ (r) => !fromSet.has(r.from)
1800
+ );
1801
+ }
1802
+ const boundarySchemas = contributions.boundaries;
1803
+ if (boundarySchemas && boundarySchemas.length > 0 && result.boundaries) {
1804
+ const boundaries = result.boundaries;
1805
+ if (boundaries.requireSchema) {
1806
+ const schemaSet = new Set(boundarySchemas);
1807
+ result.boundaries = {
1808
+ ...boundaries,
1809
+ requireSchema: boundaries.requireSchema.filter((s) => !schemaSet.has(s))
1810
+ };
1811
+ }
1812
+ }
1813
+ const thresholdKeys = contributions["architecture.thresholds"];
1814
+ if (thresholdKeys && thresholdKeys.length > 0 && result.architecture) {
1815
+ const arch = { ...result.architecture };
1816
+ const thresholds = { ...arch.thresholds };
1817
+ for (const key of thresholdKeys) {
1818
+ delete thresholds[key];
1819
+ }
1820
+ arch.thresholds = thresholds;
1821
+ result.architecture = arch;
1822
+ }
1823
+ const moduleKeys = contributions["architecture.modules"];
1824
+ if (moduleKeys && moduleKeys.length > 0 && result.architecture) {
1825
+ const arch = { ...result.architecture };
1826
+ const modules = { ...arch.modules };
1827
+ for (const key of moduleKeys) {
1828
+ const colonIdx = key.indexOf(":");
1829
+ if (colonIdx === -1) continue;
1830
+ const modulePath = key.substring(0, colonIdx);
1831
+ const category = key.substring(colonIdx + 1);
1832
+ if (modules[modulePath]) {
1833
+ const moduleCategories = { ...modules[modulePath] };
1834
+ delete moduleCategories[category];
1835
+ if (Object.keys(moduleCategories).length === 0) {
1836
+ delete modules[modulePath];
1837
+ } else {
1838
+ modules[modulePath] = moduleCategories;
1839
+ }
1840
+ }
1841
+ }
1842
+ arch.modules = modules;
1843
+ result.architecture = arch;
1844
+ }
1845
+ const ruleIds = contributions["security.rules"];
1846
+ if (ruleIds && ruleIds.length > 0 && result.security) {
1847
+ const security = { ...result.security };
1848
+ const rules = { ...security.rules };
1849
+ for (const id of ruleIds) {
1850
+ delete rules[id];
1851
+ }
1852
+ security.rules = rules;
1853
+ result.security = security;
1854
+ }
1855
+ return result;
1856
+ }
1857
+
1782
1858
  // src/shared/parsers/typescript.ts
1783
1859
  var import_typescript_estree = require("@typescript-eslint/typescript-estree");
1784
1860
 
@@ -1804,11 +1880,11 @@ function walk(node, visitor) {
1804
1880
  var TypeScriptParser = class {
1805
1881
  name = "typescript";
1806
1882
  extensions = [".ts", ".tsx", ".mts", ".cts"];
1807
- async parseFile(path13) {
1808
- const contentResult = await readFileContent(path13);
1883
+ async parseFile(path20) {
1884
+ const contentResult = await readFileContent(path20);
1809
1885
  if (!contentResult.ok) {
1810
1886
  return (0, import_types.Err)(
1811
- createParseError("NOT_FOUND", `File not found: ${path13}`, { path: path13 }, [
1887
+ createParseError("NOT_FOUND", `File not found: ${path20}`, { path: path20 }, [
1812
1888
  "Check that the file exists",
1813
1889
  "Verify the path is correct"
1814
1890
  ])
@@ -1818,7 +1894,7 @@ var TypeScriptParser = class {
1818
1894
  const ast = (0, import_typescript_estree.parse)(contentResult.value, {
1819
1895
  loc: true,
1820
1896
  range: true,
1821
- jsx: path13.endsWith(".tsx"),
1897
+ jsx: path20.endsWith(".tsx"),
1822
1898
  errorOnUnknownASTType: false
1823
1899
  });
1824
1900
  return (0, import_types.Ok)({
@@ -1829,7 +1905,7 @@ var TypeScriptParser = class {
1829
1905
  } catch (e) {
1830
1906
  const error = e;
1831
1907
  return (0, import_types.Err)(
1832
- createParseError("SYNTAX_ERROR", `Failed to parse ${path13}: ${error.message}`, { path: path13 }, [
1908
+ createParseError("SYNTAX_ERROR", `Failed to parse ${path20}: ${error.message}`, { path: path20 }, [
1833
1909
  "Check for syntax errors in the file",
1834
1910
  "Ensure valid TypeScript syntax"
1835
1911
  ])
@@ -2113,22 +2189,22 @@ function extractInlineRefs(content) {
2113
2189
  }
2114
2190
  return refs;
2115
2191
  }
2116
- async function parseDocumentationFile(path13) {
2117
- const contentResult = await readFileContent(path13);
2192
+ async function parseDocumentationFile(path20) {
2193
+ const contentResult = await readFileContent(path20);
2118
2194
  if (!contentResult.ok) {
2119
2195
  return (0, import_types.Err)(
2120
2196
  createEntropyError(
2121
2197
  "PARSE_ERROR",
2122
- `Failed to read documentation file: ${path13}`,
2123
- { file: path13 },
2198
+ `Failed to read documentation file: ${path20}`,
2199
+ { file: path20 },
2124
2200
  ["Check that the file exists"]
2125
2201
  )
2126
2202
  );
2127
2203
  }
2128
2204
  const content = contentResult.value;
2129
- const type = path13.endsWith(".md") ? "markdown" : "text";
2205
+ const type = path20.endsWith(".md") ? "markdown" : "text";
2130
2206
  return (0, import_types.Ok)({
2131
- path: path13,
2207
+ path: path20,
2132
2208
  type,
2133
2209
  content,
2134
2210
  codeBlocks: extractCodeBlocks(content),
@@ -2939,15 +3015,34 @@ async function detectPatternViolations(snapshot, config) {
2939
3015
  }
2940
3016
  }
2941
3017
  }
3018
+ if (config?.customPatterns) {
3019
+ for (const file of snapshot.files) {
3020
+ for (const custom of config.customPatterns) {
3021
+ const matches = custom.check(file, snapshot);
3022
+ for (const match of matches) {
3023
+ violations.push({
3024
+ pattern: custom.name,
3025
+ file: file.path,
3026
+ line: match.line,
3027
+ message: match.message,
3028
+ suggestion: match.suggestion || "Review and fix this pattern violation",
3029
+ severity: custom.severity
3030
+ });
3031
+ }
3032
+ }
3033
+ }
3034
+ }
2942
3035
  const errorCount = violations.filter((v) => v.severity === "error").length;
2943
3036
  const warningCount = violations.filter((v) => v.severity === "warning").length;
2944
- const totalChecks = snapshot.files.length * patterns.length;
2945
- const passRate = totalChecks > 0 ? (totalChecks - violations.length) / totalChecks : 1;
3037
+ const customCount = config?.customPatterns?.length ?? 0;
3038
+ const allPatternsCount = patterns.length + customCount;
3039
+ const totalChecks = snapshot.files.length * allPatternsCount;
3040
+ const passRate = totalChecks > 0 ? Math.max(0, (totalChecks - violations.length) / totalChecks) : 1;
2946
3041
  return (0, import_types.Ok)({
2947
3042
  violations,
2948
3043
  stats: {
2949
3044
  filesChecked: snapshot.files.length,
2950
- patternsApplied: patterns.length,
3045
+ patternsApplied: allPatternsCount,
2951
3046
  violationCount: violations.length,
2952
3047
  errorCount,
2953
3048
  warningCount
@@ -5446,8 +5541,8 @@ var import_node_path3 = require("path");
5446
5541
  // src/architecture/collectors/hash.ts
5447
5542
  var import_node_crypto = require("crypto");
5448
5543
  function violationId(relativePath, category, normalizedDetail) {
5449
- const path13 = relativePath.replace(/\\/g, "/");
5450
- const input = `${path13}:${category}:${normalizedDetail}`;
5544
+ const path20 = relativePath.replace(/\\/g, "/");
5545
+ const input = `${path20}:${category}:${normalizedDetail}`;
5451
5546
  return (0, import_node_crypto.createHash)("sha256").update(input).digest("hex");
5452
5547
  }
5453
5548
  function constraintRuleId(category, scope, description) {
@@ -6625,10 +6720,13 @@ var DEFAULT_STATE = {
6625
6720
  progress: {}
6626
6721
  };
6627
6722
 
6628
- // src/state/state-manager.ts
6629
- var fs6 = __toESM(require("fs"));
6630
- var path3 = __toESM(require("path"));
6631
- var import_child_process2 = require("child_process");
6723
+ // src/state/state-persistence.ts
6724
+ var fs8 = __toESM(require("fs"));
6725
+ var path5 = __toESM(require("path"));
6726
+
6727
+ // src/state/state-shared.ts
6728
+ var fs7 = __toESM(require("fs"));
6729
+ var path4 = __toESM(require("path"));
6632
6730
 
6633
6731
  // src/state/stream-resolver.ts
6634
6732
  var fs5 = __toESM(require("fs"));
@@ -6654,10 +6752,20 @@ var DEFAULT_STREAM_INDEX = {
6654
6752
  streams: {}
6655
6753
  };
6656
6754
 
6657
- // src/state/stream-resolver.ts
6755
+ // src/state/constants.ts
6658
6756
  var HARNESS_DIR = ".harness";
6659
- var STREAMS_DIR = "streams";
6757
+ var STATE_FILE = "state.json";
6758
+ var LEARNINGS_FILE = "learnings.md";
6759
+ var FAILURES_FILE = "failures.md";
6760
+ var HANDOFF_FILE = "handoff.json";
6761
+ var GATE_CONFIG_FILE = "gate.json";
6660
6762
  var INDEX_FILE = "index.json";
6763
+ var SESSIONS_DIR = "sessions";
6764
+ var SESSION_INDEX_FILE = "index.md";
6765
+ var SUMMARY_FILE = "summary.md";
6766
+
6767
+ // src/state/stream-resolver.ts
6768
+ var STREAMS_DIR = "streams";
6661
6769
  var STREAM_NAME_REGEX = /^[a-z0-9][a-z0-9._-]*$/;
6662
6770
  function streamsDir(projectPath) {
6663
6771
  return path2.join(projectPath, HARNESS_DIR, STREAMS_DIR);
@@ -6884,26 +6992,65 @@ async function migrateToStreams(projectPath) {
6884
6992
  return saveStreamIndex(projectPath, index);
6885
6993
  }
6886
6994
 
6887
- // src/state/state-manager.ts
6888
- var HARNESS_DIR2 = ".harness";
6889
- var STATE_FILE = "state.json";
6890
- var LEARNINGS_FILE = "learnings.md";
6891
- var FAILURES_FILE = "failures.md";
6892
- var HANDOFF_FILE = "handoff.json";
6893
- var GATE_CONFIG_FILE = "gate.json";
6894
- var INDEX_FILE2 = "index.json";
6995
+ // src/state/session-resolver.ts
6996
+ var fs6 = __toESM(require("fs"));
6997
+ var path3 = __toESM(require("path"));
6998
+ function resolveSessionDir(projectPath, sessionSlug, options) {
6999
+ if (!sessionSlug || sessionSlug.trim() === "") {
7000
+ return (0, import_types.Err)(new Error("Session slug must not be empty"));
7001
+ }
7002
+ if (sessionSlug.includes("..") || sessionSlug.includes("/") || sessionSlug.includes("\\")) {
7003
+ return (0, import_types.Err)(
7004
+ new Error(`Invalid session slug '${sessionSlug}': must not contain path traversal characters`)
7005
+ );
7006
+ }
7007
+ const sessionDir = path3.join(projectPath, HARNESS_DIR, SESSIONS_DIR, sessionSlug);
7008
+ if (options?.create) {
7009
+ fs6.mkdirSync(sessionDir, { recursive: true });
7010
+ }
7011
+ return (0, import_types.Ok)(sessionDir);
7012
+ }
7013
+ function updateSessionIndex(projectPath, sessionSlug, description) {
7014
+ const sessionsDir = path3.join(projectPath, HARNESS_DIR, SESSIONS_DIR);
7015
+ fs6.mkdirSync(sessionsDir, { recursive: true });
7016
+ const indexPath2 = path3.join(sessionsDir, SESSION_INDEX_FILE);
7017
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
7018
+ const newLine = `- [${sessionSlug}](${sessionSlug}/summary.md) \u2014 ${description} (${date})`;
7019
+ if (!fs6.existsSync(indexPath2)) {
7020
+ fs6.writeFileSync(indexPath2, `## Active Sessions
7021
+
7022
+ ${newLine}
7023
+ `);
7024
+ return;
7025
+ }
7026
+ const content = fs6.readFileSync(indexPath2, "utf-8");
7027
+ const lines = content.split("\n");
7028
+ const slugPattern = `- [${sessionSlug}]`;
7029
+ const existingIdx = lines.findIndex((l) => l.startsWith(slugPattern));
7030
+ if (existingIdx >= 0) {
7031
+ lines[existingIdx] = newLine;
7032
+ } else {
7033
+ const lastNonEmpty = lines.reduce((last, line, i) => line.trim() !== "" ? i : last, 0);
7034
+ lines.splice(lastNonEmpty + 1, 0, newLine);
7035
+ }
7036
+ fs6.writeFileSync(indexPath2, lines.join("\n"));
7037
+ }
7038
+
7039
+ // src/state/state-shared.ts
6895
7040
  var MAX_CACHE_ENTRIES = 8;
6896
- var learningsCacheMap = /* @__PURE__ */ new Map();
6897
- var failuresCacheMap = /* @__PURE__ */ new Map();
6898
7041
  function evictIfNeeded(map) {
6899
7042
  if (map.size > MAX_CACHE_ENTRIES) {
6900
7043
  const oldest = map.keys().next().value;
6901
7044
  if (oldest !== void 0) map.delete(oldest);
6902
7045
  }
6903
7046
  }
6904
- async function getStateDir(projectPath, stream) {
6905
- const streamsIndexPath = path3.join(projectPath, HARNESS_DIR2, "streams", INDEX_FILE2);
6906
- const hasStreams = fs6.existsSync(streamsIndexPath);
7047
+ async function getStateDir(projectPath, stream, session) {
7048
+ if (session) {
7049
+ const sessionResult = resolveSessionDir(projectPath, session, { create: true });
7050
+ return sessionResult;
7051
+ }
7052
+ const streamsIndexPath = path4.join(projectPath, HARNESS_DIR, "streams", INDEX_FILE);
7053
+ const hasStreams = fs7.existsSync(streamsIndexPath);
6907
7054
  if (stream || hasStreams) {
6908
7055
  const result = await resolveStreamPath(projectPath, stream ? { stream } : void 0);
6909
7056
  if (result.ok) {
@@ -6913,18 +7060,20 @@ async function getStateDir(projectPath, stream) {
6913
7060
  return result;
6914
7061
  }
6915
7062
  }
6916
- return (0, import_types.Ok)(path3.join(projectPath, HARNESS_DIR2));
7063
+ return (0, import_types.Ok)(path4.join(projectPath, HARNESS_DIR));
6917
7064
  }
6918
- async function loadState(projectPath, stream) {
7065
+
7066
+ // src/state/state-persistence.ts
7067
+ async function loadState(projectPath, stream, session) {
6919
7068
  try {
6920
- const dirResult = await getStateDir(projectPath, stream);
7069
+ const dirResult = await getStateDir(projectPath, stream, session);
6921
7070
  if (!dirResult.ok) return dirResult;
6922
7071
  const stateDir = dirResult.value;
6923
- const statePath = path3.join(stateDir, STATE_FILE);
6924
- if (!fs6.existsSync(statePath)) {
7072
+ const statePath = path5.join(stateDir, STATE_FILE);
7073
+ if (!fs8.existsSync(statePath)) {
6925
7074
  return (0, import_types.Ok)({ ...DEFAULT_STATE });
6926
7075
  }
6927
- const raw = fs6.readFileSync(statePath, "utf-8");
7076
+ const raw = fs8.readFileSync(statePath, "utf-8");
6928
7077
  const parsed = JSON.parse(raw);
6929
7078
  const result = HarnessStateSchema.safeParse(parsed);
6930
7079
  if (!result.success) {
@@ -6937,14 +7086,14 @@ async function loadState(projectPath, stream) {
6937
7086
  );
6938
7087
  }
6939
7088
  }
6940
- async function saveState(projectPath, state, stream) {
7089
+ async function saveState(projectPath, state, stream, session) {
6941
7090
  try {
6942
- const dirResult = await getStateDir(projectPath, stream);
7091
+ const dirResult = await getStateDir(projectPath, stream, session);
6943
7092
  if (!dirResult.ok) return dirResult;
6944
7093
  const stateDir = dirResult.value;
6945
- const statePath = path3.join(stateDir, STATE_FILE);
6946
- fs6.mkdirSync(stateDir, { recursive: true });
6947
- fs6.writeFileSync(statePath, JSON.stringify(state, null, 2));
7094
+ const statePath = path5.join(stateDir, STATE_FILE);
7095
+ fs8.mkdirSync(stateDir, { recursive: true });
7096
+ fs8.writeFileSync(statePath, JSON.stringify(state, null, 2));
6948
7097
  return (0, import_types.Ok)(void 0);
6949
7098
  } catch (error) {
6950
7099
  return (0, import_types.Err)(
@@ -6952,13 +7101,21 @@ async function saveState(projectPath, state, stream) {
6952
7101
  );
6953
7102
  }
6954
7103
  }
6955
- async function appendLearning(projectPath, learning, skillName, outcome, stream) {
7104
+
7105
+ // src/state/learnings.ts
7106
+ var fs9 = __toESM(require("fs"));
7107
+ var path6 = __toESM(require("path"));
7108
+ var learningsCacheMap = /* @__PURE__ */ new Map();
7109
+ function clearLearningsCache() {
7110
+ learningsCacheMap.clear();
7111
+ }
7112
+ async function appendLearning(projectPath, learning, skillName, outcome, stream, session) {
6956
7113
  try {
6957
- const dirResult = await getStateDir(projectPath, stream);
7114
+ const dirResult = await getStateDir(projectPath, stream, session);
6958
7115
  if (!dirResult.ok) return dirResult;
6959
7116
  const stateDir = dirResult.value;
6960
- const learningsPath = path3.join(stateDir, LEARNINGS_FILE);
6961
- fs6.mkdirSync(stateDir, { recursive: true });
7117
+ const learningsPath = path6.join(stateDir, LEARNINGS_FILE);
7118
+ fs9.mkdirSync(stateDir, { recursive: true });
6962
7119
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
6963
7120
  let entry;
6964
7121
  if (skillName && outcome) {
@@ -6974,11 +7131,11 @@ async function appendLearning(projectPath, learning, skillName, outcome, stream)
6974
7131
  - **${timestamp}:** ${learning}
6975
7132
  `;
6976
7133
  }
6977
- if (!fs6.existsSync(learningsPath)) {
6978
- fs6.writeFileSync(learningsPath, `# Learnings
7134
+ if (!fs9.existsSync(learningsPath)) {
7135
+ fs9.writeFileSync(learningsPath, `# Learnings
6979
7136
  ${entry}`);
6980
7137
  } else {
6981
- fs6.appendFileSync(learningsPath, entry);
7138
+ fs9.appendFileSync(learningsPath, entry);
6982
7139
  }
6983
7140
  learningsCacheMap.delete(learningsPath);
6984
7141
  return (0, import_types.Ok)(void 0);
@@ -6990,23 +7147,92 @@ ${entry}`);
6990
7147
  );
6991
7148
  }
6992
7149
  }
6993
- async function loadRelevantLearnings(projectPath, skillName, stream) {
7150
+ function estimateTokens(text) {
7151
+ return Math.ceil(text.length / 4);
7152
+ }
7153
+ function scoreRelevance(entry, intent) {
7154
+ if (!intent || intent.trim() === "") return 0;
7155
+ const intentWords = intent.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
7156
+ if (intentWords.length === 0) return 0;
7157
+ const entryLower = entry.toLowerCase();
7158
+ const matches = intentWords.filter((word) => entryLower.includes(word));
7159
+ return matches.length / intentWords.length;
7160
+ }
7161
+ function parseDateFromEntry(entry) {
7162
+ const match = entry.match(/(\d{4}-\d{2}-\d{2})/);
7163
+ return match ? match[1] ?? null : null;
7164
+ }
7165
+ function analyzeLearningPatterns(entries) {
7166
+ const tagGroups = /* @__PURE__ */ new Map();
7167
+ for (const entry of entries) {
7168
+ const tagMatches = entry.matchAll(/\[(skill:[^\]]+)\]|\[(outcome:[^\]]+)\]/g);
7169
+ for (const match of tagMatches) {
7170
+ const tag = match[1] ?? match[2];
7171
+ if (tag) {
7172
+ const group = tagGroups.get(tag) ?? [];
7173
+ group.push(entry);
7174
+ tagGroups.set(tag, group);
7175
+ }
7176
+ }
7177
+ }
7178
+ const patterns = [];
7179
+ for (const [tag, groupEntries] of tagGroups) {
7180
+ if (groupEntries.length >= 3) {
7181
+ patterns.push({ tag, count: groupEntries.length, entries: groupEntries });
7182
+ }
7183
+ }
7184
+ return patterns.sort((a, b) => b.count - a.count);
7185
+ }
7186
+ async function loadBudgetedLearnings(projectPath, options) {
7187
+ const { intent, tokenBudget = 1e3, skill, session, stream } = options;
7188
+ const sortByRecencyAndRelevance = (entries) => {
7189
+ return [...entries].sort((a, b) => {
7190
+ const dateA = parseDateFromEntry(a) ?? "0000-00-00";
7191
+ const dateB = parseDateFromEntry(b) ?? "0000-00-00";
7192
+ const dateCompare = dateB.localeCompare(dateA);
7193
+ if (dateCompare !== 0) return dateCompare;
7194
+ return scoreRelevance(b, intent) - scoreRelevance(a, intent);
7195
+ });
7196
+ };
7197
+ const allEntries = [];
7198
+ if (session) {
7199
+ const sessionResult = await loadRelevantLearnings(projectPath, skill, stream, session);
7200
+ if (sessionResult.ok) {
7201
+ allEntries.push(...sortByRecencyAndRelevance(sessionResult.value));
7202
+ }
7203
+ }
7204
+ const globalResult = await loadRelevantLearnings(projectPath, skill, stream);
7205
+ if (globalResult.ok) {
7206
+ allEntries.push(...sortByRecencyAndRelevance(globalResult.value));
7207
+ }
7208
+ const budgeted = [];
7209
+ let totalTokens = 0;
7210
+ for (const entry of allEntries) {
7211
+ const separator = budgeted.length > 0 ? "\n" : "";
7212
+ const entryCost = estimateTokens(entry + separator);
7213
+ if (totalTokens + entryCost > tokenBudget) break;
7214
+ budgeted.push(entry);
7215
+ totalTokens += entryCost;
7216
+ }
7217
+ return (0, import_types.Ok)(budgeted);
7218
+ }
7219
+ async function loadRelevantLearnings(projectPath, skillName, stream, session) {
6994
7220
  try {
6995
- const dirResult = await getStateDir(projectPath, stream);
7221
+ const dirResult = await getStateDir(projectPath, stream, session);
6996
7222
  if (!dirResult.ok) return dirResult;
6997
7223
  const stateDir = dirResult.value;
6998
- const learningsPath = path3.join(stateDir, LEARNINGS_FILE);
6999
- if (!fs6.existsSync(learningsPath)) {
7224
+ const learningsPath = path6.join(stateDir, LEARNINGS_FILE);
7225
+ if (!fs9.existsSync(learningsPath)) {
7000
7226
  return (0, import_types.Ok)([]);
7001
7227
  }
7002
- const stats = fs6.statSync(learningsPath);
7228
+ const stats = fs9.statSync(learningsPath);
7003
7229
  const cacheKey = learningsPath;
7004
7230
  const cached = learningsCacheMap.get(cacheKey);
7005
7231
  let entries;
7006
7232
  if (cached && cached.mtimeMs === stats.mtimeMs) {
7007
7233
  entries = cached.entries;
7008
7234
  } else {
7009
- const content = fs6.readFileSync(learningsPath, "utf-8");
7235
+ const content = fs9.readFileSync(learningsPath, "utf-8");
7010
7236
  const lines = content.split("\n");
7011
7237
  entries = [];
7012
7238
  let currentBlock = [];
@@ -7042,23 +7268,110 @@ async function loadRelevantLearnings(projectPath, skillName, stream) {
7042
7268
  );
7043
7269
  }
7044
7270
  }
7045
- var FAILURE_LINE_REGEX = /^- \*\*(\d{4}-\d{2}-\d{2}) \[skill:([^\]]+)\] \[type:([^\]]+)\]:\*\* (.+)$/;
7046
- async function appendFailure(projectPath, description, skillName, type, stream) {
7271
+ async function archiveLearnings(projectPath, entries, stream) {
7272
+ try {
7273
+ const dirResult = await getStateDir(projectPath, stream);
7274
+ if (!dirResult.ok) return dirResult;
7275
+ const stateDir = dirResult.value;
7276
+ const archiveDir = path6.join(stateDir, "learnings-archive");
7277
+ fs9.mkdirSync(archiveDir, { recursive: true });
7278
+ const now = /* @__PURE__ */ new Date();
7279
+ const yearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
7280
+ const archivePath = path6.join(archiveDir, `${yearMonth}.md`);
7281
+ const archiveContent = entries.join("\n\n") + "\n";
7282
+ if (fs9.existsSync(archivePath)) {
7283
+ fs9.appendFileSync(archivePath, "\n" + archiveContent);
7284
+ } else {
7285
+ fs9.writeFileSync(archivePath, `# Learnings Archive
7286
+
7287
+ ${archiveContent}`);
7288
+ }
7289
+ return (0, import_types.Ok)(void 0);
7290
+ } catch (error) {
7291
+ return (0, import_types.Err)(
7292
+ new Error(
7293
+ `Failed to archive learnings: ${error instanceof Error ? error.message : String(error)}`
7294
+ )
7295
+ );
7296
+ }
7297
+ }
7298
+ async function pruneLearnings(projectPath, stream) {
7047
7299
  try {
7048
7300
  const dirResult = await getStateDir(projectPath, stream);
7049
7301
  if (!dirResult.ok) return dirResult;
7050
7302
  const stateDir = dirResult.value;
7051
- const failuresPath = path3.join(stateDir, FAILURES_FILE);
7052
- fs6.mkdirSync(stateDir, { recursive: true });
7303
+ const learningsPath = path6.join(stateDir, LEARNINGS_FILE);
7304
+ if (!fs9.existsSync(learningsPath)) {
7305
+ return (0, import_types.Ok)({ kept: 0, archived: 0, patterns: [] });
7306
+ }
7307
+ const loadResult = await loadRelevantLearnings(projectPath, void 0, stream);
7308
+ if (!loadResult.ok) return loadResult;
7309
+ const allEntries = loadResult.value;
7310
+ if (allEntries.length <= 20) {
7311
+ const cutoffDate = /* @__PURE__ */ new Date();
7312
+ cutoffDate.setDate(cutoffDate.getDate() - 14);
7313
+ const cutoffStr = cutoffDate.toISOString().split("T")[0];
7314
+ const hasOld = allEntries.some((entry) => {
7315
+ const date = parseDateFromEntry(entry);
7316
+ return date !== null && date < cutoffStr;
7317
+ });
7318
+ if (!hasOld) {
7319
+ return (0, import_types.Ok)({ kept: allEntries.length, archived: 0, patterns: [] });
7320
+ }
7321
+ }
7322
+ const sorted = [...allEntries].sort((a, b) => {
7323
+ const dateA = parseDateFromEntry(a) ?? "0000-00-00";
7324
+ const dateB = parseDateFromEntry(b) ?? "0000-00-00";
7325
+ return dateB.localeCompare(dateA);
7326
+ });
7327
+ const toKeep = sorted.slice(0, 20);
7328
+ const toArchive = sorted.slice(20);
7329
+ const patterns = analyzeLearningPatterns(allEntries);
7330
+ if (toArchive.length > 0) {
7331
+ const archiveResult = await archiveLearnings(projectPath, toArchive, stream);
7332
+ if (!archiveResult.ok) return archiveResult;
7333
+ }
7334
+ const newContent = "# Learnings\n\n" + toKeep.join("\n\n") + "\n";
7335
+ fs9.writeFileSync(learningsPath, newContent);
7336
+ learningsCacheMap.delete(learningsPath);
7337
+ return (0, import_types.Ok)({
7338
+ kept: toKeep.length,
7339
+ archived: toArchive.length,
7340
+ patterns
7341
+ });
7342
+ } catch (error) {
7343
+ return (0, import_types.Err)(
7344
+ new Error(
7345
+ `Failed to prune learnings: ${error instanceof Error ? error.message : String(error)}`
7346
+ )
7347
+ );
7348
+ }
7349
+ }
7350
+
7351
+ // src/state/failures.ts
7352
+ var fs10 = __toESM(require("fs"));
7353
+ var path7 = __toESM(require("path"));
7354
+ var failuresCacheMap = /* @__PURE__ */ new Map();
7355
+ function clearFailuresCache() {
7356
+ failuresCacheMap.clear();
7357
+ }
7358
+ var FAILURE_LINE_REGEX = /^- \*\*(\d{4}-\d{2}-\d{2}) \[skill:([^\]]+)\] \[type:([^\]]+)\]:\*\* (.+)$/;
7359
+ async function appendFailure(projectPath, description, skillName, type, stream, session) {
7360
+ try {
7361
+ const dirResult = await getStateDir(projectPath, stream, session);
7362
+ if (!dirResult.ok) return dirResult;
7363
+ const stateDir = dirResult.value;
7364
+ const failuresPath = path7.join(stateDir, FAILURES_FILE);
7365
+ fs10.mkdirSync(stateDir, { recursive: true });
7053
7366
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
7054
7367
  const entry = `
7055
7368
  - **${timestamp} [skill:${skillName}] [type:${type}]:** ${description}
7056
7369
  `;
7057
- if (!fs6.existsSync(failuresPath)) {
7058
- fs6.writeFileSync(failuresPath, `# Failures
7370
+ if (!fs10.existsSync(failuresPath)) {
7371
+ fs10.writeFileSync(failuresPath, `# Failures
7059
7372
  ${entry}`);
7060
7373
  } else {
7061
- fs6.appendFileSync(failuresPath, entry);
7374
+ fs10.appendFileSync(failuresPath, entry);
7062
7375
  }
7063
7376
  failuresCacheMap.delete(failuresPath);
7064
7377
  return (0, import_types.Ok)(void 0);
@@ -7070,22 +7383,22 @@ ${entry}`);
7070
7383
  );
7071
7384
  }
7072
7385
  }
7073
- async function loadFailures(projectPath, stream) {
7386
+ async function loadFailures(projectPath, stream, session) {
7074
7387
  try {
7075
- const dirResult = await getStateDir(projectPath, stream);
7388
+ const dirResult = await getStateDir(projectPath, stream, session);
7076
7389
  if (!dirResult.ok) return dirResult;
7077
7390
  const stateDir = dirResult.value;
7078
- const failuresPath = path3.join(stateDir, FAILURES_FILE);
7079
- if (!fs6.existsSync(failuresPath)) {
7391
+ const failuresPath = path7.join(stateDir, FAILURES_FILE);
7392
+ if (!fs10.existsSync(failuresPath)) {
7080
7393
  return (0, import_types.Ok)([]);
7081
7394
  }
7082
- const stats = fs6.statSync(failuresPath);
7395
+ const stats = fs10.statSync(failuresPath);
7083
7396
  const cacheKey = failuresPath;
7084
7397
  const cached = failuresCacheMap.get(cacheKey);
7085
7398
  if (cached && cached.mtimeMs === stats.mtimeMs) {
7086
7399
  return (0, import_types.Ok)(cached.entries);
7087
7400
  }
7088
- const content = fs6.readFileSync(failuresPath, "utf-8");
7401
+ const content = fs10.readFileSync(failuresPath, "utf-8");
7089
7402
  const entries = [];
7090
7403
  for (const line of content.split("\n")) {
7091
7404
  const match = line.match(FAILURE_LINE_REGEX);
@@ -7109,25 +7422,25 @@ async function loadFailures(projectPath, stream) {
7109
7422
  );
7110
7423
  }
7111
7424
  }
7112
- async function archiveFailures(projectPath, stream) {
7425
+ async function archiveFailures(projectPath, stream, session) {
7113
7426
  try {
7114
- const dirResult = await getStateDir(projectPath, stream);
7427
+ const dirResult = await getStateDir(projectPath, stream, session);
7115
7428
  if (!dirResult.ok) return dirResult;
7116
7429
  const stateDir = dirResult.value;
7117
- const failuresPath = path3.join(stateDir, FAILURES_FILE);
7118
- if (!fs6.existsSync(failuresPath)) {
7430
+ const failuresPath = path7.join(stateDir, FAILURES_FILE);
7431
+ if (!fs10.existsSync(failuresPath)) {
7119
7432
  return (0, import_types.Ok)(void 0);
7120
7433
  }
7121
- const archiveDir = path3.join(stateDir, "archive");
7122
- fs6.mkdirSync(archiveDir, { recursive: true });
7434
+ const archiveDir = path7.join(stateDir, "archive");
7435
+ fs10.mkdirSync(archiveDir, { recursive: true });
7123
7436
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
7124
7437
  let archiveName = `failures-${date}.md`;
7125
7438
  let counter = 2;
7126
- while (fs6.existsSync(path3.join(archiveDir, archiveName))) {
7439
+ while (fs10.existsSync(path7.join(archiveDir, archiveName))) {
7127
7440
  archiveName = `failures-${date}-${counter}.md`;
7128
7441
  counter++;
7129
7442
  }
7130
- fs6.renameSync(failuresPath, path3.join(archiveDir, archiveName));
7443
+ fs10.renameSync(failuresPath, path7.join(archiveDir, archiveName));
7131
7444
  failuresCacheMap.delete(failuresPath);
7132
7445
  return (0, import_types.Ok)(void 0);
7133
7446
  } catch (error) {
@@ -7138,14 +7451,18 @@ async function archiveFailures(projectPath, stream) {
7138
7451
  );
7139
7452
  }
7140
7453
  }
7141
- async function saveHandoff(projectPath, handoff, stream) {
7454
+
7455
+ // src/state/handoff.ts
7456
+ var fs11 = __toESM(require("fs"));
7457
+ var path8 = __toESM(require("path"));
7458
+ async function saveHandoff(projectPath, handoff, stream, session) {
7142
7459
  try {
7143
- const dirResult = await getStateDir(projectPath, stream);
7460
+ const dirResult = await getStateDir(projectPath, stream, session);
7144
7461
  if (!dirResult.ok) return dirResult;
7145
7462
  const stateDir = dirResult.value;
7146
- const handoffPath = path3.join(stateDir, HANDOFF_FILE);
7147
- fs6.mkdirSync(stateDir, { recursive: true });
7148
- fs6.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2));
7463
+ const handoffPath = path8.join(stateDir, HANDOFF_FILE);
7464
+ fs11.mkdirSync(stateDir, { recursive: true });
7465
+ fs11.writeFileSync(handoffPath, JSON.stringify(handoff, null, 2));
7149
7466
  return (0, import_types.Ok)(void 0);
7150
7467
  } catch (error) {
7151
7468
  return (0, import_types.Err)(
@@ -7153,16 +7470,16 @@ async function saveHandoff(projectPath, handoff, stream) {
7153
7470
  );
7154
7471
  }
7155
7472
  }
7156
- async function loadHandoff(projectPath, stream) {
7473
+ async function loadHandoff(projectPath, stream, session) {
7157
7474
  try {
7158
- const dirResult = await getStateDir(projectPath, stream);
7475
+ const dirResult = await getStateDir(projectPath, stream, session);
7159
7476
  if (!dirResult.ok) return dirResult;
7160
7477
  const stateDir = dirResult.value;
7161
- const handoffPath = path3.join(stateDir, HANDOFF_FILE);
7162
- if (!fs6.existsSync(handoffPath)) {
7478
+ const handoffPath = path8.join(stateDir, HANDOFF_FILE);
7479
+ if (!fs11.existsSync(handoffPath)) {
7163
7480
  return (0, import_types.Ok)(null);
7164
7481
  }
7165
- const raw = fs6.readFileSync(handoffPath, "utf-8");
7482
+ const raw = fs11.readFileSync(handoffPath, "utf-8");
7166
7483
  const parsed = JSON.parse(raw);
7167
7484
  const result = HandoffSchema.safeParse(parsed);
7168
7485
  if (!result.success) {
@@ -7175,73 +7492,82 @@ async function loadHandoff(projectPath, stream) {
7175
7492
  );
7176
7493
  }
7177
7494
  }
7495
+
7496
+ // src/state/mechanical-gate.ts
7497
+ var fs12 = __toESM(require("fs"));
7498
+ var path9 = __toESM(require("path"));
7499
+ var import_child_process2 = require("child_process");
7500
+ var 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:.-]+$/;
7501
+ function loadChecksFromConfig(gateConfigPath) {
7502
+ if (!fs12.existsSync(gateConfigPath)) return [];
7503
+ const raw = JSON.parse(fs12.readFileSync(gateConfigPath, "utf-8"));
7504
+ const config = GateConfigSchema.safeParse(raw);
7505
+ if (config.success && config.data.checks) return config.data.checks;
7506
+ return [];
7507
+ }
7508
+ function discoverChecksFromProject(projectPath) {
7509
+ const checks = [];
7510
+ const packageJsonPath = path9.join(projectPath, "package.json");
7511
+ if (fs12.existsSync(packageJsonPath)) {
7512
+ const pkg = JSON.parse(fs12.readFileSync(packageJsonPath, "utf-8"));
7513
+ const scripts = pkg.scripts || {};
7514
+ if (scripts.test) checks.push({ name: "test", command: "npm test" });
7515
+ if (scripts.lint) checks.push({ name: "lint", command: "npm run lint" });
7516
+ if (scripts.typecheck) checks.push({ name: "typecheck", command: "npm run typecheck" });
7517
+ if (scripts.build) checks.push({ name: "build", command: "npm run build" });
7518
+ }
7519
+ if (fs12.existsSync(path9.join(projectPath, "go.mod"))) {
7520
+ checks.push({ name: "test", command: "go test ./..." });
7521
+ checks.push({ name: "build", command: "go build ./..." });
7522
+ }
7523
+ if (fs12.existsSync(path9.join(projectPath, "pyproject.toml")) || fs12.existsSync(path9.join(projectPath, "setup.py"))) {
7524
+ checks.push({ name: "test", command: "python -m pytest" });
7525
+ }
7526
+ return checks;
7527
+ }
7528
+ function executeCheck(check, projectPath) {
7529
+ if (!SAFE_GATE_COMMAND.test(check.command)) {
7530
+ return {
7531
+ name: check.name,
7532
+ passed: false,
7533
+ command: check.command,
7534
+ output: `Blocked: command does not match safe gate pattern. Allowed prefixes: npm, pnpm, yarn, go, python, python3, make, cargo, gradle, mvn`,
7535
+ duration: 0
7536
+ };
7537
+ }
7538
+ const start = Date.now();
7539
+ try {
7540
+ (0, import_child_process2.execSync)(check.command, {
7541
+ cwd: projectPath,
7542
+ stdio: "pipe",
7543
+ timeout: 12e4
7544
+ });
7545
+ return {
7546
+ name: check.name,
7547
+ passed: true,
7548
+ command: check.command,
7549
+ duration: Date.now() - start
7550
+ };
7551
+ } catch (error) {
7552
+ const output = error instanceof Error ? error.stderr?.toString() || error.message : String(error);
7553
+ return {
7554
+ name: check.name,
7555
+ passed: false,
7556
+ command: check.command,
7557
+ output: output.slice(0, 2e3),
7558
+ duration: Date.now() - start
7559
+ };
7560
+ }
7561
+ }
7178
7562
  async function runMechanicalGate(projectPath) {
7179
- const harnessDir = path3.join(projectPath, HARNESS_DIR2);
7180
- const gateConfigPath = path3.join(harnessDir, GATE_CONFIG_FILE);
7563
+ const harnessDir = path9.join(projectPath, HARNESS_DIR);
7564
+ const gateConfigPath = path9.join(harnessDir, GATE_CONFIG_FILE);
7181
7565
  try {
7182
- let checks = [];
7183
- if (fs6.existsSync(gateConfigPath)) {
7184
- const raw = JSON.parse(fs6.readFileSync(gateConfigPath, "utf-8"));
7185
- const config = GateConfigSchema.safeParse(raw);
7186
- if (config.success && config.data.checks) {
7187
- checks = config.data.checks;
7188
- }
7189
- }
7566
+ let checks = loadChecksFromConfig(gateConfigPath);
7190
7567
  if (checks.length === 0) {
7191
- const packageJsonPath = path3.join(projectPath, "package.json");
7192
- if (fs6.existsSync(packageJsonPath)) {
7193
- const pkg = JSON.parse(fs6.readFileSync(packageJsonPath, "utf-8"));
7194
- const scripts = pkg.scripts || {};
7195
- if (scripts.test) checks.push({ name: "test", command: "npm test" });
7196
- if (scripts.lint) checks.push({ name: "lint", command: "npm run lint" });
7197
- if (scripts.typecheck) checks.push({ name: "typecheck", command: "npm run typecheck" });
7198
- if (scripts.build) checks.push({ name: "build", command: "npm run build" });
7199
- }
7200
- if (fs6.existsSync(path3.join(projectPath, "go.mod"))) {
7201
- checks.push({ name: "test", command: "go test ./..." });
7202
- checks.push({ name: "build", command: "go build ./..." });
7203
- }
7204
- if (fs6.existsSync(path3.join(projectPath, "pyproject.toml")) || fs6.existsSync(path3.join(projectPath, "setup.py"))) {
7205
- checks.push({ name: "test", command: "python -m pytest" });
7206
- }
7207
- }
7208
- const results = [];
7209
- const 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:.-]+$/;
7210
- for (const check of checks) {
7211
- if (!SAFE_GATE_COMMAND.test(check.command)) {
7212
- results.push({
7213
- name: check.name,
7214
- passed: false,
7215
- command: check.command,
7216
- output: `Blocked: command does not match safe gate pattern. Allowed prefixes: npm, npx, pnpm, yarn, go, python, python3, make, cargo, gradle, mvn`,
7217
- duration: 0
7218
- });
7219
- continue;
7220
- }
7221
- const start = Date.now();
7222
- try {
7223
- (0, import_child_process2.execSync)(check.command, {
7224
- cwd: projectPath,
7225
- stdio: "pipe",
7226
- timeout: 12e4
7227
- });
7228
- results.push({
7229
- name: check.name,
7230
- passed: true,
7231
- command: check.command,
7232
- duration: Date.now() - start
7233
- });
7234
- } catch (error) {
7235
- const output = error instanceof Error ? error.stderr?.toString() || error.message : String(error);
7236
- results.push({
7237
- name: check.name,
7238
- passed: false,
7239
- command: check.command,
7240
- output: output.slice(0, 2e3),
7241
- duration: Date.now() - start
7242
- });
7243
- }
7568
+ checks = discoverChecksFromProject(projectPath);
7244
7569
  }
7570
+ const results = checks.map((check) => executeCheck(check, projectPath));
7245
7571
  return (0, import_types.Ok)({
7246
7572
  passed: results.length === 0 || results.every((r) => r.passed),
7247
7573
  checks: results
@@ -7255,6 +7581,96 @@ async function runMechanicalGate(projectPath) {
7255
7581
  }
7256
7582
  }
7257
7583
 
7584
+ // src/state/session-summary.ts
7585
+ var fs13 = __toESM(require("fs"));
7586
+ var path10 = __toESM(require("path"));
7587
+ function formatSummary(data) {
7588
+ const lines = [
7589
+ "## Session Summary",
7590
+ "",
7591
+ `**Session:** ${data.session}`,
7592
+ `**Last active:** ${data.lastActive}`,
7593
+ `**Skill:** ${data.skill}`
7594
+ ];
7595
+ if (data.phase) {
7596
+ lines.push(`**Phase:** ${data.phase}`);
7597
+ }
7598
+ lines.push(`**Status:** ${data.status}`);
7599
+ if (data.spec) {
7600
+ lines.push(`**Spec:** ${data.spec}`);
7601
+ }
7602
+ if (data.plan) {
7603
+ lines.push(`**Plan:** ${data.plan}`);
7604
+ }
7605
+ lines.push(`**Key context:** ${data.keyContext}`);
7606
+ lines.push(`**Next step:** ${data.nextStep}`);
7607
+ lines.push("");
7608
+ return lines.join("\n");
7609
+ }
7610
+ function deriveIndexDescription(data) {
7611
+ const skillShort = data.skill.replace("harness-", "");
7612
+ const parts = [skillShort];
7613
+ if (data.phase) {
7614
+ parts.push(`phase ${data.phase}`);
7615
+ }
7616
+ parts.push(data.status.toLowerCase());
7617
+ return parts.join(", ");
7618
+ }
7619
+ function writeSessionSummary(projectPath, sessionSlug, data) {
7620
+ try {
7621
+ const dirResult = resolveSessionDir(projectPath, sessionSlug, { create: true });
7622
+ if (!dirResult.ok) return dirResult;
7623
+ const sessionDir = dirResult.value;
7624
+ const summaryPath = path10.join(sessionDir, SUMMARY_FILE);
7625
+ const content = formatSummary(data);
7626
+ fs13.writeFileSync(summaryPath, content);
7627
+ const description = deriveIndexDescription(data);
7628
+ updateSessionIndex(projectPath, sessionSlug, description);
7629
+ return (0, import_types.Ok)(void 0);
7630
+ } catch (error) {
7631
+ return (0, import_types.Err)(
7632
+ new Error(
7633
+ `Failed to write session summary: ${error instanceof Error ? error.message : String(error)}`
7634
+ )
7635
+ );
7636
+ }
7637
+ }
7638
+ function loadSessionSummary(projectPath, sessionSlug) {
7639
+ try {
7640
+ const dirResult = resolveSessionDir(projectPath, sessionSlug);
7641
+ if (!dirResult.ok) return dirResult;
7642
+ const sessionDir = dirResult.value;
7643
+ const summaryPath = path10.join(sessionDir, SUMMARY_FILE);
7644
+ if (!fs13.existsSync(summaryPath)) {
7645
+ return (0, import_types.Ok)(null);
7646
+ }
7647
+ const content = fs13.readFileSync(summaryPath, "utf-8");
7648
+ return (0, import_types.Ok)(content);
7649
+ } catch (error) {
7650
+ return (0, import_types.Err)(
7651
+ new Error(
7652
+ `Failed to load session summary: ${error instanceof Error ? error.message : String(error)}`
7653
+ )
7654
+ );
7655
+ }
7656
+ }
7657
+ function listActiveSessions(projectPath) {
7658
+ try {
7659
+ const indexPath2 = path10.join(projectPath, HARNESS_DIR, SESSIONS_DIR, SESSION_INDEX_FILE);
7660
+ if (!fs13.existsSync(indexPath2)) {
7661
+ return (0, import_types.Ok)(null);
7662
+ }
7663
+ const content = fs13.readFileSync(indexPath2, "utf-8");
7664
+ return (0, import_types.Ok)(content);
7665
+ } catch (error) {
7666
+ return (0, import_types.Err)(
7667
+ new Error(
7668
+ `Failed to list active sessions: ${error instanceof Error ? error.message : String(error)}`
7669
+ )
7670
+ );
7671
+ }
7672
+ }
7673
+
7258
7674
  // src/workflow/runner.ts
7259
7675
  async function executeWorkflow(workflow, executor) {
7260
7676
  const stepResults = [];
@@ -7404,7 +7820,7 @@ async function runMultiTurnPipeline(initialContext, turnExecutor, options) {
7404
7820
  }
7405
7821
 
7406
7822
  // src/security/scanner.ts
7407
- var fs8 = __toESM(require("fs/promises"));
7823
+ var fs15 = __toESM(require("fs/promises"));
7408
7824
 
7409
7825
  // src/security/rules/registry.ts
7410
7826
  var RuleRegistry = class {
@@ -7491,15 +7907,15 @@ function resolveRuleSeverity(ruleId, defaultSeverity, overrides, strict) {
7491
7907
  }
7492
7908
 
7493
7909
  // src/security/stack-detector.ts
7494
- var fs7 = __toESM(require("fs"));
7495
- var path4 = __toESM(require("path"));
7910
+ var fs14 = __toESM(require("fs"));
7911
+ var path11 = __toESM(require("path"));
7496
7912
  function detectStack(projectRoot) {
7497
7913
  const stacks = [];
7498
- const pkgJsonPath = path4.join(projectRoot, "package.json");
7499
- if (fs7.existsSync(pkgJsonPath)) {
7914
+ const pkgJsonPath = path11.join(projectRoot, "package.json");
7915
+ if (fs14.existsSync(pkgJsonPath)) {
7500
7916
  stacks.push("node");
7501
7917
  try {
7502
- const pkgJson = JSON.parse(fs7.readFileSync(pkgJsonPath, "utf-8"));
7918
+ const pkgJson = JSON.parse(fs14.readFileSync(pkgJsonPath, "utf-8"));
7503
7919
  const allDeps = {
7504
7920
  ...pkgJson.dependencies,
7505
7921
  ...pkgJson.devDependencies
@@ -7514,13 +7930,13 @@ function detectStack(projectRoot) {
7514
7930
  } catch {
7515
7931
  }
7516
7932
  }
7517
- const goModPath = path4.join(projectRoot, "go.mod");
7518
- if (fs7.existsSync(goModPath)) {
7933
+ const goModPath = path11.join(projectRoot, "go.mod");
7934
+ if (fs14.existsSync(goModPath)) {
7519
7935
  stacks.push("go");
7520
7936
  }
7521
- const requirementsPath = path4.join(projectRoot, "requirements.txt");
7522
- const pyprojectPath = path4.join(projectRoot, "pyproject.toml");
7523
- if (fs7.existsSync(requirementsPath) || fs7.existsSync(pyprojectPath)) {
7937
+ const requirementsPath = path11.join(projectRoot, "requirements.txt");
7938
+ const pyprojectPath = path11.join(projectRoot, "pyproject.toml");
7939
+ if (fs14.existsSync(requirementsPath) || fs14.existsSync(pyprojectPath)) {
7524
7940
  stacks.push("python");
7525
7941
  }
7526
7942
  return stacks;
@@ -7947,7 +8363,7 @@ var SecurityScanner = class {
7947
8363
  }
7948
8364
  async scanFile(filePath) {
7949
8365
  if (!this.config.enabled) return [];
7950
- const content = await fs8.readFile(filePath, "utf-8");
8366
+ const content = await fs15.readFile(filePath, "utf-8");
7951
8367
  return this.scanContent(content, filePath, 1);
7952
8368
  }
7953
8369
  async scanFiles(filePaths) {
@@ -7972,7 +8388,7 @@ var SecurityScanner = class {
7972
8388
  };
7973
8389
 
7974
8390
  // src/ci/check-orchestrator.ts
7975
- var path5 = __toESM(require("path"));
8391
+ var path12 = __toESM(require("path"));
7976
8392
  var ALL_CHECKS = [
7977
8393
  "validate",
7978
8394
  "deps",
@@ -7989,7 +8405,7 @@ async function runSingleCheck(name, projectRoot, config) {
7989
8405
  try {
7990
8406
  switch (name) {
7991
8407
  case "validate": {
7992
- const agentsPath = path5.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
8408
+ const agentsPath = path12.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
7993
8409
  const result = await validateAgentsMap(agentsPath);
7994
8410
  if (!result.ok) {
7995
8411
  issues.push({ severity: "error", message: result.error.message });
@@ -8044,7 +8460,7 @@ async function runSingleCheck(name, projectRoot, config) {
8044
8460
  break;
8045
8461
  }
8046
8462
  case "docs": {
8047
- const docsDir = path5.join(projectRoot, config.docsDir ?? "docs");
8463
+ const docsDir = path12.join(projectRoot, config.docsDir ?? "docs");
8048
8464
  const entropyConfig = config.entropy || {};
8049
8465
  const result = await checkDocCoverage("project", {
8050
8466
  docsDir,
@@ -8282,7 +8698,7 @@ async function runCIChecks(input) {
8282
8698
  }
8283
8699
 
8284
8700
  // src/review/mechanical-checks.ts
8285
- var path6 = __toESM(require("path"));
8701
+ var path13 = __toESM(require("path"));
8286
8702
  async function runMechanicalChecks(options) {
8287
8703
  const { projectRoot, config, skip = [], changedFiles } = options;
8288
8704
  const findings = [];
@@ -8294,7 +8710,7 @@ async function runMechanicalChecks(options) {
8294
8710
  };
8295
8711
  if (!skip.includes("validate")) {
8296
8712
  try {
8297
- const agentsPath = path6.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
8713
+ const agentsPath = path13.join(projectRoot, config.agentsMapPath ?? "AGENTS.md");
8298
8714
  const result = await validateAgentsMap(agentsPath);
8299
8715
  if (!result.ok) {
8300
8716
  statuses.validate = "fail";
@@ -8331,7 +8747,7 @@ async function runMechanicalChecks(options) {
8331
8747
  statuses.validate = "fail";
8332
8748
  findings.push({
8333
8749
  tool: "validate",
8334
- file: path6.join(projectRoot, "AGENTS.md"),
8750
+ file: path13.join(projectRoot, "AGENTS.md"),
8335
8751
  message: err instanceof Error ? err.message : String(err),
8336
8752
  severity: "error"
8337
8753
  });
@@ -8395,7 +8811,7 @@ async function runMechanicalChecks(options) {
8395
8811
  (async () => {
8396
8812
  const localFindings = [];
8397
8813
  try {
8398
- const docsDir = path6.join(projectRoot, config.docsDir ?? "docs");
8814
+ const docsDir = path13.join(projectRoot, config.docsDir ?? "docs");
8399
8815
  const result = await checkDocCoverage("project", { docsDir });
8400
8816
  if (!result.ok) {
8401
8817
  statuses["check-docs"] = "warn";
@@ -8422,7 +8838,7 @@ async function runMechanicalChecks(options) {
8422
8838
  statuses["check-docs"] = "warn";
8423
8839
  localFindings.push({
8424
8840
  tool: "check-docs",
8425
- file: path6.join(projectRoot, "docs"),
8841
+ file: path13.join(projectRoot, "docs"),
8426
8842
  message: err instanceof Error ? err.message : String(err),
8427
8843
  severity: "warning"
8428
8844
  });
@@ -8570,7 +8986,7 @@ function detectChangeType(commitMessage, diff2) {
8570
8986
  }
8571
8987
 
8572
8988
  // src/review/context-scoper.ts
8573
- var path7 = __toESM(require("path"));
8989
+ var path14 = __toESM(require("path"));
8574
8990
  var ALL_DOMAINS = ["compliance", "bug", "security", "architecture"];
8575
8991
  var SECURITY_PATTERNS = /auth|crypto|password|secret|token|session|cookie|hash|encrypt|decrypt|sql|shell|exec|eval/i;
8576
8992
  function computeContextBudget(diffLines) {
@@ -8578,18 +8994,18 @@ function computeContextBudget(diffLines) {
8578
8994
  return diffLines;
8579
8995
  }
8580
8996
  function isWithinProject(absPath, projectRoot) {
8581
- const resolvedRoot = path7.resolve(projectRoot) + path7.sep;
8582
- const resolvedPath = path7.resolve(absPath);
8583
- return resolvedPath.startsWith(resolvedRoot) || resolvedPath === path7.resolve(projectRoot);
8997
+ const resolvedRoot = path14.resolve(projectRoot) + path14.sep;
8998
+ const resolvedPath = path14.resolve(absPath);
8999
+ return resolvedPath.startsWith(resolvedRoot) || resolvedPath === path14.resolve(projectRoot);
8584
9000
  }
8585
9001
  async function readContextFile(projectRoot, filePath, reason) {
8586
- const absPath = path7.isAbsolute(filePath) ? filePath : path7.join(projectRoot, filePath);
9002
+ const absPath = path14.isAbsolute(filePath) ? filePath : path14.join(projectRoot, filePath);
8587
9003
  if (!isWithinProject(absPath, projectRoot)) return null;
8588
9004
  const result = await readFileContent(absPath);
8589
9005
  if (!result.ok) return null;
8590
9006
  const content = result.value;
8591
9007
  const lines = content.split("\n").length;
8592
- const relPath = path7.isAbsolute(filePath) ? path7.relative(projectRoot, filePath) : filePath;
9008
+ const relPath = path14.isAbsolute(filePath) ? path14.relative(projectRoot, filePath) : filePath;
8593
9009
  return { path: relPath, content, reason, lines };
8594
9010
  }
8595
9011
  function extractImportSources2(content) {
@@ -8604,18 +9020,18 @@ function extractImportSources2(content) {
8604
9020
  }
8605
9021
  async function resolveImportPath2(projectRoot, fromFile, importSource) {
8606
9022
  if (!importSource.startsWith(".")) return null;
8607
- const fromDir = path7.dirname(path7.join(projectRoot, fromFile));
8608
- const basePath = path7.resolve(fromDir, importSource);
9023
+ const fromDir = path14.dirname(path14.join(projectRoot, fromFile));
9024
+ const basePath = path14.resolve(fromDir, importSource);
8609
9025
  if (!isWithinProject(basePath, projectRoot)) return null;
8610
- const relBase = path7.relative(projectRoot, basePath);
9026
+ const relBase = path14.relative(projectRoot, basePath);
8611
9027
  const candidates = [
8612
9028
  relBase + ".ts",
8613
9029
  relBase + ".tsx",
8614
9030
  relBase + ".mts",
8615
- path7.join(relBase, "index.ts")
9031
+ path14.join(relBase, "index.ts")
8616
9032
  ];
8617
9033
  for (const candidate of candidates) {
8618
- const absCandidate = path7.join(projectRoot, candidate);
9034
+ const absCandidate = path14.join(projectRoot, candidate);
8619
9035
  if (await fileExists(absCandidate)) {
8620
9036
  return candidate;
8621
9037
  }
@@ -8623,10 +9039,10 @@ async function resolveImportPath2(projectRoot, fromFile, importSource) {
8623
9039
  return null;
8624
9040
  }
8625
9041
  async function findTestFiles(projectRoot, sourceFile) {
8626
- const baseName = path7.basename(sourceFile, path7.extname(sourceFile));
9042
+ const baseName = path14.basename(sourceFile, path14.extname(sourceFile));
8627
9043
  const pattern = `**/${baseName}.{test,spec}.{ts,tsx,mts}`;
8628
9044
  const results = await findFiles(pattern, projectRoot);
8629
- return results.map((f) => path7.relative(projectRoot, f));
9045
+ return results.map((f) => path14.relative(projectRoot, f));
8630
9046
  }
8631
9047
  async function gatherImportContext(projectRoot, changedFiles, budget) {
8632
9048
  const contextFiles = [];
@@ -9414,7 +9830,7 @@ async function fanOutReview(options) {
9414
9830
  }
9415
9831
 
9416
9832
  // src/review/validate-findings.ts
9417
- var path8 = __toESM(require("path"));
9833
+ var path15 = __toESM(require("path"));
9418
9834
  var DOWNGRADE_MAP = {
9419
9835
  critical: "important",
9420
9836
  important: "suggestion",
@@ -9435,7 +9851,7 @@ function normalizePath(filePath, projectRoot) {
9435
9851
  let normalized = filePath;
9436
9852
  normalized = normalized.replace(/\\/g, "/");
9437
9853
  const normalizedRoot = projectRoot.replace(/\\/g, "/");
9438
- if (path8.isAbsolute(normalized)) {
9854
+ if (path15.isAbsolute(normalized)) {
9439
9855
  const root = normalizedRoot.endsWith("/") ? normalizedRoot : normalizedRoot + "/";
9440
9856
  if (normalized.startsWith(root)) {
9441
9857
  normalized = normalized.slice(root.length);
@@ -9460,12 +9876,12 @@ function followImportChain(fromFile, fileContents, maxDepth = 2) {
9460
9876
  while ((match = importRegex.exec(content)) !== null) {
9461
9877
  const importPath = match[1];
9462
9878
  if (!importPath.startsWith(".")) continue;
9463
- const dir = path8.dirname(current.file);
9464
- let resolved = path8.join(dir, importPath).replace(/\\/g, "/");
9879
+ const dir = path15.dirname(current.file);
9880
+ let resolved = path15.join(dir, importPath).replace(/\\/g, "/");
9465
9881
  if (!resolved.match(/\.(ts|tsx|js|jsx)$/)) {
9466
9882
  resolved += ".ts";
9467
9883
  }
9468
- resolved = path8.normalize(resolved).replace(/\\/g, "/");
9884
+ resolved = path15.normalize(resolved).replace(/\\/g, "/");
9469
9885
  if (!visited.has(resolved) && current.depth + 1 <= maxDepth) {
9470
9886
  queue.push({ file: resolved, depth: current.depth + 1 });
9471
9887
  }
@@ -9482,7 +9898,7 @@ async function validateFindings(options) {
9482
9898
  if (exclusionSet.isExcluded(normalizedFile, finding.lineRange) || exclusionSet.isExcluded(finding.file, finding.lineRange)) {
9483
9899
  continue;
9484
9900
  }
9485
- const absoluteFile = path8.isAbsolute(finding.file) ? finding.file : path8.join(projectRoot, finding.file).replace(/\\/g, "/");
9901
+ const absoluteFile = path15.isAbsolute(finding.file) ? finding.file : path15.join(projectRoot, finding.file).replace(/\\/g, "/");
9486
9902
  if (exclusionSet.isExcluded(absoluteFile, finding.lineRange)) {
9487
9903
  continue;
9488
9904
  }
@@ -9965,7 +10381,7 @@ async function runReviewPipeline(options) {
9965
10381
  }
9966
10382
 
9967
10383
  // src/roadmap/parse.ts
9968
- var import_types16 = require("@harness-engineering/types");
10384
+ var import_types18 = require("@harness-engineering/types");
9969
10385
  var VALID_STATUSES = /* @__PURE__ */ new Set([
9970
10386
  "backlog",
9971
10387
  "planned",
@@ -9977,14 +10393,14 @@ var EM_DASH = "\u2014";
9977
10393
  function parseRoadmap(markdown) {
9978
10394
  const fmMatch = markdown.match(/^---\n([\s\S]*?)\n---/);
9979
10395
  if (!fmMatch) {
9980
- return (0, import_types16.Err)(new Error("Missing or malformed YAML frontmatter"));
10396
+ return (0, import_types18.Err)(new Error("Missing or malformed YAML frontmatter"));
9981
10397
  }
9982
10398
  const fmResult = parseFrontmatter(fmMatch[1]);
9983
10399
  if (!fmResult.ok) return fmResult;
9984
10400
  const body = markdown.slice(fmMatch[0].length);
9985
10401
  const milestonesResult = parseMilestones(body);
9986
10402
  if (!milestonesResult.ok) return milestonesResult;
9987
- return (0, import_types16.Ok)({
10403
+ return (0, import_types18.Ok)({
9988
10404
  frontmatter: fmResult.value,
9989
10405
  milestones: milestonesResult.value
9990
10406
  });
@@ -10003,8 +10419,10 @@ function parseFrontmatter(raw) {
10003
10419
  const versionStr = map.get("version");
10004
10420
  const lastSynced = map.get("last_synced");
10005
10421
  const lastManualEdit = map.get("last_manual_edit");
10422
+ const created = map.get("created");
10423
+ const updated = map.get("updated");
10006
10424
  if (!project || !versionStr || !lastSynced || !lastManualEdit) {
10007
- return (0, import_types16.Err)(
10425
+ return (0, import_types18.Err)(
10008
10426
  new Error(
10009
10427
  "Frontmatter missing required fields: project, version, last_synced, last_manual_edit"
10010
10428
  )
@@ -10012,9 +10430,12 @@ function parseFrontmatter(raw) {
10012
10430
  }
10013
10431
  const version = parseInt(versionStr, 10);
10014
10432
  if (isNaN(version)) {
10015
- return (0, import_types16.Err)(new Error("Frontmatter version must be a number"));
10433
+ return (0, import_types18.Err)(new Error("Frontmatter version must be a number"));
10016
10434
  }
10017
- return (0, import_types16.Ok)({ project, version, lastSynced, lastManualEdit });
10435
+ const fm = { project, version, lastSynced, lastManualEdit };
10436
+ if (created) fm.created = created;
10437
+ if (updated) fm.updated = updated;
10438
+ return (0, import_types18.Ok)(fm);
10018
10439
  }
10019
10440
  function parseMilestones(body) {
10020
10441
  const milestones = [];
@@ -10022,12 +10443,12 @@ function parseMilestones(body) {
10022
10443
  const h2Matches = [];
10023
10444
  let match;
10024
10445
  while ((match = h2Pattern.exec(body)) !== null) {
10025
- h2Matches.push({ heading: match[1], startIndex: match.index });
10446
+ h2Matches.push({ heading: match[1], startIndex: match.index, fullMatch: match[0] });
10026
10447
  }
10027
10448
  for (let i = 0; i < h2Matches.length; i++) {
10028
10449
  const h2 = h2Matches[i];
10029
10450
  const nextStart = i + 1 < h2Matches.length ? h2Matches[i + 1].startIndex : body.length;
10030
- const sectionBody = body.slice(h2.startIndex + h2.heading.length + 4, nextStart);
10451
+ const sectionBody = body.slice(h2.startIndex + h2.fullMatch.length, nextStart);
10031
10452
  const isBacklog = h2.heading === "Backlog";
10032
10453
  const milestoneName = isBacklog ? "Backlog" : h2.heading.replace(/^Milestone:\s*/, "");
10033
10454
  const featuresResult = parseFeatures(sectionBody);
@@ -10038,28 +10459,25 @@ function parseMilestones(body) {
10038
10459
  features: featuresResult.value
10039
10460
  });
10040
10461
  }
10041
- return (0, import_types16.Ok)(milestones);
10462
+ return (0, import_types18.Ok)(milestones);
10042
10463
  }
10043
10464
  function parseFeatures(sectionBody) {
10044
10465
  const features = [];
10045
- const h3Pattern = /^### Feature: (.+)$/gm;
10466
+ const h3Pattern = /^### (?:Feature: )?(.+)$/gm;
10046
10467
  const h3Matches = [];
10047
10468
  let match;
10048
10469
  while ((match = h3Pattern.exec(sectionBody)) !== null) {
10049
- h3Matches.push({ name: match[1], startIndex: match.index });
10470
+ h3Matches.push({ name: match[1], startIndex: match.index, fullMatch: match[0] });
10050
10471
  }
10051
10472
  for (let i = 0; i < h3Matches.length; i++) {
10052
10473
  const h3 = h3Matches[i];
10053
10474
  const nextStart = i + 1 < h3Matches.length ? h3Matches[i + 1].startIndex : sectionBody.length;
10054
- const featureBody = sectionBody.slice(
10055
- h3.startIndex + `### Feature: ${h3.name}`.length,
10056
- nextStart
10057
- );
10475
+ const featureBody = sectionBody.slice(h3.startIndex + h3.fullMatch.length, nextStart);
10058
10476
  const featureResult = parseFeatureFields(h3.name, featureBody);
10059
10477
  if (!featureResult.ok) return featureResult;
10060
10478
  features.push(featureResult.value);
10061
10479
  }
10062
- return (0, import_types16.Ok)(features);
10480
+ return (0, import_types18.Ok)(features);
10063
10481
  }
10064
10482
  function parseFeatureFields(name, body) {
10065
10483
  const fieldMap = /* @__PURE__ */ new Map();
@@ -10070,7 +10488,7 @@ function parseFeatureFields(name, body) {
10070
10488
  }
10071
10489
  const statusRaw = fieldMap.get("Status");
10072
10490
  if (!statusRaw || !VALID_STATUSES.has(statusRaw)) {
10073
- return (0, import_types16.Err)(
10491
+ return (0, import_types18.Err)(
10074
10492
  new Error(
10075
10493
  `Feature "${name}" has invalid status: "${statusRaw ?? "(missing)"}". Valid statuses: ${[...VALID_STATUSES].join(", ")}`
10076
10494
  )
@@ -10079,12 +10497,12 @@ function parseFeatureFields(name, body) {
10079
10497
  const status = statusRaw;
10080
10498
  const specRaw = fieldMap.get("Spec") ?? EM_DASH;
10081
10499
  const spec = specRaw === EM_DASH ? null : specRaw;
10082
- const plansRaw = fieldMap.get("Plans") ?? EM_DASH;
10083
- const plans = plansRaw === EM_DASH ? [] : plansRaw.split(",").map((p) => p.trim());
10084
- const blockedByRaw = fieldMap.get("Blocked by") ?? EM_DASH;
10085
- const blockedBy = blockedByRaw === EM_DASH ? [] : blockedByRaw.split(",").map((b) => b.trim());
10500
+ const plansRaw = fieldMap.get("Plans") ?? fieldMap.get("Plan") ?? EM_DASH;
10501
+ const plans = plansRaw === EM_DASH || plansRaw === "none" ? [] : plansRaw.split(",").map((p) => p.trim());
10502
+ const blockedByRaw = fieldMap.get("Blocked by") ?? fieldMap.get("Blockers") ?? EM_DASH;
10503
+ const blockedBy = blockedByRaw === EM_DASH || blockedByRaw === "none" ? [] : blockedByRaw.split(",").map((b) => b.trim());
10086
10504
  const summary = fieldMap.get("Summary") ?? "";
10087
- return (0, import_types16.Ok)({ name, status, spec, plans, blockedBy, summary });
10505
+ return (0, import_types18.Ok)({ name, status, spec, plans, blockedBy, summary });
10088
10506
  }
10089
10507
 
10090
10508
  // src/roadmap/serialize.ts
@@ -10094,11 +10512,17 @@ function serializeRoadmap(roadmap) {
10094
10512
  lines.push("---");
10095
10513
  lines.push(`project: ${roadmap.frontmatter.project}`);
10096
10514
  lines.push(`version: ${roadmap.frontmatter.version}`);
10515
+ if (roadmap.frontmatter.created) {
10516
+ lines.push(`created: ${roadmap.frontmatter.created}`);
10517
+ }
10518
+ if (roadmap.frontmatter.updated) {
10519
+ lines.push(`updated: ${roadmap.frontmatter.updated}`);
10520
+ }
10097
10521
  lines.push(`last_synced: ${roadmap.frontmatter.lastSynced}`);
10098
10522
  lines.push(`last_manual_edit: ${roadmap.frontmatter.lastManualEdit}`);
10099
10523
  lines.push("---");
10100
10524
  lines.push("");
10101
- lines.push("# Project Roadmap");
10525
+ lines.push("# Roadmap");
10102
10526
  for (const milestone of roadmap.milestones) {
10103
10527
  lines.push("");
10104
10528
  lines.push(serializeMilestoneHeading(milestone));
@@ -10111,26 +10535,27 @@ function serializeRoadmap(roadmap) {
10111
10535
  return lines.join("\n");
10112
10536
  }
10113
10537
  function serializeMilestoneHeading(milestone) {
10114
- return milestone.isBacklog ? "## Backlog" : `## Milestone: ${milestone.name}`;
10538
+ return milestone.isBacklog ? "## Backlog" : `## ${milestone.name}`;
10115
10539
  }
10116
10540
  function serializeFeature(feature) {
10117
10541
  const spec = feature.spec ?? EM_DASH2;
10118
10542
  const plans = feature.plans.length > 0 ? feature.plans.join(", ") : EM_DASH2;
10119
10543
  const blockedBy = feature.blockedBy.length > 0 ? feature.blockedBy.join(", ") : EM_DASH2;
10120
10544
  return [
10121
- `### Feature: ${feature.name}`,
10545
+ `### ${feature.name}`,
10546
+ "",
10122
10547
  `- **Status:** ${feature.status}`,
10123
10548
  `- **Spec:** ${spec}`,
10124
- `- **Plans:** ${plans}`,
10125
- `- **Blocked by:** ${blockedBy}`,
10126
- `- **Summary:** ${feature.summary}`
10549
+ `- **Summary:** ${feature.summary}`,
10550
+ `- **Blockers:** ${blockedBy}`,
10551
+ `- **Plan:** ${plans}`
10127
10552
  ];
10128
10553
  }
10129
10554
 
10130
10555
  // src/roadmap/sync.ts
10131
- var fs9 = __toESM(require("fs"));
10132
- var path9 = __toESM(require("path"));
10133
- var import_types17 = require("@harness-engineering/types");
10556
+ var fs16 = __toESM(require("fs"));
10557
+ var path16 = __toESM(require("path"));
10558
+ var import_types19 = require("@harness-engineering/types");
10134
10559
  function inferStatus(feature, projectPath, allFeatures) {
10135
10560
  if (feature.blockedBy.length > 0) {
10136
10561
  const blockerNotDone = feature.blockedBy.some((blockerName) => {
@@ -10144,10 +10569,10 @@ function inferStatus(feature, projectPath, allFeatures) {
10144
10569
  const featuresWithPlans = allFeatures.filter((f) => f.plans.length > 0);
10145
10570
  const useRootState = featuresWithPlans.length <= 1;
10146
10571
  if (useRootState) {
10147
- const rootStatePath = path9.join(projectPath, ".harness", "state.json");
10148
- if (fs9.existsSync(rootStatePath)) {
10572
+ const rootStatePath = path16.join(projectPath, ".harness", "state.json");
10573
+ if (fs16.existsSync(rootStatePath)) {
10149
10574
  try {
10150
- const raw = fs9.readFileSync(rootStatePath, "utf-8");
10575
+ const raw = fs16.readFileSync(rootStatePath, "utf-8");
10151
10576
  const state = JSON.parse(raw);
10152
10577
  if (state.progress) {
10153
10578
  for (const status of Object.values(state.progress)) {
@@ -10158,16 +10583,16 @@ function inferStatus(feature, projectPath, allFeatures) {
10158
10583
  }
10159
10584
  }
10160
10585
  }
10161
- const sessionsDir = path9.join(projectPath, ".harness", "sessions");
10162
- if (fs9.existsSync(sessionsDir)) {
10586
+ const sessionsDir = path16.join(projectPath, ".harness", "sessions");
10587
+ if (fs16.existsSync(sessionsDir)) {
10163
10588
  try {
10164
- const sessionDirs = fs9.readdirSync(sessionsDir, { withFileTypes: true });
10589
+ const sessionDirs = fs16.readdirSync(sessionsDir, { withFileTypes: true });
10165
10590
  for (const entry of sessionDirs) {
10166
10591
  if (!entry.isDirectory()) continue;
10167
- const autopilotPath = path9.join(sessionsDir, entry.name, "autopilot-state.json");
10168
- if (!fs9.existsSync(autopilotPath)) continue;
10592
+ const autopilotPath = path16.join(sessionsDir, entry.name, "autopilot-state.json");
10593
+ if (!fs16.existsSync(autopilotPath)) continue;
10169
10594
  try {
10170
- const raw = fs9.readFileSync(autopilotPath, "utf-8");
10595
+ const raw = fs16.readFileSync(autopilotPath, "utf-8");
10171
10596
  const autopilot = JSON.parse(raw);
10172
10597
  if (!autopilot.phases) continue;
10173
10598
  const linkedPhases = autopilot.phases.filter(
@@ -10214,7 +10639,7 @@ function syncRoadmap(options) {
10214
10639
  to: inferred
10215
10640
  });
10216
10641
  }
10217
- return (0, import_types17.Ok)(changes);
10642
+ return (0, import_types19.Ok)(changes);
10218
10643
  }
10219
10644
 
10220
10645
  // src/interaction/types.ts
@@ -10247,17 +10672,17 @@ var EmitInteractionInputSchema = import_zod7.z.object({
10247
10672
  });
10248
10673
 
10249
10674
  // src/blueprint/scanner.ts
10250
- var fs10 = __toESM(require("fs/promises"));
10251
- var path10 = __toESM(require("path"));
10675
+ var fs17 = __toESM(require("fs/promises"));
10676
+ var path17 = __toESM(require("path"));
10252
10677
  var ProjectScanner = class {
10253
10678
  constructor(rootDir) {
10254
10679
  this.rootDir = rootDir;
10255
10680
  }
10256
10681
  async scan() {
10257
- let projectName = path10.basename(this.rootDir);
10682
+ let projectName = path17.basename(this.rootDir);
10258
10683
  try {
10259
- const pkgPath = path10.join(this.rootDir, "package.json");
10260
- const pkgRaw = await fs10.readFile(pkgPath, "utf-8");
10684
+ const pkgPath = path17.join(this.rootDir, "package.json");
10685
+ const pkgRaw = await fs17.readFile(pkgPath, "utf-8");
10261
10686
  const pkg = JSON.parse(pkgRaw);
10262
10687
  if (pkg.name) projectName = pkg.name;
10263
10688
  } catch {
@@ -10298,8 +10723,8 @@ var ProjectScanner = class {
10298
10723
  };
10299
10724
 
10300
10725
  // src/blueprint/generator.ts
10301
- var fs11 = __toESM(require("fs/promises"));
10302
- var path11 = __toESM(require("path"));
10726
+ var fs18 = __toESM(require("fs/promises"));
10727
+ var path18 = __toESM(require("path"));
10303
10728
  var ejs = __toESM(require("ejs"));
10304
10729
 
10305
10730
  // src/blueprint/templates.ts
@@ -10327,16 +10752,6 @@ var SHELL_TEMPLATE = `
10327
10752
  <div class="content">
10328
10753
  <h3>Code Translation</h3>
10329
10754
  <div class="translation"><%- module.content.codeTranslation %></div>
10330
- <h3>Knowledge Check</h3>
10331
- <div class="quiz">
10332
- <% module.content.quiz.questions.forEach((q, i) => { %>
10333
- <div class="question">
10334
- <p><%= q.question %></p>
10335
- <button onclick="reveal(this)">Reveal Answer</button>
10336
- <p class="answer" style="display:none;"><%= q.answer %></p>
10337
- </div>
10338
- <% }) %>
10339
- </div>
10340
10755
  </div>
10341
10756
  </article>
10342
10757
 
@@ -10355,10 +10770,6 @@ header { border-bottom: 2px solid #eee; margin-bottom: 20px; padding-bottom: 10p
10355
10770
  .module h2 { margin-top: 0; color: #0066cc; }
10356
10771
  `;
10357
10772
  var SCRIPTS = `
10358
- function reveal(btn) {
10359
- btn.nextElementSibling.style.display = 'block';
10360
- btn.style.display = 'none';
10361
- }
10362
10773
  console.log('Blueprint player initialized.');
10363
10774
  `;
10364
10775
 
@@ -10377,20 +10788,8 @@ var ContentPipeline = class {
10377
10788
  const translation = await llmService.generate(
10378
10789
  `You are a technical educator. Explain the following code clearly and concisely: ${codeContext}`
10379
10790
  );
10380
- const quizJson = await llmService.generate(
10381
- `Create 3 technical quiz questions for this code. Return ONLY valid JSON in this format: { "questions": [{ "question": "...", "answer": "..." }] }. Code: ${codeContext}`
10382
- );
10383
- let quiz;
10384
- try {
10385
- const cleanJson = quizJson.replace(/```json/g, "").replace(/```/g, "").trim();
10386
- quiz = JSON.parse(cleanJson);
10387
- } catch (e) {
10388
- console.error("Failed to parse quiz JSON", e);
10389
- quiz = { questions: [{ question: "Failed to generate quiz", answer: "N/A" }] };
10390
- }
10391
10791
  return {
10392
- codeTranslation: translation,
10393
- quiz
10792
+ codeTranslation: translation
10394
10793
  };
10395
10794
  }
10396
10795
  };
@@ -10409,19 +10808,19 @@ var BlueprintGenerator = class {
10409
10808
  styles: STYLES,
10410
10809
  scripts: SCRIPTS
10411
10810
  });
10412
- await fs11.mkdir(options.outputDir, { recursive: true });
10413
- await fs11.writeFile(path11.join(options.outputDir, "index.html"), html);
10811
+ await fs18.mkdir(options.outputDir, { recursive: true });
10812
+ await fs18.writeFile(path18.join(options.outputDir, "index.html"), html);
10414
10813
  }
10415
10814
  };
10416
10815
 
10417
10816
  // src/update-checker.ts
10418
- var fs12 = __toESM(require("fs"));
10419
- var path12 = __toESM(require("path"));
10817
+ var fs19 = __toESM(require("fs"));
10818
+ var path19 = __toESM(require("path"));
10420
10819
  var os = __toESM(require("os"));
10421
10820
  var import_child_process3 = require("child_process");
10422
10821
  function getStatePath() {
10423
10822
  const home = process.env["HOME"] || os.homedir();
10424
- return path12.join(home, ".harness", "update-check.json");
10823
+ return path19.join(home, ".harness", "update-check.json");
10425
10824
  }
10426
10825
  function isUpdateCheckEnabled(configInterval) {
10427
10826
  if (process.env["HARNESS_NO_UPDATE_CHECK"] === "1") return false;
@@ -10434,7 +10833,7 @@ function shouldRunCheck(state, intervalMs) {
10434
10833
  }
10435
10834
  function readCheckState() {
10436
10835
  try {
10437
- const raw = fs12.readFileSync(getStatePath(), "utf-8");
10836
+ const raw = fs19.readFileSync(getStatePath(), "utf-8");
10438
10837
  const parsed = JSON.parse(raw);
10439
10838
  if (typeof parsed === "object" && parsed !== null && "lastCheckTime" in parsed && typeof parsed.lastCheckTime === "number" && "currentVersion" in parsed && typeof parsed.currentVersion === "string") {
10440
10839
  const state = parsed;
@@ -10451,7 +10850,7 @@ function readCheckState() {
10451
10850
  }
10452
10851
  function spawnBackgroundCheck(currentVersion) {
10453
10852
  const statePath = getStatePath();
10454
- const stateDir = path12.dirname(statePath);
10853
+ const stateDir = path19.dirname(statePath);
10455
10854
  const script = `
10456
10855
  const { execSync } = require('child_process');
10457
10856
  const fs = require('fs');
@@ -10583,6 +10982,7 @@ var VERSION = "0.11.0";
10583
10982
  ViolationSchema,
10584
10983
  addProvenance,
10585
10984
  analyzeDiff,
10985
+ analyzeLearningPatterns,
10586
10986
  appendFailure,
10587
10987
  appendLearning,
10588
10988
  applyFixes,
@@ -10591,6 +10991,7 @@ var VERSION = "0.11.0";
10591
10991
  archModule,
10592
10992
  architecture,
10593
10993
  archiveFailures,
10994
+ archiveLearnings,
10594
10995
  archiveStream,
10595
10996
  buildDependencyGraph,
10596
10997
  buildExclusionSet,
@@ -10598,6 +10999,8 @@ var VERSION = "0.11.0";
10598
10999
  checkDocCoverage,
10599
11000
  checkEligibility,
10600
11001
  classifyFinding,
11002
+ clearFailuresCache,
11003
+ clearLearningsCache,
10601
11004
  configureFeedback,
10602
11005
  constraintRuleId,
10603
11006
  contextBudget,
@@ -10653,16 +11056,20 @@ var VERSION = "0.11.0";
10653
11056
  injectionRules,
10654
11057
  isSmallSuggestion,
10655
11058
  isUpdateCheckEnabled,
11059
+ listActiveSessions,
10656
11060
  listStreams,
11061
+ loadBudgetedLearnings,
10657
11062
  loadFailures,
10658
11063
  loadHandoff,
10659
11064
  loadRelevantLearnings,
11065
+ loadSessionSummary,
10660
11066
  loadState,
10661
11067
  loadStreamIndex,
10662
11068
  logAgentAction,
10663
11069
  migrateToStreams,
10664
11070
  networkRules,
10665
11071
  nodeRules,
11072
+ parseDateFromEntry,
10666
11073
  parseDiff,
10667
11074
  parseManifest,
10668
11075
  parseRoadmap,
@@ -10670,9 +11077,11 @@ var VERSION = "0.11.0";
10670
11077
  parseSize,
10671
11078
  pathTraversalRules,
10672
11079
  previewFix,
11080
+ pruneLearnings,
10673
11081
  reactRules,
10674
11082
  readCheckState,
10675
11083
  readLockfile,
11084
+ removeContributions,
10676
11085
  removeProvenance,
10677
11086
  requestMultiplePeerReviews,
10678
11087
  requestPeerReview,
@@ -10680,6 +11089,7 @@ var VERSION = "0.11.0";
10680
11089
  resolveFileToLayer,
10681
11090
  resolveModelTier,
10682
11091
  resolveRuleSeverity,
11092
+ resolveSessionDir,
10683
11093
  resolveStreamPath,
10684
11094
  resolveThresholds,
10685
11095
  runAll,
@@ -10706,6 +11116,7 @@ var VERSION = "0.11.0";
10706
11116
  syncRoadmap,
10707
11117
  touchStream,
10708
11118
  trackAction,
11119
+ updateSessionIndex,
10709
11120
  validateAgentsMap,
10710
11121
  validateBoundaries,
10711
11122
  validateCommitMessage,
@@ -10718,6 +11129,7 @@ var VERSION = "0.11.0";
10718
11129
  violationId,
10719
11130
  writeConfig,
10720
11131
  writeLockfile,
11132
+ writeSessionSummary,
10721
11133
  xssRules,
10722
11134
  ...require("@harness-engineering/types")
10723
11135
  });