harnery 0.42.0 → 0.44.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 (343) hide show
  1. package/README.md +3 -3
  2. package/dist/commander.d.ts +16 -0
  3. package/dist/commander.d.ts.map +1 -1
  4. package/dist/commander.js +18 -0
  5. package/dist/commands/agents.d.ts.map +1 -1
  6. package/dist/commands/agents.js +95 -52
  7. package/dist/commands/browse.d.ts.map +1 -1
  8. package/dist/commands/browse.js +38 -11
  9. package/dist/commands/diagnostics.d.ts.map +1 -1
  10. package/dist/commands/diagnostics.js +10 -0
  11. package/dist/commands/doctor.d.ts +12 -0
  12. package/dist/commands/doctor.d.ts.map +1 -1
  13. package/dist/commands/doctor.js +22 -7
  14. package/dist/commands/governor.js +22 -10
  15. package/dist/commands/inbox.d.ts +1 -1
  16. package/dist/commands/inbox.d.ts.map +1 -1
  17. package/dist/commands/inbox.js +55 -2
  18. package/dist/commands/rm.d.ts.map +1 -1
  19. package/dist/commands/rm.js +28 -4
  20. package/dist/commands/servers.d.ts.map +1 -1
  21. package/dist/commands/servers.js +16 -1
  22. package/dist/commands/supervisor.d.ts.map +1 -1
  23. package/dist/commands/supervisor.js +7 -2
  24. package/dist/commands/toc.d.ts +14 -0
  25. package/dist/commands/toc.d.ts.map +1 -1
  26. package/dist/commands/toc.js +7 -4
  27. package/dist/commands/tunnel.d.ts +65 -0
  28. package/dist/commands/tunnel.d.ts.map +1 -1
  29. package/dist/commands/tunnel.js +290 -101
  30. package/dist/commands/web-fetch.d.ts +3 -2
  31. package/dist/commands/web-fetch.d.ts.map +1 -1
  32. package/dist/commands/web-fetch.js +25 -19
  33. package/dist/commands/web.d.ts +7 -1
  34. package/dist/commands/web.d.ts.map +1 -1
  35. package/dist/commands/web.js +9 -3
  36. package/dist/commands/workflow.js +24 -30
  37. package/dist/core/agents/live-authority-v3.d.ts +1 -0
  38. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  39. package/dist/core/agents/live-authority-v3.js +11 -0
  40. package/dist/core/agents/live-lifecycle-v3.d.ts +4 -2
  41. package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
  42. package/dist/core/agents/live-lifecycle-v3.js +28 -7
  43. package/dist/core/agents/mailbox.d.ts +9 -8
  44. package/dist/core/agents/mailbox.d.ts.map +1 -1
  45. package/dist/core/agents/mailbox.js +24 -17
  46. package/dist/core/agents/render/prompt-context.d.ts +2 -0
  47. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  48. package/dist/core/agents/render/prompt-context.js +19 -17
  49. package/dist/core/agents/render/session-context.d.ts +2 -8
  50. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  51. package/dist/core/agents/render/session-context.js +64 -43
  52. package/dist/core/agents/rules/stop-hook.js +3 -3
  53. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  54. package/dist/core/agents/state/heartbeat-writer.js +25 -14
  55. package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -1
  56. package/dist/core/agents/state/live-coordination-writer.js +5 -0
  57. package/dist/core/agents/state/names.d.ts +43 -3
  58. package/dist/core/agents/state/names.d.ts.map +1 -1
  59. package/dist/core/agents/state/names.js +87 -3
  60. package/dist/core/agents/state/pidmap.d.ts.map +1 -1
  61. package/dist/core/agents/state/pidmap.js +5 -0
  62. package/dist/core/agents/state/proc-start.d.ts +19 -0
  63. package/dist/core/agents/state/proc-start.d.ts.map +1 -1
  64. package/dist/core/agents/state/proc-start.js +41 -0
  65. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  66. package/dist/core/agents/state/stale-sweep.js +180 -70
  67. package/dist/core/agents/state/unchanged-file.d.ts +44 -0
  68. package/dist/core/agents/state/unchanged-file.d.ts.map +1 -0
  69. package/dist/core/agents/state/unchanged-file.js +390 -0
  70. package/dist/core/context/index.d.ts +22 -10
  71. package/dist/core/context/index.d.ts.map +1 -1
  72. package/dist/core/context/index.js +381 -119
  73. package/dist/core/context/observation.d.ts +26 -0
  74. package/dist/core/context/observation.d.ts.map +1 -0
  75. package/dist/core/context/observation.js +11 -0
  76. package/dist/core/diagnostics/bundle.d.ts.map +1 -1
  77. package/dist/core/diagnostics/bundle.js +25 -14
  78. package/dist/core/diagnostics/path-identity.d.ts +3 -0
  79. package/dist/core/diagnostics/path-identity.d.ts.map +1 -0
  80. package/dist/core/diagnostics/path-identity.js +12 -0
  81. package/dist/core/diagnostics/sanitize.d.ts.map +1 -1
  82. package/dist/core/diagnostics/sanitize.js +4 -3
  83. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
  84. package/dist/core/events/v3/authority-outbox.js +29 -0
  85. package/dist/core/events/v3/generation-custody.d.ts +5 -0
  86. package/dist/core/events/v3/generation-custody.d.ts.map +1 -0
  87. package/dist/core/events/v3/generation-custody.js +50 -0
  88. package/dist/core/events/v3/producers/coordination-recorder.d.ts +1 -0
  89. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  90. package/dist/core/events/v3/producers/coordination-recorder.js +7 -0
  91. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  92. package/dist/core/events/v3/producers/recorder.js +77 -64
  93. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -1
  94. package/dist/core/events/v3/support-storage/pack-reader.js +42 -16
  95. package/dist/core/governor/planning.d.ts.map +1 -1
  96. package/dist/core/governor/planning.js +14 -1
  97. package/dist/core/governor/service-read.d.ts +10 -2
  98. package/dist/core/governor/service-read.d.ts.map +1 -1
  99. package/dist/core/governor/service-read.js +105 -22
  100. package/dist/core/governor/service.d.ts +20 -2
  101. package/dist/core/governor/service.d.ts.map +1 -1
  102. package/dist/core/governor/service.js +72 -47
  103. package/dist/core/hooks/cli.js +120 -23
  104. package/dist/core/hooks/fork-lineage.d.ts +40 -0
  105. package/dist/core/hooks/fork-lineage.d.ts.map +1 -0
  106. package/dist/core/hooks/fork-lineage.js +62 -0
  107. package/dist/core/hooks/resolve/transcript.d.ts +16 -0
  108. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  109. package/dist/core/hooks/resolve/transcript.js +84 -0
  110. package/dist/core/hooks/shell-rm.d.ts +2 -0
  111. package/dist/core/hooks/shell-rm.d.ts.map +1 -0
  112. package/dist/core/hooks/shell-rm.js +105 -0
  113. package/dist/core/hooks/shell-tokens.d.ts +12 -0
  114. package/dist/core/hooks/shell-tokens.d.ts.map +1 -0
  115. package/dist/core/hooks/shell-tokens.js +97 -0
  116. package/dist/core/hooks/shell-waiter.d.ts.map +1 -1
  117. package/dist/core/hooks/shell-waiter.js +3 -93
  118. package/dist/core/inbox/contract.d.ts +2 -1
  119. package/dist/core/inbox/contract.d.ts.map +1 -1
  120. package/dist/core/inbox/index.d.ts +2 -0
  121. package/dist/core/inbox/index.d.ts.map +1 -1
  122. package/dist/core/inbox/index.js +2 -0
  123. package/dist/core/inbox/peer-messages.d.ts +37 -0
  124. package/dist/core/inbox/peer-messages.d.ts.map +1 -0
  125. package/dist/core/inbox/peer-messages.js +72 -0
  126. package/dist/core/inbox/service.d.ts +8 -1
  127. package/dist/core/inbox/service.d.ts.map +1 -1
  128. package/dist/core/inbox/service.js +67 -21
  129. package/dist/core/inbox/targets.d.ts +22 -0
  130. package/dist/core/inbox/targets.d.ts.map +1 -0
  131. package/dist/core/inbox/targets.js +108 -0
  132. package/dist/core/inbox/watcher.js +7 -3
  133. package/dist/core/journal/index.d.ts.map +1 -1
  134. package/dist/core/journal/index.js +17 -2
  135. package/dist/core/resources/contract.d.ts +3 -0
  136. package/dist/core/resources/contract.d.ts.map +1 -1
  137. package/dist/core/resources/service-status.d.ts +14 -1
  138. package/dist/core/resources/service-status.d.ts.map +1 -1
  139. package/dist/core/resources/service-status.js +23 -13
  140. package/dist/core/resources/service.d.ts +9 -1
  141. package/dist/core/resources/service.d.ts.map +1 -1
  142. package/dist/core/resources/service.js +47 -27
  143. package/dist/core/resources/status.d.ts +2 -5
  144. package/dist/core/resources/status.d.ts.map +1 -1
  145. package/dist/core/resources/status.js +36 -7
  146. package/dist/core/semantic/contract.d.ts +5 -5
  147. package/dist/core/servers/index.d.ts +24 -13
  148. package/dist/core/servers/index.d.ts.map +1 -1
  149. package/dist/core/servers/index.js +132 -92
  150. package/dist/core/servers/tunnels.d.ts +3 -5
  151. package/dist/core/servers/tunnels.d.ts.map +1 -1
  152. package/dist/core/servers/tunnels.js +3 -9
  153. package/dist/core/storage/process-log.d.ts +12 -0
  154. package/dist/core/storage/process-log.d.ts.map +1 -1
  155. package/dist/core/storage/process-log.js +10 -2
  156. package/dist/core/supervisor/contract.d.ts +12 -0
  157. package/dist/core/supervisor/contract.d.ts.map +1 -1
  158. package/dist/core/supervisor/explanations.d.ts.map +1 -1
  159. package/dist/core/supervisor/explanations.js +2 -1
  160. package/dist/core/supervisor/findings.d.ts.map +1 -1
  161. package/dist/core/supervisor/findings.js +54 -9
  162. package/dist/core/supervisor/service.d.ts +9 -1
  163. package/dist/core/supervisor/service.d.ts.map +1 -1
  164. package/dist/core/supervisor/service.js +59 -29
  165. package/dist/core/supervisor/services.d.ts.map +1 -1
  166. package/dist/core/supervisor/services.js +22 -1
  167. package/dist/core/supervisor/status.d.ts +17 -2
  168. package/dist/core/supervisor/status.d.ts.map +1 -1
  169. package/dist/core/supervisor/status.js +70 -12
  170. package/dist/core/supervisor/timeline.d.ts.map +1 -1
  171. package/dist/core/supervisor/timeline.js +2 -1
  172. package/dist/core/work/state.js +7 -7
  173. package/dist/core/workflow/engine.d.ts.map +1 -1
  174. package/dist/core/workflow/engine.js +105 -32
  175. package/dist/core/workflow/failure-evidence.d.ts +16 -0
  176. package/dist/core/workflow/failure-evidence.d.ts.map +1 -0
  177. package/dist/core/workflow/failure-evidence.js +114 -0
  178. package/dist/core/workflow/index.d.ts +1 -1
  179. package/dist/core/workflow/index.d.ts.map +1 -1
  180. package/dist/core/workflow/index.js +1 -1
  181. package/dist/core/workflow/live-session-v3.d.ts +6 -0
  182. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  183. package/dist/core/workflow/live-session-v3.js +126 -5
  184. package/dist/core/workflow/proof.d.ts +5 -5
  185. package/dist/core/workflow/proof.d.ts.map +1 -1
  186. package/dist/core/workflow/proof.js +115 -20
  187. package/dist/core/workflow/run-state.d.ts +3 -1
  188. package/dist/core/workflow/run-state.d.ts.map +1 -1
  189. package/dist/core/workflow/run-state.js +31 -27
  190. package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
  191. package/dist/core/workflow/spawn-claude.js +19 -0
  192. package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
  193. package/dist/core/workflow/spawn-codex.js +13 -0
  194. package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
  195. package/dist/core/workflow/spawn-cursor.js +19 -0
  196. package/dist/core/workflow/spawn-opencode.d.ts.map +1 -1
  197. package/dist/core/workflow/spawn-opencode.js +14 -0
  198. package/dist/core/workflow/types.d.ts +64 -17
  199. package/dist/core/workflow/types.d.ts.map +1 -1
  200. package/dist/core/workflow/workspaces/index.d.ts +0 -1
  201. package/dist/core/workflow/workspaces/index.d.ts.map +1 -1
  202. package/dist/core/workflow/workspaces/index.js +0 -1
  203. package/dist/core/workflow/workspaces/leases.d.ts +3 -1
  204. package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
  205. package/dist/core/workflow/workspaces/leases.js +30 -16
  206. package/dist/core/workflow/workspaces/local-git.d.ts +6 -2
  207. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  208. package/dist/core/workflow/workspaces/local-git.js +270 -6
  209. package/dist/core/workflow/workspaces/ownership.d.ts +11 -0
  210. package/dist/core/workflow/workspaces/ownership.d.ts.map +1 -0
  211. package/dist/core/workflow/workspaces/ownership.js +194 -0
  212. package/dist/core/workflow/workspaces/reclaim.d.ts +35 -0
  213. package/dist/core/workflow/workspaces/reclaim.d.ts.map +1 -1
  214. package/dist/core/workflow/workspaces/reclaim.js +14 -0
  215. package/dist/core/workflow/workspaces/recovery.d.ts.map +1 -1
  216. package/dist/core/workflow/workspaces/recovery.js +21 -13
  217. package/dist/core/workflow/workspaces/state.d.ts +1 -0
  218. package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
  219. package/dist/core/workflow/workspaces/state.js +21 -1
  220. package/dist/lib/browser/windows-chrome.d.ts +100 -12
  221. package/dist/lib/browser/windows-chrome.d.ts.map +1 -1
  222. package/dist/lib/browser/windows-chrome.js +262 -73
  223. package/dist/lib/docs-links.d.ts.map +1 -1
  224. package/dist/lib/docs-links.js +45 -2
  225. package/dist/lib/guarded-remove.d.ts +7 -0
  226. package/dist/lib/guarded-remove.d.ts.map +1 -1
  227. package/dist/lib/guarded-remove.js +106 -12
  228. package/dist/lib/identities/assume.d.ts.map +1 -1
  229. package/dist/lib/identities/assume.js +4 -0
  230. package/dist/lib/tunnel/allowlist.d.ts +44 -0
  231. package/dist/lib/tunnel/allowlist.d.ts.map +1 -0
  232. package/dist/lib/tunnel/allowlist.js +204 -0
  233. package/dist/lib/tunnel/current-address.d.ts +41 -0
  234. package/dist/lib/tunnel/current-address.d.ts.map +1 -0
  235. package/dist/lib/tunnel/current-address.js +123 -0
  236. package/dist/lib/tunnel/gate.js +13 -6
  237. package/dist/lib/tunnel/processes.d.ts +39 -0
  238. package/dist/lib/tunnel/processes.d.ts.map +1 -0
  239. package/dist/lib/tunnel/processes.js +121 -0
  240. package/dist/lib/tunnel/state.d.ts +28 -3
  241. package/dist/lib/tunnel/state.d.ts.map +1 -1
  242. package/dist/lib/tunnel/state.js +98 -27
  243. package/dist/lib/zip/index.d.ts +41 -0
  244. package/dist/lib/zip/index.d.ts.map +1 -0
  245. package/dist/lib/zip/index.js +398 -0
  246. package/package.json +8 -1
  247. package/src/commander.ts +32 -0
  248. package/src/commands/agents.ts +151 -74
  249. package/src/commands/browse.ts +50 -14
  250. package/src/commands/diagnostics.ts +10 -0
  251. package/src/commands/doctor.ts +26 -7
  252. package/src/commands/governor.ts +23 -10
  253. package/src/commands/inbox.ts +52 -2
  254. package/src/commands/rm.ts +43 -4
  255. package/src/commands/servers.ts +16 -4
  256. package/src/commands/supervisor.ts +7 -2
  257. package/src/commands/toc.ts +14 -6
  258. package/src/commands/tunnel.ts +394 -116
  259. package/src/commands/web-fetch.ts +30 -19
  260. package/src/commands/web.ts +9 -3
  261. package/src/commands/workflow.ts +30 -30
  262. package/src/core/agents/live-authority-v3.ts +17 -0
  263. package/src/core/agents/live-lifecycle-v3.ts +52 -14
  264. package/src/core/agents/mailbox.ts +26 -17
  265. package/src/core/agents/render/prompt-context.ts +35 -20
  266. package/src/core/agents/render/session-context.ts +92 -48
  267. package/src/core/agents/rules/stop-hook.ts +3 -3
  268. package/src/core/agents/state/heartbeat-writer.ts +29 -12
  269. package/src/core/agents/state/live-coordination-writer.ts +29 -0
  270. package/src/core/agents/state/names.ts +117 -6
  271. package/src/core/agents/state/pidmap.ts +13 -0
  272. package/src/core/agents/state/proc-start.ts +57 -0
  273. package/src/core/agents/state/stale-sweep.ts +247 -82
  274. package/src/core/agents/state/unchanged-file.ts +456 -0
  275. package/src/core/context/index.ts +446 -136
  276. package/src/core/context/observation.ts +29 -0
  277. package/src/core/diagnostics/bundle.ts +23 -18
  278. package/src/core/diagnostics/path-identity.ts +15 -0
  279. package/src/core/diagnostics/sanitize.ts +4 -3
  280. package/src/core/events/v3/authority-outbox.ts +56 -0
  281. package/src/core/events/v3/generation-custody.ts +59 -0
  282. package/src/core/events/v3/producers/coordination-recorder.ts +15 -0
  283. package/src/core/events/v3/producers/recorder.ts +94 -68
  284. package/src/core/events/v3/support-storage/pack-reader.ts +45 -19
  285. package/src/core/governor/planning.ts +20 -8
  286. package/src/core/governor/service-read.ts +128 -20
  287. package/src/core/governor/service.ts +119 -42
  288. package/src/core/hooks/cli.ts +139 -22
  289. package/src/core/hooks/fork-lineage.ts +82 -0
  290. package/src/core/hooks/resolve/transcript.ts +88 -0
  291. package/src/core/hooks/shell-rm.ts +103 -0
  292. package/src/core/hooks/shell-tokens.ts +96 -0
  293. package/src/core/hooks/shell-waiter.ts +4 -91
  294. package/src/core/inbox/contract.ts +2 -1
  295. package/src/core/inbox/index.ts +2 -0
  296. package/src/core/inbox/peer-messages.ts +94 -0
  297. package/src/core/inbox/service.ts +88 -22
  298. package/src/core/inbox/targets.ts +148 -0
  299. package/src/core/inbox/watcher.ts +8 -9
  300. package/src/core/journal/index.ts +19 -2
  301. package/src/core/resources/contract.ts +4 -0
  302. package/src/core/resources/service-status.ts +35 -12
  303. package/src/core/resources/service.ts +71 -24
  304. package/src/core/resources/status.ts +57 -8
  305. package/src/core/servers/index.ts +177 -91
  306. package/src/core/servers/tunnels.ts +3 -11
  307. package/src/core/storage/process-log.ts +17 -2
  308. package/src/core/supervisor/contract.ts +13 -0
  309. package/src/core/supervisor/explanations.ts +4 -1
  310. package/src/core/supervisor/findings.ts +68 -10
  311. package/src/core/supervisor/service.ts +88 -26
  312. package/src/core/supervisor/services.ts +26 -8
  313. package/src/core/supervisor/status.ts +89 -12
  314. package/src/core/supervisor/timeline.ts +2 -1
  315. package/src/core/work/state.ts +7 -7
  316. package/src/core/workflow/engine.ts +131 -49
  317. package/src/core/workflow/failure-evidence.ts +141 -0
  318. package/src/core/workflow/index.ts +0 -1
  319. package/src/core/workflow/live-session-v3.ts +146 -5
  320. package/src/core/workflow/proof.ts +134 -26
  321. package/src/core/workflow/run-state.ts +31 -29
  322. package/src/core/workflow/spawn-claude.ts +18 -0
  323. package/src/core/workflow/spawn-codex.ts +13 -0
  324. package/src/core/workflow/spawn-cursor.ts +18 -0
  325. package/src/core/workflow/spawn-opencode.ts +14 -0
  326. package/src/core/workflow/types.ts +51 -17
  327. package/src/core/workflow/workspaces/index.ts +0 -1
  328. package/src/core/workflow/workspaces/leases.ts +48 -17
  329. package/src/core/workflow/workspaces/local-git.ts +315 -5
  330. package/src/core/workflow/workspaces/ownership.ts +232 -0
  331. package/src/core/workflow/workspaces/reclaim.ts +58 -0
  332. package/src/core/workflow/workspaces/recovery.ts +25 -13
  333. package/src/core/workflow/workspaces/state.ts +20 -0
  334. package/src/lib/browser/windows-chrome.ts +346 -86
  335. package/src/lib/docs-links.ts +49 -2
  336. package/src/lib/guarded-remove.ts +132 -14
  337. package/src/lib/identities/assume.ts +4 -0
  338. package/src/lib/tunnel/allowlist.ts +208 -0
  339. package/src/lib/tunnel/current-address.ts +158 -0
  340. package/src/lib/tunnel/gate.ts +16 -8
  341. package/src/lib/tunnel/processes.ts +149 -0
  342. package/src/lib/tunnel/state.ts +123 -27
  343. package/src/lib/zip/index.ts +483 -0
