@agntk/agent-harness 0.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 (212) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +41 -0
  3. package/README.md +445 -0
  4. package/defaults/agents/summarizer.md +49 -0
  5. package/defaults/instincts/lead-with-answer.md +24 -0
  6. package/defaults/instincts/qualify-before-recommending.md +40 -0
  7. package/defaults/instincts/read-before-edit.md +23 -0
  8. package/defaults/instincts/search-before-create.md +23 -0
  9. package/defaults/playbooks/ship-feature.md +31 -0
  10. package/defaults/rules/ask-before-assuming.md +35 -0
  11. package/defaults/rules/operations.md +35 -0
  12. package/defaults/rules/respect-the-user.md +39 -0
  13. package/defaults/skills/business-analyst.md +181 -0
  14. package/defaults/skills/content-marketer.md +184 -0
  15. package/defaults/skills/research.md +34 -0
  16. package/defaults/tools/example-web-search.md +60 -0
  17. package/defaults/workflows/daily-reflection.md +54 -0
  18. package/dist/agent-framework-K4GUIICH.js +344 -0
  19. package/dist/agent-framework-K4GUIICH.js.map +1 -0
  20. package/dist/analytics-RPT73WNM.js +12 -0
  21. package/dist/analytics-RPT73WNM.js.map +1 -0
  22. package/dist/auto-processor-OLE45UI3.js +13 -0
  23. package/dist/auto-processor-OLE45UI3.js.map +1 -0
  24. package/dist/chunk-274RV3YO.js +162 -0
  25. package/dist/chunk-274RV3YO.js.map +1 -0
  26. package/dist/chunk-4CWAGBNS.js +168 -0
  27. package/dist/chunk-4CWAGBNS.js.map +1 -0
  28. package/dist/chunk-4FDUOGSZ.js +69 -0
  29. package/dist/chunk-4FDUOGSZ.js.map +1 -0
  30. package/dist/chunk-5H34JPMB.js +199 -0
  31. package/dist/chunk-5H34JPMB.js.map +1 -0
  32. package/dist/chunk-6EMOEYGU.js +102 -0
  33. package/dist/chunk-6EMOEYGU.js.map +1 -0
  34. package/dist/chunk-A7BJPQQ6.js +236 -0
  35. package/dist/chunk-A7BJPQQ6.js.map +1 -0
  36. package/dist/chunk-AGAAFJEO.js +76 -0
  37. package/dist/chunk-AGAAFJEO.js.map +1 -0
  38. package/dist/chunk-BSKDOFRT.js +65 -0
  39. package/dist/chunk-BSKDOFRT.js.map +1 -0
  40. package/dist/chunk-CHJ5GNZC.js +100 -0
  41. package/dist/chunk-CHJ5GNZC.js.map +1 -0
  42. package/dist/chunk-CSL3ERUI.js +307 -0
  43. package/dist/chunk-CSL3ERUI.js.map +1 -0
  44. package/dist/chunk-DA7IKHC4.js +229 -0
  45. package/dist/chunk-DA7IKHC4.js.map +1 -0
  46. package/dist/chunk-DGUM43GV.js +11 -0
  47. package/dist/chunk-DGUM43GV.js.map +1 -0
  48. package/dist/chunk-DTTXPHFW.js +211 -0
  49. package/dist/chunk-DTTXPHFW.js.map +1 -0
  50. package/dist/chunk-FD55B3IO.js +204 -0
  51. package/dist/chunk-FD55B3IO.js.map +1 -0
  52. package/dist/chunk-FLZU44SV.js +230 -0
  53. package/dist/chunk-FLZU44SV.js.map +1 -0
  54. package/dist/chunk-GJNNR2RA.js +200 -0
  55. package/dist/chunk-GJNNR2RA.js.map +1 -0
  56. package/dist/chunk-GNUSHD2Y.js +111 -0
  57. package/dist/chunk-GNUSHD2Y.js.map +1 -0
  58. package/dist/chunk-GUJTBGVS.js +2212 -0
  59. package/dist/chunk-GUJTBGVS.js.map +1 -0
  60. package/dist/chunk-IZ6UZ3ZL.js +207 -0
  61. package/dist/chunk-IZ6UZ3ZL.js.map +1 -0
  62. package/dist/chunk-JKMGYWXB.js +197 -0
  63. package/dist/chunk-JKMGYWXB.js.map +1 -0
  64. package/dist/chunk-KFX54TQM.js +165 -0
  65. package/dist/chunk-KFX54TQM.js.map +1 -0
  66. package/dist/chunk-M7NXUK55.js +199 -0
  67. package/dist/chunk-M7NXUK55.js.map +1 -0
  68. package/dist/chunk-MPZ3BPUI.js +374 -0
  69. package/dist/chunk-MPZ3BPUI.js.map +1 -0
  70. package/dist/chunk-OC6YSTDX.js +119 -0
  71. package/dist/chunk-OC6YSTDX.js.map +1 -0
  72. package/dist/chunk-RC6MEZB6.js +469 -0
  73. package/dist/chunk-RC6MEZB6.js.map +1 -0
  74. package/dist/chunk-RY3ZFII7.js +3440 -0
  75. package/dist/chunk-RY3ZFII7.js.map +1 -0
  76. package/dist/chunk-TAT6JU3X.js +167 -0
  77. package/dist/chunk-TAT6JU3X.js.map +1 -0
  78. package/dist/chunk-UDZIS2AQ.js +79 -0
  79. package/dist/chunk-UDZIS2AQ.js.map +1 -0
  80. package/dist/chunk-UPLBF4RZ.js +115 -0
  81. package/dist/chunk-UPLBF4RZ.js.map +1 -0
  82. package/dist/chunk-UWQTZMNI.js +154 -0
  83. package/dist/chunk-UWQTZMNI.js.map +1 -0
  84. package/dist/chunk-W4T7PGI2.js +346 -0
  85. package/dist/chunk-W4T7PGI2.js.map +1 -0
  86. package/dist/chunk-XTBKL5BI.js +111 -0
  87. package/dist/chunk-XTBKL5BI.js.map +1 -0
  88. package/dist/chunk-YIJY5DBV.js +399 -0
  89. package/dist/chunk-YIJY5DBV.js.map +1 -0
  90. package/dist/chunk-YUFNYN2H.js +242 -0
  91. package/dist/chunk-YUFNYN2H.js.map +1 -0
  92. package/dist/chunk-Z2PUCXTZ.js +94 -0
  93. package/dist/chunk-Z2PUCXTZ.js.map +1 -0
  94. package/dist/chunk-ZZJOFKAT.js +13 -0
  95. package/dist/chunk-ZZJOFKAT.js.map +1 -0
  96. package/dist/cli/index.js +3661 -0
  97. package/dist/cli/index.js.map +1 -0
  98. package/dist/config-WVMRUOCA.js +13 -0
  99. package/dist/config-WVMRUOCA.js.map +1 -0
  100. package/dist/context-loader-3ORBPMHJ.js +13 -0
  101. package/dist/context-loader-3ORBPMHJ.js.map +1 -0
  102. package/dist/conversation-QDEIDQPH.js +22 -0
  103. package/dist/conversation-QDEIDQPH.js.map +1 -0
  104. package/dist/cost-tracker-RS3W7SVY.js +24 -0
  105. package/dist/cost-tracker-RS3W7SVY.js.map +1 -0
  106. package/dist/delegate-VJCJLYEK.js +29 -0
  107. package/dist/delegate-VJCJLYEK.js.map +1 -0
  108. package/dist/emotional-state-VQVRA6ED.js +206 -0
  109. package/dist/emotional-state-VQVRA6ED.js.map +1 -0
  110. package/dist/env-discovery-2BLVMAIM.js +251 -0
  111. package/dist/env-discovery-2BLVMAIM.js.map +1 -0
  112. package/dist/export-6GCYHEHQ.js +165 -0
  113. package/dist/export-6GCYHEHQ.js.map +1 -0
  114. package/dist/graph-YUIPOSOO.js +14 -0
  115. package/dist/graph-YUIPOSOO.js.map +1 -0
  116. package/dist/harness-LCHA3DWP.js +10 -0
  117. package/dist/harness-LCHA3DWP.js.map +1 -0
  118. package/dist/harness-WE4SLCML.js +26 -0
  119. package/dist/harness-WE4SLCML.js.map +1 -0
  120. package/dist/health-NZ6WNIMV.js +23 -0
  121. package/dist/health-NZ6WNIMV.js.map +1 -0
  122. package/dist/index.d.ts +3612 -0
  123. package/dist/index.js +13501 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/indexer-LONANRRM.js +16 -0
  126. package/dist/indexer-LONANRRM.js.map +1 -0
  127. package/dist/instinct-learner-SRM72DHF.js +20 -0
  128. package/dist/instinct-learner-SRM72DHF.js.map +1 -0
  129. package/dist/intake-4M3HNU43.js +21 -0
  130. package/dist/intake-4M3HNU43.js.map +1 -0
  131. package/dist/intelligence-HJOCA4SJ.js +1081 -0
  132. package/dist/intelligence-HJOCA4SJ.js.map +1 -0
  133. package/dist/journal-WANJL3MI.js +24 -0
  134. package/dist/journal-WANJL3MI.js.map +1 -0
  135. package/dist/loader-C3TKIKZR.js +23 -0
  136. package/dist/loader-C3TKIKZR.js.map +1 -0
  137. package/dist/mcp-WTQJJZAO.js +15 -0
  138. package/dist/mcp-WTQJJZAO.js.map +1 -0
  139. package/dist/mcp-discovery-WPAQFL6S.js +377 -0
  140. package/dist/mcp-discovery-WPAQFL6S.js.map +1 -0
  141. package/dist/mcp-installer-6O2XXD3V.js +394 -0
  142. package/dist/mcp-installer-6O2XXD3V.js.map +1 -0
  143. package/dist/metrics-KXGNFAAB.js +20 -0
  144. package/dist/metrics-KXGNFAAB.js.map +1 -0
  145. package/dist/primitive-registry-I6VTIR4W.js +512 -0
  146. package/dist/primitive-registry-I6VTIR4W.js.map +1 -0
  147. package/dist/project-discovery-C4UMD7JI.js +246 -0
  148. package/dist/project-discovery-C4UMD7JI.js.map +1 -0
  149. package/dist/provider-LQHQX7Z7.js +26 -0
  150. package/dist/provider-LQHQX7Z7.js.map +1 -0
  151. package/dist/provider-SXPQZ74H.js +28 -0
  152. package/dist/provider-SXPQZ74H.js.map +1 -0
  153. package/dist/rate-limiter-RLRVM325.js +22 -0
  154. package/dist/rate-limiter-RLRVM325.js.map +1 -0
  155. package/dist/rule-engine-YGQ3RYZM.js +182 -0
  156. package/dist/rule-engine-YGQ3RYZM.js.map +1 -0
  157. package/dist/scaffold-A3VRRCBV.js +347 -0
  158. package/dist/scaffold-A3VRRCBV.js.map +1 -0
  159. package/dist/scheduler-XHHIVHRI.js +397 -0
  160. package/dist/scheduler-XHHIVHRI.js.map +1 -0
  161. package/dist/search-V3W5JMJG.js +75 -0
  162. package/dist/search-V3W5JMJG.js.map +1 -0
  163. package/dist/semantic-search-2DTOO5UX.js +241 -0
  164. package/dist/semantic-search-2DTOO5UX.js.map +1 -0
  165. package/dist/serve-DTQ3HENY.js +291 -0
  166. package/dist/serve-DTQ3HENY.js.map +1 -0
  167. package/dist/sessions-CZGVXKQE.js +21 -0
  168. package/dist/sessions-CZGVXKQE.js.map +1 -0
  169. package/dist/sources-RW5DT56F.js +32 -0
  170. package/dist/sources-RW5DT56F.js.map +1 -0
  171. package/dist/starter-packs-76YUVHEU.js +893 -0
  172. package/dist/starter-packs-76YUVHEU.js.map +1 -0
  173. package/dist/state-GMXILIHW.js +13 -0
  174. package/dist/state-GMXILIHW.js.map +1 -0
  175. package/dist/state-merge-NKO5FRBA.js +174 -0
  176. package/dist/state-merge-NKO5FRBA.js.map +1 -0
  177. package/dist/telemetry-UC6PBXC7.js +22 -0
  178. package/dist/telemetry-UC6PBXC7.js.map +1 -0
  179. package/dist/tool-executor-MJ7IG7PQ.js +28 -0
  180. package/dist/tool-executor-MJ7IG7PQ.js.map +1 -0
  181. package/dist/tools-DZ4KETET.js +20 -0
  182. package/dist/tools-DZ4KETET.js.map +1 -0
  183. package/dist/types-EW7AIB3R.js +18 -0
  184. package/dist/types-EW7AIB3R.js.map +1 -0
  185. package/dist/types-WGDLSPO6.js +16 -0
  186. package/dist/types-WGDLSPO6.js.map +1 -0
  187. package/dist/universal-installer-QGS4SJGX.js +578 -0
  188. package/dist/universal-installer-QGS4SJGX.js.map +1 -0
  189. package/dist/validator-7WXMDIHH.js +22 -0
  190. package/dist/validator-7WXMDIHH.js.map +1 -0
  191. package/dist/verification-gate-FYXUX6LH.js +246 -0
  192. package/dist/verification-gate-FYXUX6LH.js.map +1 -0
  193. package/dist/versioning-Z3XNE2Q2.js +271 -0
  194. package/dist/versioning-Z3XNE2Q2.js.map +1 -0
  195. package/dist/watcher-ISJC7YKL.js +109 -0
  196. package/dist/watcher-ISJC7YKL.js.map +1 -0
  197. package/dist/web-server-DD7ZOP46.js +28 -0
  198. package/dist/web-server-DD7ZOP46.js.map +1 -0
  199. package/package.json +76 -0
  200. package/sources.yaml +121 -0
  201. package/templates/assistant/CORE.md +24 -0
  202. package/templates/assistant/SYSTEM.md +24 -0
  203. package/templates/assistant/config.yaml +51 -0
  204. package/templates/base/CORE.md +17 -0
  205. package/templates/base/SYSTEM.md +24 -0
  206. package/templates/base/config.yaml +51 -0
  207. package/templates/claude-opus/config.yaml +51 -0
  208. package/templates/code-reviewer/CORE.md +25 -0
  209. package/templates/code-reviewer/SYSTEM.md +30 -0
  210. package/templates/code-reviewer/config.yaml +51 -0
  211. package/templates/gpt4/config.yaml +51 -0
  212. package/templates/local/config.yaml +51 -0
