harnery 0.30.0 → 0.31.1

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 (517) 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 +185 -74
  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/grep.d.ts +1 -1
  34. package/dist/commands/grep.d.ts.map +1 -1
  35. package/dist/commands/grep.js +19 -2
  36. package/dist/commands/init.d.ts +12 -12
  37. package/dist/commands/init.d.ts.map +1 -1
  38. package/dist/commands/init.js +44 -30
  39. package/dist/commands/{session.d.ts → journal.d.ts} +2 -2
  40. package/dist/commands/journal.d.ts.map +1 -0
  41. package/dist/commands/{scratch.js → journal.js} +47 -47
  42. package/dist/commands/policy.js +1 -1
  43. package/dist/commands/presence.js +2 -2
  44. package/dist/commands/sync.d.ts +1 -1
  45. package/dist/commands/sync.js +3 -3
  46. package/dist/commands/tunnel.d.ts +16 -0
  47. package/dist/commands/tunnel.d.ts.map +1 -1
  48. package/dist/commands/tunnel.js +213 -27
  49. package/dist/commands/web-fetch.js +1 -1
  50. package/dist/commands/web.d.ts +19 -0
  51. package/dist/commands/web.d.ts.map +1 -1
  52. package/dist/commands/web.js +51 -0
  53. package/dist/commands/work.d.ts.map +1 -1
  54. package/dist/commands/work.js +38 -22
  55. package/dist/commands/workflow.d.ts.map +1 -1
  56. package/dist/commands/workflow.js +35 -28
  57. package/dist/core/{harnesses → adapters}/attest-projection.d.ts +2 -2
  58. package/dist/core/adapters/attest-projection.d.ts.map +1 -0
  59. package/dist/core/{harnesses → adapters}/attest.d.ts +16 -16
  60. package/dist/core/adapters/attest.d.ts.map +1 -0
  61. package/dist/core/{harnesses → adapters}/attest.js +9 -9
  62. package/dist/core/{harnesses → adapters}/attestation.d.ts +16 -16
  63. package/dist/core/adapters/attestation.d.ts.map +1 -0
  64. package/dist/core/{harnesses → adapters}/attestation.js +20 -20
  65. package/dist/core/{harnesses → adapters}/bench.d.ts +12 -12
  66. package/dist/core/adapters/bench.d.ts.map +1 -0
  67. package/dist/core/{harnesses → adapters}/bench.js +12 -12
  68. package/dist/core/adapters/index.d.ts +13 -0
  69. package/dist/core/adapters/index.d.ts.map +1 -0
  70. package/dist/core/adapters/index.js +6 -0
  71. package/dist/core/{harnesses → adapters}/profiles.d.ts +11 -11
  72. package/dist/core/adapters/profiles.d.ts.map +1 -0
  73. package/dist/core/{harnesses → adapters}/profiles.js +11 -11
  74. package/dist/core/adapters/registry.d.ts +15 -0
  75. package/dist/core/adapters/registry.d.ts.map +1 -0
  76. package/dist/core/{harnesses → adapters}/registry.js +11 -11
  77. package/dist/core/{harnesses → adapters}/types.d.ts +23 -23
  78. package/dist/core/adapters/types.d.ts.map +1 -0
  79. package/dist/core/{harnesses → adapters}/types.js +1 -1
  80. package/dist/core/agents/canonical-emit.d.ts +9 -14
  81. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  82. package/dist/core/agents/canonical-emit.js +15 -44
  83. package/dist/core/agents/cli-emit.js +1 -1
  84. package/dist/core/agents/cli.js +30 -26
  85. package/dist/core/agents/codex-replay.d.ts +1 -1
  86. package/dist/core/agents/codex-replay.js +6 -6
  87. package/dist/core/agents/coord-bin.d.ts +33 -0
  88. package/dist/core/agents/coord-bin.d.ts.map +1 -0
  89. package/dist/core/agents/coord-bin.js +89 -0
  90. package/dist/core/agents/coord-client.d.ts +78 -8
  91. package/dist/core/agents/coord-client.d.ts.map +1 -1
  92. package/dist/core/agents/coord-client.js +303 -75
  93. package/dist/core/agents/events/consume.d.ts +1 -1
  94. package/dist/core/agents/events/emit.d.ts +5 -6
  95. package/dist/core/agents/events/emit.d.ts.map +1 -1
  96. package/dist/core/agents/events/emit.js +2 -2
  97. package/dist/core/agents/paths.d.ts +5 -2
  98. package/dist/core/agents/paths.d.ts.map +1 -1
  99. package/dist/core/agents/paths.js +7 -13
  100. package/dist/core/agents/render/prompt-context.d.ts +21 -9
  101. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  102. package/dist/core/agents/render/prompt-context.js +82 -30
  103. package/dist/core/agents/render/session-context.d.ts +1 -1
  104. package/dist/core/agents/render/session-context.js +5 -5
  105. package/dist/core/agents/rules/claim-conflict.d.ts +2 -6
  106. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
  107. package/dist/core/agents/rules/claim-conflict.js +1 -1
  108. package/dist/core/agents/rules/commit-conflict.js +98 -22
  109. package/dist/core/agents/rules/stop-hook.d.ts +9 -9
  110. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  111. package/dist/core/agents/rules/stop-hook.js +23 -5
  112. package/dist/core/agents/rules/verdict.d.ts +14 -0
  113. package/dist/core/agents/rules/verdict.d.ts.map +1 -0
  114. package/dist/core/agents/rules/verdict.js +1 -0
  115. package/dist/core/agents/session-events.js +3 -3
  116. package/dist/core/agents/state/council.d.ts +1 -1
  117. package/dist/core/agents/state/council.js +1 -1
  118. package/dist/core/agents/state/heartbeat-projector.d.ts +3 -2
  119. package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
  120. package/dist/core/agents/state/heartbeat-projector.js +14 -10
  121. package/dist/core/agents/state/heartbeat-writer.d.ts +1 -1
  122. package/dist/core/agents/state/heartbeat-writer.js +12 -12
  123. package/dist/core/agents/state/{scratch.d.ts → journal.d.ts} +7 -7
  124. package/dist/core/agents/state/{scratch.d.ts.map → journal.d.ts.map} +1 -1
  125. package/dist/core/agents/state/{scratch.js → journal.js} +12 -12
  126. package/dist/core/agents/state/pidmap.d.ts +28 -4
  127. package/dist/core/agents/state/pidmap.d.ts.map +1 -1
  128. package/dist/core/agents/state/pidmap.js +130 -15
  129. package/dist/core/agents/state/proc-start.d.ts +95 -0
  130. package/dist/core/agents/state/proc-start.d.ts.map +1 -0
  131. package/dist/core/agents/state/proc-start.js +199 -0
  132. package/dist/core/agents/state/shell-mutation.d.ts +1 -1
  133. package/dist/core/agents/state/shell-mutation.js +1 -1
  134. package/dist/core/agents/state/stale-sweep.js +7 -7
  135. package/dist/core/artifacts/index.d.ts +86 -0
  136. package/dist/core/artifacts/index.d.ts.map +1 -0
  137. package/dist/core/artifacts/index.js +421 -0
  138. package/dist/core/config.d.ts +9 -2
  139. package/dist/core/config.d.ts.map +1 -1
  140. package/dist/core/config.js +26 -2
  141. package/dist/core/context/index.d.ts +12 -12
  142. package/dist/core/context/index.js +10 -10
  143. package/dist/core/governor/adapter-spread.d.ts +52 -0
  144. package/dist/core/governor/adapter-spread.d.ts.map +1 -0
  145. package/dist/core/governor/adapter-spread.js +52 -0
  146. package/dist/core/governor/index.d.ts +7 -0
  147. package/dist/core/governor/index.d.ts.map +1 -0
  148. package/dist/core/governor/index.js +6 -0
  149. package/dist/core/governor/plan-api.d.ts +38 -0
  150. package/dist/core/governor/plan-api.d.ts.map +1 -0
  151. package/dist/core/governor/plan-api.js +83 -0
  152. package/dist/core/governor/plan-read.d.ts +5 -0
  153. package/dist/core/governor/plan-read.d.ts.map +1 -0
  154. package/dist/core/{supervisor → governor}/plan-read.js +66 -52
  155. package/dist/core/{supervisor → governor}/plan-types.d.ts +57 -56
  156. package/dist/core/governor/plan-types.d.ts.map +1 -0
  157. package/dist/core/{supervisor → governor}/plan-types.js +4 -4
  158. package/dist/core/governor/planning.d.ts +48 -0
  159. package/dist/core/governor/planning.d.ts.map +1 -0
  160. package/dist/core/{supervisor → governor}/planning.js +125 -94
  161. package/dist/core/governor/read.d.ts +6 -0
  162. package/dist/core/governor/read.d.ts.map +1 -0
  163. package/dist/core/governor/read.js +4 -0
  164. package/dist/core/governor/runner.d.ts +37 -0
  165. package/dist/core/governor/runner.d.ts.map +1 -0
  166. package/dist/core/{supervisor → governor}/runner.js +15 -15
  167. package/dist/core/governor/service-read.d.ts +6 -0
  168. package/dist/core/governor/service-read.d.ts.map +1 -0
  169. package/dist/core/{supervisor → governor}/service-read.js +12 -12
  170. package/dist/core/governor/service.d.ts +114 -0
  171. package/dist/core/governor/service.d.ts.map +1 -0
  172. package/dist/core/{supervisor → governor}/service.js +57 -57
  173. package/dist/core/governor/state.d.ts +116 -0
  174. package/dist/core/governor/state.d.ts.map +1 -0
  175. package/dist/core/{supervisor → governor}/state.js +228 -108
  176. package/dist/core/hooks/adapter/detect.d.ts +9 -0
  177. package/dist/core/hooks/{harness → adapter}/detect.d.ts.map +1 -1
  178. package/dist/core/hooks/{harness → adapter}/detect.js +8 -8
  179. package/dist/core/hooks/{harness → adapter}/events.d.ts +15 -14
  180. package/dist/core/hooks/adapter/events.d.ts.map +1 -0
  181. package/dist/core/hooks/{harness → adapter}/events.js +5 -5
  182. package/dist/core/hooks/{harness → adapter}/output.d.ts +20 -14
  183. package/dist/core/hooks/adapter/output.d.ts.map +1 -0
  184. package/dist/core/hooks/{harness → adapter}/output.js +30 -22
  185. package/dist/core/hooks/{harness → adapter}/parse.d.ts +5 -5
  186. package/dist/core/hooks/{harness → adapter}/parse.d.ts.map +1 -1
  187. package/dist/core/hooks/{harness → adapter}/parse.js +4 -4
  188. package/dist/core/hooks/{harness → adapter}/wiring.d.ts +15 -15
  189. package/dist/core/hooks/{harness → adapter}/wiring.d.ts.map +1 -1
  190. package/dist/core/hooks/{harness → adapter}/wiring.js +13 -13
  191. package/dist/core/hooks/cli.d.ts +3 -3
  192. package/dist/core/hooks/cli.js +187 -162
  193. package/dist/core/hooks/effects/image-capture.d.ts +5 -5
  194. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  195. package/dist/core/hooks/effects/image-capture.js +3 -3
  196. package/dist/core/hooks/effects/index.d.ts +12 -12
  197. package/dist/core/hooks/effects/index.d.ts.map +1 -1
  198. package/dist/core/hooks/effects/index.js +19 -19
  199. package/dist/core/hooks/events/emit.d.ts +2 -2
  200. package/dist/core/hooks/events/emit.d.ts.map +1 -1
  201. package/dist/core/hooks/events/emit.js +1 -1
  202. package/dist/core/hooks/events/rotate.js +1 -1
  203. package/dist/core/hooks/events/schema.d.ts +13 -5
  204. package/dist/core/hooks/events/schema.d.ts.map +1 -1
  205. package/dist/core/hooks/guard-path.d.ts +2 -2
  206. package/dist/core/hooks/guard-path.js +2 -2
  207. package/dist/core/hooks/index.d.ts +1 -1
  208. package/dist/core/hooks/index.d.ts.map +1 -1
  209. package/dist/core/hooks/resolve/anchor.d.ts +14 -5
  210. package/dist/core/hooks/resolve/anchor.d.ts.map +1 -1
  211. package/dist/core/hooks/resolve/anchor.js +64 -7
  212. package/dist/core/hooks/resolve/coord-root.d.ts +16 -11
  213. package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
  214. package/dist/core/hooks/resolve/coord-root.js +18 -43
  215. package/dist/core/hooks/resolve/intent.js +1 -1
  216. package/dist/core/hooks/resolve/owner.d.ts +1 -1
  217. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  218. package/dist/core/hooks/resolve/owner.js +11 -5
  219. package/dist/core/{scratch → journal}/index.d.ts +25 -25
  220. package/dist/core/{scratch → journal}/index.d.ts.map +1 -1
  221. package/dist/core/{scratch → journal}/index.js +38 -38
  222. package/dist/core/policy/evaluate.d.ts +1 -1
  223. package/dist/core/policy/evaluate.d.ts.map +1 -1
  224. package/dist/core/policy/evaluate.js +7 -7
  225. package/dist/core/policy/types.d.ts +3 -3
  226. package/dist/core/policy/types.d.ts.map +1 -1
  227. package/dist/core/work/state.d.ts +12 -4
  228. package/dist/core/work/state.d.ts.map +1 -1
  229. package/dist/core/work/state.js +50 -17
  230. package/dist/core/workflow/adapters.d.ts +17 -0
  231. package/dist/core/workflow/adapters.d.ts.map +1 -0
  232. package/dist/core/workflow/adapters.js +21 -0
  233. package/dist/core/workflow/approvals.js +6 -6
  234. package/dist/core/workflow/billing.d.ts +9 -9
  235. package/dist/core/workflow/billing.js +9 -9
  236. package/dist/core/workflow/child-env.d.ts +10 -2
  237. package/dist/core/workflow/child-env.d.ts.map +1 -1
  238. package/dist/core/workflow/child-env.js +12 -4
  239. package/dist/core/workflow/engine.d.ts +15 -5
  240. package/dist/core/workflow/engine.d.ts.map +1 -1
  241. package/dist/core/workflow/engine.js +138 -83
  242. package/dist/core/workflow/evidence-preflight.d.ts +24 -0
  243. package/dist/core/workflow/evidence-preflight.d.ts.map +1 -0
  244. package/dist/core/workflow/evidence-preflight.js +134 -0
  245. package/dist/core/workflow/index.d.ts +1 -1
  246. package/dist/core/workflow/index.d.ts.map +1 -1
  247. package/dist/core/workflow/proof.d.ts +11 -5
  248. package/dist/core/workflow/proof.d.ts.map +1 -1
  249. package/dist/core/workflow/proof.js +45 -36
  250. package/dist/core/workflow/run-state.d.ts +1 -1
  251. package/dist/core/workflow/run-state.js +7 -7
  252. package/dist/core/workflow/sandbox-projection.d.ts +6 -6
  253. package/dist/core/workflow/sandbox-projection.d.ts.map +1 -1
  254. package/dist/core/workflow/sandbox-projection.js +11 -11
  255. package/dist/core/workflow/spawn-claude.d.ts +3 -3
  256. package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
  257. package/dist/core/workflow/spawn-claude.js +9 -6
  258. package/dist/core/workflow/spawn-codex.d.ts +4 -4
  259. package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
  260. package/dist/core/workflow/spawn-codex.js +9 -6
  261. package/dist/core/workflow/spawn-cursor.d.ts +4 -4
  262. package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
  263. package/dist/core/workflow/spawn-cursor.js +9 -6
  264. package/dist/core/workflow/spawn-failure.d.ts +1 -1
  265. package/dist/core/workflow/spawn-failure.js +1 -1
  266. package/dist/core/workflow/specialists.js +2 -2
  267. package/dist/core/workflow/{journal.d.ts → transcript.d.ts} +8 -8
  268. package/dist/core/workflow/transcript.d.ts.map +1 -0
  269. package/dist/core/workflow/{journal.js → transcript.js} +14 -14
  270. package/dist/core/workflow/types.d.ts +98 -51
  271. package/dist/core/workflow/types.d.ts.map +1 -1
  272. package/dist/core/workflow/types.js +11 -1
  273. package/dist/core/workflow/validate.d.ts +1 -1
  274. package/dist/core/workflow/validate.js +1 -1
  275. package/dist/core/workflow/workspaces/cancellation.js +2 -2
  276. package/dist/core/workflow/workspaces/cleanup.js +2 -2
  277. package/dist/core/workflow/workspaces/execution.js +6 -6
  278. package/dist/core/workflow/workspaces/inspect.js +9 -9
  279. package/dist/core/workflow/workspaces/integration.js +14 -14
  280. package/dist/core/workflow/workspaces/lifecycle.d.ts +1 -1
  281. package/dist/core/workflow/workspaces/lifecycle.d.ts.map +1 -1
  282. package/dist/core/workflow/workspaces/lifecycle.js +9 -9
  283. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  284. package/dist/core/workflow/workspaces/local-git.js +39 -5
  285. package/dist/core/workflow/workspaces/recovery.js +3 -3
  286. package/dist/core/workflow/workspaces/state.d.ts +1 -1
  287. package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
  288. package/dist/core/workflow/workspaces/state.js +3 -3
  289. package/dist/core/workflow/workspaces/types.d.ts +1 -1
  290. package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
  291. package/dist/lib/browser/asserts.d.ts +28 -0
  292. package/dist/lib/browser/asserts.d.ts.map +1 -0
  293. package/dist/lib/browser/asserts.js +152 -0
  294. package/dist/lib/browser/client.d.ts +49 -0
  295. package/dist/lib/browser/client.d.ts.map +1 -1
  296. package/dist/lib/browser/client.js +155 -14
  297. package/dist/lib/browser/content-checks.d.ts +108 -0
  298. package/dist/lib/browser/content-checks.d.ts.map +1 -0
  299. package/dist/lib/browser/content-checks.js +474 -0
  300. package/dist/lib/browser/critique.d.ts +91 -0
  301. package/dist/lib/browser/critique.d.ts.map +1 -0
  302. package/dist/lib/browser/critique.js +167 -0
  303. package/dist/lib/browser/geometry.d.ts +32 -0
  304. package/dist/lib/browser/geometry.d.ts.map +1 -1
  305. package/dist/lib/browser/geometry.js +244 -1
  306. package/dist/lib/browser/index.d.ts +4 -1
  307. package/dist/lib/browser/index.d.ts.map +1 -1
  308. package/dist/lib/browser/index.js +2 -0
  309. package/dist/lib/claude-desktop.d.ts.map +1 -1
  310. package/dist/lib/claude-desktop.js +4 -1
  311. package/dist/lib/context/index.js +9 -2
  312. package/dist/lib/council/index.d.ts +6 -6
  313. package/dist/lib/council/index.d.ts.map +1 -1
  314. package/dist/lib/council/index.js +8 -8
  315. package/dist/lib/identities/assume.d.ts +2 -2
  316. package/dist/lib/identities/assume.js +7 -7
  317. package/dist/lib/instructions/apply.d.ts +3 -3
  318. package/dist/lib/instructions/apply.d.ts.map +1 -1
  319. package/dist/lib/instructions/apply.js +75 -27
  320. package/dist/lib/instructions/host-addendum.d.ts +54 -0
  321. package/dist/lib/instructions/host-addendum.d.ts.map +1 -0
  322. package/dist/lib/instructions/host-addendum.js +107 -0
  323. package/dist/lib/instructions/templates.d.ts +10 -3
  324. package/dist/lib/instructions/templates.d.ts.map +1 -1
  325. package/dist/lib/instructions/templates.js +41 -12
  326. package/dist/lib/machine.d.ts +2 -2
  327. package/dist/lib/machine.js +2 -2
  328. package/package.json +26 -21
  329. package/schemas/config.schema.json +26 -1
  330. package/src/commander.ts +22 -13
  331. package/src/commands/{harness.ts → adapter.ts} +46 -46
  332. package/src/commands/agents.ts +200 -78
  333. package/src/commands/artifacts.ts +168 -0
  334. package/src/commands/backup.ts +47 -33
  335. package/src/commands/browse.ts +438 -2
  336. package/src/commands/checkpoint.ts +196 -0
  337. package/src/commands/context.ts +3 -176
  338. package/src/commands/decision.ts +41 -7
  339. package/src/commands/deinit.ts +16 -16
  340. package/src/commands/doctor.ts +28 -28
  341. package/src/commands/{supervisor.ts → governor.ts} +184 -154
  342. package/src/commands/grep.ts +19 -2
  343. package/src/commands/init.ts +50 -34
  344. package/src/commands/{scratch.ts → journal.ts} +60 -60
  345. package/src/commands/policy.ts +1 -1
  346. package/src/commands/presence.ts +2 -2
  347. package/src/commands/sync.ts +3 -3
  348. package/src/commands/tunnel.ts +256 -38
  349. package/src/commands/web-fetch.ts +1 -1
  350. package/src/commands/web.ts +56 -1
  351. package/src/commands/work.ts +50 -35
  352. package/src/commands/workflow.ts +43 -34
  353. package/src/core/{harnesses → adapters}/attest-projection.ts +2 -2
  354. package/src/core/{harnesses → adapters}/attest.ts +27 -27
  355. package/src/core/{harnesses → adapters}/attestation.ts +41 -41
  356. package/src/core/{harnesses → adapters}/bench.ts +34 -43
  357. package/src/core/adapters/index.ts +56 -0
  358. package/src/core/{harnesses → adapters}/profiles.ts +16 -16
  359. package/src/core/{harnesses → adapters}/registry.ts +23 -23
  360. package/src/core/{harnesses → adapters}/types.ts +23 -23
  361. package/src/core/agents/canonical-emit.ts +16 -43
  362. package/src/core/agents/cli-emit.ts +1 -1
  363. package/src/core/agents/cli.ts +30 -28
  364. package/src/core/agents/codex-replay.ts +6 -6
  365. package/src/core/agents/coord-bin.ts +92 -0
  366. package/src/core/agents/coord-client.ts +302 -78
  367. package/src/core/agents/events/consume.ts +1 -1
  368. package/src/core/agents/events/emit.ts +7 -6
  369. package/src/core/agents/paths.ts +7 -11
  370. package/src/core/agents/render/prompt-context.ts +107 -31
  371. package/src/core/agents/render/session-context.ts +6 -6
  372. package/src/core/agents/rules/claim-conflict.ts +4 -7
  373. package/src/core/agents/rules/commit-conflict.ts +103 -22
  374. package/src/core/agents/rules/stop-hook.ts +33 -17
  375. package/src/core/agents/rules/verdict.ts +13 -0
  376. package/src/core/agents/session-events.ts +4 -4
  377. package/src/core/agents/state/council.ts +1 -1
  378. package/src/core/agents/state/heartbeat-projector.ts +16 -12
  379. package/src/core/agents/state/heartbeat-writer.ts +12 -12
  380. package/src/core/agents/state/{scratch.ts → journal.ts} +12 -12
  381. package/src/core/agents/state/pidmap.ts +130 -15
  382. package/src/core/agents/state/proc-start.ts +208 -0
  383. package/src/core/agents/state/shell-mutation.ts +1 -1
  384. package/src/core/agents/state/stale-sweep.ts +7 -7
  385. package/src/core/artifacts/index.ts +557 -0
  386. package/src/core/config.ts +30 -2
  387. package/src/core/context/index.ts +15 -15
  388. package/src/core/governor/adapter-spread.ts +82 -0
  389. package/src/core/governor/index.ts +91 -0
  390. package/src/core/governor/plan-api.ts +115 -0
  391. package/src/core/{supervisor → governor}/plan-read.ts +112 -97
  392. package/src/core/{supervisor → governor}/plan-types.ts +59 -56
  393. package/src/core/{supervisor → governor}/planning.ts +223 -192
  394. package/src/core/governor/read.ts +59 -0
  395. package/src/core/{supervisor → governor}/runner.ts +39 -39
  396. package/src/core/{supervisor → governor}/service-read.ts +22 -22
  397. package/src/core/{supervisor → governor}/service.ts +117 -119
  398. package/src/core/{supervisor → governor}/state.ts +325 -167
  399. package/src/core/hooks/adapter/detect.ts +30 -0
  400. package/src/core/hooks/{harness → adapter}/events.ts +16 -14
  401. package/src/core/hooks/{harness → adapter}/output.ts +31 -23
  402. package/src/core/hooks/{harness → adapter}/parse.ts +5 -5
  403. package/src/core/hooks/{harness → adapter}/wiring.ts +21 -21
  404. package/src/core/hooks/cli.ts +197 -173
  405. package/src/core/hooks/effects/image-capture.ts +6 -6
  406. package/src/core/hooks/effects/index.ts +19 -19
  407. package/src/core/hooks/events/emit.ts +3 -3
  408. package/src/core/hooks/events/rotate.ts +1 -1
  409. package/src/core/hooks/events/schema.ts +15 -7
  410. package/src/core/hooks/guard-path.ts +2 -2
  411. package/src/core/hooks/index.ts +1 -1
  412. package/src/core/hooks/resolve/anchor.ts +63 -8
  413. package/src/core/hooks/resolve/coord-root.ts +18 -40
  414. package/src/core/hooks/resolve/intent.ts +1 -1
  415. package/src/core/hooks/resolve/owner.ts +11 -5
  416. package/src/core/{scratch → journal}/index.ts +53 -53
  417. package/src/core/policy/evaluate.ts +8 -8
  418. package/src/core/policy/types.ts +3 -3
  419. package/src/core/work/state.ts +65 -23
  420. package/src/core/workflow/adapters.ts +33 -0
  421. package/src/core/workflow/approvals.ts +7 -7
  422. package/src/core/workflow/billing.ts +12 -12
  423. package/src/core/workflow/child-env.ts +13 -4
  424. package/src/core/workflow/engine.ts +155 -90
  425. package/src/core/workflow/evidence-preflight.ts +165 -0
  426. package/src/core/workflow/index.ts +3 -3
  427. package/src/core/workflow/proof.ts +60 -50
  428. package/src/core/workflow/run-state.ts +7 -7
  429. package/src/core/workflow/sandbox-projection.ts +16 -16
  430. package/src/core/workflow/spawn-claude.ts +13 -10
  431. package/src/core/workflow/spawn-codex.ts +13 -10
  432. package/src/core/workflow/spawn-cursor.ts +13 -10
  433. package/src/core/workflow/spawn-failure.ts +1 -1
  434. package/src/core/workflow/specialists.ts +2 -2
  435. package/src/core/workflow/{journal.ts → transcript.ts} +16 -16
  436. package/src/core/workflow/types.ts +108 -51
  437. package/src/core/workflow/validate.ts +1 -1
  438. package/src/core/workflow/workspaces/cancellation.ts +2 -2
  439. package/src/core/workflow/workspaces/cleanup.ts +2 -2
  440. package/src/core/workflow/workspaces/execution.ts +6 -6
  441. package/src/core/workflow/workspaces/inspect.ts +14 -11
  442. package/src/core/workflow/workspaces/integration.ts +18 -14
  443. package/src/core/workflow/workspaces/lifecycle.ts +10 -10
  444. package/src/core/workflow/workspaces/local-git.ts +47 -5
  445. package/src/core/workflow/workspaces/recovery.ts +3 -3
  446. package/src/core/workflow/workspaces/state.ts +4 -3
  447. package/src/core/workflow/workspaces/types.ts +1 -1
  448. package/src/lib/browser/asserts.ts +177 -0
  449. package/src/lib/browser/client.ts +189 -14
  450. package/src/lib/browser/content-checks.ts +571 -0
  451. package/src/lib/browser/critique.ts +231 -0
  452. package/src/lib/browser/geometry.ts +297 -1
  453. package/src/lib/browser/index.ts +34 -0
  454. package/src/lib/claude-desktop.ts +4 -1
  455. package/src/lib/context/index.ts +11 -1
  456. package/src/lib/council/index.ts +9 -9
  457. package/src/lib/identities/assume.ts +7 -7
  458. package/src/lib/instructions/apply.ts +87 -25
  459. package/src/lib/instructions/host-addendum.ts +126 -0
  460. package/src/lib/instructions/templates.ts +44 -15
  461. package/src/lib/machine.ts +2 -2
  462. package/dist/commands/harness.d.ts +0 -12
  463. package/dist/commands/harness.d.ts.map +0 -1
  464. package/dist/commands/scratch.d.ts +0 -4
  465. package/dist/commands/scratch.d.ts.map +0 -1
  466. package/dist/commands/session.d.ts.map +0 -1
  467. package/dist/commands/session.js +0 -162
  468. package/dist/commands/supervisor.d.ts +0 -4
  469. package/dist/commands/supervisor.d.ts.map +0 -1
  470. package/dist/core/harnesses/attest-projection.d.ts.map +0 -1
  471. package/dist/core/harnesses/attest.d.ts.map +0 -1
  472. package/dist/core/harnesses/attestation.d.ts.map +0 -1
  473. package/dist/core/harnesses/bench.d.ts.map +0 -1
  474. package/dist/core/harnesses/index.d.ts +0 -13
  475. package/dist/core/harnesses/index.d.ts.map +0 -1
  476. package/dist/core/harnesses/index.js +0 -6
  477. package/dist/core/harnesses/profiles.d.ts.map +0 -1
  478. package/dist/core/harnesses/registry.d.ts +0 -15
  479. package/dist/core/harnesses/registry.d.ts.map +0 -1
  480. package/dist/core/harnesses/types.d.ts.map +0 -1
  481. package/dist/core/hooks/harness/detect.d.ts +0 -9
  482. package/dist/core/hooks/harness/events.d.ts.map +0 -1
  483. package/dist/core/hooks/harness/output.d.ts.map +0 -1
  484. package/dist/core/supervisor/index.d.ts +0 -7
  485. package/dist/core/supervisor/index.d.ts.map +0 -1
  486. package/dist/core/supervisor/index.js +0 -6
  487. package/dist/core/supervisor/plan-api.d.ts +0 -23
  488. package/dist/core/supervisor/plan-api.d.ts.map +0 -1
  489. package/dist/core/supervisor/plan-api.js +0 -50
  490. package/dist/core/supervisor/plan-read.d.ts +0 -5
  491. package/dist/core/supervisor/plan-read.d.ts.map +0 -1
  492. package/dist/core/supervisor/plan-types.d.ts.map +0 -1
  493. package/dist/core/supervisor/planning.d.ts +0 -33
  494. package/dist/core/supervisor/planning.d.ts.map +0 -1
  495. package/dist/core/supervisor/read.d.ts +0 -6
  496. package/dist/core/supervisor/read.d.ts.map +0 -1
  497. package/dist/core/supervisor/read.js +0 -4
  498. package/dist/core/supervisor/runner.d.ts +0 -37
  499. package/dist/core/supervisor/runner.d.ts.map +0 -1
  500. package/dist/core/supervisor/service-read.d.ts +0 -6
  501. package/dist/core/supervisor/service-read.d.ts.map +0 -1
  502. package/dist/core/supervisor/service.d.ts +0 -114
  503. package/dist/core/supervisor/service.d.ts.map +0 -1
  504. package/dist/core/supervisor/state.d.ts +0 -95
  505. package/dist/core/supervisor/state.d.ts.map +0 -1
  506. package/dist/core/workflow/harnesses.d.ts +0 -17
  507. package/dist/core/workflow/harnesses.d.ts.map +0 -1
  508. package/dist/core/workflow/harnesses.js +0 -21
  509. package/dist/core/workflow/journal.d.ts.map +0 -1
  510. package/src/commands/session.ts +0 -187
  511. package/src/core/harnesses/index.ts +0 -56
  512. package/src/core/hooks/harness/detect.ts +0 -30
  513. package/src/core/supervisor/index.ts +0 -89
  514. package/src/core/supervisor/plan-api.ts +0 -73
  515. package/src/core/supervisor/read.ts +0 -59
  516. package/src/core/workflow/harnesses.ts +0 -33
  517. /package/dist/core/{harnesses → adapters}/attest-projection.js +0 -0
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { spawnSync } from "node:child_process";
10
10
  import { existsSync, readdirSync, readFileSync } from "node:fs";
