agent-bober 0.17.1 → 0.18.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 (355) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +15 -0
  3. package/README.md +158 -5
  4. package/dist/chat/answerer.d.ts +17 -0
  5. package/dist/chat/answerer.d.ts.map +1 -0
  6. package/dist/chat/answerer.js +52 -0
  7. package/dist/chat/answerer.js.map +1 -0
  8. package/dist/chat/approval-cursor.d.ts +25 -0
  9. package/dist/chat/approval-cursor.d.ts.map +1 -0
  10. package/dist/chat/approval-cursor.js +61 -0
  11. package/dist/chat/approval-cursor.js.map +1 -0
  12. package/dist/chat/approval-reader.d.ts +11 -0
  13. package/dist/chat/approval-reader.d.ts.map +1 -0
  14. package/dist/chat/approval-reader.js +20 -0
  15. package/dist/chat/approval-reader.js.map +1 -0
  16. package/dist/chat/careful-sidecar.d.ts +15 -0
  17. package/dist/chat/careful-sidecar.d.ts.map +1 -0
  18. package/dist/chat/careful-sidecar.js +39 -0
  19. package/dist/chat/careful-sidecar.js.map +1 -0
  20. package/dist/chat/chat-session.d.ts +129 -0
  21. package/dist/chat/chat-session.d.ts.map +1 -0
  22. package/dist/chat/chat-session.js +470 -0
  23. package/dist/chat/chat-session.js.map +1 -0
  24. package/dist/chat/completion-tailer.d.ts +27 -0
  25. package/dist/chat/completion-tailer.d.ts.map +1 -0
  26. package/dist/chat/completion-tailer.js +187 -0
  27. package/dist/chat/completion-tailer.js.map +1 -0
  28. package/dist/chat/conversation-store.d.ts +22 -0
  29. package/dist/chat/conversation-store.d.ts.map +1 -0
  30. package/dist/chat/conversation-store.js +66 -0
  31. package/dist/chat/conversation-store.js.map +1 -0
  32. package/dist/chat/cursor-store.d.ts +23 -0
  33. package/dist/chat/cursor-store.d.ts.map +1 -0
  34. package/dist/chat/cursor-store.js +42 -0
  35. package/dist/chat/cursor-store.js.map +1 -0
  36. package/dist/chat/pid-sidecar.d.ts +22 -0
  37. package/dist/chat/pid-sidecar.d.ts.map +1 -0
  38. package/dist/chat/pid-sidecar.js +42 -0
  39. package/dist/chat/pid-sidecar.js.map +1 -0
  40. package/dist/chat/roster-reader.d.ts +16 -0
  41. package/dist/chat/roster-reader.d.ts.map +1 -0
  42. package/dist/chat/roster-reader.js +39 -0
  43. package/dist/chat/roster-reader.js.map +1 -0
  44. package/dist/chat/run-spawner.d.ts +71 -0
  45. package/dist/chat/run-spawner.d.ts.map +1 -0
  46. package/dist/chat/run-spawner.js +121 -0
  47. package/dist/chat/run-spawner.js.map +1 -0
  48. package/dist/chat/slash-commands.d.ts +36 -0
  49. package/dist/chat/slash-commands.d.ts.map +1 -0
  50. package/dist/chat/slash-commands.js +133 -0
  51. package/dist/chat/slash-commands.js.map +1 -0
  52. package/dist/chat/steer-cleanup.d.ts +12 -0
  53. package/dist/chat/steer-cleanup.d.ts.map +1 -0
  54. package/dist/chat/steer-cleanup.js +60 -0
  55. package/dist/chat/steer-cleanup.js.map +1 -0
  56. package/dist/chat/turn-classifier.d.ts +43 -0
  57. package/dist/chat/turn-classifier.d.ts.map +1 -0
  58. package/dist/chat/turn-classifier.js +150 -0
  59. package/dist/chat/turn-classifier.js.map +1 -0
  60. package/dist/cli/commands/blackboard.d.ts +33 -0
  61. package/dist/cli/commands/blackboard.d.ts.map +1 -0
  62. package/dist/cli/commands/blackboard.js +114 -0
  63. package/dist/cli/commands/blackboard.js.map +1 -0
  64. package/dist/cli/commands/chat.d.ts +13 -0
  65. package/dist/cli/commands/chat.d.ts.map +1 -0
  66. package/dist/cli/commands/chat.js +43 -0
  67. package/dist/cli/commands/chat.js.map +1 -0
  68. package/dist/cli/commands/evolve.d.ts +18 -0
  69. package/dist/cli/commands/evolve.d.ts.map +1 -0
  70. package/dist/cli/commands/evolve.js +72 -0
  71. package/dist/cli/commands/evolve.js.map +1 -0
  72. package/dist/cli/commands/facts.d.ts +15 -0
  73. package/dist/cli/commands/facts.d.ts.map +1 -0
  74. package/dist/cli/commands/facts.js +213 -0
  75. package/dist/cli/commands/facts.js.map +1 -0
  76. package/dist/cli/commands/medical.d.ts +24 -0
  77. package/dist/cli/commands/medical.d.ts.map +1 -0
  78. package/dist/cli/commands/medical.js +132 -0
  79. package/dist/cli/commands/medical.js.map +1 -0
  80. package/dist/cli/commands/memory.d.ts +2 -1
  81. package/dist/cli/commands/memory.d.ts.map +1 -1
  82. package/dist/cli/commands/memory.js +94 -7
  83. package/dist/cli/commands/memory.js.map +1 -1
  84. package/dist/cli/commands/plan.d.ts.map +1 -1
  85. package/dist/cli/commands/plan.js +29 -3
  86. package/dist/cli/commands/plan.js.map +1 -1
  87. package/dist/cli/commands/replay.d.ts +17 -0
  88. package/dist/cli/commands/replay.d.ts.map +1 -0
  89. package/dist/cli/commands/replay.js +261 -0
  90. package/dist/cli/commands/replay.js.map +1 -0
  91. package/dist/cli/commands/run.d.ts +9 -0
  92. package/dist/cli/commands/run.d.ts.map +1 -1
  93. package/dist/cli/commands/run.js +27 -1
  94. package/dist/cli/commands/run.js.map +1 -1
  95. package/dist/cli/commands/sprint.d.ts.map +1 -1
  96. package/dist/cli/commands/sprint.js +17 -3
  97. package/dist/cli/commands/sprint.js.map +1 -1
  98. package/dist/cli/index.js +12 -0
  99. package/dist/cli/index.js.map +1 -1
  100. package/dist/config/defaults.d.ts.map +1 -1
  101. package/dist/config/defaults.js +8 -0
  102. package/dist/config/defaults.js.map +1 -1
  103. package/dist/config/role-providers.d.ts +1 -1
  104. package/dist/config/role-providers.d.ts.map +1 -1
  105. package/dist/config/role-providers.js +6 -1
  106. package/dist/config/role-providers.js.map +1 -1
  107. package/dist/config/schema.d.ts +467 -222
  108. package/dist/config/schema.d.ts.map +1 -1
  109. package/dist/config/schema.js +25 -0
  110. package/dist/config/schema.js.map +1 -1
  111. package/dist/contracts/eval-result.d.ts +84 -84
  112. package/dist/contracts/spec.d.ts +28 -28
  113. package/dist/contracts/sprint-contract.d.ts +4 -4
  114. package/dist/fleet/critic-deep.d.ts +53 -0
  115. package/dist/fleet/critic-deep.d.ts.map +1 -0
  116. package/dist/fleet/critic-deep.js +199 -0
  117. package/dist/fleet/critic-deep.js.map +1 -0
  118. package/dist/fleet/decomposer-deep-constants.d.ts +4 -0
  119. package/dist/fleet/decomposer-deep-constants.d.ts.map +1 -0
  120. package/dist/fleet/decomposer-deep-constants.js +14 -0
  121. package/dist/fleet/decomposer-deep-constants.js.map +1 -0
  122. package/dist/fleet/decomposer-deep-types.d.ts +8 -0
  123. package/dist/fleet/decomposer-deep-types.d.ts.map +1 -0
  124. package/dist/fleet/decomposer-deep-types.js +9 -0
  125. package/dist/fleet/decomposer-deep-types.js.map +1 -0
  126. package/dist/fleet/decomposer-deep.d.ts +51 -0
  127. package/dist/fleet/decomposer-deep.d.ts.map +1 -0
  128. package/dist/fleet/decomposer-deep.js +261 -0
  129. package/dist/fleet/decomposer-deep.js.map +1 -0
  130. package/dist/fleet/decomposer.d.ts +22 -0
  131. package/dist/fleet/decomposer.d.ts.map +1 -0
  132. package/dist/fleet/decomposer.js +144 -0
  133. package/dist/fleet/decomposer.js.map +1 -0
  134. package/dist/fleet/index.d.ts +93 -0
  135. package/dist/fleet/index.d.ts.map +1 -1
  136. package/dist/fleet/index.js +230 -2
  137. package/dist/fleet/index.js.map +1 -1
  138. package/dist/fleet/manifest-write.d.ts +30 -0
  139. package/dist/fleet/manifest-write.d.ts.map +1 -0
  140. package/dist/fleet/manifest-write.js +90 -0
  141. package/dist/fleet/manifest-write.js.map +1 -0
  142. package/dist/fleet/manifest.d.ts +6 -6
  143. package/dist/fleet/shared-blackboard.d.ts +51 -0
  144. package/dist/fleet/shared-blackboard.d.ts.map +1 -0
  145. package/dist/fleet/shared-blackboard.js +79 -0
  146. package/dist/fleet/shared-blackboard.js.map +1 -0
  147. package/dist/fleet/synthesis.d.ts +16 -0
  148. package/dist/fleet/synthesis.d.ts.map +1 -0
  149. package/dist/fleet/synthesis.js +22 -0
  150. package/dist/fleet/synthesis.js.map +1 -0
  151. package/dist/fleet/tier-policy.d.ts +18 -0
  152. package/dist/fleet/tier-policy.d.ts.map +1 -0
  153. package/dist/fleet/tier-policy.js +53 -0
  154. package/dist/fleet/tier-policy.js.map +1 -0
  155. package/dist/fleet/tool-role-guard.d.ts +24 -0
  156. package/dist/fleet/tool-role-guard.d.ts.map +1 -0
  157. package/dist/fleet/tool-role-guard.js +55 -0
  158. package/dist/fleet/tool-role-guard.js.map +1 -0
  159. package/dist/incident/resolution-verify.d.ts +4 -4
  160. package/dist/incident/types.d.ts +8 -8
  161. package/dist/mcp/run-manager.d.ts +9 -1
  162. package/dist/mcp/run-manager.d.ts.map +1 -1
  163. package/dist/mcp/run-manager.js.map +1 -1
  164. package/dist/medical/adapters/apple-health.d.ts +32 -0
  165. package/dist/medical/adapters/apple-health.d.ts.map +1 -0
  166. package/dist/medical/adapters/apple-health.js +100 -0
  167. package/dist/medical/adapters/apple-health.js.map +1 -0
  168. package/dist/medical/audit.d.ts +31 -0
  169. package/dist/medical/audit.d.ts.map +1 -0
  170. package/dist/medical/audit.js +56 -0
  171. package/dist/medical/audit.js.map +1 -0
  172. package/dist/medical/consent.d.ts +37 -0
  173. package/dist/medical/consent.d.ts.map +1 -0
  174. package/dist/medical/consent.js +73 -0
  175. package/dist/medical/consent.js.map +1 -0
  176. package/dist/medical/disclaimer.d.ts +11 -0
  177. package/dist/medical/disclaimer.d.ts.map +1 -0
  178. package/dist/medical/disclaimer.js +21 -0
  179. package/dist/medical/disclaimer.js.map +1 -0
  180. package/dist/medical/egress.d.ts +30 -0
  181. package/dist/medical/egress.d.ts.map +1 -0
  182. package/dist/medical/egress.js +50 -0
  183. package/dist/medical/egress.js.map +1 -0
  184. package/dist/medical/engine.d.ts +73 -0
  185. package/dist/medical/engine.d.ts.map +1 -0
  186. package/dist/medical/engine.js +333 -0
  187. package/dist/medical/engine.js.map +1 -0
  188. package/dist/medical/guardrails.d.ts +47 -0
  189. package/dist/medical/guardrails.d.ts.map +1 -0
  190. package/dist/medical/guardrails.js +92 -0
  191. package/dist/medical/guardrails.js.map +1 -0
  192. package/dist/medical/health-store.d.ts +80 -0
  193. package/dist/medical/health-store.d.ts.map +1 -0
  194. package/dist/medical/health-store.js +204 -0
  195. package/dist/medical/health-store.js.map +1 -0
  196. package/dist/medical/inference.d.ts +22 -0
  197. package/dist/medical/inference.d.ts.map +1 -0
  198. package/dist/medical/inference.js +39 -0
  199. package/dist/medical/inference.js.map +1 -0
  200. package/dist/medical/ingestion.d.ts +33 -0
  201. package/dist/medical/ingestion.d.ts.map +1 -0
  202. package/dist/medical/ingestion.js +52 -0
  203. package/dist/medical/ingestion.js.map +1 -0
  204. package/dist/medical/numerics.d.ts +66 -0
  205. package/dist/medical/numerics.d.ts.map +1 -0
  206. package/dist/medical/numerics.js +216 -0
  207. package/dist/medical/numerics.js.map +1 -0
  208. package/dist/medical/red-flag.d.ts +42 -0
  209. package/dist/medical/red-flag.d.ts.map +1 -0
  210. package/dist/medical/red-flag.js +161 -0
  211. package/dist/medical/red-flag.js.map +1 -0
  212. package/dist/medical/refusal.d.ts +46 -0
  213. package/dist/medical/refusal.d.ts.map +1 -0
  214. package/dist/medical/refusal.js +131 -0
  215. package/dist/medical/refusal.js.map +1 -0
  216. package/dist/medical/retrieval/grounding-critic.d.ts +34 -0
  217. package/dist/medical/retrieval/grounding-critic.d.ts.map +1 -0
  218. package/dist/medical/retrieval/grounding-critic.js +153 -0
  219. package/dist/medical/retrieval/grounding-critic.js.map +1 -0
  220. package/dist/medical/retrieval/literature.d.ts +78 -0
  221. package/dist/medical/retrieval/literature.d.ts.map +1 -0
  222. package/dist/medical/retrieval/literature.js +292 -0
  223. package/dist/medical/retrieval/literature.js.map +1 -0
  224. package/dist/medical/retrieval/medline-source.d.ts +72 -0
  225. package/dist/medical/retrieval/medline-source.d.ts.map +1 -0
  226. package/dist/medical/retrieval/medline-source.js +120 -0
  227. package/dist/medical/retrieval/medline-source.js.map +1 -0
  228. package/dist/medical/team.d.ts +15 -0
  229. package/dist/medical/team.d.ts.map +1 -0
  230. package/dist/medical/team.js +44 -0
  231. package/dist/medical/team.js.map +1 -0
  232. package/dist/medical/types.d.ts +175 -0
  233. package/dist/medical/types.d.ts.map +1 -0
  234. package/dist/medical/types.js +8 -0
  235. package/dist/medical/types.js.map +1 -0
  236. package/dist/medical/whoop/whoop-client.d.ts +114 -0
  237. package/dist/medical/whoop/whoop-client.d.ts.map +1 -0
  238. package/dist/medical/whoop/whoop-client.js +226 -0
  239. package/dist/medical/whoop/whoop-client.js.map +1 -0
  240. package/dist/medical/whoop/whoop-sync.d.ts +25 -0
  241. package/dist/medical/whoop/whoop-sync.d.ts.map +1 -0
  242. package/dist/medical/whoop/whoop-sync.js +97 -0
  243. package/dist/medical/whoop/whoop-sync.js.map +1 -0
  244. package/dist/medical/whoop/whoop-token.d.ts +44 -0
  245. package/dist/medical/whoop/whoop-token.d.ts.map +1 -0
  246. package/dist/medical/whoop/whoop-token.js +66 -0
  247. package/dist/medical/whoop/whoop-token.js.map +1 -0
  248. package/dist/orchestrator/context-handoff.d.ts +60 -60
  249. package/dist/orchestrator/contract-materialization.d.ts +33 -0
  250. package/dist/orchestrator/contract-materialization.d.ts.map +1 -0
  251. package/dist/orchestrator/contract-materialization.js +113 -0
  252. package/dist/orchestrator/contract-materialization.js.map +1 -0
  253. package/dist/orchestrator/memory/distill.d.ts +4 -1
  254. package/dist/orchestrator/memory/distill.d.ts.map +1 -1
  255. package/dist/orchestrator/memory/distill.js +41 -1
  256. package/dist/orchestrator/memory/distill.js.map +1 -1
  257. package/dist/orchestrator/memory/fact-detector.d.ts +61 -0
  258. package/dist/orchestrator/memory/fact-detector.d.ts.map +1 -0
  259. package/dist/orchestrator/memory/fact-detector.js +153 -0
  260. package/dist/orchestrator/memory/fact-detector.js.map +1 -0
  261. package/dist/orchestrator/memory/fact-judge.d.ts +19 -0
  262. package/dist/orchestrator/memory/fact-judge.d.ts.map +1 -0
  263. package/dist/orchestrator/memory/fact-judge.js +121 -0
  264. package/dist/orchestrator/memory/fact-judge.js.map +1 -0
  265. package/dist/orchestrator/memory/fact-retrieve.d.ts +52 -0
  266. package/dist/orchestrator/memory/fact-retrieve.d.ts.map +1 -0
  267. package/dist/orchestrator/memory/fact-retrieve.js +117 -0
  268. package/dist/orchestrator/memory/fact-retrieve.js.map +1 -0
  269. package/dist/orchestrator/memory/hygiene.d.ts +66 -0
  270. package/dist/orchestrator/memory/hygiene.d.ts.map +1 -0
  271. package/dist/orchestrator/memory/hygiene.js +153 -0
  272. package/dist/orchestrator/memory/hygiene.js.map +1 -0
  273. package/dist/orchestrator/memory/reconcile.d.ts +47 -0
  274. package/dist/orchestrator/memory/reconcile.d.ts.map +1 -0
  275. package/dist/orchestrator/memory/reconcile.js +116 -0
  276. package/dist/orchestrator/memory/reconcile.js.map +1 -0
  277. package/dist/orchestrator/memory/retrieve.d.ts +5 -3
  278. package/dist/orchestrator/memory/retrieve.d.ts.map +1 -1
  279. package/dist/orchestrator/memory/retrieve.js +9 -6
  280. package/dist/orchestrator/memory/retrieve.js.map +1 -1
  281. package/dist/orchestrator/pipeline.d.ts +19 -3
  282. package/dist/orchestrator/pipeline.d.ts.map +1 -1
  283. package/dist/orchestrator/pipeline.js +63 -52
  284. package/dist/orchestrator/pipeline.js.map +1 -1
  285. package/dist/orchestrator/planner-agent.d.ts.map +1 -1
  286. package/dist/orchestrator/planner-agent.js +16 -1
  287. package/dist/orchestrator/planner-agent.js.map +1 -1
  288. package/dist/orchestrator/selfimprove/eval-guards.d.ts +51 -0
  289. package/dist/orchestrator/selfimprove/eval-guards.d.ts.map +1 -0
  290. package/dist/orchestrator/selfimprove/eval-guards.js +120 -0
  291. package/dist/orchestrator/selfimprove/eval-guards.js.map +1 -0
  292. package/dist/orchestrator/selfimprove/gepa.d.ts +74 -0
  293. package/dist/orchestrator/selfimprove/gepa.d.ts.map +1 -0
  294. package/dist/orchestrator/selfimprove/gepa.js +227 -0
  295. package/dist/orchestrator/selfimprove/gepa.js.map +1 -0
  296. package/dist/orchestrator/selfimprove/replay-harness.d.ts +65 -0
  297. package/dist/orchestrator/selfimprove/replay-harness.d.ts.map +1 -0
  298. package/dist/orchestrator/selfimprove/replay-harness.js +134 -0
  299. package/dist/orchestrator/selfimprove/replay-harness.js.map +1 -0
  300. package/dist/orchestrator/selfimprove/replay-store.d.ts +45 -0
  301. package/dist/orchestrator/selfimprove/replay-store.d.ts.map +1 -0
  302. package/dist/orchestrator/selfimprove/replay-store.js +119 -0
  303. package/dist/orchestrator/selfimprove/replay-store.js.map +1 -0
  304. package/dist/orchestrator/selfimprove/replay-types.d.ts +32 -0
  305. package/dist/orchestrator/selfimprove/replay-types.d.ts.map +1 -0
  306. package/dist/orchestrator/selfimprove/replay-types.js +15 -0
  307. package/dist/orchestrator/selfimprove/replay-types.js.map +1 -0
  308. package/dist/orchestrator/workflow/engine.d.ts +3 -1
  309. package/dist/orchestrator/workflow/engine.d.ts.map +1 -1
  310. package/dist/orchestrator/workflow/selector.d.ts +18 -0
  311. package/dist/orchestrator/workflow/selector.d.ts.map +1 -1
  312. package/dist/orchestrator/workflow/selector.js +41 -0
  313. package/dist/orchestrator/workflow/selector.js.map +1 -1
  314. package/dist/orchestrator/workflow/ts-engine.d.ts +3 -1
  315. package/dist/orchestrator/workflow/ts-engine.d.ts.map +1 -1
  316. package/dist/orchestrator/workflow/ts-engine.js +2 -2
  317. package/dist/orchestrator/workflow/ts-engine.js.map +1 -1
  318. package/dist/orchestrator/workflow/workflow-engine.d.ts +3 -1
  319. package/dist/orchestrator/workflow/workflow-engine.d.ts.map +1 -1
  320. package/dist/orchestrator/workflow/workflow-engine.js +3 -3
  321. package/dist/orchestrator/workflow/workflow-engine.js.map +1 -1
  322. package/dist/state/facts.d.ts +110 -0
  323. package/dist/state/facts.d.ts.map +1 -0
  324. package/dist/state/facts.js +208 -0
  325. package/dist/state/facts.js.map +1 -0
  326. package/dist/state/guidance.d.ts +37 -0
  327. package/dist/state/guidance.d.ts.map +1 -0
  328. package/dist/state/guidance.js +144 -0
  329. package/dist/state/guidance.js.map +1 -0
  330. package/dist/state/history.d.ts +2 -2
  331. package/dist/state/index.d.ts +1 -1
  332. package/dist/state/index.d.ts.map +1 -1
  333. package/dist/state/index.js +1 -1
  334. package/dist/state/index.js.map +1 -1
  335. package/dist/state/memory.d.ts +43 -11
  336. package/dist/state/memory.d.ts.map +1 -1
  337. package/dist/state/memory.js +93 -15
  338. package/dist/state/memory.js.map +1 -1
  339. package/dist/state/pause.d.ts +47 -0
  340. package/dist/state/pause.d.ts.map +1 -0
  341. package/dist/state/pause.js +146 -0
  342. package/dist/state/pause.js.map +1 -0
  343. package/dist/state/sprint-state.d.ts +8 -0
  344. package/dist/state/sprint-state.d.ts.map +1 -1
  345. package/dist/state/sprint-state.js +32 -1
  346. package/dist/state/sprint-state.js.map +1 -1
  347. package/dist/teams/registry.d.ts +16 -0
  348. package/dist/teams/registry.d.ts.map +1 -0
  349. package/dist/teams/registry.js +53 -0
  350. package/dist/teams/registry.js.map +1 -0
  351. package/dist/teams/types.d.ts +25 -0
  352. package/dist/teams/types.d.ts.map +1 -0
  353. package/dist/teams/types.js +2 -0
  354. package/dist/teams/types.js.map +1 -0
  355. package/package.json +3 -1
