harnery 0.30.0 → 0.31.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 (501) hide show
  1. package/README.md +4 -4
  2. package/dist/commander.d.ts +8 -0
  3. package/dist/commander.d.ts.map +1 -1
  4. package/dist/commander.js +14 -13
  5. package/dist/commands/adapter.d.ts +12 -0
  6. package/dist/commands/adapter.d.ts.map +1 -0
  7. package/dist/commands/{harness.js → adapter.js} +35 -35
  8. package/dist/commands/agents.d.ts +3 -2
  9. package/dist/commands/agents.d.ts.map +1 -1
  10. package/dist/commands/agents.js +61 -60
  11. package/dist/commands/artifacts.d.ts +4 -0
  12. package/dist/commands/artifacts.d.ts.map +1 -0
  13. package/dist/commands/artifacts.js +143 -0
  14. package/dist/commands/backup.d.ts +1 -1
  15. package/dist/commands/backup.d.ts.map +1 -1
  16. package/dist/commands/backup.js +5 -2
  17. package/dist/commands/browse.d.ts.map +1 -1
  18. package/dist/commands/browse.js +310 -7
  19. package/dist/commands/checkpoint.d.ts +12 -0
  20. package/dist/commands/checkpoint.d.ts.map +1 -0
  21. package/dist/commands/checkpoint.js +162 -0
  22. package/dist/commands/context.d.ts +2 -2
  23. package/dist/commands/context.d.ts.map +1 -1
  24. package/dist/commands/context.js +3 -151
  25. package/dist/commands/decision.d.ts.map +1 -1
  26. package/dist/commands/decision.js +31 -7
  27. package/dist/commands/deinit.d.ts +2 -2
  28. package/dist/commands/deinit.js +15 -15
  29. package/dist/commands/doctor.js +23 -23
  30. package/dist/commands/governor.d.ts +4 -0
  31. package/dist/commands/governor.d.ts.map +1 -0
  32. package/dist/commands/{supervisor.js → governor.js} +133 -108
  33. package/dist/commands/init.d.ts +12 -12
  34. package/dist/commands/init.d.ts.map +1 -1
  35. package/dist/commands/init.js +44 -30
  36. package/dist/commands/{session.d.ts → journal.d.ts} +2 -2
  37. package/dist/commands/journal.d.ts.map +1 -0
  38. package/dist/commands/{scratch.js → journal.js} +47 -47
  39. package/dist/commands/policy.js +1 -1
  40. package/dist/commands/presence.js +2 -2
  41. package/dist/commands/sync.d.ts +1 -1
  42. package/dist/commands/sync.js +3 -3
  43. package/dist/commands/tunnel.d.ts +16 -0
  44. package/dist/commands/tunnel.d.ts.map +1 -1
  45. package/dist/commands/tunnel.js +193 -23
  46. package/dist/commands/web-fetch.js +1 -1
  47. package/dist/commands/web.d.ts +19 -0
  48. package/dist/commands/web.d.ts.map +1 -1
  49. package/dist/commands/web.js +51 -0
  50. package/dist/commands/work.d.ts.map +1 -1
  51. package/dist/commands/work.js +38 -22
  52. package/dist/commands/workflow.d.ts.map +1 -1
  53. package/dist/commands/workflow.js +35 -28
  54. package/dist/core/{harnesses → adapters}/attest-projection.d.ts +2 -2
  55. package/dist/core/adapters/attest-projection.d.ts.map +1 -0
  56. package/dist/core/{harnesses → adapters}/attest.d.ts +16 -16
  57. package/dist/core/adapters/attest.d.ts.map +1 -0
  58. package/dist/core/{harnesses → adapters}/attest.js +9 -9
  59. package/dist/core/{harnesses → adapters}/attestation.d.ts +16 -16
  60. package/dist/core/adapters/attestation.d.ts.map +1 -0
  61. package/dist/core/{harnesses → adapters}/attestation.js +20 -20
  62. package/dist/core/{harnesses → adapters}/bench.d.ts +12 -12
  63. package/dist/core/adapters/bench.d.ts.map +1 -0
  64. package/dist/core/{harnesses → adapters}/bench.js +12 -12
  65. package/dist/core/adapters/index.d.ts +13 -0
  66. package/dist/core/adapters/index.d.ts.map +1 -0
  67. package/dist/core/adapters/index.js +6 -0
  68. package/dist/core/{harnesses → adapters}/profiles.d.ts +11 -11
  69. package/dist/core/adapters/profiles.d.ts.map +1 -0
  70. package/dist/core/{harnesses → adapters}/profiles.js +11 -11
  71. package/dist/core/adapters/registry.d.ts +15 -0
  72. package/dist/core/adapters/registry.d.ts.map +1 -0
  73. package/dist/core/{harnesses → adapters}/registry.js +11 -11
  74. package/dist/core/{harnesses → adapters}/types.d.ts +23 -23
  75. package/dist/core/adapters/types.d.ts.map +1 -0
  76. package/dist/core/{harnesses → adapters}/types.js +1 -1
  77. package/dist/core/agents/canonical-emit.d.ts +4 -4
  78. package/dist/core/agents/canonical-emit.js +5 -5
  79. package/dist/core/agents/cli-emit.js +1 -1
  80. package/dist/core/agents/cli.js +30 -26
  81. package/dist/core/agents/codex-replay.d.ts +1 -1
  82. package/dist/core/agents/codex-replay.js +6 -6
  83. package/dist/core/agents/coord-client.d.ts +21 -2
  84. package/dist/core/agents/coord-client.d.ts.map +1 -1
  85. package/dist/core/agents/coord-client.js +122 -27
  86. package/dist/core/agents/events/consume.d.ts +1 -1
  87. package/dist/core/agents/events/emit.d.ts +5 -6
  88. package/dist/core/agents/events/emit.d.ts.map +1 -1
  89. package/dist/core/agents/events/emit.js +2 -2
  90. package/dist/core/agents/render/prompt-context.d.ts +21 -9
  91. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  92. package/dist/core/agents/render/prompt-context.js +82 -30
  93. package/dist/core/agents/render/session-context.d.ts +1 -1
  94. package/dist/core/agents/render/session-context.js +5 -5
  95. package/dist/core/agents/rules/claim-conflict.d.ts +2 -6
  96. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
  97. package/dist/core/agents/rules/claim-conflict.js +1 -1
  98. package/dist/core/agents/rules/commit-conflict.js +98 -22
  99. package/dist/core/agents/rules/stop-hook.d.ts +9 -9
  100. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  101. package/dist/core/agents/rules/stop-hook.js +23 -5
  102. package/dist/core/agents/rules/verdict.d.ts +14 -0
  103. package/dist/core/agents/rules/verdict.d.ts.map +1 -0
  104. package/dist/core/agents/rules/verdict.js +1 -0
  105. package/dist/core/agents/session-events.js +3 -3
  106. package/dist/core/agents/state/council.d.ts +1 -1
  107. package/dist/core/agents/state/council.js +1 -1
  108. package/dist/core/agents/state/heartbeat-projector.d.ts +3 -2
  109. package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
  110. package/dist/core/agents/state/heartbeat-projector.js +14 -10
  111. package/dist/core/agents/state/heartbeat-writer.d.ts +1 -1
  112. package/dist/core/agents/state/heartbeat-writer.js +12 -12
  113. package/dist/core/agents/state/{scratch.d.ts → journal.d.ts} +7 -7
  114. package/dist/core/agents/state/{scratch.d.ts.map → journal.d.ts.map} +1 -1
  115. package/dist/core/agents/state/{scratch.js → journal.js} +12 -12
  116. package/dist/core/agents/state/pidmap.d.ts +28 -4
  117. package/dist/core/agents/state/pidmap.d.ts.map +1 -1
  118. package/dist/core/agents/state/pidmap.js +130 -15
  119. package/dist/core/agents/state/proc-start.d.ts +95 -0
  120. package/dist/core/agents/state/proc-start.d.ts.map +1 -0
  121. package/dist/core/agents/state/proc-start.js +199 -0
  122. package/dist/core/agents/state/shell-mutation.d.ts +1 -1
  123. package/dist/core/agents/state/shell-mutation.js +1 -1
  124. package/dist/core/agents/state/stale-sweep.js +7 -7
  125. package/dist/core/artifacts/index.d.ts +86 -0
  126. package/dist/core/artifacts/index.d.ts.map +1 -0
  127. package/dist/core/artifacts/index.js +421 -0
  128. package/dist/core/config.d.ts +9 -2
  129. package/dist/core/config.d.ts.map +1 -1
  130. package/dist/core/config.js +26 -2
  131. package/dist/core/context/index.d.ts +12 -12
  132. package/dist/core/context/index.js +10 -10
  133. package/dist/core/governor/adapter-spread.d.ts +52 -0
  134. package/dist/core/governor/adapter-spread.d.ts.map +1 -0
  135. package/dist/core/governor/adapter-spread.js +52 -0
  136. package/dist/core/governor/index.d.ts +7 -0
  137. package/dist/core/governor/index.d.ts.map +1 -0
  138. package/dist/core/governor/index.js +6 -0
  139. package/dist/core/governor/plan-api.d.ts +38 -0
  140. package/dist/core/governor/plan-api.d.ts.map +1 -0
  141. package/dist/core/governor/plan-api.js +83 -0
  142. package/dist/core/governor/plan-read.d.ts +5 -0
  143. package/dist/core/governor/plan-read.d.ts.map +1 -0
  144. package/dist/core/{supervisor → governor}/plan-read.js +66 -52
  145. package/dist/core/{supervisor → governor}/plan-types.d.ts +57 -56
  146. package/dist/core/governor/plan-types.d.ts.map +1 -0
  147. package/dist/core/{supervisor → governor}/plan-types.js +4 -4
  148. package/dist/core/governor/planning.d.ts +48 -0
  149. package/dist/core/governor/planning.d.ts.map +1 -0
  150. package/dist/core/{supervisor → governor}/planning.js +125 -94
  151. package/dist/core/governor/read.d.ts +6 -0
  152. package/dist/core/governor/read.d.ts.map +1 -0
  153. package/dist/core/governor/read.js +4 -0
  154. package/dist/core/governor/runner.d.ts +37 -0
  155. package/dist/core/governor/runner.d.ts.map +1 -0
  156. package/dist/core/{supervisor → governor}/runner.js +15 -15
  157. package/dist/core/governor/service-read.d.ts +6 -0
  158. package/dist/core/governor/service-read.d.ts.map +1 -0
  159. package/dist/core/{supervisor → governor}/service-read.js +12 -12
  160. package/dist/core/governor/service.d.ts +114 -0
  161. package/dist/core/governor/service.d.ts.map +1 -0
  162. package/dist/core/{supervisor → governor}/service.js +57 -57
  163. package/dist/core/governor/state.d.ts +116 -0
  164. package/dist/core/governor/state.d.ts.map +1 -0
  165. package/dist/core/{supervisor → governor}/state.js +228 -108
  166. package/dist/core/hooks/adapter/detect.d.ts +9 -0
  167. package/dist/core/hooks/{harness → adapter}/detect.d.ts.map +1 -1
  168. package/dist/core/hooks/{harness → adapter}/detect.js +8 -8
  169. package/dist/core/hooks/{harness → adapter}/events.d.ts +15 -14
  170. package/dist/core/hooks/adapter/events.d.ts.map +1 -0
  171. package/dist/core/hooks/{harness → adapter}/events.js +5 -5
  172. package/dist/core/hooks/{harness → adapter}/output.d.ts +20 -14
  173. package/dist/core/hooks/adapter/output.d.ts.map +1 -0
  174. package/dist/core/hooks/{harness → adapter}/output.js +30 -22
  175. package/dist/core/hooks/{harness → adapter}/parse.d.ts +5 -5
  176. package/dist/core/hooks/{harness → adapter}/parse.d.ts.map +1 -1
  177. package/dist/core/hooks/{harness → adapter}/parse.js +4 -4
  178. package/dist/core/hooks/{harness → adapter}/wiring.d.ts +15 -15
  179. package/dist/core/hooks/{harness → adapter}/wiring.d.ts.map +1 -1
  180. package/dist/core/hooks/{harness → adapter}/wiring.js +13 -13
  181. package/dist/core/hooks/cli.d.ts +3 -3
  182. package/dist/core/hooks/cli.js +175 -151
  183. package/dist/core/hooks/effects/image-capture.d.ts +5 -5
  184. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  185. package/dist/core/hooks/effects/image-capture.js +3 -3
  186. package/dist/core/hooks/effects/index.d.ts +12 -12
  187. package/dist/core/hooks/effects/index.d.ts.map +1 -1
  188. package/dist/core/hooks/effects/index.js +17 -17
  189. package/dist/core/hooks/events/emit.d.ts +2 -2
  190. package/dist/core/hooks/events/emit.d.ts.map +1 -1
  191. package/dist/core/hooks/events/emit.js +1 -1
  192. package/dist/core/hooks/events/rotate.js +1 -1
  193. package/dist/core/hooks/events/schema.d.ts +13 -5
  194. package/dist/core/hooks/events/schema.d.ts.map +1 -1
  195. package/dist/core/hooks/guard-path.d.ts +2 -2
  196. package/dist/core/hooks/guard-path.js +2 -2
  197. package/dist/core/hooks/index.d.ts +1 -1
  198. package/dist/core/hooks/index.d.ts.map +1 -1
  199. package/dist/core/hooks/resolve/anchor.d.ts +14 -5
  200. package/dist/core/hooks/resolve/anchor.d.ts.map +1 -1
  201. package/dist/core/hooks/resolve/anchor.js +64 -7
  202. package/dist/core/hooks/resolve/coord-root.d.ts +3 -3
  203. package/dist/core/hooks/resolve/coord-root.js +4 -4
  204. package/dist/core/hooks/resolve/intent.js +1 -1
  205. package/dist/core/hooks/resolve/owner.d.ts +1 -1
  206. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  207. package/dist/core/hooks/resolve/owner.js +11 -5
  208. package/dist/core/{scratch → journal}/index.d.ts +25 -25
  209. package/dist/core/{scratch → journal}/index.d.ts.map +1 -1
  210. package/dist/core/{scratch → journal}/index.js +38 -38
  211. package/dist/core/policy/evaluate.d.ts +1 -1
  212. package/dist/core/policy/evaluate.d.ts.map +1 -1
  213. package/dist/core/policy/evaluate.js +7 -7
  214. package/dist/core/policy/types.d.ts +3 -3
  215. package/dist/core/policy/types.d.ts.map +1 -1
  216. package/dist/core/work/state.d.ts +12 -4
  217. package/dist/core/work/state.d.ts.map +1 -1
  218. package/dist/core/work/state.js +50 -17
  219. package/dist/core/workflow/adapters.d.ts +17 -0
  220. package/dist/core/workflow/adapters.d.ts.map +1 -0
  221. package/dist/core/workflow/adapters.js +21 -0
  222. package/dist/core/workflow/approvals.js +6 -6
  223. package/dist/core/workflow/billing.d.ts +9 -9
  224. package/dist/core/workflow/billing.js +9 -9
  225. package/dist/core/workflow/child-env.d.ts +10 -2
  226. package/dist/core/workflow/child-env.d.ts.map +1 -1
  227. package/dist/core/workflow/child-env.js +12 -4
  228. package/dist/core/workflow/engine.d.ts +15 -5
  229. package/dist/core/workflow/engine.d.ts.map +1 -1
  230. package/dist/core/workflow/engine.js +138 -83
  231. package/dist/core/workflow/evidence-preflight.d.ts +24 -0
  232. package/dist/core/workflow/evidence-preflight.d.ts.map +1 -0
  233. package/dist/core/workflow/evidence-preflight.js +134 -0
  234. package/dist/core/workflow/index.d.ts +1 -1
  235. package/dist/core/workflow/index.d.ts.map +1 -1
  236. package/dist/core/workflow/proof.d.ts +11 -5
  237. package/dist/core/workflow/proof.d.ts.map +1 -1
  238. package/dist/core/workflow/proof.js +45 -36
  239. package/dist/core/workflow/run-state.d.ts +1 -1
  240. package/dist/core/workflow/run-state.js +7 -7
  241. package/dist/core/workflow/sandbox-projection.d.ts +6 -6
  242. package/dist/core/workflow/sandbox-projection.d.ts.map +1 -1
  243. package/dist/core/workflow/sandbox-projection.js +11 -11
  244. package/dist/core/workflow/spawn-claude.d.ts +3 -3
  245. package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
  246. package/dist/core/workflow/spawn-claude.js +9 -6
  247. package/dist/core/workflow/spawn-codex.d.ts +4 -4
  248. package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
  249. package/dist/core/workflow/spawn-codex.js +9 -6
  250. package/dist/core/workflow/spawn-cursor.d.ts +4 -4
  251. package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
  252. package/dist/core/workflow/spawn-cursor.js +9 -6
  253. package/dist/core/workflow/spawn-failure.d.ts +1 -1
  254. package/dist/core/workflow/spawn-failure.js +1 -1
  255. package/dist/core/workflow/specialists.js +2 -2
  256. package/dist/core/workflow/{journal.d.ts → transcript.d.ts} +8 -8
  257. package/dist/core/workflow/transcript.d.ts.map +1 -0
  258. package/dist/core/workflow/{journal.js → transcript.js} +14 -14
  259. package/dist/core/workflow/types.d.ts +98 -51
  260. package/dist/core/workflow/types.d.ts.map +1 -1
  261. package/dist/core/workflow/types.js +11 -1
  262. package/dist/core/workflow/validate.d.ts +1 -1
  263. package/dist/core/workflow/validate.js +1 -1
  264. package/dist/core/workflow/workspaces/cancellation.js +2 -2
  265. package/dist/core/workflow/workspaces/cleanup.js +2 -2
  266. package/dist/core/workflow/workspaces/execution.js +6 -6
  267. package/dist/core/workflow/workspaces/inspect.js +9 -9
  268. package/dist/core/workflow/workspaces/integration.js +14 -14
  269. package/dist/core/workflow/workspaces/lifecycle.d.ts +1 -1
  270. package/dist/core/workflow/workspaces/lifecycle.d.ts.map +1 -1
  271. package/dist/core/workflow/workspaces/lifecycle.js +9 -9
  272. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  273. package/dist/core/workflow/workspaces/local-git.js +39 -5
  274. package/dist/core/workflow/workspaces/recovery.js +3 -3
  275. package/dist/core/workflow/workspaces/state.d.ts +1 -1
  276. package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
  277. package/dist/core/workflow/workspaces/state.js +3 -3
  278. package/dist/core/workflow/workspaces/types.d.ts +1 -1
  279. package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
  280. package/dist/lib/browser/asserts.d.ts +28 -0
  281. package/dist/lib/browser/asserts.d.ts.map +1 -0
  282. package/dist/lib/browser/asserts.js +152 -0
  283. package/dist/lib/browser/client.d.ts +49 -0
  284. package/dist/lib/browser/client.d.ts.map +1 -1
  285. package/dist/lib/browser/client.js +155 -14
  286. package/dist/lib/browser/content-checks.d.ts +108 -0
  287. package/dist/lib/browser/content-checks.d.ts.map +1 -0
  288. package/dist/lib/browser/content-checks.js +474 -0
  289. package/dist/lib/browser/critique.d.ts +91 -0
  290. package/dist/lib/browser/critique.d.ts.map +1 -0
  291. package/dist/lib/browser/critique.js +167 -0
  292. package/dist/lib/browser/geometry.d.ts +32 -0
  293. package/dist/lib/browser/geometry.d.ts.map +1 -1
  294. package/dist/lib/browser/geometry.js +244 -1
  295. package/dist/lib/browser/index.d.ts +4 -1
  296. package/dist/lib/browser/index.d.ts.map +1 -1
  297. package/dist/lib/browser/index.js +2 -0
  298. package/dist/lib/claude-desktop.d.ts.map +1 -1
  299. package/dist/lib/claude-desktop.js +4 -1
  300. package/dist/lib/council/index.d.ts +6 -6
  301. package/dist/lib/council/index.d.ts.map +1 -1
  302. package/dist/lib/council/index.js +8 -8
  303. package/dist/lib/identities/assume.d.ts +2 -2
  304. package/dist/lib/identities/assume.js +7 -7
  305. package/dist/lib/instructions/apply.d.ts +3 -3
  306. package/dist/lib/instructions/apply.d.ts.map +1 -1
  307. package/dist/lib/instructions/apply.js +75 -27
  308. package/dist/lib/instructions/host-addendum.d.ts +54 -0
  309. package/dist/lib/instructions/host-addendum.d.ts.map +1 -0
  310. package/dist/lib/instructions/host-addendum.js +107 -0
  311. package/dist/lib/instructions/templates.d.ts +10 -3
  312. package/dist/lib/instructions/templates.d.ts.map +1 -1
  313. package/dist/lib/instructions/templates.js +41 -12
  314. package/dist/lib/machine.d.ts +2 -2
  315. package/dist/lib/machine.js +2 -2
  316. package/package.json +26 -21
  317. package/schemas/config.schema.json +26 -1
  318. package/src/commander.ts +22 -13
  319. package/src/commands/{harness.ts → adapter.ts} +46 -46
  320. package/src/commands/agents.ts +71 -64
  321. package/src/commands/artifacts.ts +168 -0
  322. package/src/commands/backup.ts +47 -33
  323. package/src/commands/browse.ts +438 -2
  324. package/src/commands/checkpoint.ts +196 -0
  325. package/src/commands/context.ts +3 -176
  326. package/src/commands/decision.ts +41 -7
  327. package/src/commands/deinit.ts +16 -16
  328. package/src/commands/doctor.ts +28 -28
  329. package/src/commands/{supervisor.ts → governor.ts} +184 -154
  330. package/src/commands/init.ts +50 -34
  331. package/src/commands/{scratch.ts → journal.ts} +60 -60
  332. package/src/commands/policy.ts +1 -1
  333. package/src/commands/presence.ts +2 -2
  334. package/src/commands/sync.ts +3 -3
  335. package/src/commands/tunnel.ts +237 -34
  336. package/src/commands/web-fetch.ts +1 -1
  337. package/src/commands/web.ts +56 -1
  338. package/src/commands/work.ts +50 -35
  339. package/src/commands/workflow.ts +43 -34
  340. package/src/core/{harnesses → adapters}/attest-projection.ts +2 -2
  341. package/src/core/{harnesses → adapters}/attest.ts +27 -27
  342. package/src/core/{harnesses → adapters}/attestation.ts +41 -41
  343. package/src/core/{harnesses → adapters}/bench.ts +34 -43
  344. package/src/core/adapters/index.ts +56 -0
  345. package/src/core/{harnesses → adapters}/profiles.ts +16 -16
  346. package/src/core/{harnesses → adapters}/registry.ts +23 -23
  347. package/src/core/{harnesses → adapters}/types.ts +23 -23
  348. package/src/core/agents/canonical-emit.ts +6 -6
  349. package/src/core/agents/cli-emit.ts +1 -1
  350. package/src/core/agents/cli.ts +30 -28
  351. package/src/core/agents/codex-replay.ts +6 -6
  352. package/src/core/agents/coord-client.ts +119 -28
  353. package/src/core/agents/events/consume.ts +1 -1
  354. package/src/core/agents/events/emit.ts +7 -6
  355. package/src/core/agents/render/prompt-context.ts +107 -31
  356. package/src/core/agents/render/session-context.ts +6 -6
  357. package/src/core/agents/rules/claim-conflict.ts +4 -7
  358. package/src/core/agents/rules/commit-conflict.ts +103 -22
  359. package/src/core/agents/rules/stop-hook.ts +33 -17
  360. package/src/core/agents/rules/verdict.ts +13 -0
  361. package/src/core/agents/session-events.ts +4 -4
  362. package/src/core/agents/state/council.ts +1 -1
  363. package/src/core/agents/state/heartbeat-projector.ts +16 -12
  364. package/src/core/agents/state/heartbeat-writer.ts +12 -12
  365. package/src/core/agents/state/{scratch.ts → journal.ts} +12 -12
  366. package/src/core/agents/state/pidmap.ts +130 -15
  367. package/src/core/agents/state/proc-start.ts +208 -0
  368. package/src/core/agents/state/shell-mutation.ts +1 -1
  369. package/src/core/agents/state/stale-sweep.ts +7 -7
  370. package/src/core/artifacts/index.ts +557 -0
  371. package/src/core/config.ts +30 -2
  372. package/src/core/context/index.ts +15 -15
  373. package/src/core/governor/adapter-spread.ts +82 -0
  374. package/src/core/governor/index.ts +91 -0
  375. package/src/core/governor/plan-api.ts +115 -0
  376. package/src/core/{supervisor → governor}/plan-read.ts +112 -97
  377. package/src/core/{supervisor → governor}/plan-types.ts +59 -56
  378. package/src/core/{supervisor → governor}/planning.ts +223 -192
  379. package/src/core/governor/read.ts +59 -0
  380. package/src/core/{supervisor → governor}/runner.ts +39 -39
  381. package/src/core/{supervisor → governor}/service-read.ts +22 -22
  382. package/src/core/{supervisor → governor}/service.ts +117 -119
  383. package/src/core/{supervisor → governor}/state.ts +325 -167
  384. package/src/core/hooks/adapter/detect.ts +30 -0
  385. package/src/core/hooks/{harness → adapter}/events.ts +16 -14
  386. package/src/core/hooks/{harness → adapter}/output.ts +31 -23
  387. package/src/core/hooks/{harness → adapter}/parse.ts +5 -5
  388. package/src/core/hooks/{harness → adapter}/wiring.ts +21 -21
  389. package/src/core/hooks/cli.ts +185 -162
  390. package/src/core/hooks/effects/image-capture.ts +6 -6
  391. package/src/core/hooks/effects/index.ts +17 -17
  392. package/src/core/hooks/events/emit.ts +3 -3
  393. package/src/core/hooks/events/rotate.ts +1 -1
  394. package/src/core/hooks/events/schema.ts +15 -7
  395. package/src/core/hooks/guard-path.ts +2 -2
  396. package/src/core/hooks/index.ts +1 -1
  397. package/src/core/hooks/resolve/anchor.ts +63 -8
  398. package/src/core/hooks/resolve/coord-root.ts +4 -4
  399. package/src/core/hooks/resolve/intent.ts +1 -1
  400. package/src/core/hooks/resolve/owner.ts +11 -5
  401. package/src/core/{scratch → journal}/index.ts +53 -53
  402. package/src/core/policy/evaluate.ts +8 -8
  403. package/src/core/policy/types.ts +3 -3
  404. package/src/core/work/state.ts +65 -23
  405. package/src/core/workflow/adapters.ts +33 -0
  406. package/src/core/workflow/approvals.ts +7 -7
  407. package/src/core/workflow/billing.ts +12 -12
  408. package/src/core/workflow/child-env.ts +13 -4
  409. package/src/core/workflow/engine.ts +155 -90
  410. package/src/core/workflow/evidence-preflight.ts +165 -0
  411. package/src/core/workflow/index.ts +3 -3
  412. package/src/core/workflow/proof.ts +60 -50
  413. package/src/core/workflow/run-state.ts +7 -7
  414. package/src/core/workflow/sandbox-projection.ts +16 -16
  415. package/src/core/workflow/spawn-claude.ts +13 -10
  416. package/src/core/workflow/spawn-codex.ts +13 -10
  417. package/src/core/workflow/spawn-cursor.ts +13 -10
  418. package/src/core/workflow/spawn-failure.ts +1 -1
  419. package/src/core/workflow/specialists.ts +2 -2
  420. package/src/core/workflow/{journal.ts → transcript.ts} +16 -16
  421. package/src/core/workflow/types.ts +108 -51
  422. package/src/core/workflow/validate.ts +1 -1
  423. package/src/core/workflow/workspaces/cancellation.ts +2 -2
  424. package/src/core/workflow/workspaces/cleanup.ts +2 -2
  425. package/src/core/workflow/workspaces/execution.ts +6 -6
  426. package/src/core/workflow/workspaces/inspect.ts +14 -11
  427. package/src/core/workflow/workspaces/integration.ts +18 -14
  428. package/src/core/workflow/workspaces/lifecycle.ts +10 -10
  429. package/src/core/workflow/workspaces/local-git.ts +47 -5
  430. package/src/core/workflow/workspaces/recovery.ts +3 -3
  431. package/src/core/workflow/workspaces/state.ts +4 -3
  432. package/src/core/workflow/workspaces/types.ts +1 -1
  433. package/src/lib/browser/asserts.ts +177 -0
  434. package/src/lib/browser/client.ts +189 -14
  435. package/src/lib/browser/content-checks.ts +571 -0
  436. package/src/lib/browser/critique.ts +231 -0
  437. package/src/lib/browser/geometry.ts +297 -1
  438. package/src/lib/browser/index.ts +34 -0
  439. package/src/lib/claude-desktop.ts +4 -1
  440. package/src/lib/council/index.ts +9 -9
  441. package/src/lib/identities/assume.ts +7 -7
  442. package/src/lib/instructions/apply.ts +87 -25
  443. package/src/lib/instructions/host-addendum.ts +126 -0
  444. package/src/lib/instructions/templates.ts +44 -15
  445. package/src/lib/machine.ts +2 -2
  446. package/dist/commands/harness.d.ts +0 -12
  447. package/dist/commands/harness.d.ts.map +0 -1
  448. package/dist/commands/scratch.d.ts +0 -4
  449. package/dist/commands/scratch.d.ts.map +0 -1
  450. package/dist/commands/session.d.ts.map +0 -1
  451. package/dist/commands/session.js +0 -162
  452. package/dist/commands/supervisor.d.ts +0 -4
  453. package/dist/commands/supervisor.d.ts.map +0 -1
  454. package/dist/core/harnesses/attest-projection.d.ts.map +0 -1
  455. package/dist/core/harnesses/attest.d.ts.map +0 -1
  456. package/dist/core/harnesses/attestation.d.ts.map +0 -1
  457. package/dist/core/harnesses/bench.d.ts.map +0 -1
  458. package/dist/core/harnesses/index.d.ts +0 -13
  459. package/dist/core/harnesses/index.d.ts.map +0 -1
  460. package/dist/core/harnesses/index.js +0 -6
  461. package/dist/core/harnesses/profiles.d.ts.map +0 -1
  462. package/dist/core/harnesses/registry.d.ts +0 -15
  463. package/dist/core/harnesses/registry.d.ts.map +0 -1
  464. package/dist/core/harnesses/types.d.ts.map +0 -1
  465. package/dist/core/hooks/harness/detect.d.ts +0 -9
  466. package/dist/core/hooks/harness/events.d.ts.map +0 -1
  467. package/dist/core/hooks/harness/output.d.ts.map +0 -1
  468. package/dist/core/supervisor/index.d.ts +0 -7
  469. package/dist/core/supervisor/index.d.ts.map +0 -1
  470. package/dist/core/supervisor/index.js +0 -6
  471. package/dist/core/supervisor/plan-api.d.ts +0 -23
  472. package/dist/core/supervisor/plan-api.d.ts.map +0 -1
  473. package/dist/core/supervisor/plan-api.js +0 -50
  474. package/dist/core/supervisor/plan-read.d.ts +0 -5
  475. package/dist/core/supervisor/plan-read.d.ts.map +0 -1
  476. package/dist/core/supervisor/plan-types.d.ts.map +0 -1
  477. package/dist/core/supervisor/planning.d.ts +0 -33
  478. package/dist/core/supervisor/planning.d.ts.map +0 -1
  479. package/dist/core/supervisor/read.d.ts +0 -6
  480. package/dist/core/supervisor/read.d.ts.map +0 -1
  481. package/dist/core/supervisor/read.js +0 -4
  482. package/dist/core/supervisor/runner.d.ts +0 -37
  483. package/dist/core/supervisor/runner.d.ts.map +0 -1
  484. package/dist/core/supervisor/service-read.d.ts +0 -6
  485. package/dist/core/supervisor/service-read.d.ts.map +0 -1
  486. package/dist/core/supervisor/service.d.ts +0 -114
  487. package/dist/core/supervisor/service.d.ts.map +0 -1
  488. package/dist/core/supervisor/state.d.ts +0 -95
  489. package/dist/core/supervisor/state.d.ts.map +0 -1
  490. package/dist/core/workflow/harnesses.d.ts +0 -17
  491. package/dist/core/workflow/harnesses.d.ts.map +0 -1
  492. package/dist/core/workflow/harnesses.js +0 -21
  493. package/dist/core/workflow/journal.d.ts.map +0 -1
  494. package/src/commands/session.ts +0 -187
  495. package/src/core/harnesses/index.ts +0 -56
  496. package/src/core/hooks/harness/detect.ts +0 -30
  497. package/src/core/supervisor/index.ts +0 -89
  498. package/src/core/supervisor/plan-api.ts +0 -73
  499. package/src/core/supervisor/read.ts +0 -59
  500. package/src/core/workflow/harnesses.ts +0 -33
  501. /package/dist/core/{harnesses → adapters}/attest-projection.js +0 -0