@@ -0,0 +1,1081 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {
4
+ validateHarness
5
+ } from "./chunk-FLZU44SV.js";
6
+ import {
7
+ buildDependencyGraph
8
+ } from "./chunk-274RV3YO.js";
9
+ import {
10
+ installInstinct
11
+ } from "./chunk-GJNNR2RA.js";
12
+ import "./chunk-W4T7PGI2.js";
13
+ import {
14
+ buildRateLimits
15
+ } from "./chunk-AGAAFJEO.js";
16
+ import "./chunk-5H34JPMB.js";
17
+ import "./chunk-4FDUOGSZ.js";
18
+ import "./chunk-UWQTZMNI.js";
19
+ import "./chunk-UDZIS2AQ.js";
20
+ import "./chunk-Z2PUCXTZ.js";
21
+ import {
22
+ checkBudget
23
+ } from "./chunk-JKMGYWXB.js";
24
+ import {
25
+ checkRateLimit
26
+ } from "./chunk-OC6YSTDX.js";
27
+ import {
28
+ loadDirectory,
29
+ loadDirectoryWithErrors
30
+ } from "./chunk-UPLBF4RZ.js";
31
+ import {
32
+ log
33
+ } from "./chunk-BSKDOFRT.js";
34
+ import "./chunk-IZ6UZ3ZL.js";
35
+ import {
36
+ loadConfig
37
+ } from "./chunk-CHJ5GNZC.js";
38
+ import {
39
+ getPrimitiveDirs
40
+ } from "./chunk-4CWAGBNS.js";
41
+ import "./chunk-ZZJOFKAT.js";
42
+
43
+ // src/runtime/intelligence.ts
44
+ import { existsSync, readdirSync, readFileSync, statSync } from "fs";
45
+ import { join, relative } from "path";
46
+ function autoPromoteInstincts(harnessDir, options) {
47
+ const threshold = options?.threshold ?? 3;
48
+ const journalDir = join(harnessDir, "memory", "journal");
49
+ if (!existsSync(journalDir)) {
50
+ return { patterns: [], promoted: [], skipped: [], journalsScanned: 0 };
51
+ }
52
+ const files = readdirSync(journalDir).filter((f) => f.endsWith(".md") && /^\d{4}-\d{2}-\d{2}/.test(f)).sort();
53
+ const behaviorMap = /* @__PURE__ */ new Map();
54
+ for (const file of files) {
55
+ const content = readFileSync(join(journalDir, file), "utf-8");
56
+ const dateMatch = file.match(/^(\d{4}-\d{2}-\d{2})/);
57
+ if (!dateMatch) continue;
58
+ const journalDate = dateMatch[1];
59
+ const sectionMatch = content.match(/## Instinct Candidates\n([\s\S]*?)(?=\n## |\n*$)/);
60
+ if (!sectionMatch) continue;
61
+ const lines = sectionMatch[1].split("\n").filter((l) => l.startsWith("- ")).map((l) => l.slice(2).trim().replace(/^INSTINCT:\s*/i, ""));
62
+ for (const line of lines) {
63
+ if (!line) continue;
64
+ const normalized = normalizeBehavior(line);
65
+ if (!normalized) continue;
66
+ const existing = behaviorMap.get(normalized);
67
+ if (existing) {
68
+ existing.dates.add(journalDate);
69
+ } else {
70
+ behaviorMap.set(normalized, { original: line, dates: /* @__PURE__ */ new Set([journalDate]) });
71
+ }
72
+ }
73
+ }
74
+ const patterns = [];
75
+ for (const [, value] of behaviorMap) {
76
+ if (value.dates.size >= threshold) {
77
+ patterns.push({
78
+ behavior: value.original,
79
+ journalDates: [...value.dates].sort(),
80
+ count: value.dates.size
81
+ });
82
+ }
83
+ }
84
+ patterns.sort((a, b) => b.count - a.count);
85
+ const existingIds = /* @__PURE__ */ new Set();
86
+ const existingBehaviors = /* @__PURE__ */ new Set();
87
+ const instinctsDir = join(harnessDir, "instincts");
88
+ if (existsSync(instinctsDir)) {
89
+ const docs = loadDirectory(instinctsDir);
90
+ for (const doc of docs) {
91
+ existingIds.add(doc.frontmatter.id);
92
+ if (doc.l0) existingBehaviors.add(normalizeBehavior(doc.l0));
93
+ }
94
+ }
95
+ const promoted = [];
96
+ const skipped = [];
97
+ for (const pattern of patterns) {
98
+ const normalized = normalizeBehavior(pattern.behavior);
99
+ const id = behaviorToId(pattern.behavior);
100
+ if (existingIds.has(id) || existingBehaviors.has(normalized)) {
101
+ skipped.push(id);
102
+ continue;
103
+ }
104
+ if (options?.install) {
105
+ const candidate = {
106
+ id,
107
+ behavior: pattern.behavior,
108
+ provenance: `auto-promote:${pattern.journalDates.length}x across ${pattern.journalDates[0]} to ${pattern.journalDates[pattern.journalDates.length - 1]}`,
109
+ confidence: Math.min(0.9, 0.5 + pattern.count * 0.1)
110
+ };
111
+ const path = installInstinct(harnessDir, candidate);
112
+ if (path) {
113
+ promoted.push(id);
114
+ } else {
115
+ skipped.push(id);
116
+ }
117
+ }
118
+ }
119
+ return { patterns, promoted, skipped, journalsScanned: files.length };
120
+ }
121
+ function normalizeBehavior(text) {
122
+ return text.toLowerCase().replace(/[^a-z0-9\s]/g, "").replace(/\s+/g, " ").trim();
123
+ }
124
+ function behaviorToId(behavior) {
125
+ return behavior.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").slice(0, 50).replace(/-+$/, "");
126
+ }
127
+ function detectDeadPrimitives(harnessDir, config, options) {
128
+ const thresholdDays = options?.thresholdDays ?? 30;
129
+ const now = Date.now();
130
+ const thresholdMs = thresholdDays * 24 * 60 * 60 * 1e3;
131
+ const graph = buildDependencyGraph(harnessDir, config);
132
+ const orphanIds = new Set(graph.orphans);
133
+ const connectedIds = /* @__PURE__ */ new Set();
134
+ for (const edge of graph.edges) {
135
+ connectedIds.add(edge.from);
136
+ connectedIds.add(edge.to);
137
+ }
138
+ const dead = [];
139
+ let totalScanned = 0;
140
+ for (const node of graph.nodes) {
141
+ totalScanned++;
142
+ if (!orphanIds.has(node.id)) continue;
143
+ const absPath = join(harnessDir, node.path);
144
+ if (!existsSync(absPath)) continue;
145
+ try {
146
+ const stat = statSync(absPath);
147
+ const mtime = stat.mtime.getTime();
148
+ const daysSince = Math.floor((now - mtime) / (24 * 60 * 60 * 1e3));
149
+ if (daysSince >= thresholdDays) {
150
+ dead.push({
151
+ id: node.id,
152
+ path: node.path,
153
+ directory: node.directory,
154
+ lastModified: stat.mtime.toISOString().split("T")[0],
155
+ daysSinceModified: daysSince,
156
+ reason: `Orphaned (no references) and not modified in ${daysSince} days`
157
+ });
158
+ }
159
+ } catch (err) {
160
+ log.warn(`Failed to stat ${absPath}: ${err instanceof Error ? err.message : String(err)}`);
161
+ }
162
+ }
163
+ dead.sort((a, b) => b.daysSinceModified - a.daysSinceModified);
164
+ return { dead, totalScanned, thresholdDays };
165
+ }
166
+ function detectContradictions(harnessDir) {
167
+ const rulesDir = join(harnessDir, "rules");
168
+ const instinctsDir = join(harnessDir, "instincts");
169
+ const rules = existsSync(rulesDir) ? loadDirectory(rulesDir) : [];
170
+ const instincts = existsSync(instinctsDir) ? loadDirectory(instinctsDir) : [];
171
+ const contradictions = [];
172
+ const ruleDirectives = rules.map((doc) => ({
173
+ doc,
174
+ directives: extractDirectives(doc),
175
+ topics: extractTopics(doc)
176
+ }));
177
+ const instinctDirectives = instincts.map((doc) => ({
178
+ doc,
179
+ directives: extractDirectives(doc),
180
+ topics: extractTopics(doc)
181
+ }));
182
+ for (const rule of ruleDirectives) {
183
+ for (const instinct of instinctDirectives) {
184
+ for (const rd of rule.directives) {
185
+ for (const id of instinct.directives) {
186
+ const negation = checkNegation(rd, id);
187
+ if (negation) {
188
+ contradictions.push({
189
+ primitiveA: {
190
+ id: rule.doc.frontmatter.id,
191
+ path: relative(harnessDir, rule.doc.path),
192
+ type: "rule",
193
+ text: rd.raw
194
+ },
195
+ primitiveB: {
196
+ id: instinct.doc.frontmatter.id,
197
+ path: relative(harnessDir, instinct.doc.path),
198
+ type: "instinct",
199
+ text: id.raw
200
+ },
201
+ reason: negation,
202
+ severity: "high"
203
+ });
204
+ }
205
+ }
206
+ }
207
+ const sharedTopics = rule.topics.filter((t) => instinct.topics.includes(t));
208
+ if (sharedTopics.length > 0) {
209
+ const ruleText = (rule.doc.l0 + " " + rule.doc.body).toLowerCase();
210
+ const instinctText = (instinct.doc.l0 + " " + instinct.doc.body).toLowerCase();
211
+ for (const topic of sharedTopics) {
212
+ const ruleHasAlways = hasPositiveDirective(ruleText, topic);
213
+ const instinctHasNever = hasNegativeDirective(instinctText, topic);
214
+ const ruleHasNever = hasNegativeDirective(ruleText, topic);
215
+ const instinctHasAlways = hasPositiveDirective(instinctText, topic);
216
+ if (ruleHasAlways && instinctHasNever || ruleHasNever && instinctHasAlways) {
217
+ const alreadyCaught = contradictions.some(
218
+ (c) => c.primitiveA.id === rule.doc.frontmatter.id && c.primitiveB.id === instinct.doc.frontmatter.id
219
+ );
220
+ if (!alreadyCaught) {
221
+ contradictions.push({
222
+ primitiveA: {
223
+ id: rule.doc.frontmatter.id,
224
+ path: relative(harnessDir, rule.doc.path),
225
+ type: "rule",
226
+ text: rule.doc.l0 || rule.doc.frontmatter.id
227
+ },
228
+ primitiveB: {
229
+ id: instinct.doc.frontmatter.id,
230
+ path: relative(harnessDir, instinct.doc.path),
231
+ type: "instinct",
232
+ text: instinct.doc.l0 || instinct.doc.frontmatter.id
233
+ },
234
+ reason: `Conflicting directives about "${topic}"`,
235
+ severity: "medium"
236
+ });
237
+ }
238
+ }
239
+ }
240
+ }
241
+ }
242
+ }
243
+ checkIntraGroupContradictions(ruleDirectives, "rule", harnessDir, contradictions);
244
+ checkIntraGroupContradictions(instinctDirectives, "instinct", harnessDir, contradictions);
245
+ return {
246
+ contradictions,
247
+ rulesChecked: rules.length,
248
+ instinctsChecked: instincts.length
249
+ };
250
+ }
251
+ function extractDirectives(doc) {
252
+ const directives = [];
253
+ const text = (doc.l0 + "\n" + doc.body).trim();
254
+ for (const line of text.split("\n")) {
255
+ const trimmed = line.trim().toLowerCase();
256
+ if (!trimmed || trimmed.startsWith("#")) continue;
257
+ const cleaned = trimmed.replace(/^[-*]\s+/, "").replace(/^\d+\.\s+/, "");
258
+ const positiveMatch = cleaned.match(
259
+ /^(always|must|should|prefer|ensure|require|use)\s+(.+)/
260
+ );
261
+ if (positiveMatch) {
262
+ directives.push({
263
+ action: "positive",
264
+ verb: positiveMatch[1],
265
+ subject: positiveMatch[2].replace(/[.!]$/, ""),
266
+ raw: cleaned
267
+ });
268
+ continue;
269
+ }
270
+ const negativeMatch = cleaned.match(
271
+ /^(never|don'?t|avoid|do not|must not|should not|shouldn'?t)\s+(.+)/
272
+ );
273
+ if (negativeMatch) {
274
+ directives.push({
275
+ action: "negative",
276
+ verb: negativeMatch[1],
277
+ subject: negativeMatch[2].replace(/[.!]$/, ""),
278
+ raw: cleaned
279
+ });
280
+ }
281
+ }
282
+ return directives;
283
+ }
284
+ function extractTopics(doc) {
285
+ const topics = [];
286
+ for (const tag of doc.frontmatter.tags) {
287
+ topics.push(tag.toLowerCase());
288
+ }
289
+ const idParts = doc.frontmatter.id.split("-").filter((p) => p.length > 2);
290
+ topics.push(...idParts.map((p) => p.toLowerCase()));
291
+ return [...new Set(topics)];
292
+ }
293
+ function checkNegation(a, b) {
294
+ if (a.action === b.action) return null;
295
+ const subA = a.subject.toLowerCase().replace(/\s+/g, " ").trim();
296
+ const subB = b.subject.toLowerCase().replace(/\s+/g, " ").trim();
297
+ if (subA === subB) {
298
+ return `Direct contradiction: "${a.raw}" vs "${b.raw}"`;
299
+ }
300
+ const wordsA = subA.split(" ").filter((w) => w.length > 3);
301
+ const wordsB = subB.split(" ").filter((w) => w.length > 3);
302
+ const overlap = wordsA.filter((w) => wordsB.includes(w));
303
+ if (overlap.length >= 2 && overlap.length >= Math.min(wordsA.length, wordsB.length) * 0.6) {
304
+ return `Likely contradiction (shared terms: ${overlap.join(", ")}): "${a.raw}" vs "${b.raw}"`;
305
+ }
306
+ return null;
307
+ }
308
+ function hasPositiveDirective(text, topic) {
309
+ const patterns = [
310
+ new RegExp(`always\\s+\\w*${topic}`, "i"),
311
+ new RegExp(`must\\s+\\w*${topic}`, "i"),
312
+ new RegExp(`should\\s+\\w*${topic}`, "i"),
313
+ new RegExp(`prefer\\s+\\w*${topic}`, "i"),
314
+ new RegExp(`use\\s+\\w*${topic}`, "i")
315
+ ];
316
+ return patterns.some((p) => p.test(text));
317
+ }
318
+ function hasNegativeDirective(text, topic) {
319
+ const patterns = [
320
+ new RegExp(`never\\s+\\w*${topic}`, "i"),
321
+ new RegExp(`avoid\\s+\\w*${topic}`, "i"),
322
+ new RegExp(`don'?t\\s+\\w*${topic}`, "i"),
323
+ new RegExp(`do not\\s+\\w*${topic}`, "i")
324
+ ];
325
+ return patterns.some((p) => p.test(text));
326
+ }
327
+ function checkIntraGroupContradictions(group, type, harnessDir, contradictions) {
328
+ for (let i = 0; i < group.length; i++) {
329
+ for (let j = i + 1; j < group.length; j++) {
330
+ const a = group[i];
331
+ const b = group[j];
332
+ for (const da of a.directives) {
333
+ for (const db of b.directives) {
334
+ const negation = checkNegation(da, db);
335
+ if (negation) {
336
+ contradictions.push({
337
+ primitiveA: {
338
+ id: a.doc.frontmatter.id,
339
+ path: relative(harnessDir, a.doc.path),
340
+ type,
341
+ text: da.raw
342
+ },
343
+ primitiveB: {
344
+ id: b.doc.frontmatter.id,
345
+ path: relative(harnessDir, b.doc.path),
346
+ type,
347
+ text: db.raw
348
+ },
349
+ reason: negation,
350
+ severity: "medium"
351
+ });
352
+ }
353
+ }
354
+ }
355
+ }
356
+ }
357
+ }
358
+ function enrichSessions(harnessDir, config, options) {
359
+ const sessionsDir = join(harnessDir, "memory", "sessions");
360
+ if (!existsSync(sessionsDir)) {
361
+ return { enriched: [], sessionsScanned: 0 };
362
+ }
363
+ const primitiveIds = /* @__PURE__ */ new Set();
364
+ const dirs = getPrimitiveDirs(config);
365
+ for (const dir of dirs) {
366
+ const fullPath = join(harnessDir, dir);
367
+ if (!existsSync(fullPath)) continue;
368
+ const { docs } = loadDirectoryWithErrors(fullPath);
369
+ for (const doc of docs) {
370
+ primitiveIds.add(doc.frontmatter.id);
371
+ }
372
+ }
373
+ const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".md") && !f.startsWith(".") && !f.startsWith("_")).sort();
374
+ const filtered = files.filter((f) => {
375
+ if (!options?.from && !options?.to) return true;
376
+ const dateMatch = f.match(/^(\d{4}-\d{2}-\d{2})/);
377
+ if (!dateMatch) return false;
378
+ const d = dateMatch[1];
379
+ if (options?.from && d < options.from) return false;
380
+ if (options?.to && d > options.to) return false;
381
+ return true;
382
+ });
383
+ const enriched = [];
384
+ for (const file of filtered) {
385
+ const content = readFileSync(join(sessionsDir, file), "utf-8");
386
+ const sessionId = file.replace(/\.md$/, "");
387
+ const enrichment = enrichSession(content, sessionId, primitiveIds);
388
+ enriched.push(enrichment);
389
+ }
390
+ return { enriched, sessionsScanned: filtered.length };
391
+ }
392
+ function enrichSession(content, sessionId, primitiveIds) {
393
+ const tokensMatch = content.match(/[Tt]okens?[:\s]+(\d[\d,]*)/);
394
+ const tokenCount = tokensMatch ? parseInt(tokensMatch[1].replace(/,/g, ""), 10) : 0;
395
+ const stepsMatch = content.match(/[Ss]teps?[:\s]+(\d+)/);
396
+ const stepCount = stepsMatch ? parseInt(stepsMatch[1], 10) : 0;
397
+ const modelMatch = content.match(/[Mm]odel[:\s]+([^\n]+)/);
398
+ const model = modelMatch ? modelMatch[1].trim() : "unknown";
399
+ const durationMatch = content.match(/[Dd]uration[:\s]+([^\n]+)/);
400
+ const duration = durationMatch ? durationMatch[1].trim() : "";
401
+ const toolsUsed = [];
402
+ const toolMatches = content.matchAll(/### Tool(?:\s+Call)?:\s*(\S+)/g);
403
+ for (const match of toolMatches) {
404
+ const toolName = match[1];
405
+ if (!toolsUsed.includes(toolName)) {
406
+ toolsUsed.push(toolName);
407
+ }
408
+ }
409
+ const toolCallMatches = content.matchAll(/toolName[:\s]+["']?(\S+)["']?/g);
410
+ for (const match of toolCallMatches) {
411
+ const toolName = match[1];
412
+ if (!toolsUsed.includes(toolName)) {
413
+ toolsUsed.push(toolName);
414
+ }
415
+ }
416
+ const primitivesReferenced = [];
417
+ for (const id of primitiveIds) {
418
+ if (id.length < 3) continue;
419
+ if (content.includes(id)) {
420
+ primitivesReferenced.push(id);
421
+ }
422
+ }
423
+ const topics = extractSessionTopics(content);
424
+ return {
425
+ sessionId,
426
+ topics,
427
+ tokenCount,
428
+ stepCount,
429
+ model,
430
+ toolsUsed,
431
+ primitivesReferenced,
432
+ duration
433
+ };
434
+ }
435
+ function extractSessionTopics(content) {
436
+ const promptMatch = content.match(/## Prompt\n([\s\S]*?)(?=\n## |$)/);
437
+ const promptText = promptMatch ? promptMatch[1] : "";
438
+ const summaryMatch = content.match(/## Summary\n([\s\S]*?)(?=\n## |$)/);
439
+ const summaryText = summaryMatch ? summaryMatch[1] : "";
440
+ const text = (promptText + " " + summaryText).toLowerCase();
441
+ const stopWords = /* @__PURE__ */ new Set([
442
+ "the",
443
+ "a",
444
+ "an",
445
+ "is",
446
+ "are",
447
+ "was",
448
+ "were",
449
+ "be",
450
+ "been",
451
+ "being",
452
+ "have",
453
+ "has",
454
+ "had",
455
+ "do",
456
+ "does",
457
+ "did",
458
+ "will",
459
+ "would",
460
+ "could",
461
+ "should",
462
+ "may",
463
+ "might",
464
+ "shall",
465
+ "can",
466
+ "need",
467
+ "must",
468
+ "to",
469
+ "of",
470
+ "in",
471
+ "for",
472
+ "on",
473
+ "with",
474
+ "at",
475
+ "by",
476
+ "from",
477
+ "as",
478
+ "into",
479
+ "about",
480
+ "like",
481
+ "through",
482
+ "after",
483
+ "before",
484
+ "between",
485
+ "under",
486
+ "during",
487
+ "and",
488
+ "or",
489
+ "but",
490
+ "not",
491
+ "no",
492
+ "nor",
493
+ "so",
494
+ "yet",
495
+ "both",
496
+ "either",
497
+ "neither",
498
+ "each",
499
+ "every",
500
+ "all",
501
+ "any",
502
+ "few",
503
+ "more",
504
+ "most",
505
+ "other",
506
+ "some",
507
+ "such",
508
+ "than",
509
+ "too",
510
+ "very",
511
+ "just",
512
+ "also",
513
+ "this",
514
+ "that",
515
+ "these",
516
+ "those",
517
+ "it",
518
+ "its",
519
+ "i",
520
+ "me",
521
+ "my",
522
+ "we",
523
+ "our",
524
+ "you",
525
+ "your",
526
+ "he",
527
+ "she",
528
+ "they",
529
+ "them",
530
+ "their",
531
+ "what",
532
+ "which",
533
+ "who",
534
+ "when",
535
+ "where",
536
+ "how",
537
+ "why",
538
+ "if",
539
+ "then",
540
+ "else",
541
+ "while",
542
+ "up",
543
+ "out",
544
+ "off",
545
+ "over",
546
+ "only",
547
+ "own",
548
+ "same",
549
+ "get",
550
+ "got",
551
+ "make",
552
+ "made",
553
+ "use",
554
+ "used",
555
+ "using",
556
+ "one",
557
+ "two",
558
+ "new"
559
+ ]);
560
+ const words = text.replace(/[^a-z0-9\s-]/g, "").split(/\s+/).filter((w) => w.length > 3 && !stopWords.has(w));
561
+ const freq = /* @__PURE__ */ new Map();
562
+ for (const word of words) {
563
+ freq.set(word, (freq.get(word) ?? 0) + 1);
564
+ }
565
+ return Array.from(freq.entries()).filter(([, count]) => count >= 1).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([word]) => word);
566
+ }
567
+ function suggestCapabilities(harnessDir, config, options) {
568
+ const minFrequency = options?.minFrequency ?? 3;
569
+ const { enriched, sessionsScanned } = enrichSessions(harnessDir, config);
570
+ const topicOccurrences = /* @__PURE__ */ new Map();
571
+ for (const session of enriched) {
572
+ const dateMatch = session.sessionId.match(/^(\d{4}-\d{2}-\d{2})/);
573
+ const date = dateMatch ? dateMatch[1] : session.sessionId;
574
+ for (const topic of session.topics) {
575
+ if (!topicOccurrences.has(topic)) {
576
+ topicOccurrences.set(topic, /* @__PURE__ */ new Set());
577
+ }
578
+ topicOccurrences.get(topic).add(date);
579
+ }
580
+ }
581
+ const coveredTopics = /* @__PURE__ */ new Set();
582
+ const skillsDir = join(harnessDir, "skills");
583
+ const playbooksDir = join(harnessDir, "playbooks");
584
+ for (const dir of [skillsDir, playbooksDir]) {
585
+ if (!existsSync(dir)) continue;
586
+ const docs = loadDirectory(dir);
587
+ for (const doc of docs) {
588
+ for (const part of doc.frontmatter.id.split("-")) {
589
+ if (part.length > 2) coveredTopics.add(part.toLowerCase());
590
+ }
591
+ for (const tag of doc.frontmatter.tags) {
592
+ coveredTopics.add(tag.toLowerCase());
593
+ }
594
+ }
595
+ }
596
+ const suggestions = [];
597
+ for (const [topic, dates] of topicOccurrences) {
598
+ if (dates.size < minFrequency) continue;
599
+ if (coveredTopics.has(topic)) continue;
600
+ const suggestedType = dates.size >= 5 ? "playbook" : "skill";
601
+ suggestions.push({
602
+ topic,
603
+ frequency: dates.size,
604
+ sessionDates: [...dates].sort(),
605
+ suggestion: `Create a ${suggestedType} for "${topic}" \u2014 appeared in ${dates.size} session(s)`,
606
+ suggestedType
607
+ });
608
+ }
609
+ suggestions.sort((a, b) => b.frequency - a.frequency);
610
+ return {
611
+ suggestions,
612
+ topicsAnalyzed: topicOccurrences.size,
613
+ sessionsScanned
614
+ };
615
+ }
616
+ var FAILURE_TAXONOMY = {
617
+ modes: {
618
+ context_overflow: {
619
+ description: "System prompt + conversation exceeds model context window",
620
+ severity: "high",
621
+ recoveryStrategies: [
622
+ "Trim oldest messages from conversation history",
623
+ "Reduce primitive loading level (L2 \u2192 L1 \u2192 L0)",
624
+ "Archive old sessions to free memory budget",
625
+ "Split into sub-conversations with summarized context"
626
+ ],
627
+ autoRecoverable: true
628
+ },
629
+ tool_execution_error: {
630
+ description: "An MCP or HTTP tool call failed during execution",
631
+ severity: "medium",
632
+ recoveryStrategies: [
633
+ "Retry with exponential backoff",
634
+ "Fall back to alternative tool if available",
635
+ "Report error to LLM and ask for alternative approach",
636
+ "Skip tool and proceed with available context"
637
+ ],
638
+ autoRecoverable: true
639
+ },
640
+ budget_exhausted: {
641
+ description: "Daily or monthly spending limit has been reached",
642
+ severity: "critical",
643
+ recoveryStrategies: [
644
+ "Wait until next budget period",
645
+ "Switch to cheaper model (fast_model or summary_model)",
646
+ "Queue non-urgent tasks for later execution",
647
+ "Alert operator to increase budget"
648
+ ],
649
+ autoRecoverable: false
650
+ },
651
+ rate_limited: {
652
+ description: "LLM API rate limit hit (per-minute/hour/day)",
653
+ severity: "medium",
654
+ recoveryStrategies: [
655
+ "Wait for retryAfterMs from rate limiter",
656
+ "Reduce request frequency",
657
+ "Queue and batch requests"
658
+ ],
659
+ autoRecoverable: true
660
+ },
661
+ llm_timeout: {
662
+ description: "LLM API call timed out without response",
663
+ severity: "medium",
664
+ recoveryStrategies: [
665
+ "Retry with same prompt",
666
+ "Retry with shorter prompt (reduce context)",
667
+ "Switch to faster model",
668
+ "Increase timeout_ms in config"
669
+ ],
670
+ autoRecoverable: true
671
+ },
672
+ llm_error: {
673
+ description: "LLM API returned an error response (4xx/5xx)",
674
+ severity: "high",
675
+ recoveryStrategies: [
676
+ "Retry with exponential backoff (max_retries in config)",
677
+ "Switch to fallback model",
678
+ "Check API key validity",
679
+ "Log error details for debugging"
680
+ ],
681
+ autoRecoverable: true
682
+ },
683
+ hallucination_detected: {
684
+ description: "LLM output contains fabricated facts or references to non-existent primitives",
685
+ severity: "medium",
686
+ recoveryStrategies: [
687
+ 'Re-prompt with explicit grounding: "Only reference primitives that exist"',
688
+ "Validate output against known primitive IDs",
689
+ "Add validation step before acting on LLM output",
690
+ "Record in journal for future training"
691
+ ],
692
+ autoRecoverable: false
693
+ },
694
+ stale_primitive: {
695
+ description: "A referenced primitive is outdated, deprecated, or orphaned",
696
+ severity: "low",
697
+ recoveryStrategies: [
698
+ "Run detectDeadPrimitives() to identify stale files",
699
+ "Archive deprecated primitives",
700
+ "Update references to point to current versions",
701
+ "Auto-flag via validator"
702
+ ],
703
+ autoRecoverable: true
704
+ },
705
+ circular_delegation: {
706
+ description: "Agent delegation loop detected (A delegates to B delegates to A)",
707
+ severity: "high",
708
+ recoveryStrategies: [
709
+ "Track delegation chain and break on cycle detection",
710
+ "Set max delegation depth (default: 3)",
711
+ "Return partial result from last agent in chain",
712
+ "Log delegation graph for debugging"
713
+ ],
714
+ autoRecoverable: true
715
+ },
716
+ missing_dependency: {
717
+ description: "A required dependency (primitive, MCP server, API key) is missing",
718
+ severity: "high",
719
+ recoveryStrategies: [
720
+ "Run doctorHarness() to auto-fix missing files",
721
+ "Check .env for required API keys",
722
+ "Install missing MCP servers",
723
+ "Prompt user to install missing bundle"
724
+ ],
725
+ autoRecoverable: false
726
+ },
727
+ parse_error: {
728
+ description: "A primitive file has invalid YAML frontmatter or malformed content",
729
+ severity: "medium",
730
+ recoveryStrategies: [
731
+ "Run fixCapability() to auto-repair frontmatter",
732
+ "Skip the malformed file and log a warning",
733
+ "Use default frontmatter values",
734
+ "Report to user for manual fix"
735
+ ],
736
+ autoRecoverable: true
737
+ },
738
+ config_invalid: {
739
+ description: "config.yaml fails schema validation",
740
+ severity: "critical",
741
+ recoveryStrategies: [
742
+ "Fall back to CONFIG_DEFAULTS",
743
+ "Report specific validation errors to user",
744
+ "Run harness doctor to attempt repair"
745
+ ],
746
+ autoRecoverable: false
747
+ },
748
+ mcp_connection_failed: {
749
+ description: "Failed to connect to an MCP server (process spawn or HTTP)",
750
+ severity: "medium",
751
+ recoveryStrategies: [
752
+ "Retry connection with backoff",
753
+ "Disable the server and continue without its tools",
754
+ "Check command/URL/env configuration",
755
+ "Fall back to built-in tools only"
756
+ ],
757
+ autoRecoverable: true
758
+ },
759
+ state_corruption: {
760
+ description: "state.md is unreadable or contains invalid data",
761
+ severity: "high",
762
+ recoveryStrategies: [
763
+ "Fall back to DEFAULT_STATE",
764
+ "Rebuild state from session history",
765
+ "Reset state.md and log the event"
766
+ ],
767
+ autoRecoverable: true
768
+ },
769
+ unknown: {
770
+ description: "An unclassified error occurred",
771
+ severity: "high",
772
+ recoveryStrategies: [
773
+ "Log full error with stack trace",
774
+ "Record in health.json failure counter",
775
+ "Alert operator",
776
+ "Graceful shutdown if critical path"
777
+ ],
778
+ autoRecoverable: false
779
+ }
780
+ }
781
+ };
782
+ function classifyFailure(error, context) {
783
+ const msg = typeof error === "string" ? error.toLowerCase() : error.message.toLowerCase();
784
+ if (msg.includes("context") && (msg.includes("overflow") || msg.includes("too long") || msg.includes("exceed"))) {
785
+ return "context_overflow";
786
+ }
787
+ if (msg.includes("tool") && (msg.includes("fail") || msg.includes("error") || msg.includes("timeout"))) {
788
+ return "tool_execution_error";
789
+ }
790
+ if (msg.includes("budget") || msg.includes("spending") || msg.includes("limit exceeded")) {
791
+ return "budget_exhausted";
792
+ }
793
+ if (msg.includes("rate limit") || msg.includes("429") || msg.includes("too many requests")) {
794
+ return "rate_limited";
795
+ }
796
+ if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("ETIMEDOUT")) {
797
+ return "llm_timeout";
798
+ }
799
+ if (msg.includes("mcp") && (msg.includes("connect") || msg.includes("spawn") || msg.includes("failed"))) {
800
+ return "mcp_connection_failed";
801
+ }
802
+ if (msg.includes("parse") || msg.includes("yaml") || msg.includes("frontmatter") || msg.includes("malformed")) {
803
+ return "parse_error";
804
+ }
805
+ if (msg.includes("config") && (msg.includes("invalid") || msg.includes("validation"))) {
806
+ return "config_invalid";
807
+ }
808
+ if (msg.includes("state") && (msg.includes("corrupt") || msg.includes("invalid") || msg.includes("unreadable"))) {
809
+ return "state_corruption";
810
+ }
811
+ if (msg.includes("circular") || msg.includes("delegation loop") || msg.includes("cycle")) {
812
+ return "circular_delegation";
813
+ }
814
+ if (msg.includes("missing") || msg.includes("not found") || msg.includes("dependency")) {
815
+ return "missing_dependency";
816
+ }
817
+ if (msg.includes("401") || msg.includes("403") || msg.includes("500") || msg.includes("502") || msg.includes("503")) {
818
+ return "llm_error";
819
+ }
820
+ return "unknown";
821
+ }
822
+ function getRecoveryStrategies(mode) {
823
+ return FAILURE_TAXONOMY.modes[mode]?.recoveryStrategies ?? ["Log error and alert operator"];
824
+ }
825
+ function analyzeFailures(harnessDir, options) {
826
+ const days = options?.days ?? 7;
827
+ const now = Date.now();
828
+ const cutoffMs = days * 24 * 60 * 60 * 1e3;
829
+ const recentFailures = [];
830
+ const healthPath = join(harnessDir, "memory", "health.json");
831
+ if (existsSync(healthPath)) {
832
+ try {
833
+ const health = JSON.parse(readFileSync(healthPath, "utf-8"));
834
+ if (health.lastError) {
835
+ const mode = classifyFailure(health.lastError);
836
+ recentFailures.push({
837
+ mode,
838
+ timestamp: health.lastFailure || (/* @__PURE__ */ new Date()).toISOString(),
839
+ message: health.lastError,
840
+ recovered: health.consecutiveFailures === 0
841
+ });
842
+ }
843
+ } catch {
844
+ }
845
+ }
846
+ const sessionsDir = join(harnessDir, "memory", "sessions");
847
+ if (existsSync(sessionsDir)) {
848
+ const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).sort().reverse();
849
+ for (const file of files) {
850
+ const dateMatch = file.match(/^(\d{4}-\d{2}-\d{2})/);
851
+ if (dateMatch) {
852
+ const fileDate = new Date(dateMatch[1]).getTime();
853
+ if (now - fileDate > cutoffMs) break;
854
+ }
855
+ try {
856
+ const content = readFileSync(join(sessionsDir, file), "utf-8");
857
+ const errorLines = content.split("\n").filter(
858
+ (l) => l.toLowerCase().includes("error") || l.toLowerCase().includes("failed") || l.toLowerCase().includes("timeout")
859
+ );
860
+ for (const line of errorLines.slice(0, 3)) {
861
+ const mode = classifyFailure(line);
862
+ if (mode !== "unknown") {
863
+ recentFailures.push({
864
+ mode,
865
+ timestamp: dateMatch?.[1] ?? "unknown",
866
+ sessionId: file.replace(".md", ""),
867
+ message: line.trim().slice(0, 200),
868
+ recovered: true
869
+ });
870
+ }
871
+ }
872
+ } catch {
873
+ }
874
+ }
875
+ }
876
+ const modeFrequency = {};
877
+ for (const f of recentFailures) {
878
+ modeFrequency[f.mode] = (modeFrequency[f.mode] ?? 0) + 1;
879
+ }
880
+ let mostCommonMode = null;
881
+ let maxFreq = 0;
882
+ for (const [mode, count] of Object.entries(modeFrequency)) {
883
+ if (count > maxFreq) {
884
+ maxFreq = count;
885
+ mostCommonMode = mode;
886
+ }
887
+ }
888
+ const suggestedRecovery = mostCommonMode ? getRecoveryStrategies(mostCommonMode) : [];
889
+ let healthImplication = "healthy";
890
+ if (recentFailures.length > 5) {
891
+ healthImplication = "unhealthy";
892
+ } else if (recentFailures.length > 0) {
893
+ healthImplication = "degraded";
894
+ }
895
+ return {
896
+ recentFailures: recentFailures.slice(0, 20),
897
+ modeFrequency,
898
+ mostCommonMode,
899
+ suggestedRecovery,
900
+ healthImplication
901
+ };
902
+ }
903
+ var BUILTIN_GATES = [
904
+ {
905
+ name: "pre-boot",
906
+ description: "Checks before agent boot: config valid, CORE.md exists, API key available",
907
+ check: (harnessDir) => {
908
+ const checks = [];
909
+ checks.push(existsSync(join(harnessDir, "CORE.md")) ? { name: "core-md", description: "CORE.md exists", status: "pass", message: "CORE.md present" } : { name: "core-md", description: "CORE.md exists", status: "fail", message: "Missing CORE.md \u2014 required for agent identity" });
910
+ try {
911
+ loadConfig(harnessDir);
912
+ checks.push({ name: "config-valid", description: "config.yaml valid", status: "pass", message: "Config parsed successfully" });
913
+ } catch (err) {
914
+ checks.push({ name: "config-valid", description: "config.yaml valid", status: "fail", message: `Config error: ${err instanceof Error ? err.message : String(err)}` });
915
+ }
916
+ const hasKey = !!(process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY);
917
+ checks.push(hasKey ? { name: "api-key", description: "API key available", status: "pass", message: "API key found in environment" } : { name: "api-key", description: "API key available", status: "warn", message: "No API key in environment \u2014 will need --api-key flag" });
918
+ const memDir = join(harnessDir, "memory");
919
+ checks.push(existsSync(memDir) ? { name: "memory-dir", description: "Memory directory exists", status: "pass", message: "memory/ directory present" } : { name: "memory-dir", description: "Memory directory exists", status: "warn", message: "memory/ directory missing \u2014 will be created on first run" });
920
+ return checks;
921
+ }
922
+ },
923
+ {
924
+ name: "pre-run",
925
+ description: "Checks before each LLM call: budget, rate limits, context budget",
926
+ check: (harnessDir) => {
927
+ const checks = [];
928
+ let config;
929
+ try {
930
+ config = loadConfig(harnessDir);
931
+ } catch {
932
+ checks.push({ name: "config-load", description: "Config loadable", status: "fail", message: "Cannot load config" });
933
+ return checks;
934
+ }
935
+ try {
936
+ const budgetStatus = checkBudget(harnessDir, config.budget);
937
+ const exceeded = budgetStatus.daily_remaining_usd !== null && budgetStatus.daily_remaining_usd <= 0 || budgetStatus.monthly_remaining_usd !== null && budgetStatus.monthly_remaining_usd <= 0;
938
+ if (exceeded) {
939
+ checks.push({ name: "budget", description: "Budget not exceeded", status: "fail", message: "Budget limit exceeded", details: { ...budgetStatus } });
940
+ } else {
941
+ checks.push({ name: "budget", description: "Budget not exceeded", status: "pass", message: "Within budget" });
942
+ }
943
+ } catch (err) {
944
+ checks.push({ name: "budget", description: "Budget not exceeded", status: "skip", message: `Budget check unavailable: ${err instanceof Error ? err.message : String(err)}` });
945
+ }
946
+ try {
947
+ const limits = buildRateLimits(config);
948
+ if (limits.length === 0) {
949
+ checks.push({ name: "rate-limit", description: "Rate limit not hit", status: "pass", message: "No rate limits configured" });
950
+ } else {
951
+ let blocked = false;
952
+ for (const limit of limits) {
953
+ const rateCheck = checkRateLimit(harnessDir, limit);
954
+ if (!rateCheck.allowed) {
955
+ const windowLabel = limit.window_ms <= 6e4 ? "minute" : limit.window_ms <= 36e5 ? "hour" : "day";
956
+ checks.push({ name: "rate-limit", description: "Rate limit not hit", status: "fail", message: `Rate limited (${windowLabel}): ${rateCheck.current}/${rateCheck.max}. Retry after ${Math.ceil(rateCheck.retry_after_ms / 1e3)}s` });
957
+ blocked = true;
958
+ break;
959
+ }
960
+ }
961
+ if (!blocked) {
962
+ checks.push({ name: "rate-limit", description: "Rate limit not hit", status: "pass", message: "Within rate limits" });
963
+ }
964
+ }
965
+ } catch (err) {
966
+ checks.push({ name: "rate-limit", description: "Rate limit not hit", status: "skip", message: `Rate limit check unavailable: ${err instanceof Error ? err.message : String(err)}` });
967
+ }
968
+ const healthPath = join(harnessDir, "memory", "health.json");
969
+ if (existsSync(healthPath)) {
970
+ try {
971
+ const health = JSON.parse(readFileSync(healthPath, "utf-8"));
972
+ if (health.consecutiveFailures >= 3) {
973
+ checks.push({ name: "health", description: "Agent healthy", status: "warn", message: `${health.consecutiveFailures} consecutive failures detected` });
974
+ } else {
975
+ checks.push({ name: "health", description: "Agent healthy", status: "pass", message: "No recent failure pattern" });
976
+ }
977
+ } catch {
978
+ checks.push({ name: "health", description: "Agent healthy", status: "skip", message: "Health data unavailable" });
979
+ }
980
+ }
981
+ return checks;
982
+ }
983
+ },
984
+ {
985
+ name: "post-session",
986
+ description: "Checks after a session: session recorded, no parse errors, primitives intact",
987
+ check: (harnessDir) => {
988
+ const checks = [];
989
+ const sessionsDir = join(harnessDir, "memory", "sessions");
990
+ if (existsSync(sessionsDir)) {
991
+ const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".md") && !f.startsWith("."));
992
+ checks.push({
993
+ name: "sessions-recorded",
994
+ description: "Sessions being recorded",
995
+ status: files.length > 0 ? "pass" : "warn",
996
+ message: `${files.length} session file(s) in memory`
997
+ });
998
+ } else {
999
+ checks.push({ name: "sessions-recorded", description: "Sessions being recorded", status: "warn", message: "No sessions directory" });
1000
+ }
1001
+ const dirs = getPrimitiveDirs();
1002
+ let totalParseErrors = 0;
1003
+ for (const dir of dirs) {
1004
+ const fullPath = join(harnessDir, dir);
1005
+ if (!existsSync(fullPath)) continue;
1006
+ const { errors } = loadDirectoryWithErrors(fullPath);
1007
+ totalParseErrors += errors.length;
1008
+ }
1009
+ checks.push(totalParseErrors === 0 ? { name: "parse-errors", description: "No primitive parse errors", status: "pass", message: "All primitives parse cleanly" } : { name: "parse-errors", description: "No primitive parse errors", status: "warn", message: `${totalParseErrors} parse error(s) in primitives` });
1010
+ return checks;
1011
+ }
1012
+ },
1013
+ {
1014
+ name: "pre-deploy",
1015
+ description: "Checks before deployment: validator passes, no dead primitives, no contradictions",
1016
+ check: (harnessDir, config) => {
1017
+ const checks = [];
1018
+ try {
1019
+ const validation = validateHarness(harnessDir);
1020
+ if (validation.errors.length > 0) {
1021
+ checks.push({ name: "validator", description: "Validator passes", status: "fail", message: `${validation.errors.length} error(s)`, details: { errors: validation.errors } });
1022
+ } else if (validation.warnings.length > 0) {
1023
+ checks.push({ name: "validator", description: "Validator passes", status: "warn", message: `${validation.warnings.length} warning(s)` });
1024
+ } else {
1025
+ checks.push({ name: "validator", description: "Validator passes", status: "pass", message: "Validation clean" });
1026
+ }
1027
+ } catch (err) {
1028
+ checks.push({ name: "validator", description: "Validator passes", status: "fail", message: `Validator error: ${err instanceof Error ? err.message : String(err)}` });
1029
+ }
1030
+ const deadResult = detectDeadPrimitives(harnessDir, config);
1031
+ checks.push(deadResult.dead.length === 0 ? { name: "dead-primitives", description: "No dead primitives", status: "pass", message: "All primitives referenced or recently modified" } : { name: "dead-primitives", description: "No dead primitives", status: "warn", message: `${deadResult.dead.length} dead primitive(s) found`, details: { dead: deadResult.dead.map((d) => d.id) } });
1032
+ const contradictionResult = detectContradictions(harnessDir);
1033
+ checks.push(contradictionResult.contradictions.length === 0 ? { name: "contradictions", description: "No contradictions", status: "pass", message: "No conflicting rules/instincts" } : { name: "contradictions", description: "No contradictions", status: "warn", message: `${contradictionResult.contradictions.length} potential contradiction(s)` });
1034
+ return checks;
1035
+ }
1036
+ }
1037
+ ];
1038
+ function runGate(gateName, harnessDir, config) {
1039
+ const gate = BUILTIN_GATES.find((g) => g.name === gateName);
1040
+ if (!gate) {
1041
+ return {
1042
+ gateName,
1043
+ passed: false,
1044
+ checks: [{ name: "gate-not-found", description: "Gate exists", status: "fail", message: `Unknown gate: ${gateName}` }],
1045
+ summary: `Gate "${gateName}" not found. Available: ${BUILTIN_GATES.map((g) => g.name).join(", ")}`
1046
+ };
1047
+ }
1048
+ const checks = gate.check(harnessDir, config);
1049
+ const hasFails = checks.some((c) => c.status === "fail");
1050
+ const hasWarns = checks.some((c) => c.status === "warn");
1051
+ const passed = !hasFails;
1052
+ const passCount = checks.filter((c) => c.status === "pass").length;
1053
+ const failCount = checks.filter((c) => c.status === "fail").length;
1054
+ const warnCount = checks.filter((c) => c.status === "warn").length;
1055
+ let summary = `${gate.name}: ${passCount} passed`;
1056
+ if (failCount > 0) summary += `, ${failCount} failed`;
1057
+ if (warnCount > 0) summary += `, ${warnCount} warnings`;
1058
+ return { gateName, passed, checks, summary };
1059
+ }
1060
+ function runAllGates(harnessDir, config) {
1061
+ return BUILTIN_GATES.map((gate) => runGate(gate.name, harnessDir, config));
1062
+ }
1063
+ function listGates() {
1064
+ return BUILTIN_GATES.map((g) => ({ name: g.name, description: g.description }));
1065
+ }
1066
+ export {
1067
+ BUILTIN_GATES,
1068
+ FAILURE_TAXONOMY,
1069
+ analyzeFailures,
1070
+ autoPromoteInstincts,
1071
+ classifyFailure,
1072
+ detectContradictions,
1073
+ detectDeadPrimitives,
1074
+ enrichSessions,
1075
+ getRecoveryStrategies,
1076
+ listGates,
1077
+ runAllGates,
1078
+ runGate,
1079
+ suggestCapabilities
1080
+ };
1081
+ //# sourceMappingURL=intelligence-HJOCA4SJ.js.map