@@ -0,0 +1,208 @@
1
+ import { join } from "node:path";
2
+ import { createHash } from "node:crypto";
3
+ import Database from "better-sqlite3";
4
+ import { z } from "zod";
5
+ import { ensureDir } from "./helpers.js";
6
+ import { memoryDir } from "./memory.js";
7
+ // ── Re-exports from reconcile layer ──────────────────────────────────────
8
+ // writeFact lives in reconcile.ts (to avoid a runtime import cycle) but is
9
+ // re-exported here so consumers can import it from the facts module.
10
+ export { writeFact } from "../orchestrator/memory/reconcile.js";
11
+ // ── Schema ────────────────────────────────────────────────────────────
12
+ /**
13
+ * Zod schema for a fact input — mirrors LessonEntrySchema in memory.ts.
14
+ * All timestamps are ISO 8601 strings; the store never reads the clock.
15
+ */
16
+ export const FactSchema = z.object({
17
+ scope: z.string(),
18
+ subject: z.string().min(1),
19
+ predicate: z.string().min(1),
20
+ value: z.string().min(1),
21
+ confidence: z.number().min(0).max(1).default(1),
22
+ sourceRunId: z.string().nullable().default(null),
23
+ tValid: z.string().datetime(),
24
+ tCreated: z.string().datetime(),
25
+ });
26
+ // ── Deterministic id ──────────────────────────────────────────────────
27
+ /**
28
+ * Derive a deterministic 16-char hex fact id from the fact signature.
29
+ * Mirrors lessonIdFromSignature in src/orchestrator/memory/distill.ts:88-99.
30
+ * Identical inputs always produce the same id — no wall-clock dependency.
31
+ */
32
+ export function factId(scope, subject, predicate, value, tCreated) {
33
+ return createHash("sha256")
34
+ .update(`${scope}|${subject}|${predicate}|${value}|${tCreated}`)
35
+ .digest("hex")
36
+ .slice(0, 16);
37
+ }
38
+ // ── Path helpers ──────────────────────────────────────────────────────
39
+ /**
40
+ * Resolve the absolute path to facts.db for the given project root and namespace.
41
+ * Uses the same memoryDir mapping rule as memory.ts (no duplication).
42
+ */
43
+ export function factsDbPath(projectRoot, namespace) {
44
+ return join(memoryDir(projectRoot, namespace), "facts.db");
45
+ }
46
+ /**
47
+ * Ensure the directory that will hold the DB file exists.
48
+ * Must be called by the CLI handler before constructing a file-backed FactStore.
49
+ * Not needed for ':memory:' paths.
50
+ */
51
+ export async function ensureFactsDir(projectRoot, namespace) {
52
+ await ensureDir(memoryDir(projectRoot, namespace));
53
+ }
54
+ function rowToRecord(row) {
55
+ return {
56
+ id: row.id,
57
+ scope: row.scope,
58
+ subject: row.subject,
59
+ predicate: row.predicate,
60
+ value: row.value,
61
+ confidence: row.confidence,
62
+ sourceRunId: row.source_run_id,
63
+ tValid: row.t_valid,
64
+ tInvalid: row.t_invalid,
65
+ tCreated: row.t_created,
66
+ tInvalidated: row.t_invalidated,
67
+ };
68
+ }
69
+ // ── FactStore ─────────────────────────────────────────────────────────
70
+ /**
71
+ * Bi-temporal SQLite-backed fact store.
72
+ *
73
+ * PURE: Never calls Date.now() or new Date() — every timestamp is a parameter.
74
+ * Hidden behind this interface so the driver (better-sqlite3) is swappable.
75
+ *
76
+ * bober: in-memory or file-backed via better-sqlite3 (synchronous); swap for
77
+ * node:sqlite when engines.node is raised to >=22.5.
78
+ */
79
+ export class FactStore {
80
+ db;
81
+ constructor(dbPath) {
82
+ this.db = new Database(dbPath);
83
+ this.db.exec(`
84
+ CREATE TABLE IF NOT EXISTS semantic_facts (
85
+ id TEXT PRIMARY KEY,
86
+ scope TEXT NOT NULL,
87
+ subject TEXT NOT NULL,
88
+ predicate TEXT NOT NULL,
89
+ value TEXT NOT NULL,
90
+ confidence REAL NOT NULL,
91
+ source_run_id TEXT,
92
+ t_valid TEXT NOT NULL,
93
+ t_invalid TEXT,
94
+ t_created TEXT NOT NULL,
95
+ t_invalidated TEXT
96
+ );
97
+ CREATE INDEX IF NOT EXISTS idx_facts_sp ON semantic_facts(scope, subject, predicate);
98
+ CREATE INDEX IF NOT EXISTS idx_facts_active ON semantic_facts(scope, t_invalidated);
99
+ `);
100
+ }
101
+ /**
102
+ * Insert a new fact. Validates input with FactSchema and derives the
103
+ * deterministic id. Returns the persisted FactRecord.
104
+ */
105
+ insertFact(input) {
106
+ const result = FactSchema.safeParse(input);
107
+ if (!result.success) {
108
+ const issues = result.error.issues
109
+ .map((i) => ` - ${i.path.join(".")}: ${i.message}`)
110
+ .join("\n");
111
+ throw new Error(`Invalid fact input:\n${issues}`);
112
+ }
113
+ const data = result.data;
114
+ const id = factId(data.scope, data.subject, data.predicate, data.value, data.tCreated);
115
+ this.db
116
+ .prepare(`INSERT OR REPLACE INTO semantic_facts
117
+ (id, scope, subject, predicate, value, confidence, source_run_id, t_valid, t_invalid, t_created, t_invalidated)
118
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, NULL)`)
119
+ .run(id, data.scope, data.subject, data.predicate, data.value, data.confidence, data.sourceRunId, data.tValid, data.tCreated);
120
+ return {
121
+ id,
122
+ scope: data.scope,
123
+ subject: data.subject,
124
+ predicate: data.predicate,
125
+ value: data.value,
126
+ confidence: data.confidence,
127
+ sourceRunId: data.sourceRunId,
128
+ tValid: data.tValid,
129
+ tInvalid: null,
130
+ tCreated: data.tCreated,
131
+ tInvalidated: null,
132
+ };
133
+ }
134
+ /**
135
+ * Return all active (non-invalidated) facts matching the given scope.
136
+ * Optionally filtered by subject and/or predicate.
137
+ * Active = t_invalidated IS NULL.
138
+ */
139
+ getActiveFacts(scope, subject, predicate) {
140
+ if (subject !== undefined && predicate !== undefined) {
141
+ const rows = this.db
142
+ .prepare(`SELECT * FROM semantic_facts
143
+ WHERE scope = ? AND subject = ? AND predicate = ? AND t_invalidated IS NULL`)
144
+ .all(scope, subject, predicate);
145
+ return rows.map(rowToRecord);
146
+ }
147
+ if (subject !== undefined) {
148
+ const rows = this.db
149
+ .prepare(`SELECT * FROM semantic_facts
150
+ WHERE scope = ? AND subject = ? AND t_invalidated IS NULL`)
151
+ .all(scope, subject);
152
+ return rows.map(rowToRecord);
153
+ }
154
+ if (predicate !== undefined) {
155
+ const rows = this.db
156
+ .prepare(`SELECT * FROM semantic_facts
157
+ WHERE scope = ? AND predicate = ? AND t_invalidated IS NULL`)
158
+ .all(scope, predicate);
159
+ return rows.map(rowToRecord);
160
+ }
161
+ const rows = this.db
162
+ .prepare(`SELECT * FROM semantic_facts
163
+ WHERE scope = ? AND t_invalidated IS NULL`)
164
+ .all(scope);
165
+ return rows.map(rowToRecord);
166
+ }
167
+ /**
168
+ * Return a single fact by its id regardless of invalidation status.
169
+ * Returns null if not found.
170
+ */
171
+ getFact(id) {
172
+ const row = this.db
173
+ .prepare(`SELECT * FROM semantic_facts WHERE id = ?`)
174
+ .get(id);
175
+ return row ? rowToRecord(row) : null;
176
+ }
177
+ /**
178
+ * Soft-delete a fact by setting t_invalidated.
179
+ * Returns true if the fact was invalidated, false if it was already invalidated or not found.
180
+ * Never deletes rows.
181
+ */
182
+ invalidateFact(id, tInvalidated) {
183
+ const info = this.db
184
+ .prepare(`UPDATE semantic_facts
185
+ SET t_invalidated = ?
186
+ WHERE id = ? AND t_invalidated IS NULL`)
187
+ .run(tInvalidated, id);
188
+ return info.changes > 0;
189
+ }
190
+ /**
191
+ * Supersede a fact: set BOTH t_invalidated (record-time) AND t_invalid (world-time end).
192
+ * Used by reconcile on UPDATE to carry both bi-temporal closure fields.
193
+ * Returns true if the row was updated; false if not found or already invalidated.
194
+ */
195
+ supersedeFact(id, tInvalidated, tInvalid) {
196
+ const info = this.db
197
+ .prepare(`UPDATE semantic_facts
198
+ SET t_invalidated = ?, t_invalid = ?
199
+ WHERE id = ? AND t_invalidated IS NULL`)
200
+ .run(tInvalidated, tInvalid, id);
201
+ return info.changes > 0;
202
+ }
203
+ /** Close the underlying database connection. */
204
+ close() {
205
+ this.db.close();
206
+ }
207
+ }
208
+ //# sourceMappingURL=facts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facts.js","sourceRoot":"","sources":["../../src/state/facts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,4EAA4E;AAC5E,2EAA2E;AAC3E,qEAAqE;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAGhE,yEAAyE;AAEzE;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAChD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAoBH,yEAAyE;AAEzE;;;;GAIG;AACH,MAAM,UAAU,MAAM,CACpB,KAAa,EACb,OAAe,EACf,SAAiB,EACjB,KAAa,EACb,QAAgB;IAEhB,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,IAAI,SAAS,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;SAC/D,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,yEAAyE;AAEzE;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,SAAkB;IACjE,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE,UAAU,CAAC,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,SAAkB;IAElB,MAAM,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;AACrD,CAAC;AAkBD,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,WAAW,EAAE,GAAG,CAAC,aAAa;QAC9B,MAAM,EAAE,GAAG,CAAC,OAAO;QACnB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,YAAY,EAAE,GAAG,CAAC,aAAa;KAChC,CAAC;AACJ,CAAC;AAED,yEAAyE;AAEzE;;;;;;;;GAQG;AACH,MAAM,OAAO,SAAS;IACZ,EAAE,CAAe;IAEzB,YAAY,MAAc;QACxB,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;KAgBZ,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,KAAgB;QACzB,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM;iBAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;iBACnD,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACzB,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEvF,IAAI,CAAC,EAAE;aACJ,OAAO,CACN;;wDAEgD,CACjD;aACA,GAAG,CACF,EAAE,EACF,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,QAAQ,CACd,CAAC;QAEJ,OAAO;YACL,EAAE;YACF,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,YAAY,EAAE,IAAI;SACnB,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,KAAa,EAAE,OAAgB,EAAE,SAAkB;QAChE,IAAI,OAAO,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YACrD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;iBACjB,OAAO,CACN;uFAC6E,CAC9E;iBACA,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAa,CAAC;YAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;iBACjB,OAAO,CACN;qEAC2D,CAC5D;iBACA,GAAG,CAAC,KAAK,EAAE,OAAO,CAAa,CAAC;YACnC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;iBACjB,OAAO,CACN;uEAC6D,CAC9D;iBACA,GAAG,CAAC,KAAK,EAAE,SAAS,CAAa,CAAC;YACrC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CACN;mDAC2C,CAC5C;aACA,GAAG,CAAC,KAAK,CAAa,CAAC;QAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,EAAU;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,OAAO,CAAC,2CAA2C,CAAC;aACpD,GAAG,CAAC,EAAE,CAAuB,CAAC;QACjC,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvC,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,EAAU,EAAE,YAAoB;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CACN;;gDAEwC,CACzC;aACA,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,EAAU,EAAE,YAAoB,EAAE,QAAgB;QAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CACN;;gDAEwC,CACzC;aACA,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,gDAAgD;IAChD,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Validate that a runId is a safe path segment.
3
+ * Rejects empty strings, strings containing path separators (/ or \),
4
+ * strings containing '..', and absolute paths.
5
+ * This is a security guard: a malicious runId must never escape .bober/runs.
6
+ */
7
+ export declare function safeSegment(runId: string): boolean;
8
+ /**
9
+ * Check whether the run directory exists for the given runId.
10
+ * Returns false if not found — never throws.
11
+ * Mirrors approval-state.ts:pendingExists.
12
+ */
13
+ export declare function hasRunDir(projectRoot: string, runId: string): Promise<boolean>;
14
+ /**
15
+ * Append a guidance entry to .bober/runs/<runId>/guidance.jsonl.
16
+ *
17
+ * Security: validates runId is a safe path segment BEFORE building any path.
18
+ * Throws with a clear message if runId is unsafe (caller should surface to user).
19
+ *
20
+ * Existence: the run directory must already exist (guard with hasRunDir if
21
+ * you want an unknown-run check; appendGuidance itself creates the dir for
22
+ * robustness, but callers in chat-session.ts should guard first for UX).
23
+ */
24
+ export declare function appendGuidance(projectRoot: string, runId: string, text: string): Promise<void>;
25
+ /**
26
+ * Drain pending (unconsumed) guidance entries for a runId.
27
+ *
28
+ * Reads all lines, collects the text of entries where consumed !== true,
29
+ * then atomically rewrites the file with ALL entries marked consumed:true
30
+ * (temp-file + rename, mirrors run-state.ts:41-52).
31
+ *
32
+ * Returns the drained texts in order.
33
+ * Missing file → returns [] (never throws — safe to call on every pipeline sprint).
34
+ * Second drain → returns [] (all entries already marked consumed).
35
+ */
36
+ export declare function drainGuidance(projectRoot: string, runId: string): Promise<string[]>;
37
+ //# sourceMappingURL=guidance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guidance.d.ts","sourceRoot":"","sources":["../../src/state/guidance.ts"],"names":[],"mappings":"AAyCA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CASlD;AAID;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOpF;AAID;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAcf;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CA+CnB"}
@@ -0,0 +1,144 @@
1
+ // ── guidance.ts ───────────────────────────────────────────────────────
2
+ //
3
+ // Disk-persistence helpers for the runId-keyed guidance channel.
4
+ //
5
+ // Layout: .bober/runs/<runId>/guidance.jsonl
6
+ // One JSON object per line: { ts: string, text: string, consumed: boolean }
7
+ //
8
+ // Every drain rewrite is atomic via temp-file + rename
9
+ // (mirrors src/state/run-state.ts:41-52 atomic write pattern).
10
+ import { readFile, writeFile, appendFile, rename, access } from "node:fs/promises";
11
+ import { constants } from "node:fs";
12
+ import { randomBytes } from "node:crypto";
13
+ import { join } from "node:path";
14
+ import { ensureDir } from "./helpers.js";
15
+ // ── Path helpers ──────────────────────────────────────────────────────
16
+ function runsRoot(projectRoot) {
17
+ return join(projectRoot, ".bober", "runs");
18
+ }
19
+ function runDir(projectRoot, runId) {
20
+ return join(runsRoot(projectRoot), runId);
21
+ }
22
+ function guidancePath(projectRoot, runId) {
23
+ return join(runDir(projectRoot, runId), "guidance.jsonl");
24
+ }
25
+ // ── Path-traversal guard ──────────────────────────────────────────────
26
+ /**
27
+ * Validate that a runId is a safe path segment.
28
+ * Rejects empty strings, strings containing path separators (/ or \),
29
+ * strings containing '..', and absolute paths.
30
+ * This is a security guard: a malicious runId must never escape .bober/runs.
31
+ */
32
+ export function safeSegment(runId) {
33
+ if (!runId)
34
+ return false;
35
+ if (runId.includes("/"))
36
+ return false;
37
+ if (runId.includes("\\"))
38
+ return false;
39
+ if (runId.includes(".."))
40
+ return false;
41
+ if (runId.startsWith("."))
42
+ return false;
43
+ // Reject if it looks like an absolute path (Unix or Windows)
44
+ if (runId.startsWith("/") || /^[A-Za-z]:[/\\]/.test(runId))
45
+ return false;
46
+ return true;
47
+ }
48
+ // ── Existence guard ───────────────────────────────────────────────────
49
+ /**
50
+ * Check whether the run directory exists for the given runId.
51
+ * Returns false if not found — never throws.
52
+ * Mirrors approval-state.ts:pendingExists.
53
+ */
54
+ export async function hasRunDir(projectRoot, runId) {
55
+ try {
56
+ await access(runDir(projectRoot, runId), constants.R_OK);
57
+ return true;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ }
63
+ // ── Append ────────────────────────────────────────────────────────────
64
+ /**
65
+ * Append a guidance entry to .bober/runs/<runId>/guidance.jsonl.
66
+ *
67
+ * Security: validates runId is a safe path segment BEFORE building any path.
68
+ * Throws with a clear message if runId is unsafe (caller should surface to user).
69
+ *
70
+ * Existence: the run directory must already exist (guard with hasRunDir if
71
+ * you want an unknown-run check; appendGuidance itself creates the dir for
72
+ * robustness, but callers in chat-session.ts should guard first for UX).
73
+ */
74
+ export async function appendGuidance(projectRoot, runId, text) {
75
+ if (!safeSegment(runId)) {
76
+ throw new Error(`Invalid runId "${runId}": must be a safe path segment (no path separators, no '..').`);
77
+ }
78
+ await ensureDir(runDir(projectRoot, runId));
79
+ const entry = {
80
+ ts: new Date().toISOString(),
81
+ text,
82
+ consumed: false,
83
+ };
84
+ // appendFile is safe for JSONL: each call writes exactly one complete line.
85
+ await appendFile(guidancePath(projectRoot, runId), JSON.stringify(entry) + "\n", "utf-8");
86
+ }
87
+ // ── Drain ─────────────────────────────────────────────────────────────
88
+ /**
89
+ * Drain pending (unconsumed) guidance entries for a runId.
90
+ *
91
+ * Reads all lines, collects the text of entries where consumed !== true,
92
+ * then atomically rewrites the file with ALL entries marked consumed:true
93
+ * (temp-file + rename, mirrors run-state.ts:41-52).
94
+ *
95
+ * Returns the drained texts in order.
96
+ * Missing file → returns [] (never throws — safe to call on every pipeline sprint).
97
+ * Second drain → returns [] (all entries already marked consumed).
98
+ */
99
+ export async function drainGuidance(projectRoot, runId) {
100
+ const filePath = guidancePath(projectRoot, runId);
101
+ let raw;
102
+ try {
103
+ raw = await readFile(filePath, "utf-8");
104
+ }
105
+ catch {
106
+ // File does not exist or is unreadable — return empty (no-op)
107
+ return [];
108
+ }
109
+ const lines = raw.split("\n").filter((l) => l.trim() !== "");
110
+ if (lines.length === 0)
111
+ return [];
112
+ const entries = [];
113
+ const drained = [];
114
+ for (const line of lines) {
115
+ try {
116
+ const entry = JSON.parse(line);
117
+ if (entry.consumed !== true) {
118
+ drained.push(entry.text);
119
+ }
120
+ entries.push({ ...entry, consumed: true });
121
+ }
122
+ catch {
123
+ // Skip malformed lines — do not lose other entries
124
+ }
125
+ }
126
+ if (drained.length === 0) {
127
+ // Nothing unconsumed — still rewrite atomically to normalize the file
128
+ // (all entries stay consumed:true from previous drain)
129
+ const allConsumed = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
130
+ const rnd = randomBytes(4).toString("hex");
131
+ const tmp = `${filePath}.${process.pid}.${Date.now()}.${rnd}.tmp`;
132
+ await writeFile(tmp, allConsumed, { encoding: "utf-8", mode: 0o600 });
133
+ await rename(tmp, filePath);
134
+ return [];
135
+ }
136
+ // Atomically rewrite all entries as consumed
137
+ const rewritten = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
138
+ const rnd = randomBytes(4).toString("hex");
139
+ const tmp = `${filePath}.${process.pid}.${Date.now()}.${rnd}.tmp`;
140
+ await writeFile(tmp, rewritten, { encoding: "utf-8", mode: 0o600 });
141
+ await rename(tmp, filePath);
142
+ return drained;
143
+ }
144
+ //# sourceMappingURL=guidance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guidance.js","sourceRoot":"","sources":["../../src/state/guidance.ts"],"names":[],"mappings":"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"}
@@ -13,13 +13,13 @@ export declare const HistoryEntrySchema: z.ZodObject<{
13
13
  details: Record<string, unknown>;
14
14
  timestamp: string;
15
15
  event: string;
16
- phase: "evaluating" | "failed" | "init" | "planning" | "curating" | "generating" | "rework" | "complete";
16
+ phase: "complete" | "failed" | "init" | "planning" | "curating" | "generating" | "evaluating" | "rework";
17
17
  sprintId?: string | undefined;
18
18
  }, {
19
19
  details: Record<string, unknown>;
20
20
  timestamp: string;
21
21
  event: string;
22
- phase: "evaluating" | "failed" | "init" | "planning" | "curating" | "generating" | "rework" | "complete";
22
+ phase: "complete" | "failed" | "init" | "planning" | "curating" | "generating" | "evaluating" | "rework";
23
23
  sprintId?: string | undefined;
24
24
  }>;
25
25
  export type HistoryEntry = z.infer<typeof HistoryEntrySchema>;
@@ -1,4 +1,4 @@
1
- export { saveContract, loadContract, listContracts, updateContract, } from "./sprint-state.js";
1
+ export { saveContract, loadContract, listContracts, updateContract, clearContractsForSpec, } from "./sprint-state.js";
2
2
  export { saveSpec, loadSpec, loadLatestSpec, listSpecs, } from "./plan-state.js";
3
3
  export { PhaseSchema, HistoryEntrySchema, type Phase, type HistoryEntry, appendHistory, loadHistory, loadRecentHistory, updateProgress, } from "./history.js";
4
4
  export { saveResearch, readResearch, listResearch, } from "./research-state.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAEL,WAAW,EACX,kBAAkB,EAElB,KAAK,KAAK,EACV,KAAK,YAAY,EAEjB,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,GACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,QAAQ,EACR,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAKxB;;;GAGG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAEL,WAAW,EACX,kBAAkB,EAElB,KAAK,KAAK,EACV,KAAK,YAAY,EAEjB,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,GACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,QAAQ,EACR,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAKxB;;;GAGG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvE"}
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { ensureDir } from "./helpers.js";
3
- export { saveContract, loadContract, listContracts, updateContract, } from "./sprint-state.js";
3
+ export { saveContract, loadContract, listContracts, updateContract, clearContractsForSpec, } from "./sprint-state.js";
4
4
  export { saveSpec, loadSpec, loadLatestSpec, listSpecs, } from "./plan-state.js";
