deepclause-sdk 0.0.88 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +418 -914
  3. package/dist/agent.d.ts +19 -2
  4. package/dist/agent.d.ts.map +1 -1
  5. package/dist/agent.js +221 -4
  6. package/dist/agent.js.map +1 -1
  7. package/dist/cli/config.d.ts +323 -176
  8. package/dist/cli/config.d.ts.map +1 -1
  9. package/dist/cli/config.js +146 -188
  10. package/dist/cli/config.js.map +1 -1
  11. package/dist/cli/index.d.ts +3 -2
  12. package/dist/cli/index.d.ts.map +1 -1
  13. package/dist/cli/index.js +61 -425
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/login.d.ts +29 -0
  16. package/dist/cli/login.d.ts.map +1 -0
  17. package/dist/cli/login.js +184 -0
  18. package/dist/cli/login.js.map +1 -0
  19. package/dist/cli/readline.d.ts +6 -0
  20. package/dist/cli/readline.d.ts.map +1 -0
  21. package/dist/cli/readline.js +15 -0
  22. package/dist/cli/readline.js.map +1 -0
  23. package/dist/cli/repl-bin.d.ts +9 -0
  24. package/dist/cli/repl-bin.d.ts.map +1 -0
  25. package/dist/cli/repl-bin.js +16 -0
  26. package/dist/cli/repl-bin.js.map +1 -0
  27. package/dist/cli/repl.d.ts +191 -0
  28. package/dist/cli/repl.d.ts.map +1 -0
  29. package/dist/cli/repl.js +1232 -0
  30. package/dist/cli/repl.js.map +1 -0
  31. package/dist/cli/run.d.ts +17 -18
  32. package/dist/cli/run.d.ts.map +1 -1
  33. package/dist/cli/run.js +196 -183
  34. package/dist/cli/run.js.map +1 -1
  35. package/dist/cli/set-backend.d.ts +53 -0
  36. package/dist/cli/set-backend.d.ts.map +1 -0
  37. package/dist/cli/set-backend.js +259 -0
  38. package/dist/cli/set-backend.js.map +1 -0
  39. package/dist/cli/visualize.d.ts +38 -0
  40. package/dist/cli/visualize.d.ts.map +1 -0
  41. package/dist/cli/visualize.js +125 -0
  42. package/dist/cli/visualize.js.map +1 -0
  43. package/dist/compiler.d.ts +5 -52
  44. package/dist/compiler.d.ts.map +1 -1
  45. package/dist/compiler.js +4 -768
  46. package/dist/compiler.js.map +1 -1
  47. package/dist/index.d.ts +29 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +20 -2
  50. package/dist/index.js.map +1 -1
  51. package/dist/judge/index.d.ts +9 -0
  52. package/dist/judge/index.d.ts.map +1 -0
  53. package/dist/judge/index.js +6 -0
  54. package/dist/judge/index.js.map +1 -0
  55. package/dist/judge/jev.d.ts +21 -0
  56. package/dist/judge/jev.d.ts.map +1 -0
  57. package/dist/judge/jev.js +218 -0
  58. package/dist/judge/jev.js.map +1 -0
  59. package/dist/judge/llm.d.ts +23 -0
  60. package/dist/judge/llm.d.ts.map +1 -0
  61. package/dist/judge/llm.js +120 -0
  62. package/dist/judge/llm.js.map +1 -0
  63. package/dist/judge/marshal.d.ts +26 -0
  64. package/dist/judge/marshal.d.ts.map +1 -0
  65. package/dist/judge/marshal.js +266 -0
  66. package/dist/judge/marshal.js.map +1 -0
  67. package/dist/judge/mock.d.ts +28 -0
  68. package/dist/judge/mock.d.ts.map +1 -0
  69. package/dist/judge/mock.js +98 -0
  70. package/dist/judge/mock.js.map +1 -0
  71. package/dist/judge/types.d.ts +95 -0
  72. package/dist/judge/types.d.ts.map +1 -0
  73. package/dist/judge/types.js +23 -0
  74. package/dist/judge/types.js.map +1 -0
  75. package/dist/prolog/bridge.d.ts +5 -1
  76. package/dist/prolog/bridge.d.ts.map +1 -1
  77. package/dist/prolog/bridge.js +29 -1
  78. package/dist/prolog/bridge.js.map +1 -1
  79. package/dist/prolog-src/deepclause_analysis.pl +10 -2
  80. package/dist/prolog-src/deepclause_mi.pl +2522 -118
  81. package/dist/repl/agent.d.ts +72 -0
  82. package/dist/repl/agent.d.ts.map +1 -0
  83. package/dist/repl/agent.js +366 -0
  84. package/dist/repl/agent.js.map +1 -0
  85. package/dist/repl/auth.d.ts +45 -0
  86. package/dist/repl/auth.d.ts.map +1 -0
  87. package/dist/repl/auth.js +116 -0
  88. package/dist/repl/auth.js.map +1 -0
  89. package/dist/repl/backend.d.ts +290 -0
  90. package/dist/repl/backend.d.ts.map +1 -0
  91. package/dist/repl/backend.js +370 -0
  92. package/dist/repl/backend.js.map +1 -0
  93. package/dist/repl/compaction.d.ts +122 -0
  94. package/dist/repl/compaction.d.ts.map +1 -0
  95. package/dist/repl/compaction.js +318 -0
  96. package/dist/repl/compaction.js.map +1 -0
  97. package/dist/repl/export.d.ts +30 -0
  98. package/dist/repl/export.d.ts.map +1 -0
  99. package/dist/repl/export.js +23 -0
  100. package/dist/repl/export.js.map +1 -0
  101. package/dist/repl/frames.d.ts +21 -0
  102. package/dist/repl/frames.d.ts.map +1 -0
  103. package/dist/repl/frames.js +79 -0
  104. package/dist/repl/frames.js.map +1 -0
  105. package/dist/repl/harness-tools.d.ts +74 -0
  106. package/dist/repl/harness-tools.d.ts.map +1 -0
  107. package/dist/repl/harness-tools.js +121 -0
  108. package/dist/repl/harness-tools.js.map +1 -0
  109. package/dist/repl/highlight.d.ts +30 -0
  110. package/dist/repl/highlight.d.ts.map +1 -0
  111. package/dist/repl/highlight.js +285 -0
  112. package/dist/repl/highlight.js.map +1 -0
  113. package/dist/repl/history.d.ts +234 -0
  114. package/dist/repl/history.d.ts.map +1 -0
  115. package/dist/repl/history.js +661 -0
  116. package/dist/repl/history.js.map +1 -0
  117. package/dist/repl/index.d.ts +120 -0
  118. package/dist/repl/index.d.ts.map +1 -0
  119. package/dist/repl/index.js +107 -0
  120. package/dist/repl/index.js.map +1 -0
  121. package/dist/repl/judge.d.ts +51 -0
  122. package/dist/repl/judge.d.ts.map +1 -0
  123. package/dist/repl/judge.js +58 -0
  124. package/dist/repl/judge.js.map +1 -0
  125. package/dist/repl/markdown.d.ts +25 -0
  126. package/dist/repl/markdown.d.ts.map +1 -0
  127. package/dist/repl/markdown.js +103 -0
  128. package/dist/repl/markdown.js.map +1 -0
  129. package/dist/repl/picker.d.ts +34 -0
  130. package/dist/repl/picker.d.ts.map +1 -0
  131. package/dist/repl/picker.js +81 -0
  132. package/dist/repl/picker.js.map +1 -0
  133. package/dist/repl/project-context.d.ts +16 -0
  134. package/dist/repl/project-context.d.ts.map +1 -0
  135. package/dist/repl/project-context.js +23 -0
  136. package/dist/repl/project-context.js.map +1 -0
  137. package/dist/repl/render.d.ts +160 -0
  138. package/dist/repl/render.d.ts.map +1 -0
  139. package/dist/repl/render.js +715 -0
  140. package/dist/repl/render.js.map +1 -0
  141. package/dist/repl/session.d.ts +356 -0
  142. package/dist/repl/session.d.ts.map +1 -0
  143. package/dist/repl/session.js +1275 -0
  144. package/dist/repl/session.js.map +1 -0
  145. package/dist/repl/status.d.ts +100 -0
  146. package/dist/repl/status.d.ts.map +1 -0
  147. package/dist/repl/status.js +218 -0
  148. package/dist/repl/status.js.map +1 -0
  149. package/dist/repl/tools.d.ts +53 -0
  150. package/dist/repl/tools.d.ts.map +1 -0
  151. package/dist/repl/tools.js +307 -0
  152. package/dist/repl/tools.js.map +1 -0
  153. package/dist/repl/toolset.d.ts +32 -0
  154. package/dist/repl/toolset.d.ts.map +1 -0
  155. package/dist/repl/toolset.js +82 -0
  156. package/dist/repl/toolset.js.map +1 -0
  157. package/dist/repl/tui/editor.d.ts +17 -0
  158. package/dist/repl/tui/editor.d.ts.map +1 -0
  159. package/dist/repl/tui/editor.js +39 -0
  160. package/dist/repl/tui/editor.js.map +1 -0
  161. package/dist/repl/tui/status-bar.d.ts +26 -0
  162. package/dist/repl/tui/status-bar.d.ts.map +1 -0
  163. package/dist/repl/tui/status-bar.js +47 -0
  164. package/dist/repl/tui/status-bar.js.map +1 -0
  165. package/dist/repl/tui/theme.d.ts +30 -0
  166. package/dist/repl/tui/theme.d.ts.map +1 -0
  167. package/dist/repl/tui/theme.js +81 -0
  168. package/dist/repl/tui/theme.js.map +1 -0
  169. package/dist/repl/tui/transcript.d.ts +39 -0
  170. package/dist/repl/tui/transcript.d.ts.map +1 -0
  171. package/dist/repl/tui/transcript.js +123 -0
  172. package/dist/repl/tui/transcript.js.map +1 -0
  173. package/dist/runner.d.ts +145 -13
  174. package/dist/runner.d.ts.map +1 -1
  175. package/dist/runner.js +600 -282
  176. package/dist/runner.js.map +1 -1
  177. package/dist/sdk.d.ts.map +1 -1
  178. package/dist/sdk.js +56 -32
  179. package/dist/sdk.js.map +1 -1
  180. package/dist/system/assets/docs/AGENT_PROMPT.md +1373 -0
  181. package/dist/system/assets/docs/DML_AUTHORING.md +195 -0
  182. package/dist/system/assets/docs/DML_REFERENCE.md +393 -72
  183. package/dist/system/assets/docs/HARNESS_EXAMPLES.md +172 -0
  184. package/dist/system/assets/docs/HARNESS_PATTERNS.md +562 -0
  185. package/dist/system/assets/docs/META_PROMPT.md +68 -0
  186. package/dist/system/assets/docs/PROLOG_SNIPPETS.md +117 -0
  187. package/dist/system/assets/index.d.ts +9 -17
  188. package/dist/system/assets/index.d.ts.map +1 -1
  189. package/dist/system/assets/index.js +26 -85
  190. package/dist/system/assets/index.js.map +1 -1
  191. package/dist/system/runtime/agentvm-manager.d.ts +9 -2
  192. package/dist/system/runtime/agentvm-manager.d.ts.map +1 -1
  193. package/dist/system/runtime/agentvm-manager.js +70 -44
  194. package/dist/system/runtime/agentvm-manager.js.map +1 -1
  195. package/dist/system/runtime/media.d.ts +23 -0
  196. package/dist/system/runtime/media.d.ts.map +1 -0
  197. package/dist/system/runtime/media.js +55 -0
  198. package/dist/system/runtime/media.js.map +1 -0
  199. package/dist/system/runtime/shell-limits.d.ts +21 -0
  200. package/dist/system/runtime/shell-limits.d.ts.map +1 -0
  201. package/dist/system/runtime/shell-limits.js +39 -0
  202. package/dist/system/runtime/shell-limits.js.map +1 -0
  203. package/dist/system/runtime/shell-manager.d.ts +8 -3
  204. package/dist/system/runtime/shell-manager.d.ts.map +1 -1
  205. package/dist/system/runtime/shell-manager.js +56 -39
  206. package/dist/system/runtime/shell-manager.js.map +1 -1
  207. package/dist/system/runtime/shell-tool-events.js +5 -0
  208. package/dist/system/runtime/shell-tool-events.js.map +1 -1
  209. package/dist/system/runtime/token-usage.d.ts +2 -0
  210. package/dist/system/runtime/token-usage.d.ts.map +1 -1
  211. package/dist/system/runtime/token-usage.js +7 -0
  212. package/dist/system/runtime/token-usage.js.map +1 -1
  213. package/dist/tools.d.ts +3 -21
  214. package/dist/tools.d.ts.map +1 -1
  215. package/dist/tools.js +14 -168
  216. package/dist/tools.js.map +1 -1
  217. package/dist/types.d.ts +149 -118
  218. package/dist/types.d.ts.map +1 -1
  219. package/dist/validate.d.ts +19 -0
  220. package/dist/validate.d.ts.map +1 -0
  221. package/dist/validate.js +338 -0
  222. package/dist/validate.js.map +1 -0
  223. package/dist/visualize/index.d.ts +52 -0
  224. package/dist/visualize/index.d.ts.map +1 -0
  225. package/dist/visualize/index.js +189 -0
  226. package/dist/visualize/index.js.map +1 -0
  227. package/package.json +17 -15
  228. package/src/prolog-src/deepclause_analysis.pl +10 -2
  229. package/src/prolog-src/deepclause_mi.pl +2522 -118
  230. package/dist/cli/commands.d.ts +0 -42
  231. package/dist/cli/commands.d.ts.map +0 -1
  232. package/dist/cli/commands.js +0 -246
  233. package/dist/cli/commands.js.map +0 -1
  234. package/dist/cli/compile.d.ts +0 -99
  235. package/dist/cli/compile.d.ts.map +0 -1
  236. package/dist/cli/compile.js +0 -363
  237. package/dist/cli/compile.js.map +0 -1
  238. package/dist/cli/default-skills.d.ts +0 -10
  239. package/dist/cli/default-skills.d.ts.map +0 -1
  240. package/dist/cli/default-skills.js +0 -206
  241. package/dist/cli/default-skills.js.map +0 -1
  242. package/dist/cli/interactive.d.ts +0 -2
  243. package/dist/cli/interactive.d.ts.map +0 -1
  244. package/dist/cli/interactive.js +0 -20
  245. package/dist/cli/interactive.js.map +0 -1
  246. package/dist/cli/mcp.d.ts +0 -56
  247. package/dist/cli/mcp.d.ts.map +0 -1
  248. package/dist/cli/mcp.js +0 -138
  249. package/dist/cli/mcp.js.map +0 -1
  250. package/dist/cli/prompt.d.ts +0 -2
  251. package/dist/cli/prompt.d.ts.map +0 -1
  252. package/dist/cli/prompt.js +0 -2
  253. package/dist/cli/prompt.js.map +0 -1
  254. package/dist/cli/search.d.ts +0 -19
  255. package/dist/cli/search.d.ts.map +0 -1
  256. package/dist/cli/search.js +0 -189
  257. package/dist/cli/search.js.map +0 -1
  258. package/dist/cli/tool-args.d.ts +0 -2
  259. package/dist/cli/tool-args.d.ts.map +0 -1
  260. package/dist/cli/tool-args.js +0 -39
  261. package/dist/cli/tool-args.js.map +0 -1
  262. package/dist/cli/tools.d.ts +0 -36
  263. package/dist/cli/tools.d.ts.map +0 -1
  264. package/dist/cli/tools.js +0 -229
  265. package/dist/cli/tools.js.map +0 -1
  266. package/dist/cli/tui/index.d.ts +0 -22
  267. package/dist/cli/tui/index.d.ts.map +0 -1
  268. package/dist/cli/tui/index.js +0 -29
  269. package/dist/cli/tui/index.js.map +0 -1
  270. package/dist/cli/tui.d.ts +0 -167
  271. package/dist/cli/tui.d.ts.map +0 -1
  272. package/dist/cli/tui.js +0 -5228
  273. package/dist/cli/tui.js.map +0 -1
  274. package/dist/compiler_prompt.d.ts +0 -20
  275. package/dist/compiler_prompt.d.ts.map +0 -1
  276. package/dist/compiler_prompt.js +0 -870
  277. package/dist/compiler_prompt.js.map +0 -1
  278. package/dist/deepclause-cli.skill +0 -0
  279. package/dist/prolog-src/deepclause_mi.pl.bak +0 -570
  280. package/dist/system/assets/compactors/default-memory-compactor.dml +0 -6
  281. package/dist/system/assets/docs/CONDUCTOR_PROMPT.md +0 -105
  282. package/dist/system/assets/docs/DML_COMPILER_PROMPT.md +0 -700
  283. package/dist/system/assets/docs/TUI.md +0 -150
  284. package/dist/system/assets/recipes/deepclause-coding-workflow/SKILL.md +0 -100
  285. package/dist/system/assets/skills/conductor.dml +0 -76
  286. package/dist/system/assets/skills/deep-planner.dml +0 -412
  287. package/dist/system/assets/skills/plan.dml +0 -429
  288. package/dist/system/assets/skills/security-planner.dml +0 -337
  289. package/dist/system/assets/skills/skill-creator.dml +0 -187
  290. package/dist/system/runtime/catalog-recipes.d.ts +0 -24
  291. package/dist/system/runtime/catalog-recipes.d.ts.map +0 -1
  292. package/dist/system/runtime/catalog-recipes.js +0 -273
  293. package/dist/system/runtime/catalog-recipes.js.map +0 -1
  294. package/dist/system/runtime/catalog-skills.d.ts +0 -50
  295. package/dist/system/runtime/catalog-skills.d.ts.map +0 -1
  296. package/dist/system/runtime/catalog-skills.js +0 -152
  297. package/dist/system/runtime/catalog-skills.js.map +0 -1
  298. package/dist/system/runtime/conductor.d.ts +0 -105
  299. package/dist/system/runtime/conductor.d.ts.map +0 -1
  300. package/dist/system/runtime/conductor.js +0 -732
  301. package/dist/system/runtime/conductor.js.map +0 -1
  302. package/dist/system/runtime/console-capture.d.ts +0 -9
  303. package/dist/system/runtime/console-capture.d.ts.map +0 -1
  304. package/dist/system/runtime/console-capture.js +0 -67
  305. package/dist/system/runtime/console-capture.js.map +0 -1
  306. package/dist/system/runtime/dml-executor.d.ts +0 -52
  307. package/dist/system/runtime/dml-executor.d.ts.map +0 -1
  308. package/dist/system/runtime/dml-executor.js +0 -203
  309. package/dist/system/runtime/dml-executor.js.map +0 -1
  310. package/dist/system/runtime/runtime-tools.d.ts +0 -31
  311. package/dist/system/runtime/runtime-tools.d.ts.map +0 -1
  312. package/dist/system/runtime/runtime-tools.js +0 -312
  313. package/dist/system/runtime/runtime-tools.js.map +0 -1
  314. package/dist/system/runtime/skill-creator.d.ts +0 -38
  315. package/dist/system/runtime/skill-creator.d.ts.map +0 -1
  316. package/dist/system/runtime/skill-creator.js +0 -763
  317. package/dist/system/runtime/skill-creator.js.map +0 -1
  318. package/src/prolog-src/deepclause_mi.pl.bak +0 -570
