harnery 0.40.0 → 0.42.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 (595) hide show
  1. package/README.md +1 -1
  2. package/dist/commander.js +4 -0
  3. package/dist/commands/agents.d.ts.map +1 -1
  4. package/dist/commands/agents.js +34 -20
  5. package/dist/commands/artifacts.d.ts.map +1 -1
  6. package/dist/commands/artifacts.js +113 -12
  7. package/dist/commands/browse-ai.d.ts.map +1 -1
  8. package/dist/commands/browse-ai.js +4 -0
  9. package/dist/commands/browse.d.ts +164 -0
  10. package/dist/commands/browse.d.ts.map +1 -1
  11. package/dist/commands/browse.js +388 -45
  12. package/dist/commands/checkpoint.js +8 -12
  13. package/dist/commands/claude-desktop.d.ts.map +1 -1
  14. package/dist/commands/claude-desktop.js +52 -0
  15. package/dist/commands/deinit.d.ts +1 -1
  16. package/dist/commands/deinit.d.ts.map +1 -1
  17. package/dist/commands/deinit.js +8 -4
  18. package/dist/commands/disk.d.ts +6 -0
  19. package/dist/commands/disk.d.ts.map +1 -0
  20. package/dist/commands/disk.js +80 -0
  21. package/dist/commands/docs.d.ts.map +1 -1
  22. package/dist/commands/docs.js +2 -0
  23. package/dist/commands/doctor.d.ts +8 -0
  24. package/dist/commands/doctor.d.ts.map +1 -1
  25. package/dist/commands/doctor.js +58 -3
  26. package/dist/commands/fetch.d.ts.map +1 -1
  27. package/dist/commands/fetch.js +10 -0
  28. package/dist/commands/files.d.ts +16 -0
  29. package/dist/commands/files.d.ts.map +1 -1
  30. package/dist/commands/files.js +54 -2
  31. package/dist/commands/init.d.ts +21 -5
  32. package/dist/commands/init.d.ts.map +1 -1
  33. package/dist/commands/init.js +271 -109
  34. package/dist/commands/instructions.js +5 -4
  35. package/dist/commands/ledger-v3.d.ts.map +1 -1
  36. package/dist/commands/ledger-v3.js +2 -1
  37. package/dist/commands/rm.d.ts +4 -0
  38. package/dist/commands/rm.d.ts.map +1 -0
  39. package/dist/commands/rm.js +87 -0
  40. package/dist/commands/servers.d.ts +7 -0
  41. package/dist/commands/servers.d.ts.map +1 -0
  42. package/dist/commands/servers.js +394 -0
  43. package/dist/commands/tunnel.d.ts.map +1 -1
  44. package/dist/commands/tunnel.js +82 -2
  45. package/dist/commands/webview.d.ts +4 -0
  46. package/dist/commands/webview.d.ts.map +1 -0
  47. package/dist/commands/webview.js +94 -0
  48. package/dist/core/adapter.d.ts +50 -1
  49. package/dist/core/adapter.d.ts.map +1 -1
  50. package/dist/core/adapter.js +59 -1
  51. package/dist/core/adapters/attestation.d.ts.map +1 -1
  52. package/dist/core/adapters/attestation.js +3 -2
  53. package/dist/core/adapters/profiles.d.ts +29 -3
  54. package/dist/core/adapters/profiles.d.ts.map +1 -1
  55. package/dist/core/adapters/profiles.js +53 -1
  56. package/dist/core/adapters/registry.d.ts.map +1 -1
  57. package/dist/core/adapters/registry.js +33 -0
  58. package/dist/core/adapters/types.d.ts +9 -0
  59. package/dist/core/adapters/types.d.ts.map +1 -1
  60. package/dist/core/agents/canonical-emit.d.ts +1 -1
  61. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  62. package/dist/core/agents/canonical-emit.js +2 -7
  63. package/dist/core/agents/cli.js +25 -16
  64. package/dist/core/agents/coord-client.d.ts.map +1 -1
  65. package/dist/core/agents/coord-client.js +7 -2
  66. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  67. package/dist/core/agents/render/session-context.js +2 -0
  68. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
  69. package/dist/core/agents/rules/claim-conflict.js +3 -9
  70. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  71. package/dist/core/agents/rules/commit-conflict.js +2 -8
  72. package/dist/core/agents/rules/stop-hook.d.ts +2 -0
  73. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  74. package/dist/core/agents/rules/stop-hook.js +1 -1
  75. package/dist/core/agents/session-events.d.ts +6 -2
  76. package/dist/core/agents/session-events.d.ts.map +1 -1
  77. package/dist/core/agents/session-events.js +105 -26
  78. package/dist/core/agents/session-finalization-state-v3.d.ts.map +1 -1
  79. package/dist/core/agents/session-finalization-state-v3.js +2 -1
  80. package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -1
  81. package/dist/core/agents/session-finalizer-v3.js +5 -4
  82. package/dist/core/agents/session-name-display.d.ts +28 -0
  83. package/dist/core/agents/session-name-display.d.ts.map +1 -1
  84. package/dist/core/agents/session-name-display.js +43 -0
  85. package/dist/core/agents/state/heartbeat-reader.d.ts +7 -0
  86. package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
  87. package/dist/core/agents/state/heartbeat-writer.d.ts +10 -0
  88. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  89. package/dist/core/agents/state/heartbeat-writer.js +21 -2
  90. package/dist/core/agents/state/live-coordination-view.d.ts +20 -0
  91. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  92. package/dist/core/agents/state/live-coordination-view.js +61 -0
  93. package/dist/core/agents/state/live-coordination-writer.js +3 -0
  94. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  95. package/dist/core/agents/state/stale-sweep.js +2 -10
  96. package/dist/core/agents/turn-changes.d.ts +17 -0
  97. package/dist/core/agents/turn-changes.d.ts.map +1 -0
  98. package/dist/core/agents/turn-changes.js +76 -0
  99. package/dist/core/artifacts/delivery-card.d.ts.map +1 -1
  100. package/dist/core/artifacts/delivery-card.js +11 -3
  101. package/dist/core/artifacts/index.d.ts +140 -4
  102. package/dist/core/artifacts/index.d.ts.map +1 -1
  103. package/dist/core/artifacts/index.js +526 -52
  104. package/dist/core/config.d.ts +73 -11
  105. package/dist/core/config.d.ts.map +1 -1
  106. package/dist/core/config.js +142 -3
  107. package/dist/core/context/index.d.ts.map +1 -1
  108. package/dist/core/context/index.js +2 -1
  109. package/dist/core/conversations/archive.d.ts.map +1 -1
  110. package/dist/core/conversations/archive.js +4 -3
  111. package/dist/core/diagnostics/bundle.d.ts.map +1 -1
  112. package/dist/core/diagnostics/bundle.js +5 -4
  113. package/dist/core/events/legacy-storage/canary.d.ts.map +1 -1
  114. package/dist/core/events/legacy-storage/canary.js +5 -4
  115. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -1
  116. package/dist/core/events/legacy-storage/compression.js +2 -1
  117. package/dist/core/events/v3/adapter-id.d.ts +10 -2
  118. package/dist/core/events/v3/adapter-id.d.ts.map +1 -1
  119. package/dist/core/events/v3/adapter-id.js +16 -0
  120. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
  121. package/dist/core/events/v3/authority-outbox.js +2 -1
  122. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  123. package/dist/core/events/v3/bootstrap.js +5 -4
  124. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  125. package/dist/core/events/v3/capabilities.js +17 -0
  126. package/dist/core/events/v3/contract.d.ts +5 -0
  127. package/dist/core/events/v3/contract.d.ts.map +1 -1
  128. package/dist/core/events/v3/contract.js +7 -1
  129. package/dist/core/events/v3/control-witness.d.ts.map +1 -1
  130. package/dist/core/events/v3/control-witness.js +3 -2
  131. package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -1
  132. package/dist/core/events/v3/coordination-transaction-recovery.js +4 -3
  133. package/dist/core/events/v3/fingerprint-keys.d.ts.map +1 -1
  134. package/dist/core/events/v3/fingerprint-keys.js +7 -6
  135. package/dist/core/events/v3/generated.d.ts +1 -1
  136. package/dist/core/events/v3/generated.js +1 -1
  137. package/dist/core/events/v3/live-feed.d.ts.map +1 -1
  138. package/dist/core/events/v3/live-feed.js +5 -4
  139. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  140. package/dist/core/events/v3/producers/command-recorder.js +8 -7
  141. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  142. package/dist/core/events/v3/producers/coordination-recorder.js +8 -7
  143. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -1
  144. package/dist/core/events/v3/producers/diagnostic-summaries.js +5 -4
  145. package/dist/core/events/v3/producers/hook-base.d.ts +1 -0
  146. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  147. package/dist/core/events/v3/producers/hook-base.js +10 -4
  148. package/dist/core/events/v3/producers/hook.d.ts +2 -0
  149. package/dist/core/events/v3/producers/hook.d.ts.map +1 -1
  150. package/dist/core/events/v3/producers/hook.js +16 -1
  151. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  152. package/dist/core/events/v3/producers/intake.js +16 -6
  153. package/dist/core/events/v3/producers/recorder.d.ts +2 -4
  154. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  155. package/dist/core/events/v3/producers/recorder.js +125 -101
  156. package/dist/core/events/v3/projection.js +9 -1
  157. package/dist/core/events/v3/recovery.d.ts.map +1 -1
  158. package/dist/core/events/v3/recovery.js +4 -3
  159. package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -1
  160. package/dist/core/events/v3/support-storage/inventory.js +2 -1
  161. package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -1
  162. package/dist/core/events/v3/support-storage/maintenance.js +4 -3
  163. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -1
  164. package/dist/core/events/v3/support-storage/pack-reader.js +4 -3
  165. package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -1
  166. package/dist/core/events/v3/support-storage/pack-writer.js +6 -5
  167. package/dist/core/events/v3/tool-line-changes.d.ts +8 -0
  168. package/dist/core/events/v3/tool-line-changes.d.ts.map +1 -0
  169. package/dist/core/events/v3/tool-line-changes.js +135 -0
  170. package/dist/core/events/v3/writer.d.ts.map +1 -1
  171. package/dist/core/events/v3/writer.js +8 -7
  172. package/dist/core/governor/planning.d.ts.map +1 -1
  173. package/dist/core/governor/planning.js +6 -5
  174. package/dist/core/governor/service.d.ts.map +1 -1
  175. package/dist/core/governor/service.js +12 -11
  176. package/dist/core/governor/state.d.ts.map +1 -1
  177. package/dist/core/governor/state.js +7 -6
  178. package/dist/core/guard/evaluator.js +1 -0
  179. package/dist/core/guard/storage.d.ts.map +1 -1
  180. package/dist/core/guard/storage.js +3 -2
  181. package/dist/core/hooks/adapter/behaviors/claude-code.d.ts +4 -0
  182. package/dist/core/hooks/adapter/behaviors/claude-code.d.ts.map +1 -0
  183. package/dist/core/hooks/adapter/behaviors/claude-code.js +31 -0
  184. package/dist/core/hooks/adapter/behaviors/codex.d.ts +15 -0
  185. package/dist/core/hooks/adapter/behaviors/codex.d.ts.map +1 -0
  186. package/dist/core/hooks/adapter/behaviors/codex.js +82 -0
  187. package/dist/core/hooks/adapter/behaviors/cursor.d.ts +7 -0
  188. package/dist/core/hooks/adapter/behaviors/cursor.d.ts.map +1 -0
  189. package/dist/core/hooks/adapter/behaviors/cursor.js +35 -0
  190. package/dist/core/hooks/adapter/behaviors/index.d.ts +11 -0
  191. package/dist/core/hooks/adapter/behaviors/index.d.ts.map +1 -0
  192. package/dist/core/hooks/adapter/behaviors/index.js +20 -0
  193. package/dist/core/hooks/adapter/behaviors/openclaw.d.ts +7 -0
  194. package/dist/core/hooks/adapter/behaviors/openclaw.d.ts.map +1 -0
  195. package/dist/core/hooks/adapter/behaviors/openclaw.js +34 -0
  196. package/dist/core/hooks/adapter/behaviors/opencode.d.ts +7 -0
  197. package/dist/core/hooks/adapter/behaviors/opencode.d.ts.map +1 -0
  198. package/dist/core/hooks/adapter/behaviors/opencode.js +34 -0
  199. package/dist/core/hooks/adapter/behaviors/types.d.ts +89 -0
  200. package/dist/core/hooks/adapter/behaviors/types.d.ts.map +1 -0
  201. package/dist/core/hooks/adapter/behaviors/types.js +1 -0
  202. package/dist/core/hooks/adapter/detect.d.ts +1 -1
  203. package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
  204. package/dist/core/hooks/adapter/detect.js +2 -3
  205. package/dist/core/hooks/adapter/events.d.ts +46 -1
  206. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  207. package/dist/core/hooks/adapter/events.js +36 -0
  208. package/dist/core/hooks/adapter/opencode-plugin.d.ts +60 -0
  209. package/dist/core/hooks/adapter/opencode-plugin.d.ts.map +1 -0
  210. package/dist/core/hooks/adapter/opencode-plugin.js +129 -0
  211. package/dist/core/hooks/adapter/output.d.ts +7 -0
  212. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  213. package/dist/core/hooks/adapter/output.js +8 -1
  214. package/dist/core/hooks/adapter/runtime-telemetry.js +3 -1
  215. package/dist/core/hooks/adapter/wiring.d.ts +52 -8
  216. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  217. package/dist/core/hooks/adapter/wiring.js +133 -12
  218. package/dist/core/hooks/cli.js +676 -531
  219. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  220. package/dist/core/hooks/effects/image-capture.js +2 -1
  221. package/dist/core/hooks/prompt-context/contract.d.ts.map +1 -1
  222. package/dist/core/hooks/prompt-context/contract.js +1 -0
  223. package/dist/core/hooks/resolve/transcript.d.ts +1 -1
  224. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  225. package/dist/core/hooks/resolve/transcript.js +35 -4
  226. package/dist/core/hooks/run-markers.d.ts +37 -0
  227. package/dist/core/hooks/run-markers.d.ts.map +1 -0
  228. package/dist/core/hooks/run-markers.js +109 -0
  229. package/dist/core/hooks/session-name-presence.d.ts +3 -1
  230. package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
  231. package/dist/core/hooks/session-name-presence.js +7 -2
  232. package/dist/core/hooks/shell-waiter.d.ts +2 -0
  233. package/dist/core/hooks/shell-waiter.d.ts.map +1 -0
  234. package/dist/core/hooks/shell-waiter.js +173 -0
  235. package/dist/core/resources/service.d.ts.map +1 -1
  236. package/dist/core/resources/service.js +5 -4
  237. package/dist/core/semantic/review.d.ts.map +1 -1
  238. package/dist/core/semantic/review.js +5 -4
  239. package/dist/core/semantic/service.d.ts.map +1 -1
  240. package/dist/core/semantic/service.js +15 -14
  241. package/dist/core/semantic/storage.d.ts.map +1 -1
  242. package/dist/core/semantic/storage.js +5 -4
  243. package/dist/core/servers/index.d.ts +211 -0
  244. package/dist/core/servers/index.d.ts.map +1 -0
  245. package/dist/core/servers/index.js +560 -0
  246. package/dist/core/servers/net.d.ts +58 -0
  247. package/dist/core/servers/net.d.ts.map +1 -0
  248. package/dist/core/servers/net.js +270 -0
  249. package/dist/core/servers/tunnels.d.ts +14 -0
  250. package/dist/core/servers/tunnels.d.ts.map +1 -0
  251. package/dist/core/servers/tunnels.js +33 -0
  252. package/dist/core/storage/atomic-json.d.ts.map +1 -1
  253. package/dist/core/storage/atomic-json.js +7 -3
  254. package/dist/core/storage/builtins.js +1 -0
  255. package/dist/core/storage/durable-history.d.ts.map +1 -1
  256. package/dist/core/storage/durable-history.js +6 -5
  257. package/dist/core/storage/maintenance-providers.d.ts.map +1 -1
  258. package/dist/core/storage/maintenance-providers.js +2 -1
  259. package/dist/core/storage/maintenance.d.ts.map +1 -1
  260. package/dist/core/storage/maintenance.js +7 -6
  261. package/dist/core/storage/metrics.d.ts.map +1 -1
  262. package/dist/core/storage/metrics.js +5 -1
  263. package/dist/core/storage/modes.d.ts +17 -0
  264. package/dist/core/storage/modes.d.ts.map +1 -0
  265. package/dist/core/storage/modes.js +47 -0
  266. package/dist/core/storage/process-log.d.ts.map +1 -1
  267. package/dist/core/storage/process-log.js +3 -2
  268. package/dist/core/storage/receipts.d.ts.map +1 -1
  269. package/dist/core/storage/receipts.js +4 -3
  270. package/dist/core/storage/segments.d.ts.map +1 -1
  271. package/dist/core/storage/segments.js +7 -6
  272. package/dist/core/supervisor/hook-health.d.ts +2 -1
  273. package/dist/core/supervisor/hook-health.d.ts.map +1 -1
  274. package/dist/core/supervisor/hook-health.js +4 -3
  275. package/dist/core/supervisor/service.d.ts.map +1 -1
  276. package/dist/core/supervisor/service.js +7 -6
  277. package/dist/core/work/state.d.ts.map +1 -1
  278. package/dist/core/work/state.js +8 -7
  279. package/dist/core/workflow/adapters.d.ts +7 -0
  280. package/dist/core/workflow/adapters.d.ts.map +1 -1
  281. package/dist/core/workflow/adapters.js +9 -0
  282. package/dist/core/workflow/approvals.d.ts.map +1 -1
  283. package/dist/core/workflow/approvals.js +6 -5
  284. package/dist/core/workflow/billing.d.ts.map +1 -1
  285. package/dist/core/workflow/billing.js +33 -4
  286. package/dist/core/workflow/durable-record.d.ts.map +1 -1
  287. package/dist/core/workflow/durable-record.js +4 -3
  288. package/dist/core/workflow/engine.d.ts.map +1 -1
  289. package/dist/core/workflow/engine.js +30 -1
  290. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  291. package/dist/core/workflow/live-session-v3.js +2 -3
  292. package/dist/core/workflow/run-state.d.ts.map +1 -1
  293. package/dist/core/workflow/run-state.js +3 -2
  294. package/dist/core/workflow/sandbox-projection.d.ts +13 -2
  295. package/dist/core/workflow/sandbox-projection.d.ts.map +1 -1
  296. package/dist/core/workflow/sandbox-projection.js +23 -0
  297. package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
  298. package/dist/core/workflow/spawn-claude.js +6 -1
  299. package/dist/core/workflow/spawn-codex.d.ts +2 -0
  300. package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
  301. package/dist/core/workflow/spawn-codex.js +20 -1
  302. package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
  303. package/dist/core/workflow/spawn-cursor.js +6 -1
  304. package/dist/core/workflow/spawn-opencode.d.ts +36 -0
  305. package/dist/core/workflow/spawn-opencode.d.ts.map +1 -0
  306. package/dist/core/workflow/spawn-opencode.js +135 -0
  307. package/dist/core/workflow/transcript.d.ts.map +1 -1
  308. package/dist/core/workflow/transcript.js +3 -2
  309. package/dist/core/workflow/types.d.ts +47 -2
  310. package/dist/core/workflow/types.d.ts.map +1 -1
  311. package/dist/core/workflow/worker-access.d.ts +92 -0
  312. package/dist/core/workflow/worker-access.d.ts.map +1 -0
  313. package/dist/core/workflow/worker-access.js +450 -0
  314. package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
  315. package/dist/core/workflow/workspaces/leases.js +5 -4
  316. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  317. package/dist/core/workflow/workspaces/local-git.js +3 -2
  318. package/dist/core/workflow/workspaces/paths.d.ts.map +1 -1
  319. package/dist/core/workflow/workspaces/paths.js +2 -1
  320. package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
  321. package/dist/core/workflow/workspaces/state.js +10 -9
  322. package/dist/lazy-commands.js +8 -1
  323. package/dist/lib/agent-browser/client.d.ts +9 -0
  324. package/dist/lib/agent-browser/client.d.ts.map +1 -1
  325. package/dist/lib/agent-browser/client.js +13 -0
  326. package/dist/lib/browser/batch-steps.d.ts +18 -0
  327. package/dist/lib/browser/batch-steps.d.ts.map +1 -0
  328. package/dist/lib/browser/batch-steps.js +82 -0
  329. package/dist/lib/browser/client.d.ts +35 -1
  330. package/dist/lib/browser/client.d.ts.map +1 -1
  331. package/dist/lib/browser/client.js +117 -8
  332. package/dist/lib/browser/collect/collector.d.ts +99 -0
  333. package/dist/lib/browser/collect/collector.d.ts.map +1 -0
  334. package/dist/lib/browser/collect/collector.js +202 -0
  335. package/dist/lib/browser/collect/fields.d.ts +31 -0
  336. package/dist/lib/browser/collect/fields.d.ts.map +1 -0
  337. package/dist/lib/browser/collect/fields.js +75 -0
  338. package/dist/lib/browser/collect/index.d.ts +6 -0
  339. package/dist/lib/browser/collect/index.d.ts.map +1 -0
  340. package/dist/lib/browser/collect/index.js +5 -0
  341. package/dist/lib/browser/collect/page-driver.d.ts +14 -0
  342. package/dist/lib/browser/collect/page-driver.d.ts.map +1 -0
  343. package/dist/lib/browser/collect/page-driver.js +306 -0
  344. package/dist/lib/browser/collect/presets.d.ts +52 -0
  345. package/dist/lib/browser/collect/presets.d.ts.map +1 -0
  346. package/dist/lib/browser/collect/presets.js +176 -0
  347. package/dist/lib/browser/collect/scroll-plan.d.ts +85 -0
  348. package/dist/lib/browser/collect/scroll-plan.d.ts.map +1 -0
  349. package/dist/lib/browser/collect/scroll-plan.js +118 -0
  350. package/dist/lib/browser/identity.d.ts +25 -0
  351. package/dist/lib/browser/identity.d.ts.map +1 -0
  352. package/dist/lib/browser/identity.js +66 -0
  353. package/dist/lib/browser/index.d.ts +3 -2
  354. package/dist/lib/browser/index.d.ts.map +1 -1
  355. package/dist/lib/browser/index.js +2 -1
  356. package/dist/lib/browser/launch-args.d.ts +26 -0
  357. package/dist/lib/browser/launch-args.d.ts.map +1 -1
  358. package/dist/lib/browser/launch-args.js +41 -1
  359. package/dist/lib/browser/page-review-judge.d.ts +2 -0
  360. package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
  361. package/dist/lib/browser/page-review-judge.js +13 -0
  362. package/dist/lib/browser/qa-run-contracts.d.ts +10 -0
  363. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
  364. package/dist/lib/browser/qa-run.d.ts.map +1 -1
  365. package/dist/lib/browser/qa-run.js +1 -0
  366. package/dist/lib/browser/user-agent.d.ts +53 -0
  367. package/dist/lib/browser/user-agent.d.ts.map +1 -0
  368. package/dist/lib/browser/user-agent.js +79 -0
  369. package/dist/lib/browser/windows-chrome.d.ts +59 -0
  370. package/dist/lib/browser/windows-chrome.d.ts.map +1 -0
  371. package/dist/lib/browser/windows-chrome.js +179 -0
  372. package/dist/lib/claude-desktop-share.d.ts +136 -0
  373. package/dist/lib/claude-desktop-share.d.ts.map +1 -0
  374. package/dist/lib/claude-desktop-share.js +394 -0
  375. package/dist/lib/disk-usage.d.ts +50 -0
  376. package/dist/lib/disk-usage.d.ts.map +1 -0
  377. package/dist/lib/disk-usage.js +303 -0
  378. package/dist/lib/docs-lint.d.ts +6 -0
  379. package/dist/lib/docs-lint.d.ts.map +1 -1
  380. package/dist/lib/docs-lint.js +8 -3
  381. package/dist/lib/docs-metadata-managed.d.ts +1 -0
  382. package/dist/lib/docs-metadata-managed.d.ts.map +1 -1
  383. package/dist/lib/docs-metadata-managed.js +17 -1
  384. package/dist/lib/guarded-remove.d.ts +34 -0
  385. package/dist/lib/guarded-remove.d.ts.map +1 -0
  386. package/dist/lib/guarded-remove.js +310 -0
  387. package/dist/lib/identities/assume.d.ts.map +1 -1
  388. package/dist/lib/identities/assume.js +4 -9
  389. package/dist/lib/instructions/apply.d.ts.map +1 -1
  390. package/dist/lib/instructions/apply.js +2 -0
  391. package/dist/lib/instructions/templates.js +8 -8
  392. package/dist/lib/pace/index.d.ts +2 -0
  393. package/dist/lib/pace/index.d.ts.map +1 -0
  394. package/dist/lib/pace/index.js +1 -0
  395. package/dist/lib/pace/pace.d.ts +95 -0
  396. package/dist/lib/pace/pace.d.ts.map +1 -0
  397. package/dist/lib/pace/pace.js +313 -0
  398. package/dist/lib/tunnel/error-page.d.ts +1 -1
  399. package/dist/lib/tunnel/error-page.d.ts.map +1 -1
  400. package/dist/lib/tunnel/error-page.js +19 -8
  401. package/dist/lib/tunnel/forward-headers.d.ts +11 -0
  402. package/dist/lib/tunnel/forward-headers.d.ts.map +1 -0
  403. package/dist/lib/tunnel/forward-headers.js +17 -0
  404. package/dist/lib/tunnel/gate.js +34 -10
  405. package/dist/lib/tunnel/path-scope.d.ts +22 -0
  406. package/dist/lib/tunnel/path-scope.d.ts.map +1 -0
  407. package/dist/lib/tunnel/path-scope.js +62 -0
  408. package/dist/lib/tunnel/state.d.ts +5 -0
  409. package/dist/lib/tunnel/state.d.ts.map +1 -1
  410. package/dist/lib/tunnel/state.js +17 -3
  411. package/dist/lib/webview/index.d.ts +2 -0
  412. package/dist/lib/webview/index.d.ts.map +1 -0
  413. package/dist/lib/webview/index.js +1 -0
  414. package/dist/lib/webview/webview.d.ts +116 -0
  415. package/dist/lib/webview/webview.d.ts.map +1 -0
  416. package/dist/lib/webview/webview.js +289 -0
  417. package/opencode-plugin/package.json +19 -0
  418. package/opencode-plugin/src/index.ts +791 -0
  419. package/package.json +16 -4
  420. package/schemas/config.schema.json +104 -0
  421. package/schemas/event-v3.schema.json +164 -0
  422. package/src/commander.ts +26 -0
  423. package/src/commands/agents.ts +47 -18
  424. package/src/commands/artifacts.ts +171 -19
  425. package/src/commands/browse-ai.ts +8 -0
  426. package/src/commands/browse.ts +570 -48
  427. package/src/commands/checkpoint.ts +7 -9
  428. package/src/commands/claude-desktop.ts +61 -0
  429. package/src/commands/deinit.ts +9 -4
  430. package/src/commands/disk.ts +114 -0
  431. package/src/commands/docs.ts +2 -0
  432. package/src/commands/doctor.ts +63 -3
  433. package/src/commands/fetch.ts +14 -0
  434. package/src/commands/files.ts +93 -2
  435. package/src/commands/init.ts +334 -122
  436. package/src/commands/instructions.ts +8 -4
  437. package/src/commands/ledger-v3.ts +2 -1
  438. package/src/commands/rm.ts +115 -0
  439. package/src/commands/servers.ts +506 -0
  440. package/src/commands/tunnel.ts +102 -2
  441. package/src/commands/webview.ts +159 -0
  442. package/src/core/adapter.ts +102 -1
  443. package/src/core/adapters/attestation.ts +3 -2
  444. package/src/core/adapters/profiles.ts +63 -1
  445. package/src/core/adapters/registry.ts +37 -0
  446. package/src/core/adapters/types.ts +10 -0
  447. package/src/core/agents/canonical-emit.ts +2 -5
  448. package/src/core/agents/cli.ts +26 -17
  449. package/src/core/agents/coord-client.ts +9 -3
  450. package/src/core/agents/render/session-context.ts +1 -0
  451. package/src/core/agents/rules/claim-conflict.ts +3 -8
  452. package/src/core/agents/rules/commit-conflict.ts +2 -7
  453. package/src/core/agents/rules/stop-hook.ts +3 -1
  454. package/src/core/agents/session-events.ts +120 -26
  455. package/src/core/agents/session-finalization-state-v3.ts +2 -1
  456. package/src/core/agents/session-finalizer-v3.ts +5 -4
  457. package/src/core/agents/session-name-display.ts +48 -0
  458. package/src/core/agents/state/heartbeat-reader.ts +7 -0
  459. package/src/core/agents/state/heartbeat-writer.ts +24 -2
  460. package/src/core/agents/state/live-coordination-view.ts +74 -0
  461. package/src/core/agents/state/live-coordination-writer.ts +3 -0
  462. package/src/core/agents/state/stale-sweep.ts +2 -9
  463. package/src/core/agents/turn-changes.ts +97 -0
  464. package/src/core/artifacts/delivery-card.ts +12 -3
  465. package/src/core/artifacts/index.ts +701 -47
  466. package/src/core/config.ts +206 -4
  467. package/src/core/context/index.ts +2 -1
  468. package/src/core/conversations/archive.ts +4 -3
  469. package/src/core/diagnostics/bundle.ts +5 -3
  470. package/src/core/events/legacy-storage/canary.ts +5 -4
  471. package/src/core/events/legacy-storage/compression.ts +2 -1
  472. package/src/core/events/v3/adapter-id.ts +29 -1
  473. package/src/core/events/v3/authority-outbox.ts +2 -1
  474. package/src/core/events/v3/bootstrap.ts +5 -4
  475. package/src/core/events/v3/capabilities.ts +17 -0
  476. package/src/core/events/v3/contract.ts +9 -1
  477. package/src/core/events/v3/control-witness.ts +3 -2
  478. package/src/core/events/v3/coordination-transaction-recovery.ts +4 -3
  479. package/src/core/events/v3/fingerprint-keys.ts +7 -6
  480. package/src/core/events/v3/generated.ts +1 -1
  481. package/src/core/events/v3/live-feed.ts +5 -4
  482. package/src/core/events/v3/producers/command-recorder.ts +8 -6
  483. package/src/core/events/v3/producers/coordination-recorder.ts +8 -7
  484. package/src/core/events/v3/producers/diagnostic-summaries.ts +5 -4
  485. package/src/core/events/v3/producers/hook-base.ts +11 -4
  486. package/src/core/events/v3/producers/hook.ts +19 -1
  487. package/src/core/events/v3/producers/intake.ts +18 -6
  488. package/src/core/events/v3/producers/recorder.ts +139 -114
  489. package/src/core/events/v3/projection.ts +11 -1
  490. package/src/core/events/v3/recovery.ts +4 -3
  491. package/src/core/events/v3/support-storage/inventory.ts +2 -1
  492. package/src/core/events/v3/support-storage/maintenance.ts +8 -3
  493. package/src/core/events/v3/support-storage/pack-reader.ts +4 -3
  494. package/src/core/events/v3/support-storage/pack-writer.ts +6 -5
  495. package/src/core/events/v3/tool-line-changes.ts +139 -0
  496. package/src/core/events/v3/writer.ts +8 -7
  497. package/src/core/governor/planning.ts +6 -5
  498. package/src/core/governor/service.ts +12 -11
  499. package/src/core/governor/state.ts +7 -6
  500. package/src/core/guard/evaluator.ts +1 -0
  501. package/src/core/guard/storage.ts +3 -2
  502. package/src/core/hooks/adapter/behaviors/claude-code.ts +33 -0
  503. package/src/core/hooks/adapter/behaviors/codex.ts +96 -0
  504. package/src/core/hooks/adapter/behaviors/cursor.ts +37 -0
  505. package/src/core/hooks/adapter/behaviors/index.ts +31 -0
  506. package/src/core/hooks/adapter/behaviors/openclaw.ts +36 -0
  507. package/src/core/hooks/adapter/behaviors/opencode.ts +36 -0
  508. package/src/core/hooks/adapter/behaviors/types.ts +110 -0
  509. package/src/core/hooks/adapter/detect.ts +2 -3
  510. package/src/core/hooks/adapter/events.ts +72 -1
  511. package/src/core/hooks/adapter/opencode-plugin.ts +177 -0
  512. package/src/core/hooks/adapter/output.ts +8 -1
  513. package/src/core/hooks/adapter/runtime-telemetry.ts +3 -1
  514. package/src/core/hooks/adapter/wiring.ts +198 -16
  515. package/src/core/hooks/cli.ts +776 -539
  516. package/src/core/hooks/effects/image-capture.ts +2 -1
  517. package/src/core/hooks/prompt-context/contract.ts +1 -0
  518. package/src/core/hooks/resolve/transcript.ts +42 -5
  519. package/src/core/hooks/run-markers.ts +132 -0
  520. package/src/core/hooks/session-name-presence.ts +10 -3
  521. package/src/core/hooks/shell-waiter.ts +166 -0
  522. package/src/core/resources/service.ts +5 -4
  523. package/src/core/semantic/review.ts +5 -4
  524. package/src/core/semantic/service.ts +15 -14
  525. package/src/core/semantic/storage.ts +5 -4
  526. package/src/core/servers/index.ts +712 -0
  527. package/src/core/servers/net.ts +283 -0
  528. package/src/core/servers/tunnels.ts +39 -0
  529. package/src/core/storage/atomic-json.ts +7 -3
  530. package/src/core/storage/builtins.ts +1 -0
  531. package/src/core/storage/durable-history.ts +6 -5
  532. package/src/core/storage/maintenance-providers.ts +2 -1
  533. package/src/core/storage/maintenance.ts +7 -6
  534. package/src/core/storage/metrics.ts +5 -1
  535. package/src/core/storage/modes.ts +53 -0
  536. package/src/core/storage/process-log.ts +3 -2
  537. package/src/core/storage/receipts.ts +4 -3
  538. package/src/core/storage/segments.ts +7 -6
  539. package/src/core/supervisor/hook-health.ts +4 -4
  540. package/src/core/supervisor/service.ts +7 -6
  541. package/src/core/work/state.ts +8 -7
  542. package/src/core/workflow/adapters.ts +15 -0
  543. package/src/core/workflow/approvals.ts +6 -5
  544. package/src/core/workflow/billing.ts +34 -4
  545. package/src/core/workflow/durable-record.ts +4 -3
  546. package/src/core/workflow/engine.ts +38 -1
  547. package/src/core/workflow/live-session-v3.ts +2 -3
  548. package/src/core/workflow/run-state.ts +3 -2
  549. package/src/core/workflow/sandbox-projection.ts +38 -2
  550. package/src/core/workflow/spawn-claude.ts +5 -1
  551. package/src/core/workflow/spawn-codex.ts +18 -1
  552. package/src/core/workflow/spawn-cursor.ts +5 -1
  553. package/src/core/workflow/spawn-opencode.ts +153 -0
  554. package/src/core/workflow/transcript.ts +3 -2
  555. package/src/core/workflow/types.ts +62 -2
  556. package/src/core/workflow/worker-access.ts +525 -0
  557. package/src/core/workflow/workspaces/leases.ts +5 -4
  558. package/src/core/workflow/workspaces/local-git.ts +3 -2
  559. package/src/core/workflow/workspaces/paths.ts +2 -1
  560. package/src/core/workflow/workspaces/state.ts +10 -9
  561. package/src/lazy-commands.ts +11 -1
  562. package/src/lib/agent-browser/client.ts +18 -0
  563. package/src/lib/browser/batch-steps.ts +79 -0
  564. package/src/lib/browser/client.ts +147 -9
  565. package/src/lib/browser/collect/collector.ts +306 -0
  566. package/src/lib/browser/collect/fields.ts +87 -0
  567. package/src/lib/browser/collect/index.ts +47 -0
  568. package/src/lib/browser/collect/page-driver.ts +327 -0
  569. package/src/lib/browser/collect/presets.ts +237 -0
  570. package/src/lib/browser/collect/scroll-plan.ts +179 -0
  571. package/src/lib/browser/identity.ts +64 -0
  572. package/src/lib/browser/index.ts +16 -1
  573. package/src/lib/browser/launch-args.ts +53 -1
  574. package/src/lib/browser/page-review-judge.ts +16 -0
  575. package/src/lib/browser/qa-run-contracts.ts +11 -0
  576. package/src/lib/browser/qa-run.ts +1 -0
  577. package/src/lib/browser/user-agent.ts +130 -0
  578. package/src/lib/browser/windows-chrome.ts +227 -0
  579. package/src/lib/claude-desktop-share.ts +511 -0
  580. package/src/lib/disk-usage.ts +347 -0
  581. package/src/lib/docs-lint.ts +8 -3
  582. package/src/lib/docs-metadata-managed.ts +21 -0
  583. package/src/lib/guarded-remove.ts +376 -0
  584. package/src/lib/identities/assume.ts +7 -7
  585. package/src/lib/instructions/apply.ts +2 -0
  586. package/src/lib/instructions/templates.ts +8 -8
  587. package/src/lib/pace/index.ts +14 -0
  588. package/src/lib/pace/pace.ts +370 -0
  589. package/src/lib/tunnel/error-page.ts +25 -9
  590. package/src/lib/tunnel/forward-headers.ts +16 -0
  591. package/src/lib/tunnel/gate.ts +39 -10
  592. package/src/lib/tunnel/path-scope.ts +73 -0
  593. package/src/lib/tunnel/state.ts +20 -3
  594. package/src/lib/webview/index.ts +13 -0
  595. package/src/lib/webview/webview.ts +457 -0
