looply-cli 0.0.0-stage → 0.3.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 (793) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +137 -3
  3. package/dist/.src-hash +1 -0
  4. package/dist/acceptance-observe.d.ts +108 -0
  5. package/dist/acceptance-observe.d.ts.map +1 -0
  6. package/dist/acceptance-observe.js +152 -0
  7. package/dist/acceptance-observe.js.map +1 -0
  8. package/dist/agent-cmd.d.ts +131 -0
  9. package/dist/agent-cmd.d.ts.map +1 -0
  10. package/dist/agent-cmd.js +154 -0
  11. package/dist/agent-cmd.js.map +1 -0
  12. package/dist/agent-contained.d.ts +114 -0
  13. package/dist/agent-contained.d.ts.map +1 -0
  14. package/dist/agent-contained.js +292 -0
  15. package/dist/agent-contained.js.map +1 -0
  16. package/dist/agent-driver.d.ts +130 -0
  17. package/dist/agent-driver.d.ts.map +1 -0
  18. package/dist/agent-driver.js +170 -0
  19. package/dist/agent-driver.js.map +1 -0
  20. package/dist/agent-envelope.d.ts +94 -0
  21. package/dist/agent-envelope.d.ts.map +1 -0
  22. package/dist/agent-envelope.js +214 -0
  23. package/dist/agent-envelope.js.map +1 -0
  24. package/dist/agent-exec.d.ts +182 -0
  25. package/dist/agent-exec.d.ts.map +1 -0
  26. package/dist/agent-exec.js +125 -0
  27. package/dist/agent-exec.js.map +1 -0
  28. package/dist/agent-runtime.d.ts +23 -0
  29. package/dist/agent-runtime.d.ts.map +1 -0
  30. package/dist/agent-runtime.js +143 -0
  31. package/dist/agent-runtime.js.map +1 -0
  32. package/dist/approval-gate-read.d.ts +66 -0
  33. package/dist/approval-gate-read.d.ts.map +1 -0
  34. package/dist/approval-gate-read.js +138 -0
  35. package/dist/approval-gate-read.js.map +1 -0
  36. package/dist/approval-resolution.d.ts +87 -0
  37. package/dist/approval-resolution.d.ts.map +1 -0
  38. package/dist/approval-resolution.js +100 -0
  39. package/dist/approval-resolution.js.map +1 -0
  40. package/dist/approval-resumes.d.ts +102 -0
  41. package/dist/approval-resumes.d.ts.map +1 -0
  42. package/dist/approval-resumes.js +167 -0
  43. package/dist/approval-resumes.js.map +1 -0
  44. package/dist/ask-brain.d.ts +167 -0
  45. package/dist/ask-brain.d.ts.map +1 -0
  46. package/dist/ask-brain.js +355 -0
  47. package/dist/ask-brain.js.map +1 -0
  48. package/dist/autonomy-authority.d.ts +80 -0
  49. package/dist/autonomy-authority.d.ts.map +1 -0
  50. package/dist/autonomy-authority.js +82 -0
  51. package/dist/autonomy-authority.js.map +1 -0
  52. package/dist/autonomy-controller.d.ts +321 -0
  53. package/dist/autonomy-controller.d.ts.map +1 -0
  54. package/dist/autonomy-controller.js +517 -0
  55. package/dist/autonomy-controller.js.map +1 -0
  56. package/dist/autonomy-store.d.ts +327 -0
  57. package/dist/autonomy-store.d.ts.map +1 -0
  58. package/dist/autonomy-store.js +581 -0
  59. package/dist/autonomy-store.js.map +1 -0
  60. package/dist/autonomy-tick.d.ts +257 -0
  61. package/dist/autonomy-tick.d.ts.map +1 -0
  62. package/dist/autonomy-tick.js +616 -0
  63. package/dist/autonomy-tick.js.map +1 -0
  64. package/dist/bin.d.ts +3 -0
  65. package/dist/bin.d.ts.map +1 -0
  66. package/dist/bin.js +2727 -0
  67. package/dist/bin.js.map +1 -0
  68. package/dist/brain-advice.d.ts +21 -0
  69. package/dist/brain-advice.d.ts.map +1 -0
  70. package/dist/brain-advice.js +51 -0
  71. package/dist/brain-advice.js.map +1 -0
  72. package/dist/candidate-replay-runtime.d.ts +125 -0
  73. package/dist/candidate-replay-runtime.d.ts.map +1 -0
  74. package/dist/candidate-replay-runtime.js +188 -0
  75. package/dist/candidate-replay-runtime.js.map +1 -0
  76. package/dist/checkout-carry.d.ts +76 -0
  77. package/dist/checkout-carry.d.ts.map +1 -0
  78. package/dist/checkout-carry.js +125 -0
  79. package/dist/checkout-carry.js.map +1 -0
  80. package/dist/citation-readers.d.ts +26 -0
  81. package/dist/citation-readers.d.ts.map +1 -0
  82. package/dist/citation-readers.js +102 -0
  83. package/dist/citation-readers.js.map +1 -0
  84. package/dist/command-receipts.d.ts +79 -0
  85. package/dist/command-receipts.d.ts.map +1 -0
  86. package/dist/command-receipts.js +143 -0
  87. package/dist/command-receipts.js.map +1 -0
  88. package/dist/command-runner.d.ts +32 -0
  89. package/dist/command-runner.d.ts.map +1 -0
  90. package/dist/command-runner.js +108 -0
  91. package/dist/command-runner.js.map +1 -0
  92. package/dist/compatible-sets.d.ts +67 -0
  93. package/dist/compatible-sets.d.ts.map +1 -0
  94. package/dist/compatible-sets.js +81 -0
  95. package/dist/compatible-sets.js.map +1 -0
  96. package/dist/compile-check.d.ts +31 -0
  97. package/dist/compile-check.d.ts.map +1 -0
  98. package/dist/compile-check.js +34 -0
  99. package/dist/compile-check.js.map +1 -0
  100. package/dist/compile-store.d.ts +16 -0
  101. package/dist/compile-store.d.ts.map +1 -0
  102. package/dist/compile-store.js +21 -0
  103. package/dist/compile-store.js.map +1 -0
  104. package/dist/completion.d.ts +106 -0
  105. package/dist/completion.d.ts.map +1 -0
  106. package/dist/completion.js +131 -0
  107. package/dist/completion.js.map +1 -0
  108. package/dist/config.d.ts +549 -0
  109. package/dist/config.d.ts.map +1 -0
  110. package/dist/config.js +763 -0
  111. package/dist/config.js.map +1 -0
  112. package/dist/control-file.d.ts +142 -0
  113. package/dist/control-file.d.ts.map +1 -0
  114. package/dist/control-file.js +144 -0
  115. package/dist/control-file.js.map +1 -0
  116. package/dist/coordinator-state.d.ts +131 -0
  117. package/dist/coordinator-state.d.ts.map +1 -0
  118. package/dist/coordinator-state.js +380 -0
  119. package/dist/coordinator-state.js.map +1 -0
  120. package/dist/coordinator.d.ts +95 -0
  121. package/dist/coordinator.d.ts.map +1 -0
  122. package/dist/coordinator.js +97 -0
  123. package/dist/coordinator.js.map +1 -0
  124. package/dist/cursor-store.d.ts +53 -0
  125. package/dist/cursor-store.d.ts.map +1 -0
  126. package/dist/cursor-store.js +98 -0
  127. package/dist/cursor-store.js.map +1 -0
  128. package/dist/daemon-cmd.d.ts +239 -0
  129. package/dist/daemon-cmd.d.ts.map +1 -0
  130. package/dist/daemon-cmd.js +1751 -0
  131. package/dist/daemon-cmd.js.map +1 -0
  132. package/dist/daemon-lock.d.ts +140 -0
  133. package/dist/daemon-lock.d.ts.map +1 -0
  134. package/dist/daemon-lock.js +352 -0
  135. package/dist/daemon-lock.js.map +1 -0
  136. package/dist/daemon-recovery.d.ts +78 -0
  137. package/dist/daemon-recovery.d.ts.map +1 -0
  138. package/dist/daemon-recovery.js +161 -0
  139. package/dist/daemon-recovery.js.map +1 -0
  140. package/dist/daemon.d.ts +368 -0
  141. package/dist/daemon.d.ts.map +1 -0
  142. package/dist/daemon.js +601 -0
  143. package/dist/daemon.js.map +1 -0
  144. package/dist/declared-response-shape.d.ts +93 -0
  145. package/dist/declared-response-shape.d.ts.map +1 -0
  146. package/dist/declared-response-shape.js +200 -0
  147. package/dist/declared-response-shape.js.map +1 -0
  148. package/dist/declared-surfaces.d.ts +16 -0
  149. package/dist/declared-surfaces.d.ts.map +1 -0
  150. package/dist/declared-surfaces.js +19 -0
  151. package/dist/declared-surfaces.js.map +1 -0
  152. package/dist/depends-review.d.ts +113 -0
  153. package/dist/depends-review.d.ts.map +1 -0
  154. package/dist/depends-review.js +110 -0
  155. package/dist/depends-review.js.map +1 -0
  156. package/dist/doctor.d.ts +91 -0
  157. package/dist/doctor.d.ts.map +1 -0
  158. package/dist/doctor.js +71 -0
  159. package/dist/doctor.js.map +1 -0
  160. package/dist/edge-approval.d.ts +105 -0
  161. package/dist/edge-approval.d.ts.map +1 -0
  162. package/dist/edge-approval.js +100 -0
  163. package/dist/edge-approval.js.map +1 -0
  164. package/dist/evidence-cache.d.ts +45 -0
  165. package/dist/evidence-cache.d.ts.map +1 -0
  166. package/dist/evidence-cache.js +90 -0
  167. package/dist/evidence-cache.js.map +1 -0
  168. package/dist/evidence-cmd.d.ts +133 -0
  169. package/dist/evidence-cmd.d.ts.map +1 -0
  170. package/dist/evidence-cmd.js +347 -0
  171. package/dist/evidence-cmd.js.map +1 -0
  172. package/dist/evidence-facts.d.ts +40 -0
  173. package/dist/evidence-facts.d.ts.map +1 -0
  174. package/dist/evidence-facts.js +114 -0
  175. package/dist/evidence-facts.js.map +1 -0
  176. package/dist/exclusive-lock.d.ts +52 -0
  177. package/dist/exclusive-lock.d.ts.map +1 -0
  178. package/dist/exclusive-lock.js +150 -0
  179. package/dist/exclusive-lock.js.map +1 -0
  180. package/dist/exec-domains.d.ts +140 -0
  181. package/dist/exec-domains.d.ts.map +1 -0
  182. package/dist/exec-domains.js +287 -0
  183. package/dist/exec-domains.js.map +1 -0
  184. package/dist/exemption-store.d.ts +197 -0
  185. package/dist/exemption-store.d.ts.map +1 -0
  186. package/dist/exemption-store.js +266 -0
  187. package/dist/exemption-store.js.map +1 -0
  188. package/dist/explicit-start-gate.d.ts +96 -0
  189. package/dist/explicit-start-gate.d.ts.map +1 -0
  190. package/dist/explicit-start-gate.js +103 -0
  191. package/dist/explicit-start-gate.js.map +1 -0
  192. package/dist/fs-trouble.d.ts +70 -0
  193. package/dist/fs-trouble.d.ts.map +1 -0
  194. package/dist/fs-trouble.js +98 -0
  195. package/dist/fs-trouble.js.map +1 -0
  196. package/dist/gate.d.ts +278 -0
  197. package/dist/gate.d.ts.map +1 -0
  198. package/dist/gate.js +278 -0
  199. package/dist/gate.js.map +1 -0
  200. package/dist/git-driver.d.ts +519 -0
  201. package/dist/git-driver.d.ts.map +1 -0
  202. package/dist/git-driver.js +900 -0
  203. package/dist/git-driver.js.map +1 -0
  204. package/dist/git-push-executor.d.ts +41 -0
  205. package/dist/git-push-executor.d.ts.map +1 -0
  206. package/dist/git-push-executor.js +142 -0
  207. package/dist/git-push-executor.js.map +1 -0
  208. package/dist/glob.d.ts +26 -0
  209. package/dist/glob.d.ts.map +1 -0
  210. package/dist/glob.js +93 -0
  211. package/dist/glob.js.map +1 -0
  212. package/dist/goal-adaptive.d.ts +295 -0
  213. package/dist/goal-adaptive.d.ts.map +1 -0
  214. package/dist/goal-adaptive.js +393 -0
  215. package/dist/goal-adaptive.js.map +1 -0
  216. package/dist/goal-compile.d.ts +342 -0
  217. package/dist/goal-compile.d.ts.map +1 -0
  218. package/dist/goal-compile.js +444 -0
  219. package/dist/goal-compile.js.map +1 -0
  220. package/dist/goal-depends-executor.d.ts +55 -0
  221. package/dist/goal-depends-executor.d.ts.map +1 -0
  222. package/dist/goal-depends-executor.js +202 -0
  223. package/dist/goal-depends-executor.js.map +1 -0
  224. package/dist/goal-execution-evidence.d.ts +135 -0
  225. package/dist/goal-execution-evidence.d.ts.map +1 -0
  226. package/dist/goal-execution-evidence.js +159 -0
  227. package/dist/goal-execution-evidence.js.map +1 -0
  228. package/dist/goal-gap.d.ts +140 -0
  229. package/dist/goal-gap.d.ts.map +1 -0
  230. package/dist/goal-gap.js +197 -0
  231. package/dist/goal-gap.js.map +1 -0
  232. package/dist/goal-met-target.d.ts +98 -0
  233. package/dist/goal-met-target.d.ts.map +1 -0
  234. package/dist/goal-met-target.js +92 -0
  235. package/dist/goal-met-target.js.map +1 -0
  236. package/dist/goal-ownership.d.ts +416 -0
  237. package/dist/goal-ownership.d.ts.map +1 -0
  238. package/dist/goal-ownership.js +576 -0
  239. package/dist/goal-ownership.js.map +1 -0
  240. package/dist/goal-runs.d.ts +82 -0
  241. package/dist/goal-runs.d.ts.map +1 -0
  242. package/dist/goal-runs.js +120 -0
  243. package/dist/goal-runs.js.map +1 -0
  244. package/dist/goal-store.d.ts +146 -0
  245. package/dist/goal-store.d.ts.map +1 -0
  246. package/dist/goal-store.js +294 -0
  247. package/dist/goal-store.js.map +1 -0
  248. package/dist/goal-view.d.ts +156 -0
  249. package/dist/goal-view.d.ts.map +1 -0
  250. package/dist/goal-view.js +499 -0
  251. package/dist/goal-view.js.map +1 -0
  252. package/dist/governed-approvals.d.ts +152 -0
  253. package/dist/governed-approvals.d.ts.map +1 -0
  254. package/dist/governed-approvals.js +246 -0
  255. package/dist/governed-approvals.js.map +1 -0
  256. package/dist/governed-broker.d.ts +169 -0
  257. package/dist/governed-broker.d.ts.map +1 -0
  258. package/dist/governed-broker.js +196 -0
  259. package/dist/governed-broker.js.map +1 -0
  260. package/dist/governed-run.d.ts +220 -0
  261. package/dist/governed-run.d.ts.map +1 -0
  262. package/dist/governed-run.js +406 -0
  263. package/dist/governed-run.js.map +1 -0
  264. package/dist/grant-reconcile.d.ts +63 -0
  265. package/dist/grant-reconcile.d.ts.map +1 -0
  266. package/dist/grant-reconcile.js +121 -0
  267. package/dist/grant-reconcile.js.map +1 -0
  268. package/dist/index-for-head.d.ts +56 -0
  269. package/dist/index-for-head.d.ts.map +1 -0
  270. package/dist/index-for-head.js +103 -0
  271. package/dist/index-for-head.js.map +1 -0
  272. package/dist/index.d.ts +39 -0
  273. package/dist/index.d.ts.map +1 -0
  274. package/dist/index.js +55 -0
  275. package/dist/index.js.map +1 -0
  276. package/dist/init-detect.d.ts +39 -0
  277. package/dist/init-detect.d.ts.map +1 -0
  278. package/dist/init-detect.js +188 -0
  279. package/dist/init-detect.js.map +1 -0
  280. package/dist/integration-deps.d.ts +62 -0
  281. package/dist/integration-deps.d.ts.map +1 -0
  282. package/dist/integration-deps.js +251 -0
  283. package/dist/integration-deps.js.map +1 -0
  284. package/dist/integration-runtime.d.ts +458 -0
  285. package/dist/integration-runtime.d.ts.map +1 -0
  286. package/dist/integration-runtime.js +681 -0
  287. package/dist/integration-runtime.js.map +1 -0
  288. package/dist/integration.d.ts +45 -0
  289. package/dist/integration.d.ts.map +1 -0
  290. package/dist/integration.js +87 -0
  291. package/dist/integration.js.map +1 -0
  292. package/dist/integrator.d.ts +84 -0
  293. package/dist/integrator.d.ts.map +1 -0
  294. package/dist/integrator.js +193 -0
  295. package/dist/integrator.js.map +1 -0
  296. package/dist/lane-claims.d.ts +174 -0
  297. package/dist/lane-claims.d.ts.map +1 -0
  298. package/dist/lane-claims.js +218 -0
  299. package/dist/lane-claims.js.map +1 -0
  300. package/dist/lane-coverage.d.ts +87 -0
  301. package/dist/lane-coverage.d.ts.map +1 -0
  302. package/dist/lane-coverage.js +129 -0
  303. package/dist/lane-coverage.js.map +1 -0
  304. package/dist/ledger-replay.d.ts +115 -0
  305. package/dist/ledger-replay.d.ts.map +1 -0
  306. package/dist/ledger-replay.js +155 -0
  307. package/dist/ledger-replay.js.map +1 -0
  308. package/dist/ledger-store.d.ts +68 -0
  309. package/dist/ledger-store.d.ts.map +1 -0
  310. package/dist/ledger-store.js +111 -0
  311. package/dist/ledger-store.js.map +1 -0
  312. package/dist/loop-safety-observer.d.ts +132 -0
  313. package/dist/loop-safety-observer.d.ts.map +1 -0
  314. package/dist/loop-safety-observer.js +76 -0
  315. package/dist/loop-safety-observer.js.map +1 -0
  316. package/dist/loop-safety-store.d.ts +339 -0
  317. package/dist/loop-safety-store.d.ts.map +1 -0
  318. package/dist/loop-safety-store.js +800 -0
  319. package/dist/loop-safety-store.js.map +1 -0
  320. package/dist/machine-store.d.ts +54 -0
  321. package/dist/machine-store.d.ts.map +1 -0
  322. package/dist/machine-store.js +149 -0
  323. package/dist/machine-store.js.map +1 -0
  324. package/dist/mcp-main.d.ts +2 -0
  325. package/dist/mcp-main.d.ts.map +1 -0
  326. package/dist/mcp-main.js +116 -0
  327. package/dist/mcp-main.js.map +1 -0
  328. package/dist/mcp-server.d.ts +72 -0
  329. package/dist/mcp-server.d.ts.map +1 -0
  330. package/dist/mcp-server.js +259 -0
  331. package/dist/mcp-server.js.map +1 -0
  332. package/dist/model-routing.d.ts +75 -0
  333. package/dist/model-routing.d.ts.map +1 -0
  334. package/dist/model-routing.js +108 -0
  335. package/dist/model-routing.js.map +1 -0
  336. package/dist/model-transport.d.ts +188 -0
  337. package/dist/model-transport.d.ts.map +1 -0
  338. package/dist/model-transport.js +625 -0
  339. package/dist/model-transport.js.map +1 -0
  340. package/dist/notify-cadence.d.ts +55 -0
  341. package/dist/notify-cadence.d.ts.map +1 -0
  342. package/dist/notify-cadence.js +68 -0
  343. package/dist/notify-cadence.js.map +1 -0
  344. package/dist/notify-channel.d.ts +69 -0
  345. package/dist/notify-channel.d.ts.map +1 -0
  346. package/dist/notify-channel.js +151 -0
  347. package/dist/notify-channel.js.map +1 -0
  348. package/dist/notify.d.ts +71 -0
  349. package/dist/notify.d.ts.map +1 -0
  350. package/dist/notify.js +125 -0
  351. package/dist/notify.js.map +1 -0
  352. package/dist/observation-inventory.d.ts +65 -0
  353. package/dist/observation-inventory.d.ts.map +1 -0
  354. package/dist/observation-inventory.js +139 -0
  355. package/dist/observation-inventory.js.map +1 -0
  356. package/dist/owned-children.d.ts +45 -0
  357. package/dist/owned-children.d.ts.map +1 -0
  358. package/dist/owned-children.js +64 -0
  359. package/dist/owned-children.js.map +1 -0
  360. package/dist/packet-for-goal.d.ts +19 -0
  361. package/dist/packet-for-goal.d.ts.map +1 -0
  362. package/dist/packet-for-goal.js +32 -0
  363. package/dist/packet-for-goal.js.map +1 -0
  364. package/dist/pair-cmd.d.ts +85 -0
  365. package/dist/pair-cmd.d.ts.map +1 -0
  366. package/dist/pair-cmd.js +205 -0
  367. package/dist/pair-cmd.js.map +1 -0
  368. package/dist/partial-asker.d.ts +96 -0
  369. package/dist/partial-asker.d.ts.map +1 -0
  370. package/dist/partial-asker.js +117 -0
  371. package/dist/partial-asker.js.map +1 -0
  372. package/dist/pdf-text-lines.d.ts +17 -0
  373. package/dist/pdf-text-lines.d.ts.map +1 -0
  374. package/dist/pdf-text-lines.js +70 -0
  375. package/dist/pdf-text-lines.js.map +1 -0
  376. package/dist/pdf-text-worker.d.ts +2 -0
  377. package/dist/pdf-text-worker.d.ts.map +1 -0
  378. package/dist/pdf-text-worker.js +81 -0
  379. package/dist/pdf-text-worker.js.map +1 -0
  380. package/dist/pdf-text.d.ts +56 -0
  381. package/dist/pdf-text.d.ts.map +1 -0
  382. package/dist/pdf-text.js +64 -0
  383. package/dist/pdf-text.js.map +1 -0
  384. package/dist/pending-action.d.ts +154 -0
  385. package/dist/pending-action.d.ts.map +1 -0
  386. package/dist/pending-action.js +148 -0
  387. package/dist/pending-action.js.map +1 -0
  388. package/dist/preemptor.d.ts +40 -0
  389. package/dist/preemptor.d.ts.map +1 -0
  390. package/dist/preemptor.js +49 -0
  391. package/dist/preemptor.js.map +1 -0
  392. package/dist/programme-mode.d.ts +29 -0
  393. package/dist/programme-mode.d.ts.map +1 -0
  394. package/dist/programme-mode.js +50 -0
  395. package/dist/programme-mode.js.map +1 -0
  396. package/dist/progress-view.d.ts +14 -0
  397. package/dist/progress-view.d.ts.map +1 -0
  398. package/dist/progress-view.js +114 -0
  399. package/dist/progress-view.js.map +1 -0
  400. package/dist/project-graph-builder.d.ts +81 -0
  401. package/dist/project-graph-builder.d.ts.map +1 -0
  402. package/dist/project-graph-builder.js +246 -0
  403. package/dist/project-graph-builder.js.map +1 -0
  404. package/dist/project-graph-runtime.d.ts +86 -0
  405. package/dist/project-graph-runtime.d.ts.map +1 -0
  406. package/dist/project-graph-runtime.js +112 -0
  407. package/dist/project-graph-runtime.js.map +1 -0
  408. package/dist/project-index-builder.d.ts +96 -0
  409. package/dist/project-index-builder.d.ts.map +1 -0
  410. package/dist/project-index-builder.js +298 -0
  411. package/dist/project-index-builder.js.map +1 -0
  412. package/dist/project-index-facts.d.ts +51 -0
  413. package/dist/project-index-facts.d.ts.map +1 -0
  414. package/dist/project-index-facts.js +117 -0
  415. package/dist/project-index-facts.js.map +1 -0
  416. package/dist/project-index-store.d.ts +97 -0
  417. package/dist/project-index-store.d.ts.map +1 -0
  418. package/dist/project-index-store.js +140 -0
  419. package/dist/project-index-store.js.map +1 -0
  420. package/dist/project-memory-store.d.ts +127 -0
  421. package/dist/project-memory-store.d.ts.map +1 -0
  422. package/dist/project-memory-store.js +302 -0
  423. package/dist/project-memory-store.js.map +1 -0
  424. package/dist/proposal-store.d.ts +14 -0
  425. package/dist/proposal-store.d.ts.map +1 -0
  426. package/dist/proposal-store.js +19 -0
  427. package/dist/proposal-store.js.map +1 -0
  428. package/dist/prover.d.ts +80 -0
  429. package/dist/prover.d.ts.map +1 -0
  430. package/dist/prover.js +137 -0
  431. package/dist/prover.js.map +1 -0
  432. package/dist/provider-identity-store.d.ts +34 -0
  433. package/dist/provider-identity-store.d.ts.map +1 -0
  434. package/dist/provider-identity-store.js +72 -0
  435. package/dist/provider-identity-store.js.map +1 -0
  436. package/dist/provider-identity.d.ts +104 -0
  437. package/dist/provider-identity.d.ts.map +1 -0
  438. package/dist/provider-identity.js +167 -0
  439. package/dist/provider-identity.js.map +1 -0
  440. package/dist/provider-limit.d.ts +79 -0
  441. package/dist/provider-limit.d.ts.map +1 -0
  442. package/dist/provider-limit.js +148 -0
  443. package/dist/provider-limit.js.map +1 -0
  444. package/dist/provider-preflight.d.ts +171 -0
  445. package/dist/provider-preflight.d.ts.map +1 -0
  446. package/dist/provider-preflight.js +395 -0
  447. package/dist/provider-preflight.js.map +1 -0
  448. package/dist/provider-state.d.ts +120 -0
  449. package/dist/provider-state.d.ts.map +1 -0
  450. package/dist/provider-state.js +182 -0
  451. package/dist/provider-state.js.map +1 -0
  452. package/dist/providers.d.ts +132 -0
  453. package/dist/providers.d.ts.map +1 -0
  454. package/dist/providers.js +161 -0
  455. package/dist/providers.js.map +1 -0
  456. package/dist/publication-recorder.d.ts +117 -0
  457. package/dist/publication-recorder.d.ts.map +1 -0
  458. package/dist/publication-recorder.js +124 -0
  459. package/dist/publication-recorder.js.map +1 -0
  460. package/dist/pursuit-delivery.d.ts +24 -0
  461. package/dist/pursuit-delivery.d.ts.map +1 -0
  462. package/dist/pursuit-delivery.js +38 -0
  463. package/dist/pursuit-delivery.js.map +1 -0
  464. package/dist/queue-store.d.ts +132 -0
  465. package/dist/queue-store.d.ts.map +1 -0
  466. package/dist/queue-store.js +185 -0
  467. package/dist/queue-store.js.map +1 -0
  468. package/dist/queue-summary.d.ts +14 -0
  469. package/dist/queue-summary.d.ts.map +1 -0
  470. package/dist/queue-summary.js +82 -0
  471. package/dist/queue-summary.js.map +1 -0
  472. package/dist/queue-view.d.ts +20 -0
  473. package/dist/queue-view.d.ts.map +1 -0
  474. package/dist/queue-view.js +163 -0
  475. package/dist/queue-view.js.map +1 -0
  476. package/dist/queue-write-lease.d.ts +106 -0
  477. package/dist/queue-write-lease.d.ts.map +1 -0
  478. package/dist/queue-write-lease.js +282 -0
  479. package/dist/queue-write-lease.js.map +1 -0
  480. package/dist/rails-home.d.ts +162 -0
  481. package/dist/rails-home.d.ts.map +1 -0
  482. package/dist/rails-home.js +452 -0
  483. package/dist/rails-home.js.map +1 -0
  484. package/dist/rails-migrations.d.ts +75 -0
  485. package/dist/rails-migrations.d.ts.map +1 -0
  486. package/dist/rails-migrations.js +199 -0
  487. package/dist/rails-migrations.js.map +1 -0
  488. package/dist/rails-stores.d.ts +49 -0
  489. package/dist/rails-stores.d.ts.map +1 -0
  490. package/dist/rails-stores.js +100 -0
  491. package/dist/rails-stores.js.map +1 -0
  492. package/dist/reaper.d.ts +69 -0
  493. package/dist/reaper.d.ts.map +1 -0
  494. package/dist/reaper.js +152 -0
  495. package/dist/reaper.js.map +1 -0
  496. package/dist/record-store.d.ts +36 -0
  497. package/dist/record-store.d.ts.map +1 -0
  498. package/dist/record-store.js +78 -0
  499. package/dist/record-store.js.map +1 -0
  500. package/dist/recovery-io.d.ts +50 -0
  501. package/dist/recovery-io.d.ts.map +1 -0
  502. package/dist/recovery-io.js +122 -0
  503. package/dist/recovery-io.js.map +1 -0
  504. package/dist/recovery.d.ts +146 -0
  505. package/dist/recovery.d.ts.map +1 -0
  506. package/dist/recovery.js +110 -0
  507. package/dist/recovery.js.map +1 -0
  508. package/dist/redraw.d.ts +34 -0
  509. package/dist/redraw.d.ts.map +1 -0
  510. package/dist/redraw.js +62 -0
  511. package/dist/redraw.js.map +1 -0
  512. package/dist/rejected-evidence.d.ts +255 -0
  513. package/dist/rejected-evidence.d.ts.map +1 -0
  514. package/dist/rejected-evidence.js +324 -0
  515. package/dist/rejected-evidence.js.map +1 -0
  516. package/dist/report-cmd.d.ts +32 -0
  517. package/dist/report-cmd.d.ts.map +1 -0
  518. package/dist/report-cmd.js +201 -0
  519. package/dist/report-cmd.js.map +1 -0
  520. package/dist/repos-cmd.d.ts +80 -0
  521. package/dist/repos-cmd.d.ts.map +1 -0
  522. package/dist/repos-cmd.js +240 -0
  523. package/dist/repos-cmd.js.map +1 -0
  524. package/dist/request-body-shape.d.ts +93 -0
  525. package/dist/request-body-shape.d.ts.map +1 -0
  526. package/dist/request-body-shape.js +407 -0
  527. package/dist/request-body-shape.js.map +1 -0
  528. package/dist/requirement-claims.d.ts +89 -0
  529. package/dist/requirement-claims.d.ts.map +1 -0
  530. package/dist/requirement-claims.js +92 -0
  531. package/dist/requirement-claims.js.map +1 -0
  532. package/dist/retention-apply-runtime.d.ts +105 -0
  533. package/dist/retention-apply-runtime.d.ts.map +1 -0
  534. package/dist/retention-apply-runtime.js +269 -0
  535. package/dist/retention-apply-runtime.js.map +1 -0
  536. package/dist/reverify.d.ts +41 -0
  537. package/dist/reverify.d.ts.map +1 -0
  538. package/dist/reverify.js +69 -0
  539. package/dist/reverify.js.map +1 -0
  540. package/dist/round-records.d.ts +65 -0
  541. package/dist/round-records.d.ts.map +1 -0
  542. package/dist/round-records.js +61 -0
  543. package/dist/round-records.js.map +1 -0
  544. package/dist/round-runner.d.ts +924 -0
  545. package/dist/round-runner.d.ts.map +1 -0
  546. package/dist/round-runner.js +1693 -0
  547. package/dist/round-runner.js.map +1 -0
  548. package/dist/run-approval.d.ts +180 -0
  549. package/dist/run-approval.d.ts.map +1 -0
  550. package/dist/run-approval.js +199 -0
  551. package/dist/run-approval.js.map +1 -0
  552. package/dist/run-cmd.d.ts +359 -0
  553. package/dist/run-cmd.d.ts.map +1 -0
  554. package/dist/run-cmd.js +4418 -0
  555. package/dist/run-cmd.js.map +1 -0
  556. package/dist/run-delivery.d.ts +71 -0
  557. package/dist/run-delivery.d.ts.map +1 -0
  558. package/dist/run-delivery.js +104 -0
  559. package/dist/run-delivery.js.map +1 -0
  560. package/dist/run-ended.d.ts +75 -0
  561. package/dist/run-ended.d.ts.map +1 -0
  562. package/dist/run-ended.js +27 -0
  563. package/dist/run-ended.js.map +1 -0
  564. package/dist/run-ending-locator.d.ts +125 -0
  565. package/dist/run-ending-locator.d.ts.map +1 -0
  566. package/dist/run-ending-locator.js +133 -0
  567. package/dist/run-ending-locator.js.map +1 -0
  568. package/dist/run-launcher.d.ts +459 -0
  569. package/dist/run-launcher.d.ts.map +1 -0
  570. package/dist/run-launcher.js +652 -0
  571. package/dist/run-launcher.js.map +1 -0
  572. package/dist/run-lease.d.ts +208 -0
  573. package/dist/run-lease.d.ts.map +1 -0
  574. package/dist/run-lease.js +301 -0
  575. package/dist/run-lease.js.map +1 -0
  576. package/dist/run-refusal-marks.d.ts +189 -0
  577. package/dist/run-refusal-marks.d.ts.map +1 -0
  578. package/dist/run-refusal-marks.js +249 -0
  579. package/dist/run-refusal-marks.js.map +1 -0
  580. package/dist/run-start-marks.d.ts +153 -0
  581. package/dist/run-start-marks.d.ts.map +1 -0
  582. package/dist/run-start-marks.js +269 -0
  583. package/dist/run-start-marks.js.map +1 -0
  584. package/dist/scan-cmd.d.ts +14 -0
  585. package/dist/scan-cmd.d.ts.map +1 -0
  586. package/dist/scan-cmd.js +270 -0
  587. package/dist/scan-cmd.js.map +1 -0
  588. package/dist/scan-events.d.ts +50 -0
  589. package/dist/scan-events.d.ts.map +1 -0
  590. package/dist/scan-events.js +91 -0
  591. package/dist/scan-events.js.map +1 -0
  592. package/dist/scan.d.ts +191 -0
  593. package/dist/scan.d.ts.map +1 -0
  594. package/dist/scan.js +417 -0
  595. package/dist/scan.js.map +1 -0
  596. package/dist/scope-rule.d.ts +148 -0
  597. package/dist/scope-rule.d.ts.map +1 -0
  598. package/dist/scope-rule.js +121 -0
  599. package/dist/scope-rule.js.map +1 -0
  600. package/dist/self-repo-id.d.ts +18 -0
  601. package/dist/self-repo-id.d.ts.map +1 -0
  602. package/dist/self-repo-id.js +70 -0
  603. package/dist/self-repo-id.js.map +1 -0
  604. package/dist/serve-cmd.d.ts +115 -0
  605. package/dist/serve-cmd.d.ts.map +1 -0
  606. package/dist/serve-cmd.js +505 -0
  607. package/dist/serve-cmd.js.map +1 -0
  608. package/dist/serve.d.ts +167 -0
  609. package/dist/serve.d.ts.map +1 -0
  610. package/dist/serve.js +336 -0
  611. package/dist/serve.js.map +1 -0
  612. package/dist/server-client.d.ts +766 -0
  613. package/dist/server-client.d.ts.map +1 -0
  614. package/dist/server-client.js +475 -0
  615. package/dist/server-client.js.map +1 -0
  616. package/dist/session-adapter-runtime.d.ts +195 -0
  617. package/dist/session-adapter-runtime.d.ts.map +1 -0
  618. package/dist/session-adapter-runtime.js +373 -0
  619. package/dist/session-adapter-runtime.js.map +1 -0
  620. package/dist/session-checkpoint-runtime.d.ts +62 -0
  621. package/dist/session-checkpoint-runtime.d.ts.map +1 -0
  622. package/dist/session-checkpoint-runtime.js +268 -0
  623. package/dist/session-checkpoint-runtime.js.map +1 -0
  624. package/dist/session-control-transport.d.ts +106 -0
  625. package/dist/session-control-transport.d.ts.map +1 -0
  626. package/dist/session-control-transport.js +232 -0
  627. package/dist/session-control-transport.js.map +1 -0
  628. package/dist/session-observation-store.d.ts +98 -0
  629. package/dist/session-observation-store.d.ts.map +1 -0
  630. package/dist/session-observation-store.js +155 -0
  631. package/dist/session-observation-store.js.map +1 -0
  632. package/dist/session-observe-runtime.d.ts +123 -0
  633. package/dist/session-observe-runtime.d.ts.map +1 -0
  634. package/dist/session-observe-runtime.js +317 -0
  635. package/dist/session-observe-runtime.js.map +1 -0
  636. package/dist/session-store.d.ts +98 -0
  637. package/dist/session-store.d.ts.map +1 -0
  638. package/dist/session-store.js +116 -0
  639. package/dist/session-store.js.map +1 -0
  640. package/dist/sessions-cmd.d.ts +202 -0
  641. package/dist/sessions-cmd.d.ts.map +1 -0
  642. package/dist/sessions-cmd.js +609 -0
  643. package/dist/sessions-cmd.js.map +1 -0
  644. package/dist/settings-overlay.d.ts +53 -0
  645. package/dist/settings-overlay.d.ts.map +1 -0
  646. package/dist/settings-overlay.js +175 -0
  647. package/dist/settings-overlay.js.map +1 -0
  648. package/dist/setup-prompt.d.ts +34 -0
  649. package/dist/setup-prompt.d.ts.map +1 -0
  650. package/dist/setup-prompt.js +92 -0
  651. package/dist/setup-prompt.js.map +1 -0
  652. package/dist/setup.d.ts +103 -0
  653. package/dist/setup.d.ts.map +1 -0
  654. package/dist/setup.js +283 -0
  655. package/dist/setup.js.map +1 -0
  656. package/dist/shared-grants.d.ts +164 -0
  657. package/dist/shared-grants.d.ts.map +1 -0
  658. package/dist/shared-grants.js +242 -0
  659. package/dist/shared-grants.js.map +1 -0
  660. package/dist/signals.d.ts +55 -0
  661. package/dist/signals.d.ts.map +1 -0
  662. package/dist/signals.js +85 -0
  663. package/dist/signals.js.map +1 -0
  664. package/dist/source-cmd.d.ts +201 -0
  665. package/dist/source-cmd.d.ts.map +1 -0
  666. package/dist/source-cmd.js +684 -0
  667. package/dist/source-cmd.js.map +1 -0
  668. package/dist/source-verdict.d.ts +99 -0
  669. package/dist/source-verdict.d.ts.map +1 -0
  670. package/dist/source-verdict.js +182 -0
  671. package/dist/source-verdict.js.map +1 -0
  672. package/dist/spend-ledger.d.ts +350 -0
  673. package/dist/spend-ledger.d.ts.map +1 -0
  674. package/dist/spend-ledger.js +546 -0
  675. package/dist/spend-ledger.js.map +1 -0
  676. package/dist/stale-run-sweep.d.ts +79 -0
  677. package/dist/stale-run-sweep.d.ts.map +1 -0
  678. package/dist/stale-run-sweep.js +116 -0
  679. package/dist/stale-run-sweep.js.map +1 -0
  680. package/dist/start-attempts.d.ts +385 -0
  681. package/dist/start-attempts.d.ts.map +1 -0
  682. package/dist/start-attempts.js +613 -0
  683. package/dist/start-attempts.js.map +1 -0
  684. package/dist/status-cmd.d.ts +28 -0
  685. package/dist/status-cmd.d.ts.map +1 -0
  686. package/dist/status-cmd.js +116 -0
  687. package/dist/status-cmd.js.map +1 -0
  688. package/dist/stop-follow-up.d.ts +107 -0
  689. package/dist/stop-follow-up.d.ts.map +1 -0
  690. package/dist/stop-follow-up.js +172 -0
  691. package/dist/stop-follow-up.js.map +1 -0
  692. package/dist/surface-lease.d.ts +118 -0
  693. package/dist/surface-lease.d.ts.map +1 -0
  694. package/dist/surface-lease.js +485 -0
  695. package/dist/surface-lease.js.map +1 -0
  696. package/dist/sync.d.ts +54 -0
  697. package/dist/sync.d.ts.map +1 -0
  698. package/dist/sync.js +93 -0
  699. package/dist/sync.js.map +1 -0
  700. package/dist/syncing-ledger.d.ts +45 -0
  701. package/dist/syncing-ledger.d.ts.map +1 -0
  702. package/dist/syncing-ledger.js +53 -0
  703. package/dist/syncing-ledger.js.map +1 -0
  704. package/dist/temp-fixtures.d.ts +68 -0
  705. package/dist/temp-fixtures.d.ts.map +1 -0
  706. package/dist/temp-fixtures.js +38 -0
  707. package/dist/temp-fixtures.js.map +1 -0
  708. package/dist/token-window.d.ts +84 -0
  709. package/dist/token-window.d.ts.map +1 -0
  710. package/dist/token-window.js +143 -0
  711. package/dist/token-window.js.map +1 -0
  712. package/dist/tool-bridge.d.ts +177 -0
  713. package/dist/tool-bridge.d.ts.map +1 -0
  714. package/dist/tool-bridge.js +329 -0
  715. package/dist/tool-bridge.js.map +1 -0
  716. package/dist/tool-call-record.d.ts +197 -0
  717. package/dist/tool-call-record.d.ts.map +1 -0
  718. package/dist/tool-call-record.js +276 -0
  719. package/dist/tool-call-record.js.map +1 -0
  720. package/dist/tool-protocol.d.ts +135 -0
  721. package/dist/tool-protocol.d.ts.map +1 -0
  722. package/dist/tool-protocol.js +104 -0
  723. package/dist/tool-protocol.js.map +1 -0
  724. package/dist/tool-worker.d.ts +3 -0
  725. package/dist/tool-worker.d.ts.map +1 -0
  726. package/dist/tool-worker.js +478 -0
  727. package/dist/tool-worker.js.map +1 -0
  728. package/dist/toolchain-mirror.d.ts +86 -0
  729. package/dist/toolchain-mirror.d.ts.map +1 -0
  730. package/dist/toolchain-mirror.js +307 -0
  731. package/dist/toolchain-mirror.js.map +1 -0
  732. package/dist/trusted-git.d.ts +243 -0
  733. package/dist/trusted-git.d.ts.map +1 -0
  734. package/dist/trusted-git.js +920 -0
  735. package/dist/trusted-git.js.map +1 -0
  736. package/dist/ui.d.ts +76 -0
  737. package/dist/ui.d.ts.map +1 -0
  738. package/dist/ui.js +118 -0
  739. package/dist/ui.js.map +1 -0
  740. package/dist/untrusted-exec.d.ts +275 -0
  741. package/dist/untrusted-exec.d.ts.map +1 -0
  742. package/dist/untrusted-exec.js +479 -0
  743. package/dist/untrusted-exec.js.map +1 -0
  744. package/dist/untrusted-gate.d.ts +73 -0
  745. package/dist/untrusted-gate.d.ts.map +1 -0
  746. package/dist/untrusted-gate.js +226 -0
  747. package/dist/untrusted-gate.js.map +1 -0
  748. package/dist/uploader.d.ts +153 -0
  749. package/dist/uploader.d.ts.map +1 -0
  750. package/dist/uploader.js +204 -0
  751. package/dist/uploader.js.map +1 -0
  752. package/dist/verifier.d.ts +66 -0
  753. package/dist/verifier.d.ts.map +1 -0
  754. package/dist/verifier.js +170 -0
  755. package/dist/verifier.js.map +1 -0
  756. package/dist/verify-apply.d.ts +26 -0
  757. package/dist/verify-apply.d.ts.map +1 -0
  758. package/dist/verify-apply.js +36 -0
  759. package/dist/verify-apply.js.map +1 -0
  760. package/dist/verify-cmd.d.ts +44 -0
  761. package/dist/verify-cmd.d.ts.map +1 -0
  762. package/dist/verify-cmd.js +125 -0
  763. package/dist/verify-cmd.js.map +1 -0
  764. package/dist/verify-pass.d.ts +73 -0
  765. package/dist/verify-pass.d.ts.map +1 -0
  766. package/dist/verify-pass.js +103 -0
  767. package/dist/verify-pass.js.map +1 -0
  768. package/dist/welcome.d.ts +43 -0
  769. package/dist/welcome.d.ts.map +1 -0
  770. package/dist/welcome.js +116 -0
  771. package/dist/welcome.js.map +1 -0
  772. package/dist/workspace-provisioner.d.ts +65 -0
  773. package/dist/workspace-provisioner.d.ts.map +1 -0
  774. package/dist/workspace-provisioner.js +66 -0
  775. package/dist/workspace-provisioner.js.map +1 -0
  776. package/dist/workspace-quarantine.d.ts +64 -0
  777. package/dist/workspace-quarantine.d.ts.map +1 -0
  778. package/dist/workspace-quarantine.js +156 -0
  779. package/dist/workspace-quarantine.js.map +1 -0
  780. package/dist/workspace-residue-sweep.d.ts +113 -0
  781. package/dist/workspace-residue-sweep.d.ts.map +1 -0
  782. package/dist/workspace-residue-sweep.js +158 -0
  783. package/dist/workspace-residue-sweep.js.map +1 -0
  784. package/dist/workspace.d.ts +639 -0
  785. package/dist/workspace.d.ts.map +1 -0
  786. package/dist/workspace.js +2026 -0
  787. package/dist/workspace.js.map +1 -0
  788. package/package.json +52 -4
  789. package/win/CredProbe.cs +64 -0
  790. package/win/FakeClaude.cs +56 -0
  791. package/win/HandleProbe.cs +116 -0
  792. package/win/TokenProbe.cs +53 -0
  793. package/win/appcontainer.ps1 +500 -0