@@ -10,7 +10,7 @@ import {
10
10
  sameFilesystemIdentity,
11
11
  validateConfiguredRoot,
12
12
  } from "./paths.ts";
13
- import { appendWorkflowJournalEvent, stableDigest, writeWorkspaceRequest } from "./state.ts";
13
+ import { appendWorkflowTranscriptEvent, stableDigest, writeWorkspaceRequest } from "./state.ts";
14
14
  import type {
15
15
  WorkspaceAttestation,
16
16
  WorkspaceBinding,
@@ -72,7 +72,7 @@ export async function resolveWorkspaceBinding(input: {
72
72
  unknowns: [],
73
73
  receipts: {},
74
74
  };
75
- appendWorkflowJournalEvent(input.opts.coordRoot, input.runId, "workspace.compatibility", {
75
+ appendWorkflowTranscriptEvent(input.opts.coordRoot, input.runId, "workspace.compatibility", {
76
76
  requested_isolation: fallback.requested_isolation,
77
77
  effective_isolation: fallback.effective_isolation,
78
78
  selection_reason: fallback.selection_reason,
@@ -114,7 +114,7 @@ export async function resolveWorkspaceBinding(input: {
114
114
  }
115
115
  throw new Error(`workflow run ${input.runId} could not reattach its frozen workspace`);
116
116
  }
117
- appendWorkflowJournalEvent(input.opts.coordRoot, input.runId, "workspace.reattach", {
117
+ appendWorkflowTranscriptEvent(input.opts.coordRoot, input.runId, "workspace.reattach", {
118
118
  binding_id: frozenBinding.binding_id,
119
119
  provider_id: frozenBinding.provider.id,
120
120
  attestation_sha256: stableDigest(reattached),
@@ -180,7 +180,7 @@ export async function resolveWorkspaceBinding(input: {
180
180
  unknowns: [...probe.unknowns],
181
181
  receipts: {},
182
182
  };
183
- appendWorkflowJournalEvent(input.opts.coordRoot, input.runId, "workspace.fallback", {
183
+ appendWorkflowTranscriptEvent(input.opts.coordRoot, input.runId, "workspace.fallback", {
184
184
  requested_isolation: fallback.requested_isolation,
185
185
  effective_isolation: fallback.effective_isolation,
186
186
  selection_reason: fallback.selection_reason,
@@ -226,7 +226,7 @@ export async function resolveWorkspaceBinding(input: {
226
226
  idempotency_key: stableDigest(requestWithoutKey),
227
227
  };
228
228
  writeWorkspaceRequest(input.opts.coordRoot, request);
229
- appendWorkflowJournalEvent(input.opts.coordRoot, input.runId, "execution.allocate.start", {
229
+ appendWorkflowTranscriptEvent(input.opts.coordRoot, input.runId, "execution.allocate.start", {
230
230
  provider_id: probe.capabilities.provider_id,
231
231
  request_sha256: stableDigest(request),
232
232
  });
@@ -261,7 +261,7 @@ export async function resolveWorkspaceBinding(input: {
261
261
  }
262
262
  throw new Error("workspace provider returned a binding that failed initial attestation");
263
263
  }
264
- appendWorkflowJournalEvent(input.opts.coordRoot, input.runId, "execution.allocate.end", {
264
+ appendWorkflowTranscriptEvent(input.opts.coordRoot, input.runId, "execution.allocate.end", {
265
265
  binding_id: binding.binding_id,
266
266
  provider_id: binding.provider.id,
267
267
  active_root: binding.active_root,
@@ -97,7 +97,7 @@ export type WorkflowWorkspaceInspection =
97
97
  | { ok: true; value: WorkflowWorkspaceStatus }
98
98
  | { ok: false; run_id: string; error: string };
99
99
 
100
- interface WorkflowJournalProjectionEvent {
100
+ interface WorkflowTranscriptProjectionEvent {
101
101
  event: string;
102
102
  ok?: boolean;
103
103
  status?: "blocked" | "lost" | "cancelled" | "unsupported" | "preserved_dirty";
@@ -119,7 +119,7 @@ export function readWorkflowWorkspaceStatus(
119
119
  const root = resolve(coordRoot);
120
120
  const runDir = workflowRunDir(root, runId);
121
121
  const manifest = readWorkflowRunManifest(root, runId);
122
- const journal = readWorkspaceJournal(runDir, runId);
122
+ const transcript = readWorkspaceTranscript(runDir, runId);
123
123
  const proofPath = join(runDir, "proof.json");
124
124
  const proof = existsSync(proofPath) ? readWorkflowProof(root, runId) : undefined;
125
125
  const proofSha256 = proof ? fileSha256(proofPath) : undefined;
@@ -129,7 +129,7 @@ export function readWorkflowWorkspaceStatus(
129
129
  if (!binding) {
130
130
  const lifecycle = deriveWorkspaceLifecycle({
131
131
  manifest,
132
- workflow_journal: journal,
132
+ workflow_transcript: transcript,
133
133
  proof,
134
134
  proof_sha256: proofSha256,
135
135
  allocation_unsupported: fallback !== undefined,
@@ -212,7 +212,7 @@ export function readWorkflowWorkspaceStatus(
212
212
  binding,
213
213
  provider_events: providerEvents,
214
214
  manifest,
215
- workflow_journal: journal,
215
+ workflow_transcript: transcript,
216
216
  proof,
217
217
  proof_sha256: proofSha256,
218
218
  integration_plan: integrationPlan,
@@ -355,8 +355,11 @@ export function renderWorkflowWorkspaceStatus(status: WorkflowWorkspaceStatus):
355
355
 
356
356
  const MAX_LISTED_DIRTY_PATHS = 12;
357
357
 
358
- function readWorkspaceJournal(runDir: string, runId: string): WorkflowJournalProjectionEvent[] {
359
- const path = join(runDir, "journal.jsonl");
358
+ function readWorkspaceTranscript(
359
+ runDir: string,
360
+ runId: string,
361
+ ): WorkflowTranscriptProjectionEvent[] {
362
+ const path = join(runDir, "transcript.jsonl");
360
363
  if (!existsSync(path)) return [];
361
364
  return readFileSync(path, "utf8")
362
365
  .split("\n")
@@ -367,7 +370,7 @@ function readWorkspaceJournal(runDir: string, runId: string): WorkflowJournalPro
367
370
  record = JSON.parse(line) as Record<string, unknown>;
368
371
  } catch (error) {
369
372
  throw new Error(
370
- `cannot parse workflow journal event ${index + 1}: ${
373
+ `cannot parse workflow transcript event ${index + 1}: ${
371
374
  error instanceof Error ? error.message : String(error)
372
375
  }`,
373
376
  );
@@ -376,12 +379,12 @@ function readWorkspaceJournal(runDir: string, runId: string): WorkflowJournalPro
376
379
  typeof record.event !== "string" ||
377
380
  (record.run_id !== undefined && record.run_id !== runId)
378
381
  ) {
379
- throw new Error(`workflow journal event ${index + 1} is foreign or unsupported`);
382
+ throw new Error(`workflow transcript event ${index + 1} is foreign or unsupported`);
380
383
  }
381
384
  return {
382
385
  event: record.event,
383
386
  ok: typeof record.ok === "boolean" ? record.ok : undefined,
384
- status: journalStatus(record.status),
387
+ status: transcriptStatus(record.status),
385
388
  work_event_seq:
386
389
  typeof record.work_event_seq === "number" ? record.work_event_seq : undefined,
387
390
  work_event_sha256:
@@ -424,10 +427,10 @@ function cleanupState(
424
427
  return intent || attemptStatus ? "pending" : "not_requested";
425
428
  }
426
429
 
427
- function journalStatus(value: unknown): WorkflowJournalProjectionEvent["status"] {
430
+ function transcriptStatus(value: unknown): WorkflowTranscriptProjectionEvent["status"] {
428
431
  return typeof value === "string" &&
429
432
  ["blocked", "lost", "cancelled", "unsupported", "preserved_dirty"].includes(value)
430
- ? (value as WorkflowJournalProjectionEvent["status"])
433
+ ? (value as WorkflowTranscriptProjectionEvent["status"])
431
434
  : undefined;
432
435
  }
433
436
 
@@ -16,7 +16,7 @@ import { readWorkflowRunManifest } from "../run-state.ts";
16
16
  import { acquireNoClobberLease } from "./leases.ts";
17
17
  import {
18
18
  appendIntegrationAttempt,
19
- appendWorkflowJournalEvent,
19
+ appendWorkflowTranscriptEvent,
20
20
  fileSha256,
21
21
  readIntegrationAttempts,
22
22
  readWorkflowSupplement,
@@ -177,7 +177,7 @@ export async function prepareIntegration(input: PrepareIntegrationInput): Promis
177
177
  }
178
178
  if (!prior) {
179
179
  writeWorkflowSupplement(input.coordRoot, input.runId, "integration/plan.json", plan);
180
- appendWorkflowJournalEvent(input.coordRoot, input.runId, "integration.plan", {
180
+ appendWorkflowTranscriptEvent(input.coordRoot, input.runId, "integration.plan", {
181
181
  plan_id: plan.plan_id,
182
182
  plan_sha256: stableDigest(plan),
183
183
  });
@@ -236,12 +236,12 @@ export async function applyIntegration(
236
236
  }
237
237
  if (
238
238
  authorization.decision_sha256 !== stableDigest(authorization.decision) ||
239
- authorization.journal_anchor.event !== "integration.plan" ||
240
- authorization.journal_anchor.plan_sha256 !== planSha256
239
+ authorization.transcript_anchor.event !== "integration.plan" ||
240
+ authorization.transcript_anchor.plan_sha256 !== planSha256
241
241
  ) {
242
- throw new Error("integration authorization digest or journal anchor is corrupt");
242
+ throw new Error("integration authorization digest or transcript anchor is corrupt");
243
243
  }
244
- assertIntegrationPlanJournal(input.coordRoot, input.runId, planSha256);
244
+ assertIntegrationPlanTranscript(input.coordRoot, input.runId, planSha256);
245
245
  if (authorization.approval_id) {
246
246
  const approval = readWorkflowApproval(input.coordRoot, authorization.approval_id);
247
247
  if (
@@ -397,7 +397,7 @@ export async function applyIntegration(
397
397
  applied_at: providerResult.applied_at,
398
398
  };
399
399
  writeWorkflowSupplement(input.coordRoot, input.runId, "integration/receipt.json", receipt);
400
- appendWorkflowJournalEvent(input.coordRoot, input.runId, "integration.apply", {
400
+ appendWorkflowTranscriptEvent(input.coordRoot, input.runId, "integration.apply", {
401
401
  receipt_id: receipt.receipt_id,
402
402
  status: receipt.status,
403
403
  target_commit: receipt.target_commit,
@@ -721,7 +721,7 @@ function authorizePlan(input: PrepareIntegrationInput, plan: IntegrationPlan): v
721
721
  approval_id: approvalId,
722
722
  approval_actor: approvalActor,
723
723
  approval_sha256: approvalSha256,
724
- journal_anchor: {
724
+ transcript_anchor: {
725
725
  event: "integration.plan",
726
726
  plan_sha256: stableDigest(plan),
727
727
  },
@@ -740,7 +740,7 @@ function authorizePlan(input: PrepareIntegrationInput, plan: IntegrationPlan): v
740
740
  prior.decision_sha256 !== stableDigest(prior.decision) ||
741
741
  prior.approval_id !== authorization.approval_id ||
742
742
  prior.approval_sha256 !== authorization.approval_sha256 ||
743
- stableDigest(prior.journal_anchor) !== stableDigest(authorization.journal_anchor)
743
+ stableDigest(prior.transcript_anchor) !== stableDigest(authorization.transcript_anchor)
744
744
  ) {
745
745
  throw new Error("existing integration authorization does not match the exact plan");
746
746
  }
@@ -752,7 +752,7 @@ function authorizePlan(input: PrepareIntegrationInput, plan: IntegrationPlan): v
752
752
  "integration/authorization.json",
753
753
  authorization,
754
754
  );
755
- appendWorkflowJournalEvent(input.coordRoot, input.runId, "integration.authorized", {
755
+ appendWorkflowTranscriptEvent(input.coordRoot, input.runId, "integration.authorized", {
756
756
  plan_id: plan.plan_id,
757
757
  authorization_sha256: stableDigest(authorization),
758
758
  policy_sha256: authorization.policy_sha256,
@@ -787,8 +787,12 @@ function requiredIntegrationRoot(binding: WorkspaceBinding): string {
787
787
  return binding.integration_root;
788
788
  }
789
789
 
790
- function assertIntegrationPlanJournal(coordRoot: string, runId: string, planSha256: string): void {
791
- const path = join(workflowRunDir(coordRoot, runId), "journal.jsonl");
790
+ function assertIntegrationPlanTranscript(
791
+ coordRoot: string,
792
+ runId: string,
793
+ planSha256: string,
794
+ ): void {
795
+ const path = join(workflowRunDir(coordRoot, runId), "transcript.jsonl");
792
796
  let records: Array<Record<string, unknown>>;
793
797
  try {
794
798
  records = readFileSync(path, "utf8")
@@ -796,7 +800,7 @@ function assertIntegrationPlanJournal(coordRoot: string, runId: string, planSha2
796
800
  .filter(Boolean)
797
801
  .map((line) => JSON.parse(line) as Record<string, unknown>);
798
802
  } catch (error) {
799
- throw new Error(`workflow journal is corrupt: ${(error as Error).message}`);
803
+ throw new Error(`workflow transcript is corrupt: ${(error as Error).message}`);
800
804
  }
801
805
  if (
802
806
  records.some((record) => record.run_id !== runId || typeof record.event !== "string") ||
@@ -804,7 +808,7 @@ function assertIntegrationPlanJournal(coordRoot: string, runId: string, planSha2
804
808
  (record) => record.event === "integration.plan" && record.plan_sha256 === planSha256,
805
809
  )
806
810
  ) {
807
- throw new Error("integration plan journal anchor is missing or mismatched");
811
+ throw new Error("integration plan transcript anchor is missing or mismatched");
808
812
  }
809
813
  }
810
814
 
@@ -135,7 +135,7 @@ export interface WorkspaceLifecycleProjectionInput {
135
135
  binding?: WorkspaceBinding;
136
136
  provider_events?: readonly WorkspaceProviderEvent[];
137
137
  manifest?: WorkflowRunManifest;
138
- workflow_journal?: readonly {
138
+ workflow_transcript?: readonly {
139
139
  event: string;
140
140
  ok?: boolean;
141
141
  status?: "blocked" | "lost" | WorkspaceCancellationResult["status"];
@@ -207,22 +207,22 @@ export function deriveWorkspaceLifecycle(
207
207
  transition(next);
208
208
  }
209
209
 
210
- const journal = input.workflow_journal ?? [];
211
- for (const event of journal) {
210
+ const transcript = input.workflow_transcript ?? [];
211
+ for (const event of transcript) {
212
212
  if (input.binding && (event.event === "run.start" || event.event === "run.resume")) {
213
213
  transition("running");
214
214
  }
215
215
  if (event.event === "run.parked") transition("parked");
216
216
  }
217
- const failedReattachment = [...journal]
217
+ const failedReattachment = [...transcript]
218
218
  .reverse()
219
219
  .find((event) => event.event === "workspace.reattach.failed");
220
220
  if (failedReattachment) transition(failedReattachment.status === "blocked" ? "blocked" : "lost");
221
221
  let workflowOutcome = proofOutcome(input.proof, input.binding);
222
- const terminalJournal = [...journal].reverse().find((event) => event.event === "run.end");
222
+ const terminalTranscript = [...transcript].reverse().find((event) => event.event === "run.end");
223
223
  if (input.proof && !failedReattachment) transition(workflowOutcome!);
224
- if (terminalJournal && !input.proof && !failedReattachment) {
225
- workflowOutcome = terminalJournal.ok === false ? "failed_retained" : null;
224
+ if (terminalTranscript && !input.proof && !failedReattachment) {
225
+ workflowOutcome = terminalTranscript.ok === false ? "failed_retained" : null;
226
226
  transition("blocked");
227
227
  }
228
228
  if (projectedIntegrationState !== "none") transition("integration_requested");
@@ -269,7 +269,7 @@ export function deriveWorkspaceLifecycle(
269
269
  ((input.cancellation_receipt?.status === "cancelled" &&
270
270
  input.cancellation_receipt.work_event_seq === latestGovernance.seq &&
271
271
  input.cancellation_receipt.work_event_sha256 === workEventSha256) ||
272
- journal.some(
272
+ transcript.some(
273
273
  (event) =>
274
274
  event.event === "workspace.cancel" &&
275
275
  event.status === "cancelled" &&
@@ -459,8 +459,8 @@ function validateIntegrationAuthorization(
459
459
  !digest(authorization.policy_sha256) ||
460
460
  authorization.decision?.verdict !== "allow" ||
461
461
  authorization.decision_sha256 !== stableDigest(authorization.decision) ||
462
- authorization.journal_anchor?.event !== "integration.plan" ||
463
- authorization.journal_anchor.plan_sha256 !== planSha256 ||
462
+ authorization.transcript_anchor?.event !== "integration.plan" ||
463
+ authorization.transcript_anchor.plan_sha256 !== planSha256 ||
464
464
  !validTimestamp(authorization.authorized_at) ||
465
465
  (authorization.approval_id !== undefined &&
466
466
  (typeof authorization.approval_actor !== "string" || !digest(authorization.approval_sha256)))
@@ -1,6 +1,13 @@
1
1
  import { randomBytes } from "node:crypto";
2
- import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync } from "node:fs";
3
- import { dirname, isAbsolute, join, relative, resolve } from "node:path";
2
+ import {
3
+ existsSync,
4
+ lstatSync,
5
+ mkdirSync,
6
+ readFileSync,
7
+ realpathSync,
8
+ writeFileSync,
9
+ } from "node:fs";
10
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
4
11
  import { WorkspaceAttestationError } from "./attestation-error.ts";
5
12
  import {
6
13
  git,
@@ -68,6 +75,8 @@ import { isWorkspaceAttestation } from "./validate.ts";
68
75
 
69
76
  const PROVIDER_ID = "local-git-worktree";
70
77
  const PROVIDER_VERSION = "1";
78
+ const WORKSPACE_PARENT_SEGMENT = ".harnery-workspaces";
79
+ const LEGACY_WORKSPACE_PARENT_SEGMENT = "harnery-workspaces";
71
80
  const LOCK_STALE_MS = 5 * 60 * 1_000;
72
81
  const OBJECT_FORMAT = /^[a-f0-9]{40,64}$/;
73
82
  const REF_FORMAT = /^refs\/heads\/[A-Za-z0-9][A-Za-z0-9._/-]{0,180}$/;
@@ -221,7 +230,11 @@ async function allocate(
221
230
  );
222
231
  const authorityOutside = describeAuthorityOutsideRoot(repo, root.realpath);
223
232
  if (authorityOutside) throw new Error(authorityOutside);
224
- const workspaceRoot = candidateUnderRoot(root, ["harnery-workspaces", bindingId]);
233
+ // Claims are immutable, so a retry must reproduce the path the first attempt
234
+ // froze. Only a genuinely new allocation picks the current parent.
235
+ const priorClaim = readWorkspaceClaim(coordRoot, PROVIDER_ID, bindingId);
236
+ const parentSegment = priorClaim ? claimedParentSegment(priorClaim) : WORKSPACE_PARENT_SEGMENT;
237
+ const workspaceRoot = candidateUnderRoot(root, [parentSegment, bindingId]);
225
238
  const activeRoot = resolve(workspaceRoot, repo.requestedRelativePath);
226
239
  if (!containsPath(workspaceRoot, activeRoot)) {
227
240
  throw new Error("requested working directory escapes the isolated workspace");
@@ -287,6 +300,33 @@ async function allocate(
287
300
  }
288
301
  }
289
302
 
303
+ /**
304
+ * A claim freezes its workspace path at allocation time, so reconciliation must
305
+ * follow the parent recorded there rather than the parent this version would
306
+ * choose. Only the names this provider has ever allocated under are accepted, so
307
+ * a tampered claim cannot redirect creation into an unrelated directory.
308
+ */
309
+ function claimedParentSegment(claim: WorkspaceClaim): string {
310
+ const segment = basename(dirname(claim.workspace_root));
311
+ if (segment !== WORKSPACE_PARENT_SEGMENT && segment !== LEGACY_WORKSPACE_PARENT_SEGMENT) {
312
+ throw new Error("claimed workspace path is not under a provider-owned workspace parent");
313
+ }
314
+ return segment;
315
+ }
316
+
317
+ /**
318
+ * The parent holds real checkouts that would otherwise surface as untracked
319
+ * content in the surrounding repository. A directory whose every entry is
320
+ * ignored, including the ignore file itself, does not appear in `git status` at
321
+ * all, which keeps the guarantee with the provider instead of asking each
322
+ * consumer to maintain a rule.
323
+ */
324
+ function hideWorkspaceParentFromGit(parent: string): void {
325
+ const ignoreFile = join(parent, ".gitignore");
326
+ if (existsSync(ignoreFile)) return;
327
+ writeFileSync(ignoreFile, "*\n", { mode: 0o600 });
328
+ }
329
+
290
330
  function reconcileAllocation(
291
331
  coordRoot: string,
292
332
  claim: WorkspaceClaim,
@@ -328,7 +368,9 @@ function reconcileAllocation(
328
368
  throw new Error("provider-owned workspace branch no longer matches its frozen base");
329
369
  }
330
370
 
331
- const workspaceParent = createContainedDirectories(root, ["harnery-workspaces"]);
371
+ const parentSegment = claimedParentSegment(claim);
372
+ const workspaceParent = createContainedDirectories(root, [parentSegment]);
373
+ hideWorkspaceParentFromGit(workspaceParent);
332
374
  const workspaceParentIdentity = filesystemIdentity(workspaceParent);
333
375
  const registered = worktreeInventory(claim.repository.source_root.realpath);
334
376
  const exact = registered.find((item) => resolve(item.path) === claim.workspace_root);
@@ -385,7 +427,7 @@ function reconcileAllocation(
385
427
  parent_identity: workspaceParentIdentity,
386
428
  });
387
429
  }
388
- const openedWorkspace = openContainedDirectory(root, ["harnery-workspaces", claim.binding_id]);
430
+ const openedWorkspace = openContainedDirectory(root, [parentSegment, claim.binding_id]);
389
431
  if (openedWorkspace.path !== claim.workspace_root) {
390
432
  openedWorkspace.close();
391
433
  throw new Error("descriptor-backed workspace directory differs from the claim");
@@ -16,11 +16,11 @@ export function readWorkflowLiveness(coordRoot: string, runId: string): Workflow
16
16
  }
17
17
  }
18
18
 
19
- const journalPath = join(root, ".harnery", "workflows", runId, "journal.jsonl");
20
- if (!existsSync(journalPath)) return "unknown";
19
+ const transcriptPath = join(root, ".harnery", "workflows", runId, "transcript.jsonl");
20
+ if (!existsSync(transcriptPath)) return "unknown";
21
21
  let events: Array<{ event?: string; run_id?: string; ok?: unknown; status?: unknown }>;
22
22
  try {
23
- events = readFileSync(journalPath, "utf8")
23
+ events = readFileSync(transcriptPath, "utf8")
24
24
  .split("\n")
25
25
  .filter(Boolean)
26
26
  .map(
@@ -18,7 +18,7 @@ import {
18
18
  writeImmutableJson,
19
19
  } from "../durable-record.ts";
20
20
 
21
- export { appendWorkflowJournalEvent } from "../journal.ts";
21
+ export { appendWorkflowTranscriptEvent } from "../transcript.ts";
22
22
 
23
23
  import type {
24
24
  GitRepositoryBinding,
@@ -232,7 +232,8 @@ export function readWorkspaceEvents(
232
232
  ): WorkspaceProviderEvent[] {
233
233
  const path = workspaceEventsPath(coordRoot, providerId, bindingId);
234
234
  if (!existsSync(path)) return [];
235
- if (statSync(path).size > JSON_LIMIT * 4) throw new Error("workspace event journal is too large");
235
+ if (statSync(path).size > JSON_LIMIT * 4)
236
+ throw new Error("workspace event transcript is too large");
236
237
  const claim = readWorkspaceClaim(coordRoot, providerId, bindingId);
237
238
  if (!claim) throw new Error("workspace event authority claim is missing");
238
239
  const records = readFileSync(path, "utf8")
@@ -391,7 +392,7 @@ function readChainedRecords<
391
392
  >(path: string, label: string): T[] {
392
393
  if (!existsSync(path)) return [];
393
394
  if (statSync(path).size > JSON_LIMIT * 4) {
394
- throw new Error(`${label} journal is too large`);
395
+ throw new Error(`${label} transcript is too large`);
395
396
  }
396
397
  const records = readFileSync(path, "utf8")
397
398
  .split("\n")
@@ -353,7 +353,7 @@ export interface IntegrationAuthorization {
353
353
  approval_id?: string;
354
354
  approval_actor?: string;
355
355
  approval_sha256?: string;
356
- journal_anchor: {
356
+ transcript_anchor: {
357
357
  event: "integration.plan";
358
358
  plan_sha256: string;
359
359
  };
@@ -0,0 +1,177 @@
1
+ // Value assertions for `harn browse --assert`.
2
+ //
3
+ // The layout + content checks answer "does the page look right"; asserts answer
4
+ // "does the page SAY the right thing" — the h1 text, a price, how many cards
5
+ // rendered, whether an error banner is absent. It lets an agent confirm the
6
+ // values it expects without a human reading the page back.
7
+ //
8
+ // One repeatable flag with a small grammar:
9
+ // --assert 'text h1 => Welcome' first match's trimmed text equals
10
+ // --assert 'contains .total => $49' first match's text contains
11
+ // --assert 'matches .sku => ^BN-\d+$' first match's text matches a regex
12
+ // --assert 'count .card => >=3' match count vs a number or comparator
13
+ // --assert 'exists .cta' at least one match
14
+ // --assert 'absent .error' zero matches
15
+ //
16
+ // `op selector => expected`; `exists`/`absent` take no `=> expected`.
17
+
18
+ export type AssertOp = "text" | "contains" | "matches" | "count" | "exists" | "absent";
19
+
20
+ export interface AssertSpec {
21
+ raw: string;
22
+ op: AssertOp;
23
+ selector: string;
24
+ expected: string;
25
+ }
26
+
27
+ export interface AssertResult {
28
+ raw: string;
29
+ op: AssertOp;
30
+ selector: string;
31
+ expected: string;
32
+ /** Observed value: the text, or the match count as a string. */
33
+ actual: string;
34
+ found: boolean;
35
+ outcome: "pass" | "fail";
36
+ /** Populated when the spec itself was malformed (e.g. bad regex, bad count). */
37
+ error?: string;
38
+ }
39
+
40
+ const OPS: readonly AssertOp[] = ["text", "contains", "matches", "count", "exists", "absent"];
41
+
42
+ /** Parse one `--assert` expression. Throws with a clear message on malformed input. */
43
+ export function parseAssertSpec(raw: string): AssertSpec {
44
+ const trimmed = raw.trim();
45
+ const spaceIdx = trimmed.indexOf(" ");
46
+ if (spaceIdx < 0) {
47
+ throw new Error(`--assert needs '<op> <selector> [=> expected]' (got: '${raw}')`);
48
+ }
49
+ const op = trimmed.slice(0, spaceIdx).toLowerCase() as AssertOp;
50
+ if (!OPS.includes(op)) {
51
+ throw new Error(`--assert op must be one of ${OPS.join(", ")} (got: '${op}')`);
52
+ }
53
+ const rest = trimmed.slice(spaceIdx + 1).trim();
54
+ const sep = rest.indexOf("=>");
55
+ if (op === "exists" || op === "absent") {
56
+ return { raw, op, selector: (sep < 0 ? rest : rest.slice(0, sep)).trim(), expected: "" };
57
+ }
58
+ if (sep < 0) {
59
+ throw new Error(`--assert '${op}' needs 'selector => expected' (got: '${raw}')`);
60
+ }
61
+ return {
62
+ raw,
63
+ op,
64
+ selector: rest.slice(0, sep).trim(),
65
+ expected: rest.slice(sep + 2).trim(),
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Build the page evaluator. Serialized into the page by Playwright, so helpers
71
+ * are nested. Comparison logic that does not touch the DOM (count comparators,
72
+ * regex) also runs in-page to keep it one round trip.
73
+ */
74
+ export function buildAssertCheck(): (specs: AssertSpec[]) => AssertResult[] {
75
+ return (specs) => {
76
+ const textOf = (el: Element): string => (el.textContent ?? "").replace(/\s+/g, " ").trim();
77
+
78
+ const compareCount = (count: number, expected: string): { ok: boolean; error?: string } => {
79
+ const m = /^(>=|<=|>|<|=)?\s*(\d+)$/.exec(expected.trim());
80
+ if (!m) return { ok: false, error: `bad count expected '${expected}'` };
81
+ const op = m[1] || "=";
82
+ const n = Number.parseInt(m[2]!, 10);
83
+ switch (op) {
84
+ case ">=":
85
+ return { ok: count >= n };
86
+ case "<=":
87
+ return { ok: count <= n };
88
+ case ">":
89
+ return { ok: count > n };
90
+ case "<":
91
+ return { ok: count < n };
92
+ default:
93
+ return { ok: count === n };
94
+ }
95
+ };
96
+
97
+ return specs.map((spec): AssertResult => {
98
+ const base = {
99
+ raw: spec.raw,
100
+ op: spec.op,
101
+ selector: spec.selector,
102
+ expected: spec.expected,
103
+ };
104
+ let nodes: Element[];
105
+ try {
106
+ nodes = Array.from(document.querySelectorAll(spec.selector));
107
+ } catch {
108
+ return { ...base, actual: "", found: false, outcome: "fail", error: "invalid selector" };
109
+ }
110
+ const first = nodes[0] ?? null;
111
+ const firstText = first ? textOf(first) : "";
112
+
113
+ switch (spec.op) {
114
+ case "exists":
115
+ return {
116
+ ...base,
117
+ actual: String(nodes.length),
118
+ found: nodes.length > 0,
119
+ outcome: nodes.length > 0 ? "pass" : "fail",
120
+ };
121
+ case "absent":
122
+ return {
123
+ ...base,
124
+ actual: String(nodes.length),
125
+ found: nodes.length > 0,
126
+ outcome: nodes.length === 0 ? "pass" : "fail",
127
+ };
128
+ case "count": {
129
+ const { ok, error } = compareCount(nodes.length, spec.expected);
130
+ return {
131
+ ...base,
132
+ actual: String(nodes.length),
133
+ found: true,
134
+ outcome: ok ? "pass" : "fail",
135
+ ...(error ? { error } : {}),
136
+ };
137
+ }
138
+ case "text":
139
+ return {
140
+ ...base,
141
+ actual: firstText,
142
+ found: !!first,
143
+ outcome: first && firstText === spec.expected ? "pass" : "fail",
144
+ };
145
+ case "contains":
146
+ return {
147
+ ...base,
148
+ actual: firstText,
149
+ found: !!first,
150
+ outcome: first && firstText.includes(spec.expected) ? "pass" : "fail",
151
+ };
152
+ case "matches": {
153
+ let re: RegExp;
154
+ try {
155
+ re = new RegExp(spec.expected);
156
+ } catch {
157
+ return {
158
+ ...base,
159
+ actual: firstText,
160
+ found: !!first,
161
+ outcome: "fail",
162
+ error: `invalid regex '${spec.expected}'`,
163
+ };
164
+ }
165
+ return {
166
+ ...base,
167
+ actual: firstText,
168
+ found: !!first,
169
+ outcome: first && re.test(firstText) ? "pass" : "fail",
170
+ };
171
+ }
172
+ default:
173
+ return { ...base, actual: "", found: false, outcome: "fail", error: "unknown op" };
174
+ }
175
+ });
176
+ };
177
+ }