@@ -0,0 +1,661 @@
1
+ /**
2
+ * Persistent session / trace / harness history.
3
+ *
4
+ * See `docs/DML_REPL_SESSION_HISTORY.md`. Storage lives under a
5
+ * workspace-relative directory (default `.deepclause/repl/`):
6
+ *
7
+ * history.dml append-only harness_* facts, consulted at
8
+ * session start and queryable from DML
9
+ * harness/HEAD.json current version pointer
10
+ * harness/changes.jsonl one line per harness change
11
+ * harness/versions/NNNN_<ts>.json full module snapshot per version
12
+ * sessions/<id>/session.json session metadata
13
+ * sessions/<id>/turns.jsonl one summary per turn
14
+ * sessions/<id>/events.jsonl runtime event trace
15
+ *
16
+ * The recorder is best-effort: callers swallow its errors so a turn never fails
17
+ * because history could not be written.
18
+ */
19
+ import { createHash } from 'crypto';
20
+ import * as fs from 'fs/promises';
21
+ import * as path from 'path';
22
+ const DEFAULT_DIR = '.deepclause/repl';
23
+ /** Stable hash of a harness module plus its linked scripts. */
24
+ export function harnessHash(module, scripts) {
25
+ return createHash('sha256')
26
+ .update(module)
27
+ .update('\n')
28
+ .update(JSON.stringify(scripts))
29
+ .digest('hex');
30
+ }
31
+ function nowIso() {
32
+ return new Date().toISOString();
33
+ }
34
+ /** Single-quoted Prolog atom. */
35
+ export function prologAtom(value) {
36
+ return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "''")}'`;
37
+ }
38
+ export class HistoryStore {
39
+ sessionId;
40
+ harnessName;
41
+ rootRel;
42
+ sessionDirRel;
43
+ rootAbs;
44
+ sessionDirAbs;
45
+ trace;
46
+ maxEventBytes;
47
+ maxSessions;
48
+ maxVersions;
49
+ redactions;
50
+ eventBuffer = [];
51
+ /** Current HEAD version (0 = empty harness) and the highest ever issued. */
52
+ headVersion = 0;
53
+ maxVersion = 0;
54
+ /** Hash recorded for the current HEAD (for session-snapshot consistency). */
55
+ headHash;
56
+ constructor(workspacePath, sessionId, options = {},
57
+ /** Harness this session edits (a project can hold several). */
58
+ harnessName = 'main') {
59
+ this.sessionId = sessionId;
60
+ this.harnessName = harnessName;
61
+ this.rootRel = (options.dir ?? DEFAULT_DIR).replace(/\\/g, '/').replace(/\/+$/, '');
62
+ this.rootAbs = path.resolve(workspacePath, this.rootRel);
63
+ this.sessionDirRel = `${this.rootRel}/sessions/${sessionId}`;
64
+ this.sessionDirAbs = path.resolve(workspacePath, this.sessionDirRel);
65
+ this.trace = options.trace ?? 'summary';
66
+ this.maxEventBytes = options.maxEventBytes ?? 8192;
67
+ this.maxSessions = options.maxSessions ?? 50;
68
+ this.maxVersions = options.maxVersions ?? 200;
69
+ this.redactions = (options.redact ?? []).map((source) => new RegExp(source, 'g'));
70
+ }
71
+ get currentVersion() {
72
+ return this.headVersion;
73
+ }
74
+ get currentHash() {
75
+ return this.headHash;
76
+ }
77
+ get tracePath() {
78
+ return `${this.sessionDirRel}/events.jsonl`;
79
+ }
80
+ get historyFile() {
81
+ return path.join(this.rootAbs, 'history.dml');
82
+ }
83
+ /** Per-harness store: `.deepclause/repl/harnesses/<name>/`. */
84
+ get harnessDir() {
85
+ return path.join(this.rootAbs, 'harnesses', this.harnessName);
86
+ }
87
+ /** The single pre-harnesses store, migrated to `harnesses/main` once. */
88
+ get legacyHarnessDir() {
89
+ return path.join(this.rootAbs, 'harness');
90
+ }
91
+ /** The current content (source of truth; portable as a `.dml`). */
92
+ get harnessFile() {
93
+ return path.join(this.harnessDir, 'harness.dml');
94
+ }
95
+ /** The module the harness started from (version 0 / rollback floor). */
96
+ get baselineFile() {
97
+ return path.join(this.harnessDir, 'baseline.dml');
98
+ }
99
+ get headFile() {
100
+ return path.join(this.harnessDir, 'HEAD.json');
101
+ }
102
+ get changesFile() {
103
+ return path.join(this.harnessDir, 'changes.jsonl');
104
+ }
105
+ /** Whether the harness has any committed versions (HEAD > baseline). */
106
+ get hasCommits() {
107
+ return this.headVersion > 0;
108
+ }
109
+ /** Facts for this harness only (`harness_change`/`changed`/`head`/`rollback`). */
110
+ get harnessFactsFile() {
111
+ return path.join(this.harnessDir, 'history.dml');
112
+ }
113
+ /** Create directories, read the current version, and prune old entries. */
114
+ async init() {
115
+ await fs.mkdir(this.sessionDirAbs, { recursive: true });
116
+ await this.migrateLegacyHarness();
117
+ await fs.mkdir(path.join(this.harnessDir, 'versions'), { recursive: true });
118
+ try {
119
+ const head = JSON.parse(await fs.readFile(this.headFile, 'utf8'));
120
+ if (typeof head.version === 'number')
121
+ this.headVersion = head.version;
122
+ if (typeof head.hash === 'string')
123
+ this.headHash = head.hash;
124
+ this.maxVersion = typeof head.maxVersion === 'number' ? head.maxVersion : this.headVersion;
125
+ }
126
+ catch {
127
+ // no HEAD yet
128
+ }
129
+ // A harness always has a baseline (empty for a fresh one) and a current file.
130
+ await this.ensureHarnessFiles();
131
+ await this.prune();
132
+ }
133
+ /** Move the legacy single `harness/` store into `harnesses/main/` (once). */
134
+ async migrateLegacyHarness() {
135
+ if (this.harnessName !== 'main')
136
+ return;
137
+ try {
138
+ await fs.access(path.join(this.legacyHarnessDir, 'HEAD.json'));
139
+ }
140
+ catch {
141
+ return; // nothing to migrate
142
+ }
143
+ try {
144
+ await fs.access(this.harnessDir);
145
+ return; // the per-harness dir already exists
146
+ }
147
+ catch {
148
+ // proceed
149
+ }
150
+ await fs.mkdir(path.dirname(this.harnessDir), { recursive: true });
151
+ await fs.rename(this.legacyHarnessDir, this.harnessDir);
152
+ }
153
+ /** Ensure `baseline.dml` and `harness.dml` exist (materializing from HEAD). */
154
+ async ensureHarnessFiles() {
155
+ let baseline = '';
156
+ try {
157
+ baseline = await fs.readFile(this.baselineFile, 'utf8');
158
+ }
159
+ catch {
160
+ await fs.writeFile(this.baselineFile, '', 'utf8');
161
+ }
162
+ try {
163
+ const current = await fs.readFile(this.harnessFile, 'utf8');
164
+ if (current.trim() || this.headVersion <= 0)
165
+ return;
166
+ }
167
+ catch {
168
+ // write below
169
+ }
170
+ const head = this.headVersion > 0 ? await this.readVersion(this.headVersion) : null;
171
+ await fs.writeFile(this.harnessFile, head?.module ?? baseline, 'utf8');
172
+ }
173
+ /** The module at HEAD: the live `harness.dml`, or the HEAD version snapshot. */
174
+ async readHeadModule() {
175
+ let module = '';
176
+ try {
177
+ module = await fs.readFile(this.harnessFile, 'utf8');
178
+ }
179
+ catch {
180
+ module = '';
181
+ }
182
+ if (module.trim())
183
+ return { version: this.headVersion, module };
184
+ if (this.headVersion > 0) {
185
+ const current = await this.readVersion(this.headVersion);
186
+ if (current?.module.trim())
187
+ return { version: this.headVersion, module: current.module };
188
+ }
189
+ return null;
190
+ }
191
+ /** The module this harness started from (version 0). */
192
+ async readBaseline() {
193
+ try {
194
+ return await fs.readFile(this.baselineFile, 'utf8');
195
+ }
196
+ catch {
197
+ return '';
198
+ }
199
+ }
200
+ /**
201
+ * Establish the baseline of a fresh harness from its first content (e.g. a
202
+ * harness file loaded with `-l`). No-op once the harness has a baseline or
203
+ * any committed version.
204
+ */
205
+ async setInitialBaseline(module) {
206
+ if (this.headVersion > 0)
207
+ return;
208
+ if ((await this.readBaseline()).trim())
209
+ return;
210
+ await fs.mkdir(this.harnessDir, { recursive: true });
211
+ await fs.writeFile(this.baselineFile, module, 'utf8');
212
+ await fs.writeFile(this.harnessFile, module, 'utf8');
213
+ }
214
+ /** The persisted facts, to be loaded into the module at session start. */
215
+ async readFacts() {
216
+ const read = async (file) => {
217
+ try {
218
+ return await fs.readFile(file, 'utf8');
219
+ }
220
+ catch {
221
+ return '';
222
+ }
223
+ };
224
+ const [workspace, harness] = await Promise.all([
225
+ read(this.historyFile),
226
+ read(this.harnessFactsFile),
227
+ ]);
228
+ return `${workspace}${harness}`;
229
+ }
230
+ /** The turns recorded for a session, oldest first (used for input history). */
231
+ async readTurns(sessionId = this.sessionId) {
232
+ const file = path.join(this.sessionsDir(), sessionId, 'turns.jsonl');
233
+ let text;
234
+ try {
235
+ text = await fs.readFile(file, 'utf8');
236
+ }
237
+ catch {
238
+ return [];
239
+ }
240
+ const turns = [];
241
+ for (const line of text.split('\n')) {
242
+ if (!line.trim())
243
+ continue;
244
+ try {
245
+ const parsed = JSON.parse(line);
246
+ if (typeof parsed?.request === 'string')
247
+ turns.push(parsed);
248
+ }
249
+ catch {
250
+ // skip malformed lines
251
+ }
252
+ }
253
+ return turns;
254
+ }
255
+ async startSession(info, options = {}) {
256
+ const sessionFile = path.join(this.sessionDirAbs, 'session.json');
257
+ if (options.resume) {
258
+ const resumedAt = nowIso();
259
+ const facts = [
260
+ `harness_session_resume(${prologAtom(this.sessionId)}, ${prologAtom(resumedAt)}).`,
261
+ ];
262
+ await this.appendFacts(facts);
263
+ let existing = {};
264
+ try {
265
+ existing = JSON.parse(await fs.readFile(sessionFile, 'utf8'));
266
+ }
267
+ catch {
268
+ // first resume of a session that never wrote session.json
269
+ }
270
+ const previous = Array.isArray(existing.resumedAt) ? existing.resumedAt : [];
271
+ await this.writeJson(sessionFile, {
272
+ ...existing,
273
+ sessionId: this.sessionId,
274
+ model: info.model,
275
+ backend: info.backend,
276
+ traceDir: this.sessionDirRel,
277
+ endedAt: null,
278
+ exit: null,
279
+ resumedAt: [...previous, resumedAt],
280
+ });
281
+ return facts;
282
+ }
283
+ const startedAt = nowIso();
284
+ const facts = [
285
+ `harness_session(${prologAtom(this.sessionId)}, ${prologAtom(startedAt)}, `
286
+ + `${prologAtom(info.model)}, ${prologAtom(info.backend)}, ${prologAtom(this.sessionDirRel)}).`,
287
+ ];
288
+ await this.appendFacts(facts);
289
+ await this.writeJson(sessionFile, {
290
+ sessionId: this.sessionId,
291
+ startedAt,
292
+ endedAt: null,
293
+ exit: null,
294
+ model: info.model,
295
+ backend: info.backend,
296
+ traceDir: this.sessionDirRel,
297
+ });
298
+ return facts;
299
+ }
300
+ async endSession(reason) {
301
+ await this.flushEvents();
302
+ const endedAt = nowIso();
303
+ const facts = [`harness_session_end(${prologAtom(this.sessionId)}, ${prologAtom(endedAt)}).`];
304
+ await this.appendFacts(facts);
305
+ const sessionFile = path.join(this.sessionDirAbs, 'session.json');
306
+ try {
307
+ const existing = JSON.parse(await fs.readFile(sessionFile, 'utf8'));
308
+ await this.writeJson(sessionFile, { ...existing, endedAt, exit: reason });
309
+ }
310
+ catch {
311
+ // best effort
312
+ }
313
+ return facts;
314
+ }
315
+ async recordTurn(record) {
316
+ const ts = nowIso();
317
+ const facts = [
318
+ `harness_turn(${prologAtom(this.sessionId)}, ${record.turn}, ${prologAtom(ts)}, `
319
+ + `${prologAtom(record.mode)}, ${prologAtom(record.outcome)}).`,
320
+ `harness_trace(${prologAtom(this.sessionId)}, ${record.turn}, ${prologAtom(this.tracePath)}).`,
321
+ ];
322
+ await this.appendFacts(facts);
323
+ await this.appendJsonl(path.join(this.sessionDirAbs, 'turns.jsonl'), { ts, ...record });
324
+ return facts;
325
+ }
326
+ /**
327
+ * Record a harness version. Returns the facts to assert and the new version.
328
+ */
329
+ async recordChange(record) {
330
+ const ts = nowIso();
331
+ const hash = harnessHash(record.module, record.scripts);
332
+ // Committing content identical to HEAD is a no-op: do not burn a version.
333
+ if (hash === this.headHash && this.headVersion > 0) {
334
+ return { facts: [], version: this.headVersion };
335
+ }
336
+ const version = this.maxVersion + 1;
337
+ this.maxVersion = version;
338
+ const parentVersion = this.headVersion;
339
+ const facts = [
340
+ `harness_change(${version}, ${prologAtom(ts)}, ${prologAtom(record.kind)}, `
341
+ + `${prologAtom(record.sessionId)}, ${record.turn}).`,
342
+ ...record.changed.map((change) => {
343
+ const [name, arity] = splitPredicate(change.predicate);
344
+ return `harness_changed(${version}, ${prologAtom(name)}, ${arity}, ${prologAtom(change.action)}).`;
345
+ }),
346
+ `harness_head(${version}, ${prologAtom(ts)}, ${prologAtom(record.sessionId)}, ${record.turn}).`,
347
+ ];
348
+ await this.appendHarnessFacts(facts);
349
+ await this.appendJsonl(this.changesFile, {
350
+ version,
351
+ ts,
352
+ sessionId: record.sessionId,
353
+ turn: record.turn,
354
+ kind: record.kind,
355
+ hash,
356
+ changed: record.changed,
357
+ scripts: record.scripts,
358
+ });
359
+ await this.writeJson(path.join(this.harnessDir, 'versions', `${String(version).padStart(4, '0')}_${fileStamp(ts)}.json`), {
360
+ version,
361
+ ts,
362
+ parentVersion: parentVersion > 0 ? parentVersion : null,
363
+ kind: record.kind,
364
+ sessionId: record.sessionId,
365
+ turn: record.turn,
366
+ hash,
367
+ changed: record.changed,
368
+ scripts: record.scripts,
369
+ module: record.module,
370
+ manifest: record.manifest,
371
+ });
372
+ await this.writeJson(this.headFile, {
373
+ version,
374
+ maxVersion: this.maxVersion,
375
+ ts,
376
+ sessionId: record.sessionId,
377
+ turn: record.turn,
378
+ hash,
379
+ });
380
+ // Keep the live harness file in step with HEAD (it is the source of truth).
381
+ await fs.writeFile(this.harnessFile, record.module, 'utf8');
382
+ this.headVersion = version;
383
+ this.headHash = hash;
384
+ return { facts, version };
385
+ }
386
+ /**
387
+ * Plan a rollback to the parent of HEAD. Returns null when there is nothing
388
+ * to undo, otherwise the module source to restore (floored at the baseline).
389
+ */
390
+ async prepareRollback() {
391
+ if (this.headVersion <= 0)
392
+ return null;
393
+ const current = await this.readVersion(this.headVersion);
394
+ const to = current?.parentVersion ?? Math.max(this.headVersion - 1, 0);
395
+ const module = to > 0 ? (await this.readVersion(to))?.module ?? '' : await this.readBaseline();
396
+ return { from: this.headVersion, to, module };
397
+ }
398
+ /** Persist a rollback (facts + HEAD + change log + harness file). */
399
+ async recordRollback(from, to, turn, sessionId, module) {
400
+ const ts = nowIso();
401
+ const facts = [
402
+ `harness_rollback(${from}, ${to}, ${prologAtom(ts)}, ${prologAtom(sessionId)}, ${turn}).`,
403
+ `harness_head(${to}, ${prologAtom(ts)}, ${prologAtom(sessionId)}, ${turn}).`,
404
+ ];
405
+ await this.appendHarnessFacts(facts);
406
+ await this.appendJsonl(this.changesFile, { ts, sessionId, turn, kind: 'rollback', from, to });
407
+ await this.writeJson(this.headFile, {
408
+ version: to,
409
+ maxVersion: this.maxVersion,
410
+ ts,
411
+ sessionId,
412
+ turn,
413
+ rollback: true,
414
+ });
415
+ if (module !== undefined) {
416
+ await fs.writeFile(this.harnessFile, module, 'utf8');
417
+ }
418
+ this.headVersion = to;
419
+ // The hash no longer matches HEAD's content until the next commit.
420
+ this.headHash = undefined;
421
+ return facts;
422
+ }
423
+ async readVersion(version) {
424
+ const dir = path.join(this.harnessDir, 'versions');
425
+ try {
426
+ const prefix = `${String(version).padStart(4, '0')}_`;
427
+ const name = (await fs.readdir(dir)).find((entry) => entry.startsWith(prefix));
428
+ if (!name)
429
+ return null;
430
+ const data = JSON.parse(await fs.readFile(path.join(dir, name), 'utf8'));
431
+ return { module: data.module ?? '', parentVersion: data.parentVersion ?? null };
432
+ }
433
+ catch {
434
+ return null;
435
+ }
436
+ }
437
+ // ---- Session lookup & durable harness snapshots (resume) ----
438
+ sessionsDir() {
439
+ return path.join(this.rootAbs, 'sessions');
440
+ }
441
+ sessionHarnessFile(sessionId) {
442
+ return path.join(this.sessionsDir(), sessionId, 'harness.json');
443
+ }
444
+ /** True when a session directory exists for `sessionId`. */
445
+ async sessionExists(sessionId) {
446
+ try {
447
+ return (await fs.stat(path.join(this.sessionsDir(), sessionId))).isDirectory();
448
+ }
449
+ catch {
450
+ return false;
451
+ }
452
+ }
453
+ /** All recorded sessions, oldest first. */
454
+ async sessionSummaries() {
455
+ let ids;
456
+ try {
457
+ ids = await fs.readdir(this.sessionsDir());
458
+ }
459
+ catch {
460
+ return [];
461
+ }
462
+ const summaries = [];
463
+ for (const id of ids) {
464
+ let meta = {};
465
+ try {
466
+ meta = JSON.parse(await fs.readFile(path.join(this.sessionsDir(), id, 'session.json'), 'utf8'));
467
+ }
468
+ catch {
469
+ // session without metadata (e.g. history disabled mid-way)
470
+ }
471
+ summaries.push({
472
+ id,
473
+ startedAt: typeof meta.startedAt === 'string' ? meta.startedAt : undefined,
474
+ endedAt: typeof meta.endedAt === 'string' ? meta.endedAt : null,
475
+ resumedAt: Array.isArray(meta.resumedAt) ? meta.resumedAt : undefined,
476
+ lastTurn: await this.lastTurn(id),
477
+ });
478
+ }
479
+ summaries.sort((a, b) => (a.startedAt ?? '').localeCompare(b.startedAt ?? ''));
480
+ return summaries;
481
+ }
482
+ /** The most recently started session, or null when there is none. */
483
+ async latestSessionId() {
484
+ const summaries = await this.sessionSummaries();
485
+ return summaries.length > 0 ? summaries[summaries.length - 1].id : null;
486
+ }
487
+ /** The highest turn number recorded for a session (0 when none). */
488
+ async lastTurn(sessionId = this.sessionId) {
489
+ const file = path.join(this.sessionsDir(), sessionId, 'turns.jsonl');
490
+ let text;
491
+ try {
492
+ text = await fs.readFile(file, 'utf8');
493
+ }
494
+ catch {
495
+ return 0;
496
+ }
497
+ const lines = text.split('\n').filter((line) => line.trim());
498
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
499
+ try {
500
+ const record = JSON.parse(lines[index]);
501
+ if (typeof record.turn === 'number')
502
+ return record.turn;
503
+ }
504
+ catch {
505
+ // skip a malformed line
506
+ }
507
+ }
508
+ return 0;
509
+ }
510
+ /** Persist the durable harness snapshot beside a session (best effort). */
511
+ async writeSessionHarness(snapshot, sessionId = this.sessionId) {
512
+ await this.writeJson(this.sessionHarnessFile(sessionId), snapshot);
513
+ }
514
+ /** Read a session's durable harness snapshot, or null when absent. */
515
+ async readSessionHarness(sessionId = this.sessionId) {
516
+ try {
517
+ const data = JSON.parse(await fs.readFile(this.sessionHarnessFile(sessionId), 'utf8'));
518
+ return typeof data?.module === 'string' ? data : null;
519
+ }
520
+ catch {
521
+ return null;
522
+ }
523
+ }
524
+ /** Buffer one event line (flushed at turn end / dispose). */
525
+ recordEvent(context, event) {
526
+ if (this.trace === 'off')
527
+ return;
528
+ try {
529
+ const line = this.serializeEvent(context, event);
530
+ if (!line)
531
+ return;
532
+ this.eventBuffer.push(line);
533
+ if (this.eventBuffer.length >= 200)
534
+ void this.flushEvents();
535
+ }
536
+ catch {
537
+ // never let tracing break the turn
538
+ }
539
+ }
540
+ async flushEvents() {
541
+ if (this.eventBuffer.length === 0)
542
+ return;
543
+ const payload = `${this.eventBuffer.join('\n')}\n`;
544
+ this.eventBuffer = [];
545
+ await this.appendRaw(path.join(this.sessionDirAbs, 'events.jsonl'), payload);
546
+ }
547
+ serializeEvent(context, event) {
548
+ const base = {
549
+ ts: nowIso(),
550
+ sessionId: this.sessionId,
551
+ turn: context.turn,
552
+ frame: context.frame,
553
+ type: event.type,
554
+ };
555
+ const put = (key, value) => {
556
+ if (value !== undefined && value !== null)
557
+ base[key] = this.scrub(value);
558
+ };
559
+ switch (event.type) {
560
+ case 'stream':
561
+ if (this.trace === 'full')
562
+ put('content', event.content);
563
+ break;
564
+ case 'output':
565
+ case 'answer':
566
+ case 'error':
567
+ case 'log':
568
+ put('content', event.content);
569
+ break;
570
+ case 'tool_call':
571
+ put('toolName', event.toolName);
572
+ put('toolState', event.toolState);
573
+ put('toolSummary', event.toolSummary);
574
+ put('toolArgs', event.toolArgs);
575
+ break;
576
+ case 'solution':
577
+ put('bindings', event.solution?.bindings);
578
+ break;
579
+ case 'usage':
580
+ put('usage', event.usage);
581
+ break;
582
+ case 'task_activity':
583
+ put('taskState', event.taskState);
584
+ put('taskDescription', event.taskDescription);
585
+ break;
586
+ default:
587
+ break;
588
+ }
589
+ return JSON.stringify(base);
590
+ }
591
+ /** Redact and truncate strings recursively. */
592
+ scrub(value) {
593
+ if (typeof value === 'string') {
594
+ let text = value;
595
+ for (const pattern of this.redactions)
596
+ text = text.replace(pattern, '[redacted]');
597
+ if (Buffer.byteLength(text, 'utf8') > this.maxEventBytes) {
598
+ text = `${text.slice(0, this.maxEventBytes)}…[truncated]`;
599
+ }
600
+ return text;
601
+ }
602
+ if (Array.isArray(value))
603
+ return value.map((entry) => this.scrub(entry));
604
+ if (value && typeof value === 'object') {
605
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, this.scrub(entry)]));
606
+ }
607
+ return value;
608
+ }
609
+ async appendFacts(facts) {
610
+ if (facts.length === 0)
611
+ return;
612
+ await this.appendRaw(this.historyFile, `${facts.join('\n')}\n`);
613
+ }
614
+ async appendHarnessFacts(facts) {
615
+ if (facts.length === 0)
616
+ return;
617
+ await this.appendRaw(this.harnessFactsFile, `${facts.join('\n')}\n`);
618
+ }
619
+ async appendJsonl(file, record) {
620
+ if (this.trace === 'off' && file.endsWith('events.jsonl'))
621
+ return;
622
+ await this.appendRaw(file, `${JSON.stringify(record)}\n`);
623
+ }
624
+ async appendRaw(file, text) {
625
+ await fs.mkdir(path.dirname(file), { recursive: true });
626
+ await fs.appendFile(file, text, 'utf8');
627
+ }
628
+ async writeJson(file, value) {
629
+ await fs.mkdir(path.dirname(file), { recursive: true });
630
+ await fs.writeFile(file, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
631
+ }
632
+ /** Keep only the newest sessions and versions. */
633
+ async prune() {
634
+ await this.pruneDir(path.join(this.rootAbs, 'sessions'), this.maxSessions);
635
+ await this.pruneDir(path.join(this.harnessDir, 'versions'), this.maxVersions);
636
+ }
637
+ async pruneDir(dir, keep) {
638
+ try {
639
+ const entries = await fs.readdir(dir);
640
+ if (entries.length <= keep)
641
+ return;
642
+ const sorted = entries.sort();
643
+ for (const entry of sorted.slice(0, entries.length - keep)) {
644
+ await fs.rm(path.join(dir, entry), { recursive: true, force: true });
645
+ }
646
+ }
647
+ catch {
648
+ // best effort
649
+ }
650
+ }
651
+ }
652
+ function splitPredicate(predicate) {
653
+ const slash = predicate.lastIndexOf('/');
654
+ if (slash === -1)
655
+ return [predicate, 0];
656
+ return [predicate.slice(0, slash), Number(predicate.slice(slash + 1)) || 0];
657
+ }
658
+ function fileStamp(iso) {
659
+ return iso.replace(/[:.]/g, '-');
660
+ }
661
+ //# sourceMappingURL=history.js.map