@@ -22,6 +22,7 @@ import { isAbsolute, join, relative, resolve, sep } from "node:path";
22
22
  import { buildEventV3 } from "../../events/v3/builder.ts";
23
23
  import type { EventV3 } from "../../events/v3/contract.ts";
24
24
  import { writeEventV3 } from "../../events/v3/writer.ts";
25
+ import { stateFileMode } from "../../storage/modes.ts";
25
26
  import type { ParsedPayload } from "../adapter/parse.ts";
26
27
 
27
28
  const IMAGE_EXTS = new Set(["png", "jpg", "jpeg", "gif", "webp", "bmp", "svg"]);
@@ -258,7 +259,7 @@ function captureOne(
258
259
  if (!existsSync(destination)) {
259
260
  mkdirSync(imagesDir, { recursive: true });
260
261
  const temporary = `${destination}.tmp.${process.pid}.${randomUUID().slice(0, 8)}`;
261
- writeFileSync(temporary, bytes, { mode: 0o600 });
262
+ writeFileSync(temporary, bytes, { mode: stateFileMode() });
262
263
  renameSync(temporary, destination);
263
264
  }
264
265
  return { hash, ext, bytes: stat.size };
@@ -71,6 +71,7 @@ const DELIVERY_BY_ADAPTER: Readonly<Record<Adapter, PromptContextDelivery>> = {
71
71
  "claude-code": "direct",
72
72
  codex: "direct",
73
73
  cursor: "direct",
74
+ opencode: "direct",
74
75
  };
75
76
 
76
77
  export function promptContextDelivery(adapter: Adapter): PromptContextDelivery {
@@ -132,7 +132,10 @@ export function scanSessionNameDisplayedImmediately(
132
132
  export type SessionNameDisplayInspection =
133
133
  | { state: "present" }
134
134
  | { state: "absent" }
135
- | { state: "unavailable"; reason: "missing_transcript" | "transcript_not_ready" };
135
+ | {
136
+ state: "unavailable";
137
+ reason: "missing_transcript" | "transcript_not_ready" | "transcript_parse_error";
138
+ };
136
139
 
137
140
  /**
138
141
  * Inspect the ordered post-mint reply without conflating a malformed display
@@ -152,17 +155,34 @@ export function inspectSessionNameDisplayImmediately(
152
155
  if (!text) return { state: "unavailable", reason: "transcript_not_ready" };
153
156
  let sawMintResult = false;
154
157
  let awaitingReply = false;
158
+ let sawParseError = false;
159
+ let missedReplyAtToolBoundary = false;
155
160
  for (const line of text.split("\n")) {
156
161
  const row = parseTranscriptRow(line);
157
- if (!row) continue;
162
+ if (!row) {
163
+ if (line.trim()) {
164
+ sawParseError = true;
165
+ // A corrupt row inside the evidence window could be the display.
166
+ // Never turn lost evidence into a negative observation.
167
+ if (awaitingReply) return { state: "unavailable", reason: "transcript_parse_error" };
168
+ }
169
+ continue;
170
+ }
158
171
  if (toolResponseMintedSessionName(row, name)) {
159
172
  sawMintResult = true;
160
173
  awaitingReply = true;
174
+ missedReplyAtToolBoundary = false;
161
175
  continue;
162
176
  }
163
177
  if (!awaitingReply) continue;
164
178
  const assistantText = assistantTextFromRow(row);
165
- if (assistantText !== null) {
179
+ if (!assistantText?.trim() && rowContainsAssistantToolCall(row)) {
180
+ missedReplyAtToolBoundary = true;
181
+ }
182
+ // Claude Code streams thinking, text, and tool_use as separate rows with
183
+ // the same message id. Only visible text can satisfy or violate the
184
+ // display contract; an empty extraction is not a mismatching reply.
185
+ if (assistantText !== null && assistantText.trim().length > 0) {
166
186
  if (startsWithBlock(assistantText, name)) return { state: "present" };
167
187
  awaitingReply = false;
168
188
  }
@@ -173,12 +193,29 @@ export function inspectSessionNameDisplayImmediately(
173
193
  // rather than proof that the agent displayed the title incorrectly. Only a
174
194
  // transcript that contains the mint followed by a non-matching assistant
175
195
  // reply can safely deny the next tool.
176
- if (!sawMintResult || awaitingReply) {
177
- return { state: "unavailable", reason: "transcript_not_ready" };
196
+ if (!sawMintResult || awaitingReply || missedReplyAtToolBoundary) {
197
+ return {
198
+ state: "unavailable",
199
+ reason: !sawMintResult && sawParseError ? "transcript_parse_error" : "transcript_not_ready",
200
+ };
178
201
  }
179
202
  return { state: "absent" };
180
203
  }
181
204
 
205
+ function rowContainsAssistantToolCall(row: Record<string, unknown>): boolean {
206
+ if (row.type === "assistant") {
207
+ const content = objectValue(row.message)?.content;
208
+ return (
209
+ Array.isArray(content) && content.some((block) => objectValue(block)?.type === "tool_use")
210
+ );
211
+ }
212
+ if (row.type === "response_item") {
213
+ const type = objectValue(row.payload)?.type;
214
+ return type === "function_call" || type === "custom_tool_call";
215
+ }
216
+ return false;
217
+ }
218
+
182
219
  /**
183
220
  * Resolve a transcript path at the adapter boundary. Windows-native Codex can
184
221
  * send `C:\...` while the managed hook executes inside WSL, where the same
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Start markers for hook runs on adapters that kill a hook at its `timeout`
3
+ * (ADR 0197). A Codex hook that times out has its process tree killed and the
4
+ * tool proceeds without that hook's checks, and the killed process never
5
+ * reaches the completion receipt in `health.ts`. A small marker written at
6
+ * start and removed at completion leaves evidence of that case for doctor.
7
+ *
8
+ * Observer-only: every write, read, and removal swallows its own errors so a
9
+ * marker can never change hook behavior.
10
+ */
11
+
12
+ import { mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
13
+ import { join } from "node:path";
14
+
15
+ /** Markers older than this are pruned when a new one is written. */
16
+ const MARKER_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
17
+ /** A run is unfinished once its marker outlives the timeout by this much. */
18
+ const UNFINISHED_GRACE_MS = 30_000;
19
+
20
+ export interface HookRunMarker {
21
+ event: string;
22
+ adapter: string;
23
+ pid: number;
24
+ started_at: string;
25
+ timeout_sec: number;
26
+ }
27
+
28
+ export function hookRunMarkerDir(coordRoot: string): string {
29
+ return join(coordRoot, ".harnery", "active", "hook-runs");
30
+ }
31
+
32
+ /** Write this run's marker; returns its path, or null when it could not be written. */
33
+ export function writeHookRunMarker(
34
+ coordRoot: string,
35
+ marker: Omit<HookRunMarker, "started_at">,
36
+ now = new Date(),
37
+ ): string | null {
38
+ try {
39
+ const dir = hookRunMarkerDir(coordRoot);
40
+ mkdirSync(dir, { recursive: true });
41
+ pruneHookRunMarkers(dir, now.getTime());
42
+ const path = join(dir, `${marker.pid}-${safeName(marker.event)}.json`);
43
+ const body: HookRunMarker = { ...marker, started_at: now.toISOString() };
44
+ writeFileSync(path, `${JSON.stringify(body)}\n`);
45
+ return path;
46
+ } catch {
47
+ return null;
48
+ }
49
+ }
50
+
51
+ export function clearHookRunMarker(path: string | null): void {
52
+ if (!path) return;
53
+ try {
54
+ rmSync(path, { force: true });
55
+ } catch {
56
+ // Observer-only.
57
+ }
58
+ }
59
+
60
+ export interface UnfinishedHookRuns {
61
+ count: number;
62
+ /** Count per event name, most frequent first. */
63
+ events: Array<{ event: string; count: number }>;
64
+ latest: string | null;
65
+ }
66
+
67
+ /**
68
+ * Markers whose run outlived its timeout plus a grace period and whose
69
+ * process is gone, within the window. A live process past its timeout is
70
+ * still running and is not counted.
71
+ */
72
+ export function findUnfinishedHookRuns(
73
+ coordRoot: string,
74
+ nowMs = Date.now(),
75
+ windowMs = 24 * 60 * 60 * 1000,
76
+ isAlive: (pid: number) => boolean = processAlive,
77
+ ): UnfinishedHookRuns {
78
+ const counts = new Map<string, number>();
79
+ let latest: string | null = null;
80
+ let count = 0;
81
+ let names: string[] = [];
82
+ try {
83
+ names = readdirSync(hookRunMarkerDir(coordRoot)).filter((n) => n.endsWith(".json"));
84
+ } catch {
85
+ return { count: 0, events: [], latest: null };
86
+ }
87
+ for (const name of names) {
88
+ let marker: HookRunMarker;
89
+ try {
90
+ marker = JSON.parse(
91
+ readFileSync(join(hookRunMarkerDir(coordRoot), name), "utf8"),
92
+ ) as HookRunMarker;
93
+ } catch {
94
+ continue;
95
+ }
96
+ const started = Date.parse(marker.started_at);
97
+ if (!Number.isFinite(started) || nowMs - started > windowMs) continue;
98
+ if (nowMs - started < marker.timeout_sec * 1000 + UNFINISHED_GRACE_MS) continue;
99
+ if (isAlive(marker.pid)) continue;
100
+ count++;
101
+ counts.set(marker.event, (counts.get(marker.event) ?? 0) + 1);
102
+ if (!latest || marker.started_at > latest) latest = marker.started_at;
103
+ }
104
+ const events = [...counts.entries()]
105
+ .map(([event, n]) => ({ event, count: n }))
106
+ .sort((a, b) => b.count - a.count || a.event.localeCompare(b.event));
107
+ return { count, events, latest };
108
+ }
109
+
110
+ function pruneHookRunMarkers(dir: string, nowMs: number): void {
111
+ for (const name of readdirSync(dir)) {
112
+ const path = join(dir, name);
113
+ try {
114
+ if (nowMs - statSync(path).mtimeMs > MARKER_RETENTION_MS) rmSync(path, { force: true });
115
+ } catch {
116
+ // Observer-only.
117
+ }
118
+ }
119
+ }
120
+
121
+ function processAlive(pid: number): boolean {
122
+ try {
123
+ process.kill(pid, 0);
124
+ return true;
125
+ } catch (err) {
126
+ return (err as NodeJS.ErrnoException).code === "EPERM";
127
+ }
128
+ }
129
+
130
+ function safeName(value: string): string {
131
+ return value.replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 64) || "unknown";
132
+ }
@@ -25,16 +25,18 @@
25
25
  import { sessionNameDisplayAcceptedNames } from "../agents/session-name-display.ts";
26
26
  import { stampSessionNameSeen } from "../agents/state/heartbeat-writer.ts";
27
27
  import { readLiveCoordinationRow } from "../agents/state/live-coordination-view.ts";
28
+ import type { SessionNameDisplayInspection } from "./resolve/transcript.ts";
28
29
 
29
30
  export interface SessionNamePresence {
30
31
  session_name_present?: boolean;
31
32
  session_name_present_for?: string;
33
+ session_name_unavailable_reason?: string;
32
34
  }
33
35
 
34
36
  export function sessionNamePresence(
35
37
  coordRoot: string,
36
38
  instanceId: string,
37
- scanAssistantText: (name: string) => boolean,
39
+ scanAssistantText: (name: string) => SessionNameDisplayInspection,
38
40
  ): SessionNamePresence {
39
41
  try {
40
42
  const row = readLiveCoordinationRow(coordRoot, instanceId);
@@ -45,12 +47,17 @@ export function sessionNamePresence(
45
47
  }
46
48
  // A display of the title Harnery last asked for counts here too, so Stop
47
49
  // and the PreToolUse gate cannot disagree about the same reply.
48
- const present = sessionNameDisplayAcceptedNames(row).some((candidate) =>
50
+ const inspections = sessionNameDisplayAcceptedNames(row).map((candidate) =>
49
51
  scanAssistantText(candidate),
50
52
  );
53
+ const present = inspections.some((inspection) => inspection.state === "present");
54
+ const unavailable = inspections.find((inspection) => inspection.state === "unavailable");
55
+ if (!present && unavailable?.state === "unavailable") {
56
+ return { session_name_unavailable_reason: unavailable.reason };
57
+ }
51
58
  if (present) stampSessionNameSeen(coordRoot, instanceId, name);
52
59
  return { session_name_present: present, session_name_present_for: name };
53
60
  } catch {
54
- return {};
61
+ return { session_name_unavailable_reason: "observation_error" };
55
62
  }
56
63
  }
@@ -0,0 +1,166 @@
1
+ /** Recognize inline waiters; this is not a proof of arbitrary shell termination. */
2
+ const REASON =
3
+ "Inline shell waiter blocked: polling loops and delayed log-only checks can outlive the job " +
4
+ "and accumulate as background tasks. Read the existing task output now, or wait on its " +
5
+ "existing task handle. If polling is necessary, use a reviewed script with a hard deadline, " +
6
+ "nonzero timeout exit, and producer-exit/failure detection. Do not create another waiter " +
7
+ "to check progress or infer completion from a broad pgrep -f pattern.";
8
+
9
+ interface Token {
10
+ value: string;
11
+ quoted: boolean;
12
+ operator?: boolean;
13
+ }
14
+
15
+ /** Keep quoted arguments opaque, including examples and heredoc bodies. */
16
+ function tokenize(source: string): Token[] {
17
+ const out: Token[] = [];
18
+ const heredocs: { end: string; tabs: boolean }[] = [];
19
+ for (let i = 0; i < source.length; ) {
20
+ const ch = source[i]!;
21
+ if (ch === "\\" && source[i + 1] === "\n") {
22
+ i += 2;
23
+ continue;
24
+ }
25
+ if (ch === "\n") {
26
+ out.push({ value: ";", quoted: false, operator: true });
27
+ i++;
28
+ for (const doc of heredocs.splice(0)) {
29
+ while (i < source.length) {
30
+ const end = source.indexOf("\n", i);
31
+ const stop = end === -1 ? source.length : end;
32
+ const line = source.slice(i, stop);
33
+ i = end === -1 ? source.length : end + 1;
34
+ if ((doc.tabs ? line.replace(/^\t+/, "") : line) === doc.end) break;
35
+ }
36
+ }
37
+ continue;
38
+ }
39
+ if (/\s/.test(ch)) {
40
+ i++;
41
+ continue;
42
+ }
43
+ if (ch === "#") {
44
+ const end = source.indexOf("\n", i);
45
+ i = end === -1 ? source.length : end;
46
+ continue;
47
+ }
48
+ if (";|&(){}<>".includes(ch)) {
49
+ const op = source.slice(i).match(/^(?:<<-?|>>|&&|\|\||[;|&(){}<>])/)![0];
50
+ out.push({ value: op, quoted: false, operator: true });
51
+ i += op.length;
52
+ continue;
53
+ }
54
+ let value = "";
55
+ let quoted = false;
56
+ while (i < source.length && !/[\s;|&(){}<>]/.test(source[i]!)) {
57
+ const next = source[i++]!;
58
+ if (next === "'" || next === '"' || next === "`") {
59
+ quoted = true;
60
+ while (i < source.length && source[i] !== next) {
61
+ if (source[i] === "\\" && next !== "'" && i + 1 < source.length) i++;
62
+ value += source[i++]!;
63
+ }
64
+ if (source[i] === next) i++;
65
+ } else if (next === "\\" && i < source.length) {
66
+ const escaped = source[i++]!;
67
+ if (escaped !== "\n") value += escaped;
68
+ } else {
69
+ value += next;
70
+ }
71
+ }
72
+ const previous = out.at(-1)?.value;
73
+ if (previous === "<<" || previous === "<<-") {
74
+ heredocs.push({ end: value, tabs: previous === "<<-" });
75
+ }
76
+ out.push({ value, quoted });
77
+ }
78
+ return out;
79
+ }
80
+
81
+ function basename(value: string): string {
82
+ return value.split(/[\\/]/).at(-1) ?? value;
83
+ }
84
+
85
+ function isWaiter(source: string, depth = 0): boolean {
86
+ if (depth > 8) return false;
87
+ const tokens = tokenize(source);
88
+ let loops = 0;
89
+ const commands: string[] = [];
90
+ let start = true;
91
+ for (let i = 0; i < tokens.length; i++) {
92
+ const token = tokens[i]!;
93
+ if (token.operator) {
94
+ if ([";", "|", "||", "&", "&&", "(", ")", "{", "}"].includes(token.value)) start = true;
95
+ continue;
96
+ }
97
+ if (!start) continue;
98
+ if (!token.quoted) {
99
+ if (["while", "until", "for", "select"].includes(token.value)) {
100
+ loops++;
101
+ continue;
102
+ }
103
+ if (token.value === "done") {
104
+ loops = Math.max(0, loops - 1);
105
+ continue;
106
+ }
107
+ if (["do", "if", "then", "elif", "else", "!"].includes(token.value)) continue;
108
+ if (/^[A-Za-z_][A-Za-z_0-9]*=/.test(token.value)) continue;
109
+ }
110
+ const name = basename(token.value);
111
+ if (name === "timeout") {
112
+ // Skip timeout options and its duration; inspect the wrapped executable.
113
+ let j = i + 1;
114
+ for (; j < tokens.length && !tokens[j]!.operator; j++) {
115
+ if (/^(?:\d+(?:\.\d*)?|\.\d+)[smhd]?$/.test(tokens[j]!.value)) {
116
+ // -k/--kill-after takes its own duration before the main duration.
117
+ const previous = tokens[j - 1]?.value;
118
+ if (previous === "-k" || previous === "--kill-after") continue;
119
+ i = j;
120
+ break;
121
+ }
122
+ }
123
+ if (i === j) continue;
124
+ }
125
+ if (["command", "exec", "builtin", "nohup"].includes(name)) continue;
126
+ start = false;
127
+ commands.push(name);
128
+ if (loops && ["sleep", "pgrep"].includes(name)) return true;
129
+ if (["bash", "sh", "dash", "zsh", "ksh"].includes(name)) {
130
+ for (let j = i + 1; j < tokens.length && !tokens[j]!.operator; j++) {
131
+ if (/^-[a-z]*c[a-z]*$/.test(tokens[j]!.value)) {
132
+ const script = tokens[j + 1];
133
+ if (script && !script.operator && isWaiter(script.value, depth + 1)) return true;
134
+ break;
135
+ }
136
+ }
137
+ }
138
+ }
139
+ const sleep = commands.indexOf("sleep");
140
+ // sed can edit files or execute commands; its name alone does not prove a log read.
141
+ const readers = new Set(["tail", "cat", "head", "grep", "rg", "wc"]);
142
+ const harmless = new Set(["sleep", "cd", "pwd", "echo", "printf", "date", ...readers]);
143
+ return (
144
+ sleep !== -1 &&
145
+ commands.slice(sleep + 1).some((name) => readers.has(name)) &&
146
+ commands.every((name) => harmless.has(name))
147
+ );
148
+ }
149
+
150
+ export function shellWaiterReason(toolName: unknown, toolInput: unknown): string | null {
151
+ if (typeof toolName !== "string") return null;
152
+ const name = toolName.toLowerCase().replace(/^functions\./, "");
153
+ if (!["bash", "shell", "shell_command", "exec_command"].includes(name)) return null;
154
+ let input = toolInput;
155
+ if (typeof input === "string") {
156
+ try {
157
+ input = JSON.parse(input);
158
+ } catch {
159
+ return null;
160
+ }
161
+ }
162
+ if (!input || typeof input !== "object") return null;
163
+ const args = input as Record<string, unknown>;
164
+ const command = args.command ?? args.cmd;
165
+ return typeof command === "string" && isWaiter(command) ? REASON : null;
166
+ }
@@ -14,6 +14,7 @@ import { hostname, platform } from "node:os";
14
14
  import { resolve } from "node:path";
15
15
  import { checkPidToken, processStartToken } from "../agents/state/proc-start.ts";
16
16
  import { closeProcessLoggers, legacyLogFields, processLogger } from "../storage/logger.ts";
17
+ import { stateDirMode, stateFileMode } from "../storage/modes.ts";
17
18
  import {
18
19
  RESOURCE_SERVICE_STATUS_SCHEMA_VERSION,
19
20
  type ResourceSamplerState,
@@ -60,7 +61,7 @@ export async function spawnResourceService(
60
61
  }
61
62
  const intervalMs = normalizeInterval(options.intervalMs);
62
63
  const paths = resourcePaths(coordRoot);
63
- mkdirSync(paths.root, { recursive: true, mode: 0o700 });
64
+ mkdirSync(paths.root, { recursive: true, mode: stateDirMode() });
64
65
  rmSync(paths.stop, { force: true });
65
66
  const harnBin = new URL("../../../bin/harn", import.meta.url).pathname;
66
67
  if (!existsSync(harnBin)) throw new Error(`cannot find harn executable at ${harnBin}`);
@@ -122,7 +123,7 @@ export function requestResourceServiceStop(coordRootRaw: string): ResourceServic
122
123
  const coordRoot = resolve(coordRootRaw);
123
124
  const paths = resourcePaths(coordRoot);
124
125
  const status = readResourceServiceStatus(coordRoot);
125
- mkdirSync(paths.root, { recursive: true, mode: 0o700 });
126
+ mkdirSync(paths.root, { recursive: true, mode: stateDirMode() });
126
127
  writePrivateJsonAtomic(paths.stop, {
127
128
  requested_at: new Date().toISOString(),
128
129
  requested_by_pid: process.pid,
@@ -231,7 +232,7 @@ export async function runResourceService(
231
232
 
232
233
  function acquireLease(coordRoot: string, now: Date): ResourceServiceLease {
233
234
  const paths = resourcePaths(coordRoot);
234
- mkdirSync(paths.root, { recursive: true, mode: 0o700 });
235
+ mkdirSync(paths.root, { recursive: true, mode: stateDirMode() });
235
236
  for (let attempt = 0; attempt < 2; attempt++) {
236
237
  const daemonStartToken = processStartToken(process.pid);
237
238
  const lease: ResourceServiceLease = {
@@ -242,7 +243,7 @@ function acquireLease(coordRoot: string, now: Date): ResourceServiceLease {
242
243
  created_at: now.toISOString(),
243
244
  };
244
245
  try {
245
- const fd = openSync(paths.lease, "wx", 0o600);
246
+ const fd = openSync(paths.lease, "wx", stateFileMode());
246
247
  try {
247
248
  writeFileSync(fd, `${JSON.stringify(lease)}\n`, "utf8");
248
249
  } finally {
@@ -11,6 +11,7 @@ import {
11
11
  writeFileSync,
12
12
  } from "node:fs";
13
13
  import { dirname, join, resolve } from "node:path";
14
+ import { stateDirMode, stateFileMode } from "../storage/modes.ts";
14
15
  import type {
15
16
  SemanticAcceptedReadModelV2,
16
17
  SemanticConfiguredModel,
@@ -630,12 +631,12 @@ function writePrivateJsonAtomic(path: string, value: unknown): void {
630
631
  const body = `${JSON.stringify(value, null, 2)}\n`;
631
632
  if (Buffer.byteLength(body) > MAX_JSON_BYTES)
632
633
  throw new Error("semantic review file is too large");
633
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
634
- chmodSync(dirname(path), 0o700);
634
+ mkdirSync(dirname(path), { recursive: true, mode: stateDirMode() });
635
+ chmodSync(dirname(path), stateDirMode());
635
636
  const temporary = `${path}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
636
- writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
637
+ writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: stateFileMode() });
637
638
  renameSync(temporary, path);
638
- chmodSync(path, 0o600);
639
+ chmodSync(path, stateFileMode());
639
640
  }
640
641
 
641
642
  function isSemanticReviewCandidate(value: unknown): value is SemanticReviewCandidateV1 {
@@ -30,6 +30,7 @@ import {
30
30
  legacyLogFields,
31
31
  processLogger,
32
32
  } from "../storage/logger.ts";
33
+ import { stateDirMode, stateFileMode } from "../storage/modes.ts";
33
34
  import type { SemanticHarness } from "./contract.ts";
34
35
  import { runSemanticOnce, type SemanticOnceReport } from "./once.ts";
35
36
  import { semanticPendingPassDue } from "./scheduler.ts";
@@ -145,10 +146,10 @@ export async function spawnSemanticService(
145
146
  throw new Error(`semantic service is already running under pid ${current.record?.pid}`);
146
147
  }
147
148
  const paths = semanticPaths(coordRoot);
148
- mkdirSync(paths.root, { recursive: true, mode: 0o700 });
149
+ mkdirSync(paths.root, { recursive: true, mode: stateDirMode() });
149
150
  const sharedLogs = coordEnv("SHARED_LOGS") !== "0";
150
- const logFd = sharedLogs ? undefined : openSync(paths.log, "a", 0o600);
151
- if (logFd !== undefined) chmodSync(paths.log, 0o600);
151
+ const logFd = sharedLogs ? undefined : openSync(paths.log, "a", stateFileMode());
152
+ if (logFd !== undefined) chmodSync(paths.log, stateFileMode());
152
153
  const harnBin = new URL("../../../bin/harn", import.meta.url).pathname;
153
154
  if (!existsSync(harnBin)) {
154
155
  if (logFd !== undefined) closeSync(logFd);
@@ -225,7 +226,7 @@ export async function ensureSemanticServiceRunning(
225
226
  export function requestSemanticServiceStop(coordRootRaw: string): SemanticServiceStatus {
226
227
  const coordRoot = resolve(coordRootRaw);
227
228
  const status = readSemanticServiceStatus(coordRoot);
228
- mkdirSync(semanticPaths(coordRoot).root, { recursive: true, mode: 0o700 });
229
+ mkdirSync(semanticPaths(coordRoot).root, { recursive: true, mode: stateDirMode() });
229
230
  writePrivateJsonAtomic(semanticPaths(coordRoot).stop, {
230
231
  requested_at: new Date().toISOString(),
231
232
  requested_by_pid: process.pid,
@@ -452,7 +453,7 @@ export async function runSemanticServiceDaemon(
452
453
 
453
454
  export function acquireSemanticServiceLease(coordRootRaw: string): () => void {
454
455
  const path = semanticPaths(coordRootRaw).lease;
455
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
456
+ mkdirSync(dirname(path), { recursive: true, mode: stateDirMode() });
456
457
  const owner: SemanticServiceLease = {
457
458
  pid: process.pid,
458
459
  host: hostname(),
@@ -461,7 +462,7 @@ export function acquireSemanticServiceLease(coordRootRaw: string): () => void {
461
462
  };
462
463
  const acquire = (): boolean => {
463
464
  try {
464
- const fd = openSync(path, "wx", 0o600);
465
+ const fd = openSync(path, "wx", stateFileMode());
465
466
  try {
466
467
  writeFileSync(fd, `${JSON.stringify(owner)}\n`, "utf8");
467
468
  } finally {
@@ -671,20 +672,20 @@ function prepareSemanticServiceDiagnostic(entry: Record<string, unknown>): {
671
672
 
672
673
  function appendSemanticServiceLegacyLog(coordRoot: string, entry: Record<string, unknown>): void {
673
674
  const path = semanticPaths(coordRoot).log;
674
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
675
+ mkdirSync(dirname(path), { recursive: true, mode: stateDirMode() });
675
676
  appendFileSync(
676
677
  path,
677
678
  `${JSON.stringify({ schema_version: 1, ts: new Date().toISOString(), ...entry })}\n`,
678
- { encoding: "utf8", mode: 0o600 },
679
+ { encoding: "utf8", mode: stateFileMode() },
679
680
  );
680
- chmodSync(path, 0o600);
681
+ chmodSync(path, stateFileMode());
681
682
  if (statSync(path).size <= MAX_LOG_BYTES) return;
682
683
  const buffer = readFileSync(path);
683
684
  const tail = buffer.subarray(Math.max(0, buffer.length - Math.floor(MAX_LOG_BYTES / 2)));
684
685
  const newline = tail.indexOf(10);
685
686
  const body = newline >= 0 ? tail.subarray(newline + 1) : tail;
686
687
  const temporary = `${path}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
687
- writeFileSync(temporary, body, { flag: "wx", mode: 0o600 });
688
+ writeFileSync(temporary, body, { flag: "wx", mode: stateFileMode() });
688
689
  renameSync(temporary, path);
689
690
  }
690
691
 
@@ -693,12 +694,12 @@ function writePrivateJsonAtomic(path: string, value: unknown): void {
693
694
  if (Buffer.byteLength(body) > MAX_FILE_BYTES) {
694
695
  throw new Error(`semantic service file exceeds ${MAX_FILE_BYTES} bytes`);
695
696
  }
696
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
697
- chmodSync(dirname(path), 0o700);
697
+ mkdirSync(dirname(path), { recursive: true, mode: stateDirMode() });
698
+ chmodSync(dirname(path), stateDirMode());
698
699
  const temporary = `${path}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
699
- writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
700
+ writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: stateFileMode() });
700
701
  renameSync(temporary, path);
701
- chmodSync(path, 0o600);
702
+ chmodSync(path, stateFileMode());
702
703
  }
703
704
 
704
705
  function validTimestamp(value: unknown): value is string {
@@ -13,6 +13,7 @@ import {
13
13
  import { dirname, join, resolve } from "node:path";
14
14
  import { canonicalJsonV3, sha256V3 } from "../events/v3/canonical.ts";
15
15
  import type { LedgerCursorV3 } from "../events/v3/reader.ts";
16
+ import { stateDirMode, stateFileMode } from "../storage/modes.ts";
16
17
  import type {
17
18
  SEMANTIC_EVIDENCE_CONTRACT_VERSION,
18
19
  SEMANTIC_PROMPT_CONTRACT_VERSION,
@@ -291,10 +292,10 @@ function writePrivateJsonAtomic(path: string, value: unknown): void {
291
292
  if (Buffer.byteLength(body) > MAX_JSON_BYTES) {
292
293
  throw new Error(`semantic file exceeds ${MAX_JSON_BYTES} bytes`);
293
294
  }
294
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
295
- chmodSync(dirname(path), 0o700);
295
+ mkdirSync(dirname(path), { recursive: true, mode: stateDirMode() });
296
+ chmodSync(dirname(path), stateDirMode());
296
297
  const temporary = `${path}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
297
- writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
298
+ writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: stateFileMode() });
298
299
  renameSync(temporary, path);
299
- chmodSync(path, 0o600);
300
+ chmodSync(path, stateFileMode());
300
301
  }