@@ -1,7 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
- import { constants, createReadStream } from "node:fs";
2
+ import { constants } from "node:fs";
3
3
  import { lstat, mkdir, open, realpath, rm, writeFile } from "node:fs/promises";
4
4
  import { dirname, isAbsolute, relative, resolve } from "node:path";
5
+ import { Readable } from "node:stream";
6
+ import { finished } from "node:stream/promises";
5
7
  import { StringDecoder } from "node:string_decoder";
6
8
  import { createGunzip, createInflateRaw } from "node:zlib";
7
9
  import { stateDirMode, stateFileMode } from "../../../storage/modes.js";
@@ -44,18 +46,12 @@ async function* streamEventV3SupportPackRecordsForManifest(manifestPath, manifes
44
46
  throw new Error("event_v3_support_payload_length_mismatch");
45
47
  if (payloadStat.size > bounded.max_payload_bytes)
46
48
  throw new Error("event_v3_support_payload_too_large");
47
- if ((await hashHandle(payloadPath, payloadHandle)) !== manifest.payload.digest) {
49
+ if ((await hashHandle(payloadHandle)) !== manifest.payload.digest) {
48
50
  throw new Error("event_v3_support_payload_digest_mismatch");
49
51
  }
50
52
  limits.fault?.("after_payload_digest", payloadPath);
51
- await assertCanonicalSingleGzipMember(payloadPath, payloadHandle, payloadStat.size, bounded.max_decompressed_bytes);
53
+ await assertCanonicalSingleGzipMember(payloadHandle, payloadStat.size, bounded.max_decompressed_bytes);
52
54
  const gunzip = createGunzip();
53
- const source = createReadStream(payloadPath, {
54
- fd: payloadHandle.fd,
55
- autoClose: false,
56
- start: 0,
57
- });
58
- source.pipe(gunzip);
59
55
  const decoder = new StringDecoder("utf8");
60
56
  let pending = "";
61
57
  let decompressedBytes = 0;
@@ -64,7 +60,7 @@ async function* streamEventV3SupportPackRecordsForManifest(manifestPath, manifes
64
60
  let priorPath;
65
61
  const entries = [];
66
62
  const seen = new Set();
67
- for await (const current of gunzip) {
63
+ for await (const current of decompressHandle(payloadHandle, 0, gunzip)) {
68
64
  const chunk = current;
69
65
  decompressedBytes += chunk.length;
70
66
  if (decompressedBytes > bounded.max_decompressed_bytes) {
@@ -176,20 +172,51 @@ export async function unpackEventV3SupportPack(manifestPath, destination, limits
176
172
  throw error;
177
173
  }
178
174
  }
179
- async function hashHandle(path, handle) {
175
+ async function hashHandle(handle) {
180
176
  const hash = createHash("sha256");
181
- const stream = createReadStream(path, { fd: handle.fd, autoClose: false, start: 0 });
182
- for await (const current of stream)
177
+ for await (const current of handleChunks(handle, 0))
183
178
  hash.update(current);
184
179
  return `sha256:${hash.digest("hex")}`;
185
180
  }
181
+ async function* handleChunks(handle, position) {
182
+ while (true) {
183
+ const buffer = Buffer.alloc(64 * 1024);
184
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);
185
+ if (bytesRead === 0)
186
+ return;
187
+ position += bytesRead;
188
+ yield buffer.subarray(0, bytesRead);
189
+ }
190
+ }
191
+ async function* decompressHandle(handle, start, decoder) {
192
+ const source = Readable.from(handleChunks(handle, start));
193
+ // Observe failures immediately, then settle source reads before the caller
194
+ // can close and reuse the verified handle, including on early rejection.
195
+ const completed = finished(source, { cleanup: true }).then(() => undefined, (error) => error);
196
+ source.once("error", (error) => decoder.destroy(error));
197
+ source.pipe(decoder);
198
+ try {
199
+ for await (const chunk of decoder)
200
+ yield chunk;
201
+ source.unpipe(decoder);
202
+ source.resume();
203
+ const error = await completed;
204
+ if (error)
205
+ throw error;
206
+ }
207
+ finally {
208
+ source.destroy();
209
+ decoder.destroy();
210
+ await completed;
211
+ }
212
+ }
186
213
  async function realDirectory(path) {
187
214
  const stat = await lstat(path);
188
215
  if (!stat.isDirectory() || stat.isSymbolicLink())
189
216
  throw new Error("event_v3_support_pack_root_invalid");
190
217
  return realpath(path);
191
218
  }
192
- async function assertCanonicalSingleGzipMember(path, handle, payloadBytes, maximumDecompressedBytes) {
219
+ async function assertCanonicalSingleGzipMember(handle, payloadBytes, maximumDecompressedBytes) {
193
220
  if (payloadBytes < 18)
194
221
  throw new Error("event_v3_support_gzip_truncated");
195
222
  const header = Buffer.alloc(10);
@@ -203,9 +230,8 @@ async function assertCanonicalSingleGzipMember(path, handle, payloadBytes, maxim
203
230
  throw new Error("event_v3_support_gzip_header_noncanonical");
204
231
  }
205
232
  const inflate = createInflateRaw();
206
- createReadStream(path, { fd: handle.fd, autoClose: false, start: 10 }).pipe(inflate);
207
233
  let decompressed = 0;
208
- for await (const current of inflate) {
234
+ for await (const current of decompressHandle(handle, 10, inflate)) {
209
235
  decompressed += current.length;
210
236
  if (decompressed > maximumDecompressedBytes) {
211
237
  inflate.destroy();
@@ -1 +1 @@
1
- {"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../../src/core/governor/planning.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,KAAK,UAAU,EAQhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,mBAAmB,EAUzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAsM9B;AAkMD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,mBAAmB,CAkHtB;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAYtB;AAED;;;;;;;;gEAQgE;AAChE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAoBtB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CA4CtB"}
1
+ {"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../../src/core/governor/planning.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,KAAK,UAAU,EAQhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,mBAAmB,EAUzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAkN9B;AAkMD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,mBAAmB,CAkHtB;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAYtB;AAED;;;;;;;;gEAQgE;AAChE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CAoBtB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CA4CtB"}
@@ -65,6 +65,7 @@ export async function runGovernorPlanner(input) {
65
65
  return recovered;
66
66
  }
67
67
  let proposalWritten = false;
68
+ let invalidProposal = false;
68
69
  try {
69
70
  const reviewRunId = reviewWorkflowRunId(request.id);
70
71
  const resumingReview = Boolean(resumable &&
@@ -87,7 +88,16 @@ export async function runGovernorPlanner(input) {
87
88
  concurrency: 1,
88
89
  onLog: input.onLog,
89
90
  })).result;
90
- const proposal = normalizeProposal(request.id, rawProposal, input.record, history.materialized_work_ids.length, request.trigger ?? "recovery", reviewInput ? persistedProposalTimestamp(reviewInput.candidate) : undefined);
91
+ let proposal;
92
+ try {
93
+ proposal = normalizeProposal(request.id, rawProposal, input.record, history.materialized_work_ids.length, request.trigger ?? "recovery", reviewInput ? persistedProposalTimestamp(reviewInput.candidate) : undefined);
94
+ }
95
+ catch (error) {
96
+ // A fresh invalid proposal can consume a replan without aborting the run.
97
+ // Corrupt persisted review input still requires investigation.
98
+ invalidProposal = !reviewInput;
99
+ throw error;
100
+ }
91
101
  if (policy.review) {
92
102
  if (proposal.decision === "attention") {
93
103
  appendPlanEvent(coordRoot, input.record.intent.id, request.id, {
@@ -181,6 +191,9 @@ export async function runGovernorPlanner(input) {
181
191
  reason: bounded(error.message, "plan failure", MAX_REASON),
182
192
  ...(failureClass ? { class: failureClass } : {}),
183
193
  });
194
+ if (invalidProposal) {
195
+ return outcome(readGovernorPlan(coordRoot, input.record.intent.id, request.id));
196
+ }
184
197
  throw error;
185
198
  }
186
199
  }
@@ -1,7 +1,15 @@
1
- import type { GovernorServiceConfig, GovernorServiceRuntime, GovernorServiceStatus } from "./service.js";
1
+ import { type ProcessGenerationVerdict } from "../agents/state/proc-start.js";
2
+ import type { GovernorServiceBuild, GovernorServiceConfig, GovernorServiceProcessDependencies, GovernorServiceRuntime, GovernorServiceStatus, GovernorServiceStatusRecord } from "./service.js";
3
+ export declare function currentGovernorServiceBuild(): GovernorServiceBuild;
4
+ export declare function governorServiceBuildStatus(record: GovernorServiceStatusRecord | undefined): Pick<GovernorServiceStatus, "running_build" | "installed_build" | "restart_needed" | "build_status">;
5
+ /** An unknown token or process probe cannot establish a running or stopped owner. */
6
+ export declare function observeGovernorServiceProcess(record: Pick<GovernorServiceStatusRecord, "pid" | "host" | "state" | "start_token"> | undefined, dependencies?: GovernorServiceProcessDependencies): {
7
+ generation: ProcessGenerationVerdict;
8
+ liveness: GovernorServiceStatus["liveness"];
9
+ };
2
10
  export declare function readGovernorServiceConfig(coordRootRaw: string): GovernorServiceConfig;
3
11
  export declare function readGovernorServiceRuntime(coordRootRaw: string): GovernorServiceRuntime | undefined;
4
- export declare function readGovernorServiceStatus(coordRootRaw: string): GovernorServiceStatus;
12
+ export declare function readGovernorServiceStatus(coordRootRaw: string, dependencies?: GovernorServiceProcessDependencies): GovernorServiceStatus;
5
13
  export declare function governorServiceLogPath(coordRoot: string): string;
6
14
  export interface GovernorServiceLogReadOptions {
7
15
  max_bytes?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"service-read.d.ts","sourceRoot":"","sources":["../../../src/core/governor/service-read.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EAEtB,MAAM,cAAc,CAAC;AAOtB,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,qBAAqB,CA0BrF;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,GACnB,sBAAsB,GAAG,SAAS,CAgBpC;AAED,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,qBAAqB,CAkBrF;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAahE;AAED,MAAM,WAAW,6BAA6B;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB;AAeD,wFAAwF;AACxF,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,6BAAkC,GAC1C,4BAA4B,CA6D9B"}
1
+ {"version":3,"file":"service-read.d.ts","sourceRoot":"","sources":["../../../src/core/governor/service-read.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,+BAA+B,CAAC;AAMvC,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,kCAAkC,EAClC,sBAAsB,EACtB,qBAAqB,EACrB,2BAA2B,EAC5B,MAAM,cAAc,CAAC;AAMtB,wBAAgB,2BAA2B,IAAI,oBAAoB,CAqBlE;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,2BAA2B,GAAG,SAAS,GAC9C,IAAI,CACL,qBAAqB,EACrB,eAAe,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,cAAc,CACxE,CAgCA;AAED,qFAAqF;AACrF,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,IAAI,CAAC,2BAA2B,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,aAAa,CAAC,GAAG,SAAS,EAC/F,YAAY,GAAE,kCAAuC,GACpD;IAAE,UAAU,EAAE,wBAAwB,CAAC;IAAC,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAA;CAAE,CA2BvF;AAOD,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,qBAAqB,CA0BrF;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,GACnB,sBAAsB,GAAG,SAAS,CAgBpC;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,YAAY,GAAE,kCAAuC,GACpD,qBAAqB,CA4BvB;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAahE;AAED,MAAM,WAAW,6BAA6B;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB;AAeD,wFAAwF;AACxF,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,6BAAkC,GAC1C,4BAA4B,CA6D9B"}
@@ -3,13 +3,99 @@ import { hostname } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
4
  import { gunzipSync } from "node:zlib";
5
5
  import { coordEnv } from "../../lib/env.js";
6
+ import { verifyProcessGeneration, } from "../agents/state/proc-start.js";
7
+ import { currentHarneryRuntimeBuild } from "../events/v3/runtime-build.js";
6
8
  import { createStorageCatalog } from "../storage/catalog.js";
7
9
  import { parseLogRecord } from "../storage/jsonl.js";
8
10
  import { familyLogDirectory, readSegmentManifest } from "../storage/segments.js";
9
11
  const MAX_FILE_BYTES = 512 * 1024;
10
12
  const MAX_LOG_RECORDS = 10_000;
11
13
  const MAX_GOALS = 100;
12
- const FOREIGN_STATUS_STALE_MS = 30_000;
14
+ export function currentGovernorServiceBuild() {
15
+ let version = "unknown";
16
+ let revision = "unknown";
17
+ try {
18
+ const manifest = JSON.parse(readFileSync(new URL("../../../package.json", import.meta.url), "utf8"));
19
+ if (typeof manifest.version === "string" && manifest.version.length <= 100) {
20
+ version = manifest.version;
21
+ }
22
+ }
23
+ catch {
24
+ // Missing package metadata cannot establish that the running build is current.
25
+ }
26
+ try {
27
+ revision = currentHarneryRuntimeBuild();
28
+ }
29
+ catch {
30
+ // Status still reports the unavailable build instead of guessing a match.
31
+ }
32
+ return { version, revision };
33
+ }
34
+ export function governorServiceBuildStatus(record) {
35
+ const installed_build = currentGovernorServiceBuild();
36
+ const candidate = record?.running_build;
37
+ const running_build = candidate &&
38
+ typeof candidate.version === "string" &&
39
+ candidate.version.length > 0 &&
40
+ candidate.version.length <= 100 &&
41
+ typeof candidate.revision === "string" &&
42
+ candidate.revision.length > 0 &&
43
+ candidate.revision.length <= 100 &&
44
+ candidate.version !== "unknown" &&
45
+ candidate.revision !== "unknown"
46
+ ? candidate
47
+ : null;
48
+ const restart_needed = running_build === null ||
49
+ installed_build.version === "unknown" ||
50
+ installed_build.revision === "unknown" ||
51
+ running_build.version !== installed_build.version ||
52
+ running_build.revision !== installed_build.revision;
53
+ return {
54
+ running_build,
55
+ installed_build,
56
+ restart_needed,
57
+ build_status: running_build === null
58
+ ? "running build unknown; restart needed"
59
+ : restart_needed
60
+ ? "restart needed"
61
+ : "current",
62
+ };
63
+ }
64
+ /** An unknown token or process probe cannot establish a running or stopped owner. */
65
+ export function observeGovernorServiceProcess(record, dependencies = {}) {
66
+ if (!record)
67
+ return { generation: "unknown", liveness: "stopped" };
68
+ const generation = record.host === hostname()
69
+ ? verifyProcessGeneration(record.pid, record.start_token, dependencies.readToken)
70
+ : "unknown";
71
+ if (record.host !== hostname())
72
+ return { generation, liveness: "unknown" };
73
+ try {
74
+ const present = (dependencies.probePid ?? probePid)(record.pid);
75
+ if (!present)
76
+ return { generation, liveness: "stopped" };
77
+ }
78
+ catch (error) {
79
+ return {
80
+ generation,
81
+ liveness: error.code === "ESRCH" ? "stopped" : "unknown",
82
+ };
83
+ }
84
+ return {
85
+ generation,
86
+ liveness: generation === "same"
87
+ ? record.state === "stopped"
88
+ ? "stopped"
89
+ : "running"
90
+ : generation === "different"
91
+ ? "stopped"
92
+ : "unknown",
93
+ };
94
+ }
95
+ function probePid(pid) {
96
+ process.kill(pid, 0);
97
+ return true;
98
+ }
13
99
  export function readGovernorServiceConfig(coordRootRaw) {
14
100
  const coordRoot = resolve(coordRootRaw);
15
101
  const config = readBoundedJson(join(serviceDir(coordRoot), "config.json"), "governor service configuration");
@@ -48,7 +134,7 @@ export function readGovernorServiceRuntime(coordRootRaw) {
48
134
  }
49
135
  return runtime;
50
136
  }
51
- export function readGovernorServiceStatus(coordRootRaw) {
137
+ export function readGovernorServiceStatus(coordRootRaw, dependencies = {}) {
52
138
  const coordRoot = resolve(coordRootRaw);
53
139
  const record = readStatusRecord(coordRoot);
54
140
  let config;
@@ -65,10 +151,19 @@ export function readGovernorServiceStatus(coordRootRaw) {
65
151
  catch {
66
152
  // Runtime is recoverable and must not make the dashboard unreadable.
67
153
  }
68
- if (!record)
69
- return { running: false, stale: false, config, runtime };
70
- const running = statusOwnerIsLive(record);
71
- return { running, stale: !running && record.state !== "stopped", record, config, runtime };
154
+ const observation = observeGovernorServiceProcess(record, dependencies);
155
+ if (!record && existsSync(join(serviceDir(coordRoot), "status.json"))) {
156
+ observation.liveness = "unknown";
157
+ }
158
+ return {
159
+ running: observation.liveness === "running" && record?.state !== "stopped",
160
+ stale: observation.liveness === "stopped" && record !== undefined && record.state !== "stopped",
161
+ ...observation,
162
+ ...governorServiceBuildStatus(record),
163
+ record,
164
+ config,
165
+ runtime,
166
+ };
72
167
  }
73
168
  export function governorServiceLogPath(coordRoot) {
74
169
  const root = resolve(coordRoot);
@@ -346,27 +441,15 @@ function readStatusRecord(coordRoot) {
346
441
  !validTimestamp(value.heartbeat_at)) {
347
442
  return undefined;
348
443
  }
349
- return value;
444
+ return {
445
+ ...value,
446
+ start_token: typeof value.start_token === "string" ? value.start_token : undefined,
447
+ };
350
448
  }
351
449
  catch {
352
450
  return undefined;
353
451
  }
354
452
  }
355
- function statusOwnerIsLive(record) {
356
- if (record.state === "stopped")
357
- return false;
358
- if (record.host === hostname()) {
359
- try {
360
- process.kill(record.pid, 0);
361
- return true;
362
- }
363
- catch (error) {
364
- return error.code === "EPERM";
365
- }
366
- }
367
- const age = Date.now() - Date.parse(record.heartbeat_at);
368
- return Number.isFinite(age) && age < FOREIGN_STATUS_STALE_MS;
369
- }
370
453
  function readBoundedJson(path, label) {
371
454
  if (!existsSync(path))
372
455
  throw new Error(`${label} does not exist`);
@@ -1,3 +1,4 @@
1
+ import { type ProcessGenerationSignalDependencies, type ProcessGenerationVerdict } from "../agents/state/proc-start.js";
1
2
  import { type NormalizedPolicy, type PolicyIsolation } from "../policy/index.js";
2
3
  import type { RunWorkItemInput } from "../work/index.js";
3
4
  import { type GovernorRunReport, type GovernorStopReason } from "./runner.js";
@@ -50,9 +51,18 @@ export interface GovernorServiceRuntime {
50
51
  goals: Record<string, GovernorServiceGoalRuntime>;
51
52
  }
52
53
  export type GovernorServiceProcessState = "starting" | "running" | "stopping" | "stopped";
54
+ export interface GovernorServiceBuild {
55
+ version: string;
56
+ revision: string;
57
+ }
58
+ export interface GovernorServiceProcessDependencies extends ProcessGenerationSignalDependencies {
59
+ probePid?: (pid: number) => boolean;
60
+ }
53
61
  export interface GovernorServiceStatusRecord {
54
62
  schema_version: typeof GOVERNOR_SERVICE_STATUS_SCHEMA_VERSION;
55
63
  pid: number;
64
+ start_token?: string;
65
+ running_build?: GovernorServiceBuild;
56
66
  host: string;
57
67
  nonce: string;
58
68
  state: GovernorServiceProcessState;
@@ -69,6 +79,14 @@ export interface GovernorServiceStatusRecord {
69
79
  export interface GovernorServiceStatus {
70
80
  running: boolean;
71
81
  stale: boolean;
82
+ generation: ProcessGenerationVerdict;
83
+ liveness: "running" | "stopped" | "unknown";
84
+ running_build: GovernorServiceBuild | null;
85
+ installed_build: GovernorServiceBuild;
86
+ restart_needed: boolean;
87
+ build_status: string;
88
+ signal_sent?: boolean;
89
+ signal_verdict?: ProcessGenerationVerdict;
72
90
  record?: GovernorServiceStatusRecord;
73
91
  config?: GovernorServiceConfig;
74
92
  runtime?: GovernorServiceRuntime;
@@ -105,9 +123,9 @@ export interface RunGovernorServiceDaemonInput {
105
123
  export declare function configureGovernorService(input: ConfigureGovernorServiceInput): GovernorServiceConfig;
106
124
  export declare function readGovernorServiceConfig(coordRootRaw: string): GovernorServiceConfig;
107
125
  export declare function readGovernorServiceRuntime(coordRootRaw: string): GovernorServiceRuntime | undefined;
108
- export declare function readGovernorServiceStatus(coordRootRaw: string): GovernorServiceStatus;
126
+ export declare function readGovernorServiceStatus(coordRootRaw: string, dependencies?: GovernorServiceProcessDependencies): GovernorServiceStatus;
109
127
  export declare function spawnGovernorService(coordRootRaw: string): Promise<GovernorServiceStatus>;
110
- export declare function requestGovernorServiceStop(coordRootRaw: string): GovernorServiceStatus;
128
+ export declare function requestGovernorServiceStop(coordRootRaw: string, dependencies?: GovernorServiceProcessDependencies): GovernorServiceStatus;
111
129
  export declare function runGovernorServiceSweep(input: RunGovernorServiceSweepInput): Promise<GovernorServiceSweepReport>;
112
130
  export declare function runGovernorServiceDaemon(input: RunGovernorServiceDaemonInput): Promise<GovernorServiceStatusRecord>;
113
131
  export declare function governorServiceLogPath(coordRoot: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/governor/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/core/governor/service.ts"],"names":[],"mappings":"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"}
@@ -4,11 +4,14 @@ import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, re
4
4
  import { hostname } from "node:os";
5
5
  import { dirname, join, resolve } from "node:path";
6
6
  import { coordEnv } from "../../lib/env.js";
7
+ import { processStartToken, signalIfSameGeneration, } from "../agents/state/proc-start.js";
8
+ import { resolveBinName } from "../config.js";
7
9
  import { normalizePolicy } from "../policy/index.js";
8
10
  import { closeProcessLoggers, legacyLogFields, processLogger } from "../storage/logger.js";
9
11
  import { stateDirMode, stateFileMode } from "../storage/modes.js";
10
12
  import { RotatingTextSink } from "../storage/process-log.js";
11
13
  import { runGovernor } from "./runner.js";
14
+ import { currentGovernorServiceBuild, governorServiceBuildStatus, observeGovernorServiceProcess, } from "./service-read.js";
12
15
  import { readGovernor } from "./state.js";
13
16
  export const GOVERNOR_SERVICE_CONFIG_SCHEMA_VERSION = 1;
14
17
  export const GOVERNOR_SERVICE_RUNTIME_SCHEMA_VERSION = 1;
@@ -16,12 +19,16 @@ export const GOVERNOR_SERVICE_STATUS_SCHEMA_VERSION = 1;
16
19
  const MAX_FILE_BYTES = 512 * 1024;
17
20
  const MAX_GOALS = 100;
18
21
  const MAX_ERROR = 2_000;
19
- const FOREIGN_STATUS_STALE_MS = 30_000;
20
22
  export function configureGovernorService(input) {
21
23
  const coordRoot = resolve(input.coordRoot);
22
24
  const active = readStatusRecord(coordRoot);
23
- if (active && statusOwnerIsLive(active)) {
24
- throw new Error(`stop governor service pid ${active.pid} before changing its configuration`);
25
+ if (!active && existsSync(serviceStatusPath(coordRoot))) {
26
+ throw serviceStartRefusal(coordRoot, undefined, "unknown");
27
+ }
28
+ if (active) {
29
+ const liveness = statusOwnerIsLive(active);
30
+ if (liveness !== "stopped")
31
+ throw serviceStartRefusal(coordRoot, active.pid, liveness);
25
32
  }
26
33
  const goalIds = unique(input.goalIds.map((value) => value.trim()).filter(Boolean));
27
34
  if (goalIds.length < 1 || goalIds.length > MAX_GOALS) {
@@ -73,7 +80,7 @@ export function readGovernorServiceRuntime(coordRootRaw) {
73
80
  }
74
81
  return runtime;
75
82
  }
76
- export function readGovernorServiceStatus(coordRootRaw) {
83
+ export function readGovernorServiceStatus(coordRootRaw, dependencies = {}) {
77
84
  const coordRoot = resolve(coordRootRaw);
78
85
  const record = readStatusRecord(coordRoot);
79
86
  let config;
@@ -90,17 +97,25 @@ export function readGovernorServiceStatus(coordRootRaw) {
90
97
  catch {
91
98
  // Status remains readable when recoverable runtime state is corrupt.
92
99
  }
93
- if (!record)
94
- return { running: false, stale: false, config, runtime };
95
- const running = statusOwnerIsLive(record);
96
- return { running, stale: !running && record.state !== "stopped", record, config, runtime };
100
+ const observation = observeGovernorServiceProcess(record, dependencies);
101
+ if (!record && existsSync(serviceStatusPath(coordRoot)))
102
+ observation.liveness = "unknown";
103
+ return {
104
+ running: observation.liveness === "running" && record?.state !== "stopped",
105
+ stale: observation.liveness === "stopped" && record !== undefined && record.state !== "stopped",
106
+ ...observation,
107
+ ...governorServiceBuildStatus(record),
108
+ record,
109
+ config,
110
+ runtime,
111
+ };
97
112
  }
98
113
  export async function spawnGovernorService(coordRootRaw) {
99
114
  const coordRoot = resolve(coordRootRaw);
100
115
  readGovernorServiceConfig(coordRoot);
101
116
  const current = readGovernorServiceStatus(coordRoot);
102
- if (current.running) {
103
- throw new Error(`governor service is already running under pid ${current.record?.pid}`);
117
+ if (current.liveness !== "stopped") {
118
+ throw serviceStartRefusal(coordRoot, current.record?.pid, current.liveness);
104
119
  }
105
120
  mkdirSync(serviceDir(coordRoot), { recursive: true, mode: stateDirMode() });
106
121
  const sharedLogs = coordEnv("SHARED_LOGS") !== "0";
@@ -143,24 +158,24 @@ export async function spawnGovernorService(coordRootRaw) {
143
158
  }
144
159
  throw new Error(`governor service failed to start; inspect ${governorServiceLogPath(coordRoot)}`);
145
160
  }
146
- export function requestGovernorServiceStop(coordRootRaw) {
161
+ export function requestGovernorServiceStop(coordRootRaw, dependencies = {}) {
147
162
  const coordRoot = resolve(coordRootRaw);
148
- const status = readGovernorServiceStatus(coordRoot);
149
- if (!status.running || !status.record)
150
- return status;
163
+ const status = readGovernorServiceStatus(coordRoot, dependencies);
164
+ if ((status.record?.state === "stopped" || !status.record) && status.liveness === "stopped") {
165
+ return { ...status, signal_sent: false, signal_verdict: status.generation };
166
+ }
151
167
  writePrivateJsonAtomic(serviceStopPath(coordRoot), {
152
168
  requested_at: new Date().toISOString(),
153
169
  requested_by_pid: process.pid,
154
170
  });
155
- if (status.record.host === hostname()) {
156
- try {
157
- process.kill(status.record.pid, "SIGTERM");
158
- }
159
- catch {
160
- // The durable stop request remains for a racing or restarted daemon.
161
- }
162
- }
163
- return readGovernorServiceStatus(coordRoot);
171
+ const signal = status.record?.host === hostname() && status.record.state !== "stopped"
172
+ ? signalIfSameGeneration(status.record.pid, status.record.start_token, "SIGTERM", dependencies)
173
+ : { sent: false, verdict: status.generation };
174
+ return {
175
+ ...readGovernorServiceStatus(coordRoot, dependencies),
176
+ signal_sent: signal.sent,
177
+ signal_verdict: signal.verdict,
178
+ };
164
179
  }
165
180
  export async function runGovernorServiceSweep(input) {
166
181
  const coordRoot = resolve(input.coordRoot);
@@ -298,12 +313,23 @@ export async function runGovernorServiceSweep(input) {
298
313
  export async function runGovernorServiceDaemon(input) {
299
314
  const coordRoot = resolve(input.coordRoot);
300
315
  const config = readGovernorServiceConfig(coordRoot);
316
+ const existing = readStatusRecord(coordRoot);
317
+ if (!existing && existsSync(serviceStatusPath(coordRoot))) {
318
+ throw serviceStartRefusal(coordRoot, undefined, "unknown");
319
+ }
320
+ if (existing) {
321
+ const liveness = statusOwnerIsLive(existing);
322
+ if (liveness !== "stopped")
323
+ throw serviceStartRefusal(coordRoot, existing.pid, liveness);
324
+ }
301
325
  const release = acquireServiceLease(coordRoot);
302
326
  rmSync(serviceStopPath(coordRoot), { force: true });
303
327
  const now = new Date().toISOString();
304
328
  const status = {
305
329
  schema_version: GOVERNOR_SERVICE_STATUS_SCHEMA_VERSION,
306
330
  pid: process.pid,
331
+ start_token: processStartToken(process.pid) ?? undefined,
332
+ running_build: currentGovernorServiceBuild(),
307
333
  host: hostname(),
308
334
  nonce: randomUUID(),
309
335
  state: "starting",
@@ -330,6 +356,8 @@ export async function runGovernorServiceDaemon(input) {
330
356
  appendGovernorServiceDiagnostic(coordRoot, {
331
357
  event: "service.started",
332
358
  pid: process.pid,
359
+ start_token: status.start_token,
360
+ running_build: status.running_build,
333
361
  goals: config.goal_ids,
334
362
  config_created_at: config.created_at,
335
363
  });
@@ -514,6 +542,8 @@ function acquireServiceLease(coordRoot) {
514
542
  mkdirSync(dirname(path), { recursive: true, mode: stateDirMode() });
515
543
  const owner = {
516
544
  pid: process.pid,
545
+ start_token: processStartToken(process.pid) ?? undefined,
546
+ running_build: currentGovernorServiceBuild(),
517
547
  host: hostname(),
518
548
  nonce: randomUUID(),
519
549
  created_at: new Date().toISOString(),
@@ -537,8 +567,9 @@ function acquireServiceLease(coordRoot) {
537
567
  };
538
568
  if (!acquire()) {
539
569
  const existing = readLease(path);
540
- if (existing && leaseOwnerIsLive(existing)) {
541
- throw new Error(`governor service is already running under pid ${existing.pid}`);
570
+ const liveness = existing ? leaseOwnerIsLive(existing) : "unknown";
571
+ if (liveness !== "stopped") {
572
+ throw serviceStartRefusal(coordRoot, existing?.pid, liveness);
542
573
  }
543
574
  unlinkSync(path);
544
575
  if (!acquire())
@@ -563,7 +594,10 @@ function readLease(path) {
563
594
  typeof value.host === "string" &&
564
595
  typeof value.nonce === "string" &&
565
596
  typeof value.created_at === "string"
566
- ? value
597
+ ? {
598
+ ...value,
599
+ start_token: typeof value.start_token === "string" ? value.start_token : undefined,
600
+ }
567
601
  : null;
568
602
  }
569
603
  catch {
@@ -571,11 +605,7 @@ function readLease(path) {
571
605
  }
572
606
  }
573
607
  function leaseOwnerIsLive(lease) {
574
- if (lease.host !== hostname()) {
575
- const age = Date.now() - Date.parse(lease.created_at);
576
- return Number.isFinite(age) && age < FOREIGN_STATUS_STALE_MS;
577
- }
578
- return pidAlive(lease.pid);
608
+ return observeGovernorServiceProcess({ ...lease, state: "running" }).liveness;
579
609
  }
580
610
  function readStatusRecord(coordRoot) {
581
611
  if (!existsSync(serviceStatusPath(coordRoot)))
@@ -591,28 +621,23 @@ function readStatusRecord(coordRoot) {
591
621
  !validTimestamp(value.heartbeat_at)) {
592
622
  return undefined;
593
623
  }
594
- return value;
624
+ return {
625
+ ...value,
626
+ start_token: typeof value.start_token === "string" ? value.start_token : undefined,
627
+ };
595
628
  }
596
629
  catch {
597
630
  return undefined;
598
631
  }
599
632
  }
600
633
  function statusOwnerIsLive(record) {
601
- if (record.state === "stopped")
602
- return false;
603
- if (record.host === hostname())
604
- return pidAlive(record.pid);
605
- const age = Date.now() - Date.parse(record.heartbeat_at);
606
- return Number.isFinite(age) && age < FOREIGN_STATUS_STALE_MS;
607
- }
608
- function pidAlive(pid) {
609
- try {
610
- process.kill(pid, 0);
611
- return true;
612
- }
613
- catch (error) {
614
- return error.code === "EPERM";
615
- }
634
+ return observeGovernorServiceProcess(record).liveness;
635
+ }
636
+ function serviceStartRefusal(coordRoot, pid, liveness) {
637
+ const reason = liveness === "unknown"
638
+ ? `governor service process generation is unknown${pid ? ` for pid ${pid}` : ""}`
639
+ : `governor service process is still running under pid ${pid}`;
640
+ return new Error(`${reason}; run \`${resolveBinName(coordRoot)} governor service stop\` to write a durable stop request before starting or reconfiguring it`);
616
641
  }
617
642
  export function appendGovernorServiceDiagnostic(coordRoot, data) {
618
643
  if (coordEnv("SHARED_LOGS") !== "0") {