5
5
  export {
6
6
  // Zod schemas
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAC;AAEzB,OAAO;AACL,cAAc;AACd,WAAW,EACX,kBAAkB;AAIlB,YAAY;AACZ,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,GACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,QAAQ,EACR,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,GAKd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAExB,MAAM,SAAS,GAAG,QAAQ,CAAC;AAC3B,MAAM,OAAO,GAAG,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAU,CAAC;AAE1J;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAmB;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC/C,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;IAE3B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;IACxC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAC;AAEzB,OAAO;AACL,cAAc;AACd,WAAW,EACX,kBAAkB;AAIlB,YAAY;AACZ,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,GACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,QAAQ,EACR,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,GAKd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAExB,MAAM,SAAS,GAAG,QAAQ,CAAC;AAC3B,MAAM,OAAO,GAAG,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAU,CAAC;AAE1J;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAmB;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC/C,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;IAE3B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;IACxC,CAAC;AACH,CAAC"}
@@ -1,4 +1,36 @@
1
1
  import { z } from "zod";
2
+ /**
3
+ * Resolve the memory directory path for the given namespace.
4
+ *
5
+ * Mapping rule (centralized here — do NOT duplicate in callers):
6
+ * namespace undefined | "" | "programming" → .bober/memory/ (current path, no subdir)
7
+ * any other value → .bober/memory/<ns>/
8
+ *
9
+ * The programming sentinel ("") comes from Sprint 1's built-in team (registry.ts:66).
10
+ * Values are constrained to ^[a-z0-9_-]+$ by the Sprint 1 schema regex, so no
11
+ * path-traversal sanitization is needed here (schema already guards config inputs).
12
+ */
13
+ export declare function memoryDir(projectRoot: string, namespace?: string): string;
14
+ export declare function lessonPath(projectRoot: string, lessonId: string, namespace?: string): string;
15
+ export declare function indexPath(projectRoot: string, namespace?: string): string;
16
+ export declare function quarantinePath(projectRoot: string, namespace?: string): string;
17
+ /**
18
+ * Move lessonId lines from INDEX.md to QUARANTINE.md (line-level rewrite).
19
+ *
20
+ * - Reads INDEX.md and partitions non-blank lines: those whose second token
21
+ * (the lessonId) is in `quarantinedIds` are moved; the rest stay.
22
+ * - Rewrites INDEX.md with the kept lines.
23
+ * - Appends the moved lines to QUARANTINE.md (creating it if absent) with a
24
+ * deterministic provenance block: `<!-- quarantined: <reason> @ <now> -->`.
25
+ * - NEVER touches per-lesson <lessonId>.md files.
26
+ *
27
+ * @param projectRoot - Absolute project root containing .bober/
28
+ * @param quarantinedIds - Set of lessonIds to move out of INDEX.md
29
+ * @param reason - Human-readable reason (e.g. "decay" | "conflict")
30
+ * @param now - ISO 8601 wall-clock, injected by the CLI handler
31
+ * @param namespace - Optional memory namespace
32
+ */
33
+ export declare function rewriteIndexForQuarantine(projectRoot: string, quarantinedIds: Set<string>, reason: string, now: string, namespace?: string): Promise<void>;
2
34
  export declare const LessonEntrySchema: z.ZodObject<{
3
35
  lessonId: z.ZodString;
4
36
  createdAt: z.ZodString;
@@ -9,21 +41,21 @@ export declare const LessonEntrySchema: z.ZodObject<{
9
41
  severity: z.ZodEnum<["info", "warn", "high"]>;
10
42
  sourceEntryRefs: z.ZodArray<z.ZodString, "many">;
11
43
  }, "strip", z.ZodTypeAny, {
12
- severity: "info" | "high" | "warn";
13
- summary: string;
14
- category: string;
15
- createdAt: string;
16
44
  lessonId: string;
45
+ createdAt: string;
46
+ category: string;
17
47
  tags: string[];
48
+ summary: string;
18
49
  occurrences: number;
50
+ severity: "info" | "warn" | "high";
19
51
  sourceEntryRefs: string[];
20
52
  }, {
21
- severity: "info" | "high" | "warn";
22
- summary: string;
23
- category: string;
24
- createdAt: string;
25
53
  lessonId: string;
54
+ createdAt: string;
55
+ category: string;
56
+ summary: string;
26
57
  occurrences: number;
58
+ severity: "info" | "warn" | "high";
27
59
  sourceEntryRefs: string[];
28
60
  tags?: string[] | undefined;
29
61
  }>;
@@ -42,7 +74,7 @@ export interface LessonIndexRecord {
42
74
  * Upserts exactly one INDEX.md line for this lessonId (replace if exists, else append).
43
75
  * Throws if the lesson fails schema validation (sourceEntryRefs must be non-empty).
44
76
  */
45
- export declare function appendLesson(projectRoot: string, lesson: LessonEntry): Promise<void>;
77
+ export declare function appendLesson(projectRoot: string, lesson: LessonEntry, namespace?: string): Promise<void>;
46
78
  /**
47
79
  * Load at most `limit` lesson index records from INDEX.md.
48
80
  * Never opens individual lesson files — parses only INDEX.md.
@@ -50,11 +82,11 @@ export declare function appendLesson(projectRoot: string, lesson: LessonEntry):
50
82
  */
51
83
  export declare function loadLessonIndex(projectRoot: string, { limit }: {
52
84
  limit: number;
53
- }): Promise<LessonIndexRecord[]>;
85
+ }, namespace?: string): Promise<LessonIndexRecord[]>;
54
86
  /**
55
87
  * Load a single lesson by ID from its <lessonId>.md file.
56
88
  * Parses front-matter and validates against LessonEntrySchema.
57
89
  * Throws a descriptive error if the file does not exist or fails validation.
58
90
  */
59
- export declare function loadLesson(projectRoot: string, lessonId: string): Promise<LessonEntry>;
91
+ export declare function loadLesson(projectRoot: string, lessonId: string, namespace?: string): Promise<LessonEntry>;
60
92
  //# sourceMappingURL=memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/state/memory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0BxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AA6ID;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CAkCf;AAID;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAoB9B;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAkCtB"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/state/memory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAKzE;AAID,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5F;AAED,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9E;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAoDf;AAID,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AA6ID;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAkCf;AAID;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAC5B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAoB9B;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,CAAC,CAkCtB"}