@@ -0,0 +1,800 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.nodeSafetyFs = exports.LoopSafetyStore = void 0;
37
+ const core_1 = require("@looply/core");
38
+ function isObservation(v) {
39
+ if (typeof v !== 'object' || v === null)
40
+ return false;
41
+ const o = v;
42
+ return (typeof o['goalId'] === 'string' &&
43
+ typeof o['goalVersion'] === 'number' &&
44
+ typeof o['ordinal'] === 'number' &&
45
+ typeof o['outcome'] === 'string' &&
46
+ typeof o['progressFingerprint'] === 'string');
47
+ }
48
+ function isIncident(v) {
49
+ if (typeof v !== 'object' || v === null)
50
+ return false;
51
+ const o = v;
52
+ return (typeof o['id'] === 'string' &&
53
+ typeof o['goalId'] === 'string' &&
54
+ typeof o['goalVersion'] === 'number' &&
55
+ typeof o['kind'] === 'string' &&
56
+ typeof o['because'] === 'string');
57
+ }
58
+ class LoopSafetyStore {
59
+ stateDir;
60
+ fs;
61
+ now;
62
+ migrate;
63
+ /** Distinguishes two writes from ONE process; the pid distinguishes processes. */
64
+ static writes = 0;
65
+ observations = [];
66
+ incidents = [];
67
+ state = 'ok';
68
+ opened = false;
69
+ /**
70
+ * ⚠️ `migrate` RUNS BEFORE ANY READ, AND ITS REFUSAL LEAVES THE STORE
71
+ * UNREADABLE — which is a REFUSAL TO START, not a silent pass.
72
+ *
73
+ * The history's home moved out of the repository (see `rails-home.ts`). During
74
+ * a move, "I could not read the old history" and "there is no old history"
75
+ * look the same, and this store must never confuse them: an empty history
76
+ * discharges every hold it holds. A `repeated_failure` hold raised an hour ago
77
+ * would vanish, the run it was stopping would start, and nothing would say why.
78
+ *
79
+ * Omitted, there is no migration and nothing changes.
80
+ */
81
+ constructor(stateDir,
82
+ /**
83
+ * ⚠️ `readDir` IS OPTIONAL, so every existing fake still satisfies this.
84
+ * A store that cannot list the ordinal claims simply falls back to deriving
85
+ * the next attempt number from the observations, which is what it did
86
+ * before — weaker, and never wrong in a direction that loses a hold.
87
+ */
88
+ fs, now = () => Date.now(), migrate) {
89
+ this.stateDir = stateDir;
90
+ this.fs = fs;
91
+ this.now = now;
92
+ this.migrate = migrate;
93
+ }
94
+ get path() {
95
+ return `${this.stateDir}/loop-safety.json`;
96
+ }
97
+ /**
98
+ * The append-only history of attempts.
99
+ *
100
+ * 🔴 A SEPARATE FILE FROM THE INCIDENTS, AND APPEND-ONLY, BECAUSE A REWRITE
101
+ * LOSES A CONCURRENT WRITER'S WORK. Two writers for one goal on one machine is
102
+ * ordinary — the run recording what it achieved, and the Start gate spending a
103
+ * retry — and a whole-document rewrite meant whichever loaded first clobbered
104
+ * the other. For the spent retry that was survivable (the marker file is the
105
+ * authority). For an OBSERVATION it was not: a shorter history holds LATER, so
106
+ * the machine keeps working, which is the direction that costs a person money.
107
+ *
108
+ * The shape is `ledger-store.ts`'s, deliberately: events appended as JSONL,
109
+ * never rewritten, with the small mutable thing kept as a projection beside
110
+ * it. ⚠️ NOT `command-receipts.ts` — that one rewrites its whole document too,
111
+ * and an earlier draft of this file's own handoff cited it as the append-only
112
+ * precedent. It is not one.
113
+ *
114
+ * NEVER COMPACT THIS FILE. `ledger-store` says the same of its own events and
115
+ * for the same reason: a compaction is a rewrite, and a concurrent append
116
+ * during one is exactly the loss this change exists to prevent.
117
+ *
118
+ * ⚠️ THE COST THIS TRADE BUYS, STATED PLAINLY RATHER THAN LEFT TO BE FOUND.
119
+ * The whole file is read and parsed on every observation, because the verdict
120
+ * must be a fact about the machine rather than about one process. So the read
121
+ * grows with the machine's LIFETIME, not with its current workload: one record
122
+ * per attempt, forever, re-parsed each time.
123
+ *
124
+ * That is affordable at the scale this runs at — attempts are minutes apart
125
+ * and bounded by the very brake this file feeds — and it is the honest
126
+ * successor to the limit it replaced, not the absence of one. If a machine
127
+ * ever accumulates enough attempts for this to matter, the answer is a second
128
+ * ledger file rolled by date with the old one left in place, NOT a compaction
129
+ * of this one.
130
+ */
131
+ get eventsPath() {
132
+ return `${this.stateDir}/loop-safety-events.jsonl`;
133
+ }
134
+ /** Where an override's exclusive-create claim lives. One file per incident. */
135
+ /**
136
+ * Where incidents are written now: APPEND-ONLY, one per line.
137
+ *
138
+ * 🔴 `persist()` REWROTE THE WHOLE DOCUMENT from an `open()`-time snapshot,
139
+ * and Phase 1 turned that into a hold-erasing race. Moving this file to the
140
+ * project state directory is what lets a hold raised in one workspace be seen
141
+ * in another — and the same change put two concurrent writers on it. Two runs
142
+ * raising holds for two different pursuits each wrote a document without the
143
+ * other's incident, so one brake vanished. Unlike an override, nothing
144
+ * recovers it.
145
+ *
146
+ * Observations were made append-only long ago for exactly this reason.
147
+ * Incidents simply never were, because until Phase 1 there could not be two
148
+ * writers.
149
+ */
150
+ get incidentsPath() {
151
+ return `${this.stateDir}/loop-safety-incidents.jsonl`;
152
+ }
153
+ /** A short unique token for an incident id. Filename-safe by construction. */
154
+ incidentToken() {
155
+ return `${this.now().toString(36)}${Math.floor(Math.random() * 1e6).toString(36)}`;
156
+ }
157
+ overridePath(incidentId) {
158
+ return `${this.stateDir}/loop-safety-overrides/${incidentId}.json`;
159
+ }
160
+ /** Read what is on disk. Never throws: an unreadable file is a state, not a crash. */
161
+ async open() {
162
+ this.opened = true;
163
+ if (this.migrate !== undefined) {
164
+ const moved = await this.migrate();
165
+ if (!moved.ok) {
166
+ this.state = 'unreadable';
167
+ return this.state;
168
+ }
169
+ }
170
+ let text;
171
+ try {
172
+ text = await this.fs.readFile(this.path);
173
+ }
174
+ catch {
175
+ this.state = 'unreadable';
176
+ return this.state;
177
+ }
178
+ if (text === null) {
179
+ this.incidents = [];
180
+ await this.loadIncidents();
181
+ await this.loadObservations();
182
+ await this.foldInSpentRetries();
183
+ this.state = 'ok';
184
+ return this.state;
185
+ }
186
+ try {
187
+ const parsed = JSON.parse(text);
188
+ if (typeof parsed !== 'object' || parsed === null) {
189
+ this.state = 'unreadable';
190
+ return this.state;
191
+ }
192
+ this.incidents = Array.isArray(parsed.incidents) ? parsed.incidents.filter(isIncident) : [];
193
+ /**
194
+ * ⚠️ OBSERVATIONS ARE READ FROM THE LEDGER, AND A DOCUMENT WRITTEN BY AN
195
+ * OLDER BUILD MAY STILL CARRY SOME. They are taken as the history's start
196
+ * so an upgrade does not silently discharge a pursuit that was three
197
+ * barren attempts deep, and the ledger is appended after them.
198
+ */
199
+ const carried = Array.isArray(parsed.observations)
200
+ ? parsed.observations.filter(isObservation)
201
+ : [];
202
+ await this.loadIncidents();
203
+ await this.loadObservations(carried);
204
+ await this.foldInSpentRetries();
205
+ this.state = 'ok';
206
+ }
207
+ catch {
208
+ /**
209
+ * Written temp-then-rename, so a torn file should be impossible. Garbage
210
+ * here is a fact about the machine rather than a race — and guessing
211
+ * "nothing has happened" would silently discharge every hold this file
212
+ * holds, which is the one direction that must never fail open.
213
+ */
214
+ this.state = 'unreadable';
215
+ }
216
+ return this.state;
217
+ }
218
+ status() {
219
+ return this.state;
220
+ }
221
+ /**
222
+ * The active incident for a pursuit, or null.
223
+ *
224
+ * ⚠️ AN UNREADABLE FILE ANSWERS `null`, AND THAT IS DELIBERATE — but it is
225
+ * NOT the same as failing open. The caller (`autonomy-tick`) treats an
226
+ * unreadable store as a hold in its own right, because a machine that cannot
227
+ * read its safety history must not spend a night on the assumption that it is
228
+ * empty. Deciding that here would hide it inside a getter.
229
+ */
230
+ /**
231
+ * Whether this store could read its history.
232
+ *
233
+ * 🔴 EXPOSED BECAUSE THE RULE ABOVE HAD A SECOND CALLER THAT DID NOT KNOW IT.
234
+ * `activeIncident` answers null on an unreadable file and says, correctly,
235
+ * that deciding there "would hide it inside a getter" — but that only works
236
+ * while every caller applies the rule. `autonomy-tick` did; the coordinator's
237
+ * `holdsFor` did not, and returned NO HOLDS for an unreadable history, which
238
+ * `decideSchedule` reads as "nothing is held" and answers with `start`.
239
+ *
240
+ * `open()` already returns this; a store that has been opened elsewhere had
241
+ * no way to be asked again.
242
+ */
243
+ readable() {
244
+ return this.state === 'ok';
245
+ }
246
+ activeIncident(goalId, goalVersion) {
247
+ return (this.incidents.find((i) => i.goalId === goalId &&
248
+ i.goalVersion === goalVersion &&
249
+ i.overriddenByStartId === undefined) ?? null);
250
+ }
251
+ /** Every incident ever derived for this pursuit, newest last. History, not state. */
252
+ history(goalId) {
253
+ return this.incidents.filter((i) => i.goalId === goalId);
254
+ }
255
+ observationsFor(goalId) {
256
+ return this.observations.filter((o) => o.goalId === goalId);
257
+ }
258
+ /**
259
+ * The number to give the next attempt for this pursuit.
260
+ *
261
+ * ⚠️ NOT `observationsFor(...).length + 1`, WHICH IS WHAT THIS REPLACED. The
262
+ * history is bounded at `MAX_SAFETY_OBSERVATIONS`, so a count SATURATES: past
263
+ * sixteen attempts every one of them is numbered seventeen, and the evidence
264
+ * a person reads to understand why their machine stopped becomes three
265
+ * identical lines. No detector reads the ordinal, so nothing went wrong — it
266
+ * was only unreadable, which is the kind of defect a test suite never has an
267
+ * opinion about.
268
+ *
269
+ * Counting on from the LAST one survives trimming, because trimming keeps the
270
+ * newest. It restarts at one for a pursuit with no history, which is correct:
271
+ * a person who has never seen this Goal run should be shown attempt one.
272
+ */
273
+ nextOrdinalFor(goalId) {
274
+ const mine = this.observationsFor(goalId);
275
+ const last = mine[mine.length - 1];
276
+ return last === undefined ? 1 : last.ordinal + 1;
277
+ }
278
+ /**
279
+ * The largest attempt number anybody has already claimed for this goal, or 0.
280
+ *
281
+ * ⚠️ CLAIMS, NOT OBSERVATIONS. See `mintOrdinal`. An unreadable directory
282
+ * answers 0, which makes the caller fall back to the observation-derived
283
+ * start — the same answer it had before, rather than a refusal.
284
+ */
285
+ async highestClaim(goalId) {
286
+ let names;
287
+ try {
288
+ names = (await this.fs.readDir?.(`${this.stateDir}/loop-safety-ordinals`)) ?? [];
289
+ }
290
+ catch {
291
+ return 0;
292
+ }
293
+ let top = 0;
294
+ const prefix = `${goalId}-`;
295
+ for (const name of names) {
296
+ if (!name.startsWith(prefix) || !name.endsWith('.json'))
297
+ continue;
298
+ const n = Number.parseInt(name.slice(prefix.length, -'.json'.length), 10);
299
+ if (Number.isInteger(n) && n > top)
300
+ top = n;
301
+ }
302
+ return top;
303
+ }
304
+ /** Where an ordinal's exclusive-create claim lives. One file per attempt. */
305
+ ordinalPath(goalId, ordinal) {
306
+ return `${this.stateDir}/loop-safety-ordinals/${goalId}-${ordinal}.json`;
307
+ }
308
+ /**
309
+ * TAKE THE NEXT ATTEMPT NUMBER, EXCLUSIVELY.
310
+ *
311
+ * 🔴 `nextOrdinalFor` IS A READ, AND TWO RUNS READ THE SAME ANSWER.
312
+ *
313
+ * It derives the next number from the last observation on disk. That was
314
+ * sound while one run owned one checkout. With N workspaces two runs on one
315
+ * goal start within the same second, both read "the last attempt was 3", and
316
+ * both record attempt 4 — so the evidence a person is shown to explain why
317
+ * their machine stopped contains two different attempt fours and no five.
318
+ * `MAX_SAME_FAILURE_REPEATS` still fires correctly, because no detector reads
319
+ * the ordinal; what breaks is the only part of a hold a person can act on.
320
+ *
321
+ * ⚠️ THE SAME PRIMITIVE THE OVERRIDE MARKER USES, three files away: the
322
+ * filesystem arbitrates, never a read-then-write, because the two claimants
323
+ * may be two processes. On EEXIST the candidate simply advances — losing a
324
+ * race means somebody else has that number, which is exactly the information
325
+ * needed to pick the next one.
326
+ *
327
+ * ⚠️ GAPS ARE FINE, DUPLICATES ARE NOT. A run that mints 4 and then crashes
328
+ * burns 4, and the next attempt is 5. Nothing counts ordinals — the history's
329
+ * length is what detectors read — so a gap costs a person nothing, while a
330
+ * duplicate costs them the ability to tell two attempts apart.
331
+ */
332
+ async mintOrdinal(goalId) {
333
+ if (!this.opened)
334
+ throw new Error('LoopSafetyStore.mintOrdinal before open()');
335
+ /**
336
+ * ⚠️ PATH SAFETY, NOT VALIDATION THEATRE: the goal id becomes a filename.
337
+ * A goal id that cannot be a filename gets the unsynchronised answer rather
338
+ * than a thrown error — this is bookkeeping for a person to read, and no
339
+ * run should ever end because its goal was named unusually.
340
+ */
341
+ if (/[^A-Za-z0-9_-]/.test(goalId))
342
+ return this.nextOrdinalFor(goalId);
343
+ await this.fs.mkdir(`${this.stateDir}/loop-safety-ordinals`);
344
+ /**
345
+ * ⚠️ RELOAD FIRST. `nextOrdinalFor` reads the snapshot taken at `open()`,
346
+ * and a run opens the store at its first second and mints hours later. The
347
+ * EEXIST loop below would climb past a stale start eventually, but starting
348
+ * from the truth means it almost never has to.
349
+ */
350
+ await this.loadObservations();
351
+ /**
352
+ * 🔴 THE START IS THE HIGHEST CLAIM ON DISK, NOT THE LAST OBSERVATION — AND
353
+ * WITHOUT THAT THE WHOLE MECHANISM WEDGED AFTER 64 MINTS.
354
+ *
355
+ * A claim file is written for every MINT; an OBSERVATION is only recorded
356
+ * when the attempt counts. An excluded attempt — awaiting approval, an
357
+ * ambiguous governed action, a blocked environment — therefore leaves a
358
+ * claim above the last observation, permanently. Starting from the last
359
+ * observation meant the loop walked the same burnt range every time, and
360
+ * after 64 such attempts it exhausted the window and fell through to the
361
+ * unsynchronised answer FOR EVER. MEASURED: 70 mints with no observations
362
+ * returned 1..64 and then 1, 1, 1, 1 — two concurrent runs both handed
363
+ * ordinal 1, which is exactly what this function exists to prevent, and
364
+ * silently.
365
+ *
366
+ * Reading the claims answers the real question — what has anyone taken —
367
+ * rather than a proxy for it.
368
+ */
369
+ const from = Math.max(this.nextOrdinalFor(goalId), (await this.highestClaim(goalId)) + 1);
370
+ /**
371
+ * Bounded, because an unbounded loop against a filesystem is a hang. The
372
+ * bound is the number of runs that could have taken a number between this
373
+ * one's read and its write; sixty-four is far past any real machine, and
374
+ * exhausting it yields the unsynchronised answer rather than failing the run.
375
+ */
376
+ for (let ordinal = from; ordinal < from + 64; ordinal++) {
377
+ try {
378
+ await this.fs.createExclusive(this.ordinalPath(goalId, ordinal), `${JSON.stringify({ goalId, ordinal, pid: process.pid, at: new Date(this.now()).toISOString() })}\n`);
379
+ return ordinal;
380
+ }
381
+ catch (e) {
382
+ if (e.code !== 'EEXIST')
383
+ return this.nextOrdinalFor(goalId);
384
+ }
385
+ }
386
+ return from;
387
+ }
388
+ /**
389
+ * Record what one attempt achieved, and say whether that makes it unsafe to
390
+ * continue.
391
+ *
392
+ * The verdict is computed from what is now on disk rather than from the
393
+ * caller's belief, so a caller that forgets to persist cannot produce a
394
+ * verdict about a history that does not exist.
395
+ */
396
+ async observe(o) {
397
+ if (!this.opened)
398
+ throw new Error('LoopSafetyStore.observe before open()');
399
+ /**
400
+ * ⚠️ THERE USED TO BE AN `unreadable` GUARD HERE, AND ITS REASON DIED WITH
401
+ * THE REWRITE. It said "refuse to rewrite a file we could not read" — true
402
+ * and load-bearing while `observe` rewrote the whole document, and false the
403
+ * moment the history became an append-only ledger. A mutation battery found
404
+ * it: deleting the guard changed no test, because there was no longer
405
+ * anything for it to protect.
406
+ *
407
+ * What it did instead was DISCARD EVIDENCE. An unreadable incidents document
408
+ * is no reason to stop recording what a run achieved: appending cannot
409
+ * corrupt anything, and `raise()` still refuses to create an incident from a
410
+ * document it could not read, so nothing is decided on bad information.
411
+ *
412
+ * A guard whose stated reason has stopped being true is worse than no guard.
413
+ * It reads as protection and is not, and the next person to touch this file
414
+ * would have reasoned from the comment rather than from the code.
415
+ */
416
+ /**
417
+ * Append, then RE-READ before judging. The re-read is what makes the verdict
418
+ * a fact about the machine rather than about this process: another writer's
419
+ * attempt is on disk and not in this object's memory, and a detector that
420
+ * counted only its own caller's attempts would hold a pursuit late by
421
+ * exactly as many attempts as the other writer made.
422
+ */
423
+ /**
424
+ * 🔴 LED BY A NEWLINE, NOT MERELY TERMINATED BY ONE — and a test written to
425
+ * check a torn append is what found this. A crash part-way through a write
426
+ * leaves a fragment with no trailing newline; the NEXT record then appends
427
+ * straight onto it and the two become one unparseable line, so a single
428
+ * torn write cost TWO attempts rather than one.
429
+ *
430
+ * Leading each record instead means a fragment always ends up alone on its
431
+ * line and is skipped by itself. The blank line this leaves in the ordinary
432
+ * case is skipped by the same rule, which is why this needs no read of the
433
+ * file first and so stays safe against another writer appending at the same
434
+ * moment.
435
+ */
436
+ /**
437
+ * ⚠️ `mkdir` FIRST, WHICH `raise` AND `record` BOTH DO AND THIS DID NOT.
438
+ *
439
+ * It never mattered while the directory was inside a checkout that had to
440
+ * exist for the run to start. The machine-level home does not: on a fresh
441
+ * machine the first thing that touches it is this append, and an ENOENT
442
+ * here is not caught anywhere on the path from `runLoop`.
443
+ */
444
+ await this.fs.mkdir(this.stateDir);
445
+ await this.fs.appendFile(this.eventsPath, `\n${JSON.stringify(o)}\n`);
446
+ await this.loadObservations();
447
+ // Named explicitly rather than relying on the caller's history happening to
448
+ // hold one pursuit: this store holds every goal on the machine.
449
+ return (0, core_1.evaluateLoopSafety)({
450
+ observations: this.observations,
451
+ goalVersion: o.goalVersion,
452
+ goalId: o.goalId,
453
+ });
454
+ }
455
+ /**
456
+ * Write down that autonomy has stopped, and why.
457
+ *
458
+ * Idempotent on the pursuit: a second derivation while one is already active
459
+ * returns the existing incident rather than stacking. Two holds for one
460
+ * stuck condition would need two overrides to clear, and a person would have
461
+ * to press the button twice for reasons nobody could explain.
462
+ */
463
+ async raise(input) {
464
+ if (!this.opened)
465
+ throw new Error('LoopSafetyStore.raise before open()');
466
+ if (this.state === 'unreadable')
467
+ return null;
468
+ const existing = this.activeIncident(input.goalId, input.goalVersion);
469
+ if (existing !== null)
470
+ return existing;
471
+ const at = new Date(this.now()).toISOString();
472
+ const incident = {
473
+ // Derived from the pursuit and the moment, so two machines cannot mint
474
+ // the same id and a person can find it in a log.
475
+ /**
476
+ * 🔴 NOT `incidents.length + 1`, AND THE REASON IS WORSE THAN A COLLISION.
477
+ *
478
+ * That counted each writer's OWN snapshot, so two concurrent raises minted
479
+ * the identical id. The override marker is keyed by id, is permanent, and
480
+ * is exclusive-create — so an id reused by a LATER generation finds a
481
+ * months-old marker waiting for it, and a genuinely new stuck-loop hold is
482
+ * discharged at birth. Measured: raise, override, lose the document to a
483
+ * concurrent writer, raise again — and the fresh hold reads as already
484
+ * overridden. The brake applies and releases itself, silently.
485
+ *
486
+ * Unique per raise, and within [A-Za-z0-9_-] because it becomes a filename.
487
+ */
488
+ id: `safety-${input.goalId}-${input.goalVersion}-${this.incidentToken()}`,
489
+ goalId: input.goalId,
490
+ goalVersion: input.goalVersion,
491
+ kind: input.kind,
492
+ because: input.because,
493
+ evidence: [...input.evidence],
494
+ triggeredAt: at,
495
+ };
496
+ this.incidents.push(incident);
497
+ // APPENDED, never rewritten. See `incidentsPath`.
498
+ await this.fs.mkdir(this.stateDir);
499
+ /**
500
+ * 🔴 LED BY A NEWLINE, LIKE THE EVENTS FILE, AND FOR THE SAME REASON.
501
+ *
502
+ * This was terminated by one only. A crash part-way through a write leaves
503
+ * a fragment with no trailing newline; the NEXT incident then appends
504
+ * straight onto it and the two become one unparseable line — so a torn
505
+ * write costs TWO incidents rather than one, and an incident is a HOLD. The
506
+ * events file worked this out and wrote it down; incidents never followed,
507
+ * because until Phase 1 there could not be two writers here.
508
+ *
509
+ * `loadIncidents` already skips blank lines, so the extra newline in the
510
+ * ordinary case costs nothing.
511
+ */
512
+ await this.fs.appendFile(this.incidentsPath, `\n${JSON.stringify(incident)}\n`);
513
+ return incident;
514
+ }
515
+ /**
516
+ * A PERSON SPENDS AN INCIDENT'S ONE RETRY.
517
+ *
518
+ * 🔴 EXCLUSIVE CREATE, AND NOTHING ELSE. Two Starts arriving together must not
519
+ * both believe they may proceed, and the filesystem is what arbitrates —
520
+ * never a read-then-write, and never an in-memory flag, because the two Starts
521
+ * may be two processes. The same Start asking twice gets the same answer, so
522
+ * a dropped response cannot cost a person their retry.
523
+ *
524
+ * ⚠️ ONE RETRY, NOT "SAFETY OFF". The incident is marked as spent rather than
525
+ * deleted, and the observation history is left exactly where it is. If the
526
+ * authorised Run also achieves nothing, the detectors see the whole history
527
+ * and raise a NEW incident — which is the difference between a person saying
528
+ * "try once more" and a person disabling a brake.
529
+ */
530
+ async override(incidentId, startId) {
531
+ if (!this.opened)
532
+ throw new Error('LoopSafetyStore.override before open()');
533
+ if (this.state === 'unreadable') {
534
+ return { ok: false, because: 'the safety history could not be read' };
535
+ }
536
+ if (/[^A-Za-z0-9_-]/.test(incidentId)) {
537
+ // Path safety, not validation theatre: the id becomes a filename.
538
+ return { ok: false, because: `${incidentId} is not a usable incident id` };
539
+ }
540
+ const found = this.incidents.find((i) => i.id === incidentId);
541
+ if (found === undefined)
542
+ return { ok: false, because: 'no such safety incident' };
543
+ if (found.overriddenByStartId !== undefined && found.overriddenByStartId !== startId) {
544
+ return { ok: false, because: 'another Start already took this one retry' };
545
+ }
546
+ await this.fs.mkdir(`${this.stateDir}/loop-safety-overrides`);
547
+ try {
548
+ await this.fs.createExclusive(this.overridePath(incidentId), `${JSON.stringify({ incidentId, startId, at: new Date(this.now()).toISOString() }, null, 2)}\n`);
549
+ }
550
+ catch (e) {
551
+ if (e.code !== 'EEXIST')
552
+ throw e;
553
+ // Somebody holds it. The SAME Start asking again is a dropped response,
554
+ // not a rival — anything else is the second Start and must be refused.
555
+ const held = await this.readOverride(incidentId);
556
+ if (held === null) {
557
+ /**
558
+ * FAILS CLOSED, AND SAYS HOW TO GET OUT. We cannot tell whether the one
559
+ * retry was spent, and guessing "not spent" would hand out a second.
560
+ * But refusing without naming a way forward leaves a person stuck at a
561
+ * sentence — amending the Goal starts a new version, which this hold
562
+ * does not cover, and that is the door they cannot see from here.
563
+ */
564
+ return {
565
+ ok: false,
566
+ because: 'the record of this retry cannot be read, so it cannot be given out again — change the goal to start a fresh version',
567
+ };
568
+ }
569
+ if (held !== startId)
570
+ return { ok: false, because: 'another Start already took this one retry' };
571
+ }
572
+ const spent = { ...found, overriddenByStartId: startId };
573
+ this.incidents = this.incidents.map((i) => (i.id === incidentId ? spent : i));
574
+ /**
575
+ * NO DOCUMENT WRITE. The exclusively-created marker above IS the record that
576
+ * this retry was spent, and `foldInSpentRetries` reads it back at every
577
+ * open — so persisting here would add nothing but a second whole-document
578
+ * rewrite racing every concurrent raise.
579
+ */
580
+ return { ok: true, incident: spent };
581
+ }
582
+ /**
583
+ * Read the attempt history from the append-only ledger.
584
+ *
585
+ * Bounded IN MEMORY rather than on disk: the file is never rewritten, so the
586
+ * only place a bound can be applied without a rewrite is here. `carried` is
587
+ * whatever an older build left in the document, and goes first because it is
588
+ * older than anything in the ledger.
589
+ *
590
+ * 🔴 A BAD LINE IS SKIPPED, NOT FATAL — and that is the opposite of how this
591
+ * class treats a bad INCIDENTS document, deliberately. A torn final line is
592
+ * what a crash mid-append leaves, and it costs one observation, which is the
593
+ * bounded loss this design already accepts. Refusing to read the history over
594
+ * it would report NO active incident and so discharge every hold on the
595
+ * machine, which is the one direction that must never fail open. The
596
+ * incidents document still fails closed; it is what holds are made of.
597
+ */
598
+ async loadObservations(carried = []) {
599
+ let text = null;
600
+ try {
601
+ text = await this.fs.readFile(this.eventsPath);
602
+ }
603
+ catch {
604
+ text = null;
605
+ }
606
+ const fromLedger = [];
607
+ for (const line of (text ?? '').split('\n')) {
608
+ if (line.trim() === '')
609
+ continue;
610
+ try {
611
+ const parsed = JSON.parse(line);
612
+ if (isObservation(parsed))
613
+ fromLedger.push(parsed);
614
+ }
615
+ catch {
616
+ // A torn write. See above: one attempt, not the whole history.
617
+ }
618
+ }
619
+ /**
620
+ * 🔴 BOUNDED PER PURSUIT, AND A GLOBAL BOUND HERE WAS A REAL DEFECT. The
621
+ * daemon runs up to `MAX_CONTROLLERS_PER_TICK` controllers, so several goals
622
+ * interleave attempts into this one ledger. Keeping the newest sixteen
623
+ * ACROSS ALL OF THEM let a busy pursuit evict a quiet one's history before
624
+ * it ever reached the three barren attempts `no_progress` needs — so the
625
+ * brake switched itself off on the machine doing the most work, silently,
626
+ * with nothing anywhere going red.
627
+ *
628
+ * Per goal, the window means what it says: sixteen attempts of THIS pursuit.
629
+ * Memory stays bounded at sixteen times the number of goals the ledger
630
+ * mentions, which is a machine's real workload rather than its uptime.
631
+ */
632
+ const byGoal = new Map();
633
+ for (const o of [...carried, ...fromLedger]) {
634
+ const mine = byGoal.get(o.goalId);
635
+ if (mine === undefined)
636
+ byGoal.set(o.goalId, [o]);
637
+ else
638
+ mine.push(o);
639
+ }
640
+ const kept = [];
641
+ for (const mine of byGoal.values()) {
642
+ kept.push(...(mine.length > core_1.MAX_SAFETY_OBSERVATIONS
643
+ ? mine.slice(mine.length - core_1.MAX_SAFETY_OBSERVATIONS)
644
+ : mine));
645
+ }
646
+ this.observations = kept;
647
+ }
648
+ /**
649
+ * Mark every incident whose retry has already been taken.
650
+ *
651
+ * 🔴 THE MARKER FILE IS THE AUTHORITY; THE FIELD IS A CACHE. `persist()`
652
+ * rewrites the whole document, so a writer that loaded before another
653
+ * writer's write clobbers it — and the daemon spending a retry while a run
654
+ * records what it achieved is not an exotic interleaving, it is what happens
655
+ * every time somebody presses Start as a run ends. The field really is lost
656
+ * there; it is measured in `loop-safety-race.spec.ts`.
657
+ *
658
+ * What cannot be lost is `loop-safety-overrides/<id>`, because it is written
659
+ * with an exclusive create and never rewritten. So the document is believed
660
+ * about WHAT was raised, and the marker files about WHICH retries are spent.
661
+ * Reading them here keeps `activeIncident` synchronous for its callers.
662
+ *
663
+ * Bounded by the incident count rather than by anything a person can grow: a
664
+ * pursuit has one active incident at a time, and only unspent ones are asked
665
+ * about.
666
+ */
667
+ /**
668
+ * Fold the append-only incident log over whatever the legacy document held.
669
+ *
670
+ * A malformed line is SKIPPED rather than fatal: an append can be torn by a
671
+ * crash mid-write, and discarding every hold on the strength of one truncated
672
+ * last line would be the fail-open this whole file exists to prevent.
673
+ */
674
+ async loadIncidents() {
675
+ let text;
676
+ try {
677
+ text = await this.fs.readFile(this.incidentsPath);
678
+ }
679
+ catch {
680
+ this.state = 'unreadable';
681
+ return;
682
+ }
683
+ if (text === null)
684
+ return;
685
+ const known = new Set(this.incidents.map((i) => i.id));
686
+ for (const line of text.split('\n')) {
687
+ if (line.trim() === '')
688
+ continue;
689
+ try {
690
+ const parsed = JSON.parse(line);
691
+ if (!isIncident(parsed))
692
+ continue;
693
+ if (known.has(parsed.id))
694
+ continue;
695
+ known.add(parsed.id);
696
+ this.incidents.push(parsed);
697
+ }
698
+ catch {
699
+ // A torn final line. Everything before it still counts.
700
+ }
701
+ }
702
+ }
703
+ async foldInSpentRetries() {
704
+ const unspent = this.incidents.filter((i) => i.overriddenByStartId === undefined);
705
+ if (unspent.length === 0)
706
+ return;
707
+ const spent = await Promise.all(unspent.map(async (i) => ({ id: i.id, startId: await this.readOverride(i.id) })));
708
+ const byId = new Map(spent.filter((x) => x.startId !== null).map((x) => [x.id, x.startId]));
709
+ if (byId.size === 0)
710
+ return;
711
+ this.incidents = this.incidents.map((i) => {
712
+ const startId = byId.get(i.id);
713
+ return startId === undefined ? i : { ...i, overriddenByStartId: startId };
714
+ });
715
+ }
716
+ async readOverride(incidentId) {
717
+ let text;
718
+ try {
719
+ text = await this.fs.readFile(this.overridePath(incidentId));
720
+ }
721
+ catch {
722
+ return null;
723
+ }
724
+ if (text === null)
725
+ return null;
726
+ try {
727
+ const parsed = JSON.parse(text);
728
+ return typeof parsed.startId === 'string' ? parsed.startId : null;
729
+ }
730
+ catch {
731
+ return null;
732
+ }
733
+ }
734
+ async persist() {
735
+ await this.fs.mkdir(this.stateDir);
736
+ /**
737
+ * Temp-then-rename, with a name PRIVATE TO THIS WRITER. A shared
738
+ * `loop-safety.json.tmp` is some other writer's half-written file, and
739
+ * renaming that over the real one is exactly the corruption the rename
740
+ * exists to prevent.
741
+ */
742
+ const tmp = `${this.path}.${process.pid}.${(LoopSafetyStore.writes += 1)}.tmp`;
743
+ // Incidents ONLY. Observations live in the append-only ledger; writing them
744
+ // here as well would reintroduce the clobber under a second name.
745
+ const body = { incidents: this.incidents };
746
+ await this.fs.writeFile(tmp, `${JSON.stringify(body, null, 2)}\n`);
747
+ await this.fs.rename(tmp, this.path);
748
+ }
749
+ }
750
+ exports.LoopSafetyStore = LoopSafetyStore;
751
+ /**
752
+ * The real filesystem, in the shape this store needs.
753
+ *
754
+ * `createExclusive` is the whole argument for a separate factory: it is the one
755
+ * operation that must be atomic against another PROCESS, and it is spelled with
756
+ * the `wx` flag rather than a read-then-write for exactly that reason.
757
+ */
758
+ exports.nodeSafetyFs = {
759
+ readFile: async (path) => {
760
+ const { readFile } = await Promise.resolve().then(() => __importStar(require('node:fs/promises')));
761
+ try {
762
+ return await readFile(path, 'utf8');
763
+ }
764
+ catch (e) {
765
+ if (e.code === 'ENOENT')
766
+ return null;
767
+ throw e;
768
+ }
769
+ },
770
+ appendFile: async (path, data) => {
771
+ const { appendFile } = await Promise.resolve().then(() => __importStar(require('node:fs/promises')));
772
+ await appendFile(path, data, 'utf8');
773
+ },
774
+ writeFile: async (path, data) => {
775
+ const { writeFile } = await Promise.resolve().then(() => __importStar(require('node:fs/promises')));
776
+ await writeFile(path, data, 'utf8');
777
+ },
778
+ rename: async (from, to) => {
779
+ const { rename } = await Promise.resolve().then(() => __importStar(require('node:fs/promises')));
780
+ await rename(from, to);
781
+ },
782
+ mkdir: async (path) => {
783
+ const { mkdir } = await Promise.resolve().then(() => __importStar(require('node:fs/promises')));
784
+ await mkdir(path, { recursive: true });
785
+ },
786
+ readDir: async (path) => {
787
+ const { readdir } = await Promise.resolve().then(() => __importStar(require('node:fs/promises')));
788
+ try {
789
+ return await readdir(path);
790
+ }
791
+ catch {
792
+ return [];
793
+ }
794
+ },
795
+ createExclusive: async (path, data) => {
796
+ const { writeFile } = await Promise.resolve().then(() => __importStar(require('node:fs/promises')));
797
+ await writeFile(path, data, { encoding: 'utf8', flag: 'wx' });
798
+ },
799
+ };
800
+ //# sourceMappingURL=loop-safety-store.js.map