11
- import { dirname, resolve, sep } from "node:path";
11
+ import { dirname, join, resolve, sep } from "node:path";
12
12
  // NOTE: kept dependency-free (node builtins only); this file is vendored verbatim into
13
13
  // a downstream consumer, so it cannot import the coordEnv helper.
14
14
  const MAX_INSTANCE_ID_LENGTH = 128;
@@ -53,52 +53,171 @@ export function resolveContainedFile(directory, fileName) {
53
53
  /**
54
54
  * Resolve the monorepo root for coord-state purposes.
55
55
  *
56
- * Resolves the coordination root,
57
- * including the `--git-common-dir` fallback that strips
58
- * `<superproject>/.git/modules/<name>/` to recover the superproject for
59
- * submodule worktrees. Without that fallback, a TS coord caller running
60
- * inside a `harn worktree add-submodule` checkout would resolve a different
61
- * `.harnery/` than the bash hooks and the two layers would silently diverge.
56
+ * Thin alias for `resolveCoordRoot()`; kept because it is the name the CLI
57
+ * command modules and the vendored downstream consumer already import.
62
58
  */
63
59
  export function monorepoRoot() {
64
- // Test-only override (matches bash HARNERY_COORD_ROOT_OVERRIDE). Lets tests
65
- // seed `.harnery/pid-map/<pid>` + `.harnery/active/<owner>.json` fixtures
66
- // in a tmpdir without needing a real git repo.
60
+ return resolveCoordRoot();
61
+ }
62
+ /**
63
+ * THE coordination-root resolution. Every surface — the hooks, the CLI's reads,
64
+ * and the CLI's canonical emits — resolves through this one function, because a
65
+ * root the two layers disagree about is a root that silently breaks the
66
+ * end-of-turn rules: the hook evaluates `state.status_checked` from the stream
67
+ * it reads, so an emit into a different `.harnery/events.ndjson` is invisible
68
+ * and rule 1/3 blocks a turn that did run `agents status`, with no sequence of
69
+ * CLI commands able to satisfy it.
70
+ *
71
+ * Precedence:
72
+ * 1. `HARNERY_COORD_ROOT_OVERRIDE` — explicit pin (tests, git hooks, and the
73
+ * root every coord-helper spawn pins for its child).
74
+ * 2. `CLAUDE_PROJECT_DIR` — the adapter stating which project it opened. Hook
75
+ * processes inherit the session's *shell* cwd, which follows `cd` into a
76
+ * subdirectory or submodule that may carry a `.harnery/` of its own (or
77
+ * none at all), so the adapter's own statement outranks the cwd walk.
78
+ * 3. The candidate root that already holds THIS session's heartbeat.
79
+ * 4. The nearest enclosing `.harnery/`, then a git-derived root.
80
+ *
81
+ * Step 3 is what makes CLI/hook disagreement structurally impossible rather
82
+ * than a coin flip. Choosing either root unconditionally is wrong in one
83
+ * direction each: preferring the git superproject strands a session whose
84
+ * adapter opened the submodule itself (its heartbeat lives in the submodule,
85
+ * so status/set-task wrote events the hook never read), while walking up from
86
+ * cwd alone strands the opposite case, a session opened on the superproject
87
+ * whose shell has cd'd into a submodule that carries its own `.harnery/`
88
+ * (regression-tested in tests/unit/coord-helper-root-pin.test.ts). The session's
89
+ * own heartbeat settles it: whichever root the hook registered this session in
90
+ * is the root the CLI must use, and the adapter-exported session id needed to
91
+ * recognize it is available to a plain tool-call subprocess even though
92
+ * `CLAUDE_PROJECT_DIR` is not.
93
+ */
94
+ export function resolveCoordRoot(start = process.cwd()) {
67
95
  const rootOverride = process.env.HARNERY_COORD_ROOT_OVERRIDE;
68
- if (rootOverride) {
96
+ if (rootOverride)
69
97
  return rootOverride;
98
+ const projectDir = process.env.CLAUDE_PROJECT_DIR;
99
+ if (projectDir) {
100
+ const fromProject = nearestCoordRoot(projectDir);
101
+ if (fromProject)
102
+ return fromProject;
70
103
  }
71
- // 1. Superproject working tree (when running from inside a submodule).
72
- const sup = spawnSync("git", ["rev-parse", "--show-superproject-working-tree"], {
73
- encoding: "utf8",
74
- });
75
- if (sup.status === 0 && sup.stdout.trim() !== "") {
76
- return sup.stdout.trim();
77
- }
78
- // 2. --git-common-dir fallback for submodule worktrees. `git worktree add`
79
- // inside a submodule produces a worktree whose --show-superproject-working-
80
- // tree is empty (the worktree has no submodule relationship of its own),
81
- // but --git-common-dir points at <superproject>/.git/modules/<name>/, so
82
- // we recover the superproject by stripping that suffix.
83
- const common = spawnSync("git", ["rev-parse", "--git-common-dir"], {
84
- encoding: "utf8",
85
- });
86
- if (common.status === 0) {
87
- const cd = common.stdout.trim();
88
- const idx = cd.indexOf("/.git/modules/");
89
- if (idx !== -1) {
90
- return cd.substring(0, idx);
91
- }
104
+ // Nearest-first, so the fallback at the end keeps the historical cwd-walk
105
+ // behavior for a shell that has no registered session at all.
106
+ const ancestors = ancestorCoordRoots(start);
107
+ for (const candidate of ancestors) {
108
+ if (rootKnowsSession(candidate))
109
+ return candidate;
92
110
  }
93
- // 3. Top-level fallback (regular checkout).
94
- const top = spawnSync("git", ["rev-parse", "--show-toplevel"], {
95
- encoding: "utf8",
96
- });
97
- if (top.status === 0 && top.stdout.trim() !== "") {
98
- return top.stdout.trim();
111
+ // Only reached when no enclosing root knows this session: a submodule
112
+ // worktree (`harn worktree add-submodule`) has no ancestor relationship with
113
+ // the superproject that registered the session, so ask git for it.
114
+ const gitRoots = gitCoordRoots(start).filter((r) => !ancestors.includes(r));
115
+ for (const candidate of gitRoots) {
116
+ if (rootKnowsSession(candidate))
117
+ return candidate;
99
118
  }
100
- return null;
119
+ if (ancestors.length > 0)
120
+ return ancestors[0];
121
+ if (gitRoots.length > 0)
122
+ return gitRoots[0];
123
+ // Nothing carries `.harnery/` yet. Hand back the enclosing checkout so a
124
+ // first run (`harn init`, agent-hook's session.start) has somewhere to
125
+ // create it.
126
+ return gitToplevel(start);
127
+ }
128
+ /** Nearest enclosing directory carrying `.harnery/`, or null. */
129
+ export function nearestCoordRoot(start) {
130
+ return ancestorCoordRoots(start)[0] ?? null;
131
+ }
132
+ /** Every enclosing directory carrying `.harnery/`, nearest first. */
133
+ function ancestorCoordRoots(start) {
134
+ const found = [];
135
+ let dir = resolve(start);
136
+ while (true) {
137
+ if (existsSync(join(dir, ".harnery")))
138
+ found.push(dir);
139
+ const parent = dirname(dir);
140
+ if (parent === dir)
141
+ break;
142
+ dir = parent;
143
+ }
144
+ return found;
145
+ }
146
+ /**
147
+ * Does this root's `.harnery/` already know the process asking?
148
+ *
149
+ * Two discriminators, both genuinely about *this* session: the adapter-exported
150
+ * session id matching a live heartbeat, and a pid-map row on our own ppid
151
+ * chain. Deliberately NOT the single-live-agent fallback that owner resolution
152
+ * ends with — a lone stranger in the wrong root is exactly how `whoami` came to
153
+ * report another agent's name and task as its own.
154
+ */
155
+ export function rootKnowsSession(root) {
156
+ if (resolveOwnerBySessionEnv(root))
157
+ return true;
158
+ return resolveOwnerByPidmap(root).owner !== null;
159
+ }
160
+ /**
161
+ * Git-derived candidate roots for `start`, in preference order, filtered to
162
+ * those that actually carry `.harnery/`.
163
+ *
164
+ * Spawns run with `cwd: start` rather than the process cwd so an injected
165
+ * start dir resolves its own repository — without that, a call about some
166
+ * unrelated directory inherits this process's repo and can resolve a root that
167
+ * has nothing to do with the question asked.
168
+ */
169
+ function gitCoordRoots(start) {
170
+ const roots = [];
171
+ const push = (value) => {
172
+ if (value && existsSync(join(value, ".harnery")) && !roots.includes(value))
173
+ roots.push(value);
174
+ };
175
+ // Superproject working tree (running from inside a submodule).
176
+ push(gitRevParse(start, "--show-superproject-working-tree"));
177
+ // `--git-common-dir` fallback for submodule worktrees: `git worktree add`
178
+ // inside a submodule produces a worktree whose superproject working tree is
179
+ // empty (the worktree has no submodule relationship of its own), but the
180
+ // common dir points at `<superproject>/.git/modules/<name>/`, so the
181
+ // superproject is recoverable by stripping that suffix.
182
+ const common = gitRevParse(start, "--git-common-dir");
183
+ if (common) {
184
+ const idx = common.indexOf("/.git/modules/");
185
+ if (idx !== -1)
186
+ push(common.substring(0, idx));
187
+ }
188
+ // Top-level (regular checkout).
189
+ push(gitRevParse(start, "--show-toplevel"));
190
+ return roots;
191
+ }
192
+ function gitToplevel(start) {
193
+ return gitRevParse(start, "--show-toplevel");
101
194
  }
195
+ function gitRevParse(cwd, flag) {
196
+ const key = `${cwd}${flag}`;
197
+ const cached = gitRevParseCache.get(key);
198
+ if (cached !== undefined)
199
+ return cached;
200
+ let value = null;
201
+ try {
202
+ // `cwd` must exist or the spawn itself fails; callers pass paths that may
203
+ // not (a project dir from a stale env var), so treat any failure as "no
204
+ // answer" rather than letting it throw.
205
+ const r = spawnSync("git", ["rev-parse", flag], { encoding: "utf8", cwd });
206
+ if (r.status === 0)
207
+ value = r.stdout.trim() || null;
208
+ }
209
+ catch {
210
+ value = null;
211
+ }
212
+ gitRevParseCache.set(key, value);
213
+ return value;
214
+ }
215
+ /**
216
+ * Memoized because git spawns are the expensive part of resolution and every
217
+ * CLI command resolves the root many times per invocation. Keyed by (cwd, flag);
218
+ * a repository's identity does not change under a running process.
219
+ */
220
+ const gitRevParseCache = new Map();
102
221
  /** Parse owner from a pid-map row (`owner` or `owner\tplatform`). */
103
222
  export function parsePidmapRowOwner(row) {
104
223
  const trimmed = row.trim();
@@ -107,9 +226,97 @@ export function parsePidmapRowOwner(row) {
107
226
  }
108
227
  /** Parse platform from a pid-map row; legacy rows default to `claude_code`. */
109
228
  export function parsePidmapRowPlatform(row) {
110
- const trimmed = row.trim();
111
- const tab = trimmed.indexOf("\t");
112
- return tab >= 0 ? trimmed.slice(tab + 1).trim() : "claude_code";
229
+ const platform = row.trim().split("\t")[1]?.trim();
230
+ return platform || "claude_code";
231
+ }
232
+ /** Parse the start token from a pid-map row; rows written before it carry none. */
233
+ export function parsePidmapRowStartToken(row) {
234
+ return row.trim().split("\t")[2]?.trim() || undefined;
235
+ }
236
+ /**
237
+ * Is the process now holding `pid` the one this row was written for?
238
+ *
239
+ * A pid is a number the OS re-issues, and quickly: a `pid_max` of 99999 against
240
+ * ~100 new processes a second recycles the whole space about every quarter
241
+ * hour. Believing a row past that point resolves this session to whichever
242
+ * agent last held the number — which is what made `whoami` report a stranger's
243
+ * name and files. The start token settles it, since two processes may share a
244
+ * pid but never a pid and a start instant.
245
+ *
246
+ * Deliberately inlined rather than imported from `state/proc-start.ts`: this
247
+ * file is vendored verbatim into a downstream consumer and stays on node
248
+ * builtins only. The token is a wire format shared with that module and with
249
+ * the host's commit guard, so the copies must agree byte for byte; exported so
250
+ * a test can hold this one against `processStartToken` and fail on drift.
251
+ */
252
+ export function pidStartToken(pid) {
253
+ const forced = process.env.HARNERY_PID_PROBE;
254
+ const useProcfs = forced === "procfs" || (forced !== "ps" && existsSync("/proc/self/stat"));
255
+ // One machine, one probe. Falling back to the other on a read failure would
256
+ // answer in the wrong dialect and read as a recycled pid.
257
+ if (useProcfs) {
258
+ try {
259
+ const stat = readFileSync(`/proc/${pid}/stat`, "utf8");
260
+ const afterComm = stat.slice(stat.lastIndexOf(") ") + 2);
261
+ // Fields after comm, 0-based: 0 is state (field 3), starttime (22) is 19.
262
+ const ticks = afterComm.split(" ")[19];
263
+ if (!ticks || !/^\d+$/.test(ticks))
264
+ return null;
265
+ // Ticks count from boot, so they repeat across reboots; the boot id scopes
266
+ // them. Rows written before it carry ticks alone and still compare.
267
+ let boot = "";
268
+ try {
269
+ const raw = readFileSync("/proc/sys/kernel/random/boot_id", "utf8")
270
+ .trim()
271
+ .replace(/-/g, "");
272
+ if (/^[0-9a-f]{8,}$/.test(raw))
273
+ boot = `${raw.slice(0, 8)}.`;
274
+ }
275
+ catch {
276
+ /* unnamed boot: fall back to the tick-only shape */
277
+ }
278
+ return `l${boot}${ticks}`;
279
+ }
280
+ catch {
281
+ return null;
282
+ }
283
+ }
284
+ try {
285
+ // TZ and locale are pinned because `ps` renders the date through them, and
286
+ // two callers with different environments must not disagree about one
287
+ // process.
288
+ const out = spawnSync("ps", ["-o", "lstart=", "-p", String(pid)], {
289
+ encoding: "utf8",
290
+ timeout: 2000,
291
+ env: { ...process.env, TZ: "UTC", LC_ALL: "C" },
292
+ });
293
+ if (out.status !== 0)
294
+ return null;
295
+ const lstart = (out.stdout ?? "").split("\n")[0]?.trim().replace(/\s+/g, " ");
296
+ return lstart ? `p${lstart}` : null;
297
+ }
298
+ catch {
299
+ return null;
300
+ }
301
+ }
302
+ function pidWasRecycled(pid, row) {
303
+ const recorded = parsePidmapRowStartToken(row);
304
+ if (!recorded)
305
+ return false; // pre-token row: unverifiable, behave as before
306
+ const current = pidStartToken(pid);
307
+ if (!current)
308
+ return false;
309
+ if (current === recorded)
310
+ return false;
311
+ // A row predating the boot segment recorded ticks alone; compare it on what
312
+ // it recorded rather than pruning every live row on the first upgraded run.
313
+ if (recorded[0] === "l" &&
314
+ current[0] === "l" &&
315
+ recorded.includes(".") !== current.includes(".")) {
316
+ const ticks = (t) => (t.includes(".") ? t.slice(t.indexOf(".") + 1) : t.slice(1));
317
+ return ticks(recorded) !== ticks(current);
318
+ }
319
+ return true;
113
320
  }
114
321
  function readPidmapRow(pidmapDir, pid) {
115
322
  const candidate = resolve(pidmapDir, String(pid));
@@ -153,15 +360,43 @@ export function resolveOwnerWithSource() {
153
360
  const root = monorepoRoot();
154
361
  if (!root)
155
362
  return { owner: null, source: "none" };
156
- // Cursor's Glass/Agents UI can run several chats under one long-lived node
157
- // process, so the pid-map row for that shared ancestor is last-writer-wins.
158
- // Prefer the per-chat session id when Cursor exposes one in the tool env.
363
+ // Every supported adapter exports its session id into the env of the
364
+ // subprocess it spawns for a tool call, and each heartbeat records the
365
+ // session id it was minted under. Matching the two names us outright, even
366
+ // with many live agents, so it goes ahead of the ppid walk rather than
367
+ // catching what the walk drops. Cursor needed this first because its
368
+ // Glass/Agents UI runs several chats under one node ancestor, making that row
369
+ // last-writer-wins; pid recycling generalises the same hazard to every
370
+ // adapter.
159
371
  if (shouldPreferSessionEnv()) {
160
372
  const bySession = resolveOwnerBySessionEnv(root);
161
373
  if (bySession) {
162
374
  return { owner: bySession, source: "session_env" };
163
375
  }
164
376
  }
377
+ if (!existsSync(resolve(root, ".harnery", "pid-map")))
378
+ return { owner: null, source: "none" };
379
+ const byPidmap = resolveOwnerByPidmap(root);
380
+ if (byPidmap.owner)
381
+ return byPidmap;
382
+ // Last resort: if exactly one agent is live in this coord root, it's
383
+ // unambiguously us — resolve to it. This is what lets the bare `agents
384
+ // status` / `set-task` the stop hook recommends work without a `--session-id`
385
+ // flag in the common single-agent case. With 0 or 2+ live agents it would be
386
+ // a guess, so we stay null and require the explicit flag.
387
+ const singleton = resolveSingleActiveOwner(root);
388
+ if (singleton) {
389
+ return { owner: singleton, source: "active_singleton" };
390
+ }
391
+ return { owner: null, source: "none" };
392
+ }
393
+ /**
394
+ * Walk our own ppid chain for a pid-map row in ONE given root.
395
+ *
396
+ * Root-parameterized (rather than resolving the root itself) so root resolution
397
+ * can use it as a discriminator without recursing back into itself.
398
+ */
399
+ export function resolveOwnerByPidmap(root) {
165
400
  const pidmapDir = resolve(root, ".harnery", "pid-map");
166
401
  if (!existsSync(pidmapDir))
167
402
  return { owner: null, source: "none" };
@@ -172,7 +407,7 @@ export function resolveOwnerWithSource() {
172
407
  if (pid === null)
173
408
  break;
174
409
  const row = readPidmapRow(pidmapDir, pid);
175
- if (row) {
410
+ if (row && !pidWasRecycled(pid, row)) {
176
411
  const rowOwner = parsePidmapRowOwner(row);
177
412
  const rowPlat = parsePidmapRowPlatform(row);
178
413
  if (rowPlat === prefer) {
@@ -186,31 +421,11 @@ export function resolveOwnerWithSource() {
186
421
  if (fallbackOwner) {
187
422
  return { owner: fallbackOwner, source: "pidmap_fallback" };
188
423
  }
189
- // The ppid walk found nothing (e.g. a Bash-tool subshell whose process tree
190
- // doesn't climb back to the harness anchor). Before guessing, try the
191
- // harness-provided session id from the environment: every supported harness
192
- // exports its session id into the tool subprocess env, and each heartbeat
193
- // records the `session_id` it was minted under. Matching the two resolves us
194
- // unambiguously even with multiple live agents, which is the case the
195
- // singleton fallback below cannot handle.
196
- const bySession = resolveOwnerBySessionEnv(root);
197
- if (bySession) {
198
- return { owner: bySession, source: "session_env" };
199
- }
200
- // Last resort: if exactly one agent is live in this coord root, it's
201
- // unambiguously us — resolve to it. This is what lets the bare `agents
202
- // status` / `set-task` the stop hook recommends work without a `--session-id`
203
- // flag in the common single-agent case. With 0 or 2+ live agents it would be
204
- // a guess, so we stay null and require the explicit flag.
205
- const singleton = resolveSingleActiveOwner(root);
206
- if (singleton) {
207
- return { owner: singleton, source: "active_singleton" };
208
- }
209
424
  return { owner: null, source: "none" };
210
425
  }
211
426
  /**
212
- * Harness-exported session-id environment variables, in precedence order. Each
213
- * supported harness propagates its session id into the env of the subprocess it
427
+ * Adapter-exported session-id environment variables, in precedence order. Each
428
+ * supported adapter propagates its session id into the env of the subprocess it
214
429
  * spawns for a tool call (Claude Code's Bash tool, Cursor's terminal, Codex's
215
430
  * shell). A coord CLI invoked as such a tool can therefore recover its own
216
431
  * identity from the env even when the ppid walk misses.
@@ -225,7 +440,7 @@ const SESSION_ID_ENV_VARS = [
225
440
  "CURSOR_CONVERSATION_ID",
226
441
  "CODEX_SESSION_ID",
227
442
  ];
228
- /** Read normalized candidates from the first non-empty harness session-id env var. */
443
+ /** Read normalized candidates from the first non-empty adapter session-id env var. */
229
444
  function sessionIdsFromEnv() {
230
445
  for (const key of SESSION_ID_ENV_VARS) {
231
446
  const v = process.env[key]?.trim();
@@ -238,18 +453,31 @@ function sessionIdsFromEnv() {
238
453
  }
239
454
  return [];
240
455
  }
241
- /** Read the first non-empty harness session-id env var, or null. */
456
+ /** Read the first non-empty adapter session-id env var, or null. */
242
457
  function sessionIdFromEnv() {
243
458
  return sessionIdsFromEnv()[0] ?? null;
244
459
  }
460
+ /**
461
+ * Should the adapter-exported session id be consulted before the ppid walk?
462
+ *
463
+ * Yes, whenever one is exported. The env var is the adapter stating its own
464
+ * identity; the walk is a guess over a namespace the OS recycles. On a box with
465
+ * `pid_max` of 99999 and ~100 pids allocated per second the whole pid space
466
+ * turns over about every quarter hour, so a row written before that can name a
467
+ * pid some unrelated process now holds. Pruning cannot save the walk here:
468
+ * it removes rows whose pid is dead, and a recycled pid is alive. Letting a
469
+ * guess outrank a statement of fact is what made `agents whoami` report another
470
+ * agent's name and file list.
471
+ *
472
+ * This only reorders the two. Session-env resolution still requires a live
473
+ * heartbeat carrying that session id, so when it does not match, the walk runs
474
+ * exactly as before.
475
+ */
245
476
  function shouldPreferSessionEnv() {
246
- if (!sessionIdFromEnv())
247
- return false;
248
- const platform = process.env.HARNERY_AGENT_COORD_PLATFORM?.trim();
249
- return process.env.CURSOR_AGENT === "1" || platform === "cursor";
477
+ return sessionIdFromEnv() !== null;
250
478
  }
251
479
  /**
252
- * Resolve the owner by matching the harness session-id env var against the
480
+ * Resolve the owner by matching the adapter session-id env var against the
253
481
  * `session_id` of a live heartbeat in this coord root. Returns the matching
254
482
  * `instance_id`, or null if there's no session-id env var or no live heartbeat
255
483
  * carries it. "Live" reuses the same 10-minute freshness window the singleton
@@ -33,7 +33,7 @@ export interface CanonicalEvent {
33
33
  parent_session_id?: string;
34
34
  turn_id?: string;
35
35
  parent_turn_id?: string;
36
- harness: string;
36
+ adapter: string;
37
37
  source: string;
38
38
  data: Record<string, unknown>;
39
39
  }
@@ -5,12 +5,12 @@
5
5
  * event/schema types).
6
6
  *
7
7
  * Phase 4: agent-coord uses this from CLI handlers (state.task_set,
8
- * state.status_checked, state.scratch_append, council.*, decision.*,
8
+ * state.status_checked, state.journal_append, council.*, decision.*,
9
9
  * presence.*).
10
10
  */
11
11
  declare const SCHEMA_VERSION: 1;
12
- export type Harness = "claude-code" | "cursor" | "codex";
13
- export type Source = "agent-hooks" | "agent-coord" | "user" | "system";
12
+ export type { Adapter, Source } from "../../hooks/events/schema.js";
13
+ import type { Adapter, Source } from "../../hooks/events/schema.js";
14
14
  export interface Envelope {
15
15
  schema_version: typeof SCHEMA_VERSION;
16
16
  event_id: string;
@@ -21,7 +21,7 @@ export interface Envelope {
21
21
  parent_session_id?: string;
22
22
  turn_id?: string;
23
23
  parent_turn_id?: string;
24
- harness: Harness;
24
+ adapter: Adapter;
25
25
  source: Source;
26
26
  data: Record<string, unknown>;
27
27
  }
@@ -29,7 +29,7 @@ export interface EmitInput {
29
29
  event_type: string;
30
30
  instance_id: string;
31
31
  session_id: string;
32
- harness: Harness;
32
+ adapter: Adapter;
33
33
  source?: Source;
34
34
  parent_session_id?: string;
35
35
  turn_id?: string;
@@ -39,5 +39,4 @@ export interface EmitInput {
39
39
  }
40
40
  export declare function buildEnvelope(input: EmitInput): Envelope;
41
41
  export declare function emit(coordRoot: string, input: EmitInput): Envelope;
42
- export {};
43
42
  //# sourceMappingURL=emit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/events/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,QAAA,MAAM,cAAc,EAAG,CAAU,CAAC;AAKlC,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;AACzD,MAAM,MAAM,MAAM,GAAG,aAAa,GAAG,aAAa,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvE,MAAM,WAAW,QAAQ;IACvB,cAAc,EAAE,OAAO,cAAc,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAexD;AAED,wBAAgB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,QAAQ,CA4BlE"}
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/events/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,QAAA,MAAM,cAAc,EAAG,CAAU,CAAC;AAKlC,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAEpE,MAAM,WAAW,QAAQ;IACvB,cAAc,EAAE,OAAO,cAAc,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAexD;AAED,wBAAgB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,QAAQ,CA4BlE"}
@@ -5,7 +5,7 @@
5
5
  * event/schema types).
6
6
  *
7
7
  * Phase 4: agent-coord uses this from CLI handlers (state.task_set,
8
- * state.status_checked, state.scratch_append, council.*, decision.*,
8
+ * state.status_checked, state.journal_append, council.*, decision.*,
9
9
  * presence.*).
10
10
  */
11
11
  import { appendFileSync, closeSync, mkdirSync, openSync } from "node:fs";
@@ -27,7 +27,7 @@ export function buildEnvelope(input) {
27
27
  parent_session_id: input.parent_session_id,
28
28
  turn_id: input.turn_id,
29
29
  parent_turn_id: input.parent_turn_id,
30
- harness: input.harness,
30
+ adapter: input.adapter,
31
31
  source: input.source ?? "agent-coord",
32
32
  data: input.data,
33
33
  };
@@ -1,6 +1,9 @@
1
1
  /**
2
- * Walk up from `start` looking for a directory containing `.harnery/`, so
3
- * adapter + legacy code agree on the same monorepo root.
2
+ * Resolve the coordination root.
3
+ *
4
+ * Delegates to `resolveCoordRoot()`. This was a third, independent copy of the
5
+ * walk-up — the kind of duplication that let the hooks and the CLI drift onto
6
+ * different roots in the first place; keep resolution in one place.
4
7
  */
5
8
  export declare function findCoordRoot(start?: string): string | null;
6
9
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/core/agents/paths.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAQ1E"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/core/agents/paths.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAE1E"}
@@ -1,17 +1,11 @@
1
- import { existsSync } from "node:fs";
2
- import { dirname, join, resolve } from "node:path";
1
+ import { resolveCoordRoot } from "./coord-client.js";
3
2
  /**
4
- * Walk up from `start` looking for a directory containing `.harnery/`, so
5
- * adapter + legacy code agree on the same monorepo root.
3
+ * Resolve the coordination root.
4
+ *
5
+ * Delegates to `resolveCoordRoot()`. This was a third, independent copy of the
6
+ * walk-up — the kind of duplication that let the hooks and the CLI drift onto
7
+ * different roots in the first place; keep resolution in one place.
6
8
  */
7
9
  export function findCoordRoot(start = process.cwd()) {
8
- let dir = resolve(start);
9
- while (true) {
10
- if (existsSync(join(dir, ".harnery")))
11
- return dir;
12
- const parent = dirname(dir);
13
- if (parent === dir)
14
- return null;
15
- dir = parent;
16
- }
10
+ return resolveCoordRoot(start);
17
11
  }
@@ -1,19 +1,25 @@
1
1
  /**
2
2
  * UserPromptSubmit UX renderer. Combines the peer-refresh dedup, the
3
- * council-pending hash-dedup, and the Cursor set-task staleness nudge.
3
+ * council-pending hash-dedup, the cross-adapter first-session naming nudge,
4
+ * the Cursor/Codex set-task staleness nudge, and the Codex status-footer
5
+ * reminder.
4
6
  * agent-hook's user_prompt.submit post-emit handler calls this
5
- * and forwards the result as the harness-shaped additionalContext payload.
7
+ * and forwards the result as the adapter-shaped additionalContext payload.
6
8
  *
7
- * Three hash-dedup'd subsections combined into one additionalContext payload:
9
+ * Four subsections combined into one additionalContext payload:
8
10
  * 1. Peer table: semantically-relevant peer fields hashed; only re-emits
9
11
  * when peers change (name + instance_id + session_id + kind + started_at
10
12
  * + sorted(files_touched) + platform, sorted by instance_id).
11
13
  * 2. Council pending: pending open-council IDs hashed; re-emits when the
12
14
  * ID set changes.
13
- * 3. Task staleness nudge (cursor only, since CC enforces via the Stop hook
14
- * transcript scan). Fires when `task` is null or `task_updated_at` is
15
- * older than HARNERY_TASK_STALE_SECONDS (default 1800 = 30 min). Hash-deduped
16
- * against the previous nudge state.
15
+ * 3. Focus nudge. Before the first set-task in a human-facing session, tells
16
+ * every adapter to reproduce set-task's suggested session name in a fenced
17
+ * code block. Cursor/Codex additionally get the existing unset/stale-task
18
+ * reminder because their Stop hooks do not enforce task declarations as
19
+ * reliably as Claude Code's.
20
+ * 4. Codex status footer: a non-deduplicated reminder to put the live status
21
+ * box after the substantive answer. Stop stays observe-only, so missing the
22
+ * footer can never trigger a replacement response.
17
23
  *
18
24
  * Hash files live at:
19
25
  * .harnery/.last-peer-hash.<instance_id>
@@ -27,9 +33,15 @@ export interface PromptContextOpts {
27
33
  instanceId: string;
28
34
  sessionId: string;
29
35
  agentName?: string;
30
- /** When true, run the task-staleness nudge check (cursor only; CC has the
31
- * Stop-hook transcript-scan enforcement). */
36
+ /** When true, remind a human-facing session to print the session name before
37
+ * its first set-task. UserPromptSubmit enables this for every adapter. */
38
+ sessionNameNudge?: boolean;
39
+ /** When true, run the unset/stale-task check after the first set-task.
40
+ * Cursor/Codex use this; Claude Code has Stop-hook transcript enforcement. */
32
41
  taskNudge?: boolean;
42
+ /** When true, append the non-deduplicated Codex status-footer reminder.
43
+ * The caller enables this only for human-facing Codex sessions. */
44
+ statusFooterNudge?: boolean;
33
45
  }
34
46
  /**
35
47
  * Build the combined UserPromptSubmit additionalContext string. Returns "" when
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/prompt-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAiCH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;iDAC6C;IAC7C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAqBnE"}
1
+ {"version":3,"file":"prompt-context.d.ts","sourceRoot":"","sources":["../../../../src/core/agents/render/prompt-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAoCH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;8EAC0E;IAC1E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;kFAC8E;IAC9E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;uEACmE;IACnE,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CA0CnE"}