harnery 0.40.0 → 0.41.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 (441) hide show
  1. package/README.md +1 -1
  2. package/dist/commander.js +1 -0
  3. package/dist/commands/agents.d.ts.map +1 -1
  4. package/dist/commands/agents.js +25 -19
  5. package/dist/commands/browse-ai.d.ts.map +1 -1
  6. package/dist/commands/browse-ai.js +4 -0
  7. package/dist/commands/browse.d.ts.map +1 -1
  8. package/dist/commands/browse.js +141 -10
  9. package/dist/commands/checkpoint.js +8 -12
  10. package/dist/commands/deinit.d.ts +1 -1
  11. package/dist/commands/deinit.d.ts.map +1 -1
  12. package/dist/commands/deinit.js +8 -4
  13. package/dist/commands/docs.d.ts.map +1 -1
  14. package/dist/commands/docs.js +2 -0
  15. package/dist/commands/doctor.js +10 -2
  16. package/dist/commands/fetch.d.ts.map +1 -1
  17. package/dist/commands/fetch.js +10 -0
  18. package/dist/commands/init.d.ts +19 -3
  19. package/dist/commands/init.d.ts.map +1 -1
  20. package/dist/commands/init.js +232 -104
  21. package/dist/commands/instructions.js +5 -4
  22. package/dist/commands/ledger-v3.d.ts.map +1 -1
  23. package/dist/commands/ledger-v3.js +2 -1
  24. package/dist/commands/webview.d.ts +4 -0
  25. package/dist/commands/webview.d.ts.map +1 -0
  26. package/dist/commands/webview.js +94 -0
  27. package/dist/core/adapter.d.ts +50 -1
  28. package/dist/core/adapter.d.ts.map +1 -1
  29. package/dist/core/adapter.js +59 -1
  30. package/dist/core/adapters/attestation.d.ts.map +1 -1
  31. package/dist/core/adapters/attestation.js +3 -2
  32. package/dist/core/adapters/profiles.d.ts +20 -3
  33. package/dist/core/adapters/profiles.d.ts.map +1 -1
  34. package/dist/core/adapters/profiles.js +32 -1
  35. package/dist/core/adapters/registry.d.ts.map +1 -1
  36. package/dist/core/adapters/registry.js +33 -0
  37. package/dist/core/agents/canonical-emit.d.ts +1 -1
  38. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  39. package/dist/core/agents/canonical-emit.js +2 -7
  40. package/dist/core/agents/cli.js +18 -16
  41. package/dist/core/agents/coord-client.d.ts.map +1 -1
  42. package/dist/core/agents/coord-client.js +7 -2
  43. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
  44. package/dist/core/agents/rules/claim-conflict.js +3 -9
  45. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  46. package/dist/core/agents/rules/commit-conflict.js +2 -8
  47. package/dist/core/agents/rules/stop-hook.d.ts +2 -0
  48. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  49. package/dist/core/agents/rules/stop-hook.js +1 -1
  50. package/dist/core/agents/session-events.d.ts +6 -2
  51. package/dist/core/agents/session-events.d.ts.map +1 -1
  52. package/dist/core/agents/session-events.js +105 -26
  53. package/dist/core/agents/session-finalization-state-v3.d.ts.map +1 -1
  54. package/dist/core/agents/session-finalization-state-v3.js +2 -1
  55. package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -1
  56. package/dist/core/agents/session-finalizer-v3.js +5 -4
  57. package/dist/core/agents/session-name-display.d.ts +28 -0
  58. package/dist/core/agents/session-name-display.d.ts.map +1 -1
  59. package/dist/core/agents/session-name-display.js +43 -0
  60. package/dist/core/agents/state/heartbeat-reader.d.ts +7 -0
  61. package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
  62. package/dist/core/agents/state/heartbeat-writer.d.ts +10 -0
  63. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  64. package/dist/core/agents/state/heartbeat-writer.js +21 -2
  65. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  66. package/dist/core/agents/state/live-coordination-view.js +1 -0
  67. package/dist/core/agents/state/live-coordination-writer.js +3 -0
  68. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  69. package/dist/core/agents/state/stale-sweep.js +2 -10
  70. package/dist/core/agents/turn-changes.d.ts +17 -0
  71. package/dist/core/agents/turn-changes.d.ts.map +1 -0
  72. package/dist/core/agents/turn-changes.js +76 -0
  73. package/dist/core/artifacts/delivery-card.d.ts.map +1 -1
  74. package/dist/core/artifacts/delivery-card.js +2 -1
  75. package/dist/core/artifacts/index.d.ts.map +1 -1
  76. package/dist/core/artifacts/index.js +4 -3
  77. package/dist/core/config.d.ts +5 -0
  78. package/dist/core/config.d.ts.map +1 -1
  79. package/dist/core/config.js +14 -0
  80. package/dist/core/context/index.d.ts.map +1 -1
  81. package/dist/core/context/index.js +2 -1
  82. package/dist/core/conversations/archive.d.ts.map +1 -1
  83. package/dist/core/conversations/archive.js +4 -3
  84. package/dist/core/diagnostics/bundle.d.ts.map +1 -1
  85. package/dist/core/diagnostics/bundle.js +3 -2
  86. package/dist/core/events/legacy-storage/canary.d.ts.map +1 -1
  87. package/dist/core/events/legacy-storage/canary.js +5 -4
  88. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -1
  89. package/dist/core/events/legacy-storage/compression.js +2 -1
  90. package/dist/core/events/v3/adapter-id.d.ts +10 -2
  91. package/dist/core/events/v3/adapter-id.d.ts.map +1 -1
  92. package/dist/core/events/v3/adapter-id.js +16 -0
  93. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
  94. package/dist/core/events/v3/authority-outbox.js +2 -1
  95. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  96. package/dist/core/events/v3/bootstrap.js +5 -4
  97. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  98. package/dist/core/events/v3/capabilities.js +17 -0
  99. package/dist/core/events/v3/contract.d.ts +5 -0
  100. package/dist/core/events/v3/contract.d.ts.map +1 -1
  101. package/dist/core/events/v3/contract.js +7 -1
  102. package/dist/core/events/v3/control-witness.d.ts.map +1 -1
  103. package/dist/core/events/v3/control-witness.js +3 -2
  104. package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -1
  105. package/dist/core/events/v3/coordination-transaction-recovery.js +4 -3
  106. package/dist/core/events/v3/fingerprint-keys.d.ts.map +1 -1
  107. package/dist/core/events/v3/fingerprint-keys.js +7 -6
  108. package/dist/core/events/v3/generated.d.ts +1 -1
  109. package/dist/core/events/v3/generated.js +1 -1
  110. package/dist/core/events/v3/live-feed.d.ts.map +1 -1
  111. package/dist/core/events/v3/live-feed.js +5 -4
  112. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  113. package/dist/core/events/v3/producers/command-recorder.js +8 -7
  114. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  115. package/dist/core/events/v3/producers/coordination-recorder.js +8 -7
  116. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -1
  117. package/dist/core/events/v3/producers/diagnostic-summaries.js +5 -4
  118. package/dist/core/events/v3/producers/hook-base.d.ts +1 -0
  119. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  120. package/dist/core/events/v3/producers/hook-base.js +10 -4
  121. package/dist/core/events/v3/producers/hook.d.ts +2 -0
  122. package/dist/core/events/v3/producers/hook.d.ts.map +1 -1
  123. package/dist/core/events/v3/producers/hook.js +16 -1
  124. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  125. package/dist/core/events/v3/producers/intake.js +16 -6
  126. package/dist/core/events/v3/producers/recorder.d.ts +2 -4
  127. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  128. package/dist/core/events/v3/producers/recorder.js +109 -101
  129. package/dist/core/events/v3/recovery.d.ts.map +1 -1
  130. package/dist/core/events/v3/recovery.js +4 -3
  131. package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -1
  132. package/dist/core/events/v3/support-storage/inventory.js +2 -1
  133. package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -1
  134. package/dist/core/events/v3/support-storage/maintenance.js +4 -3
  135. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -1
  136. package/dist/core/events/v3/support-storage/pack-reader.js +4 -3
  137. package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -1
  138. package/dist/core/events/v3/support-storage/pack-writer.js +6 -5
  139. package/dist/core/events/v3/tool-line-changes.d.ts +8 -0
  140. package/dist/core/events/v3/tool-line-changes.d.ts.map +1 -0
  141. package/dist/core/events/v3/tool-line-changes.js +135 -0
  142. package/dist/core/events/v3/writer.d.ts.map +1 -1
  143. package/dist/core/events/v3/writer.js +8 -7
  144. package/dist/core/governor/planning.d.ts.map +1 -1
  145. package/dist/core/governor/planning.js +6 -5
  146. package/dist/core/governor/service.d.ts.map +1 -1
  147. package/dist/core/governor/service.js +12 -11
  148. package/dist/core/governor/state.d.ts.map +1 -1
  149. package/dist/core/governor/state.js +7 -6
  150. package/dist/core/guard/evaluator.js +1 -0
  151. package/dist/core/guard/storage.d.ts.map +1 -1
  152. package/dist/core/guard/storage.js +3 -2
  153. package/dist/core/hooks/adapter/behaviors/claude-code.d.ts +4 -0
  154. package/dist/core/hooks/adapter/behaviors/claude-code.d.ts.map +1 -0
  155. package/dist/core/hooks/adapter/behaviors/claude-code.js +31 -0
  156. package/dist/core/hooks/adapter/behaviors/codex.d.ts +15 -0
  157. package/dist/core/hooks/adapter/behaviors/codex.d.ts.map +1 -0
  158. package/dist/core/hooks/adapter/behaviors/codex.js +82 -0
  159. package/dist/core/hooks/adapter/behaviors/cursor.d.ts +7 -0
  160. package/dist/core/hooks/adapter/behaviors/cursor.d.ts.map +1 -0
  161. package/dist/core/hooks/adapter/behaviors/cursor.js +35 -0
  162. package/dist/core/hooks/adapter/behaviors/index.d.ts +11 -0
  163. package/dist/core/hooks/adapter/behaviors/index.d.ts.map +1 -0
  164. package/dist/core/hooks/adapter/behaviors/index.js +20 -0
  165. package/dist/core/hooks/adapter/behaviors/openclaw.d.ts +7 -0
  166. package/dist/core/hooks/adapter/behaviors/openclaw.d.ts.map +1 -0
  167. package/dist/core/hooks/adapter/behaviors/openclaw.js +34 -0
  168. package/dist/core/hooks/adapter/behaviors/opencode.d.ts +7 -0
  169. package/dist/core/hooks/adapter/behaviors/opencode.d.ts.map +1 -0
  170. package/dist/core/hooks/adapter/behaviors/opencode.js +34 -0
  171. package/dist/core/hooks/adapter/behaviors/types.d.ts +89 -0
  172. package/dist/core/hooks/adapter/behaviors/types.d.ts.map +1 -0
  173. package/dist/core/hooks/adapter/behaviors/types.js +1 -0
  174. package/dist/core/hooks/adapter/detect.d.ts +1 -1
  175. package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
  176. package/dist/core/hooks/adapter/detect.js +2 -3
  177. package/dist/core/hooks/adapter/events.d.ts +29 -1
  178. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  179. package/dist/core/hooks/adapter/events.js +31 -0
  180. package/dist/core/hooks/adapter/opencode-plugin.d.ts +60 -0
  181. package/dist/core/hooks/adapter/opencode-plugin.d.ts.map +1 -0
  182. package/dist/core/hooks/adapter/opencode-plugin.js +129 -0
  183. package/dist/core/hooks/adapter/output.d.ts +7 -0
  184. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  185. package/dist/core/hooks/adapter/output.js +8 -1
  186. package/dist/core/hooks/adapter/wiring.d.ts +15 -1
  187. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  188. package/dist/core/hooks/adapter/wiring.js +74 -11
  189. package/dist/core/hooks/cli.js +635 -529
  190. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  191. package/dist/core/hooks/effects/image-capture.js +2 -1
  192. package/dist/core/hooks/prompt-context/contract.d.ts.map +1 -1
  193. package/dist/core/hooks/prompt-context/contract.js +1 -0
  194. package/dist/core/hooks/resolve/transcript.d.ts +1 -1
  195. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  196. package/dist/core/hooks/resolve/transcript.js +35 -4
  197. package/dist/core/hooks/session-name-presence.d.ts +3 -1
  198. package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
  199. package/dist/core/hooks/session-name-presence.js +7 -2
  200. package/dist/core/hooks/shell-waiter.d.ts +2 -0
  201. package/dist/core/hooks/shell-waiter.d.ts.map +1 -0
  202. package/dist/core/hooks/shell-waiter.js +173 -0
  203. package/dist/core/resources/service.d.ts.map +1 -1
  204. package/dist/core/resources/service.js +5 -4
  205. package/dist/core/semantic/review.d.ts.map +1 -1
  206. package/dist/core/semantic/review.js +5 -4
  207. package/dist/core/semantic/service.d.ts.map +1 -1
  208. package/dist/core/semantic/service.js +15 -14
  209. package/dist/core/semantic/storage.d.ts.map +1 -1
  210. package/dist/core/semantic/storage.js +5 -4
  211. package/dist/core/storage/atomic-json.d.ts.map +1 -1
  212. package/dist/core/storage/atomic-json.js +7 -3
  213. package/dist/core/storage/durable-history.d.ts.map +1 -1
  214. package/dist/core/storage/durable-history.js +6 -5
  215. package/dist/core/storage/maintenance-providers.d.ts.map +1 -1
  216. package/dist/core/storage/maintenance-providers.js +2 -1
  217. package/dist/core/storage/maintenance.d.ts.map +1 -1
  218. package/dist/core/storage/maintenance.js +7 -6
  219. package/dist/core/storage/metrics.d.ts.map +1 -1
  220. package/dist/core/storage/metrics.js +5 -1
  221. package/dist/core/storage/modes.d.ts +17 -0
  222. package/dist/core/storage/modes.d.ts.map +1 -0
  223. package/dist/core/storage/modes.js +47 -0
  224. package/dist/core/storage/process-log.d.ts.map +1 -1
  225. package/dist/core/storage/process-log.js +3 -2
  226. package/dist/core/storage/receipts.d.ts.map +1 -1
  227. package/dist/core/storage/receipts.js +4 -3
  228. package/dist/core/storage/segments.d.ts.map +1 -1
  229. package/dist/core/storage/segments.js +7 -6
  230. package/dist/core/supervisor/hook-health.d.ts +2 -1
  231. package/dist/core/supervisor/hook-health.d.ts.map +1 -1
  232. package/dist/core/supervisor/hook-health.js +4 -3
  233. package/dist/core/supervisor/service.d.ts.map +1 -1
  234. package/dist/core/supervisor/service.js +7 -6
  235. package/dist/core/work/state.d.ts.map +1 -1
  236. package/dist/core/work/state.js +8 -7
  237. package/dist/core/workflow/adapters.d.ts +7 -0
  238. package/dist/core/workflow/adapters.d.ts.map +1 -1
  239. package/dist/core/workflow/adapters.js +9 -0
  240. package/dist/core/workflow/approvals.d.ts.map +1 -1
  241. package/dist/core/workflow/approvals.js +6 -5
  242. package/dist/core/workflow/billing.d.ts.map +1 -1
  243. package/dist/core/workflow/billing.js +33 -4
  244. package/dist/core/workflow/durable-record.d.ts.map +1 -1
  245. package/dist/core/workflow/durable-record.js +4 -3
  246. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  247. package/dist/core/workflow/live-session-v3.js +2 -3
  248. package/dist/core/workflow/run-state.d.ts.map +1 -1
  249. package/dist/core/workflow/run-state.js +3 -2
  250. package/dist/core/workflow/spawn-opencode.d.ts +36 -0
  251. package/dist/core/workflow/spawn-opencode.d.ts.map +1 -0
  252. package/dist/core/workflow/spawn-opencode.js +132 -0
  253. package/dist/core/workflow/transcript.d.ts.map +1 -1
  254. package/dist/core/workflow/transcript.js +3 -2
  255. package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
  256. package/dist/core/workflow/workspaces/leases.js +5 -4
  257. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  258. package/dist/core/workflow/workspaces/local-git.js +3 -2
  259. package/dist/core/workflow/workspaces/paths.d.ts.map +1 -1
  260. package/dist/core/workflow/workspaces/paths.js +2 -1
  261. package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
  262. package/dist/core/workflow/workspaces/state.js +10 -9
  263. package/dist/lazy-commands.js +8 -1
  264. package/dist/lib/agent-browser/client.d.ts +9 -0
  265. package/dist/lib/agent-browser/client.d.ts.map +1 -1
  266. package/dist/lib/agent-browser/client.js +13 -0
  267. package/dist/lib/browser/client.d.ts +35 -1
  268. package/dist/lib/browser/client.d.ts.map +1 -1
  269. package/dist/lib/browser/client.js +117 -8
  270. package/dist/lib/browser/identity.d.ts +25 -0
  271. package/dist/lib/browser/identity.d.ts.map +1 -0
  272. package/dist/lib/browser/identity.js +66 -0
  273. package/dist/lib/browser/index.d.ts +2 -1
  274. package/dist/lib/browser/index.d.ts.map +1 -1
  275. package/dist/lib/browser/index.js +2 -1
  276. package/dist/lib/browser/launch-args.d.ts +26 -0
  277. package/dist/lib/browser/launch-args.d.ts.map +1 -1
  278. package/dist/lib/browser/launch-args.js +41 -1
  279. package/dist/lib/browser/user-agent.d.ts +53 -0
  280. package/dist/lib/browser/user-agent.d.ts.map +1 -0
  281. package/dist/lib/browser/user-agent.js +79 -0
  282. package/dist/lib/docs-metadata-managed.d.ts +1 -0
  283. package/dist/lib/docs-metadata-managed.d.ts.map +1 -1
  284. package/dist/lib/docs-metadata-managed.js +17 -1
  285. package/dist/lib/identities/assume.d.ts.map +1 -1
  286. package/dist/lib/identities/assume.js +4 -9
  287. package/dist/lib/instructions/apply.d.ts.map +1 -1
  288. package/dist/lib/instructions/apply.js +2 -0
  289. package/dist/lib/pace/index.d.ts +2 -0
  290. package/dist/lib/pace/index.d.ts.map +1 -0
  291. package/dist/lib/pace/index.js +1 -0
  292. package/dist/lib/pace/pace.d.ts +95 -0
  293. package/dist/lib/pace/pace.d.ts.map +1 -0
  294. package/dist/lib/pace/pace.js +313 -0
  295. package/dist/lib/tunnel/forward-headers.d.ts +11 -0
  296. package/dist/lib/tunnel/forward-headers.d.ts.map +1 -0
  297. package/dist/lib/tunnel/forward-headers.js +17 -0
  298. package/dist/lib/tunnel/gate.js +15 -10
  299. package/dist/lib/webview/index.d.ts +2 -0
  300. package/dist/lib/webview/index.d.ts.map +1 -0
  301. package/dist/lib/webview/index.js +1 -0
  302. package/dist/lib/webview/webview.d.ts +116 -0
  303. package/dist/lib/webview/webview.d.ts.map +1 -0
  304. package/dist/lib/webview/webview.js +289 -0
  305. package/opencode-plugin/package.json +19 -0
  306. package/opencode-plugin/src/index.ts +791 -0
  307. package/package.json +11 -4
  308. package/schemas/config.schema.json +13 -0
  309. package/schemas/event-v3.schema.json +164 -0
  310. package/src/commander.ts +7 -0
  311. package/src/commands/agents.ts +33 -18
  312. package/src/commands/browse-ai.ts +8 -0
  313. package/src/commands/browse.ts +189 -10
  314. package/src/commands/checkpoint.ts +7 -9
  315. package/src/commands/deinit.ts +9 -4
  316. package/src/commands/docs.ts +2 -0
  317. package/src/commands/doctor.ts +11 -2
  318. package/src/commands/fetch.ts +14 -0
  319. package/src/commands/init.ts +281 -119
  320. package/src/commands/instructions.ts +8 -4
  321. package/src/commands/ledger-v3.ts +2 -1
  322. package/src/commands/webview.ts +159 -0
  323. package/src/core/adapter.ts +102 -1
  324. package/src/core/adapters/attestation.ts +3 -2
  325. package/src/core/adapters/profiles.ts +42 -1
  326. package/src/core/adapters/registry.ts +37 -0
  327. package/src/core/agents/canonical-emit.ts +2 -5
  328. package/src/core/agents/cli.ts +18 -17
  329. package/src/core/agents/coord-client.ts +9 -3
  330. package/src/core/agents/rules/claim-conflict.ts +3 -8
  331. package/src/core/agents/rules/commit-conflict.ts +2 -7
  332. package/src/core/agents/rules/stop-hook.ts +3 -1
  333. package/src/core/agents/session-events.ts +120 -26
  334. package/src/core/agents/session-finalization-state-v3.ts +2 -1
  335. package/src/core/agents/session-finalizer-v3.ts +5 -4
  336. package/src/core/agents/session-name-display.ts +48 -0
  337. package/src/core/agents/state/heartbeat-reader.ts +7 -0
  338. package/src/core/agents/state/heartbeat-writer.ts +24 -2
  339. package/src/core/agents/state/live-coordination-view.ts +1 -0
  340. package/src/core/agents/state/live-coordination-writer.ts +3 -0
  341. package/src/core/agents/state/stale-sweep.ts +2 -9
  342. package/src/core/agents/turn-changes.ts +97 -0
  343. package/src/core/artifacts/delivery-card.ts +2 -1
  344. package/src/core/artifacts/index.ts +4 -3
  345. package/src/core/config.ts +23 -0
  346. package/src/core/context/index.ts +2 -1
  347. package/src/core/conversations/archive.ts +4 -3
  348. package/src/core/diagnostics/bundle.ts +3 -2
  349. package/src/core/events/legacy-storage/canary.ts +5 -4
  350. package/src/core/events/legacy-storage/compression.ts +2 -1
  351. package/src/core/events/v3/adapter-id.ts +29 -1
  352. package/src/core/events/v3/authority-outbox.ts +2 -1
  353. package/src/core/events/v3/bootstrap.ts +5 -4
  354. package/src/core/events/v3/capabilities.ts +17 -0
  355. package/src/core/events/v3/contract.ts +9 -1
  356. package/src/core/events/v3/control-witness.ts +3 -2
  357. package/src/core/events/v3/coordination-transaction-recovery.ts +4 -3
  358. package/src/core/events/v3/fingerprint-keys.ts +7 -6
  359. package/src/core/events/v3/generated.ts +1 -1
  360. package/src/core/events/v3/live-feed.ts +5 -4
  361. package/src/core/events/v3/producers/command-recorder.ts +8 -6
  362. package/src/core/events/v3/producers/coordination-recorder.ts +8 -7
  363. package/src/core/events/v3/producers/diagnostic-summaries.ts +5 -4
  364. package/src/core/events/v3/producers/hook-base.ts +11 -4
  365. package/src/core/events/v3/producers/hook.ts +19 -1
  366. package/src/core/events/v3/producers/intake.ts +18 -6
  367. package/src/core/events/v3/producers/recorder.ts +123 -114
  368. package/src/core/events/v3/recovery.ts +4 -3
  369. package/src/core/events/v3/support-storage/inventory.ts +2 -1
  370. package/src/core/events/v3/support-storage/maintenance.ts +8 -3
  371. package/src/core/events/v3/support-storage/pack-reader.ts +4 -3
  372. package/src/core/events/v3/support-storage/pack-writer.ts +6 -5
  373. package/src/core/events/v3/tool-line-changes.ts +139 -0
  374. package/src/core/events/v3/writer.ts +8 -7
  375. package/src/core/governor/planning.ts +6 -5
  376. package/src/core/governor/service.ts +12 -11
  377. package/src/core/governor/state.ts +7 -6
  378. package/src/core/guard/evaluator.ts +1 -0
  379. package/src/core/guard/storage.ts +3 -2
  380. package/src/core/hooks/adapter/behaviors/claude-code.ts +33 -0
  381. package/src/core/hooks/adapter/behaviors/codex.ts +96 -0
  382. package/src/core/hooks/adapter/behaviors/cursor.ts +37 -0
  383. package/src/core/hooks/adapter/behaviors/index.ts +31 -0
  384. package/src/core/hooks/adapter/behaviors/openclaw.ts +36 -0
  385. package/src/core/hooks/adapter/behaviors/opencode.ts +36 -0
  386. package/src/core/hooks/adapter/behaviors/types.ts +110 -0
  387. package/src/core/hooks/adapter/detect.ts +2 -3
  388. package/src/core/hooks/adapter/events.ts +53 -1
  389. package/src/core/hooks/adapter/opencode-plugin.ts +177 -0
  390. package/src/core/hooks/adapter/output.ts +8 -1
  391. package/src/core/hooks/adapter/wiring.ts +85 -11
  392. package/src/core/hooks/cli.ts +733 -537
  393. package/src/core/hooks/effects/image-capture.ts +2 -1
  394. package/src/core/hooks/prompt-context/contract.ts +1 -0
  395. package/src/core/hooks/resolve/transcript.ts +42 -5
  396. package/src/core/hooks/session-name-presence.ts +10 -3
  397. package/src/core/hooks/shell-waiter.ts +166 -0
  398. package/src/core/resources/service.ts +5 -4
  399. package/src/core/semantic/review.ts +5 -4
  400. package/src/core/semantic/service.ts +15 -14
  401. package/src/core/semantic/storage.ts +5 -4
  402. package/src/core/storage/atomic-json.ts +7 -3
  403. package/src/core/storage/durable-history.ts +6 -5
  404. package/src/core/storage/maintenance-providers.ts +2 -1
  405. package/src/core/storage/maintenance.ts +7 -6
  406. package/src/core/storage/metrics.ts +5 -1
  407. package/src/core/storage/modes.ts +53 -0
  408. package/src/core/storage/process-log.ts +3 -2
  409. package/src/core/storage/receipts.ts +4 -3
  410. package/src/core/storage/segments.ts +7 -6
  411. package/src/core/supervisor/hook-health.ts +4 -4
  412. package/src/core/supervisor/service.ts +7 -6
  413. package/src/core/work/state.ts +8 -7
  414. package/src/core/workflow/adapters.ts +15 -0
  415. package/src/core/workflow/approvals.ts +6 -5
  416. package/src/core/workflow/billing.ts +34 -4
  417. package/src/core/workflow/durable-record.ts +4 -3
  418. package/src/core/workflow/live-session-v3.ts +2 -3
  419. package/src/core/workflow/run-state.ts +3 -2
  420. package/src/core/workflow/spawn-opencode.ts +150 -0
  421. package/src/core/workflow/transcript.ts +3 -2
  422. package/src/core/workflow/workspaces/leases.ts +5 -4
  423. package/src/core/workflow/workspaces/local-git.ts +3 -2
  424. package/src/core/workflow/workspaces/paths.ts +2 -1
  425. package/src/core/workflow/workspaces/state.ts +10 -9
  426. package/src/lazy-commands.ts +11 -1
  427. package/src/lib/agent-browser/client.ts +18 -0
  428. package/src/lib/browser/client.ts +147 -9
  429. package/src/lib/browser/identity.ts +64 -0
  430. package/src/lib/browser/index.ts +15 -1
  431. package/src/lib/browser/launch-args.ts +53 -1
  432. package/src/lib/browser/user-agent.ts +130 -0
  433. package/src/lib/docs-metadata-managed.ts +21 -0
  434. package/src/lib/identities/assume.ts +7 -7
  435. package/src/lib/instructions/apply.ts +2 -0
  436. package/src/lib/pace/index.ts +14 -0
  437. package/src/lib/pace/pace.ts +370 -0
  438. package/src/lib/tunnel/forward-headers.ts +16 -0
  439. package/src/lib/tunnel/gate.ts +18 -10
  440. package/src/lib/webview/index.ts +13 -0
  441. package/src/lib/webview/webview.ts +457 -0
@@ -1,7 +1,9 @@
1
+ import { spawn } from "node:child_process";
1
2
  import { existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
2
3
  import { homedir } from "node:os";
3
4
  import { dirname, isAbsolute, resolve } from "node:path";
4
5
  import type { Command } from "commander";
6
+ import { chromium } from "playwright";
5
7
  import { PNG } from "pngjs";
6
8
  import type { EmitContext, HarneryProgramContext } from "../commander.ts";
7
9
  import { resolveBinName } from "../core/config.ts";
@@ -24,15 +26,19 @@ import {
24
26
  type CritiqueResult,
25
27
  type CritiqueTile,
26
28
  captureDevOverlay,
29
+ chromeMajorFromExecutable,
27
30
  DEFAULT_CRITIQUE_RUBRIC,
28
31
  type DevOverlayResult,
29
32
  type Diagnostics,
30
33
  extractObservedIp,
34
+ installedChromeChannel,
35
+ installedChromePath,
31
36
  type LayoutAxis,
32
37
  type LayoutLintResult,
33
38
  type OverflowResult,
34
39
  parseAssertSpec,
35
40
  type RuntsResult,
41
+ resolveUserAgent,
36
42
  runCritique,
37
43
  type StandaloneHtmlResult,
38
44
  type TargetSizeProfile,
@@ -108,6 +114,7 @@ import {
108
114
  saveBaseline,
109
115
  } from "../lib/browser/visual-diff.ts";
110
116
  import { applyExtraCookies, CookieJar } from "../lib/cookies/index.ts";
117
+ import { commandPaceGate } from "../lib/pace/index.ts";
111
118
 
112
119
  /**
113
120
  * `harn browse <url>`: Playwright-backed page navigation with shared
@@ -162,13 +169,17 @@ interface BrowseOpts {
162
169
  batch?: string;
163
170
  networkHar?: string;
164
171
  login?: boolean;
172
+ plain?: boolean;
165
173
  loginCloseFile?: string;
166
174
  controlFile?: string;
167
175
  headed?: boolean;
168
176
  browserArg?: string[];
177
+ browserChannel?: string;
178
+ userAgent?: string;
169
179
  proxyFromEnv?: boolean;
170
180
  exportCookies?: string;
171
181
  cookies?: boolean;
182
+ pace?: boolean;
172
183
  store?: string;
173
184
  profile?: string;
174
185
  viewport?: string;
@@ -339,8 +350,7 @@ export function registerBrowseCommand(
339
350
  .option("--network-har <path>", "Record network traffic to a HAR file (finalized on close)")
340
351
  .option(
341
352
  "--viewport <preset|WxH>",
342
- "Viewport: mobile (390x844), tablet (820x1180), desktop (1280x800), hd (1920x1080), or explicit '1920x1080'",
343
- "desktop",
353
+ "Viewport: mobile (390x844), tablet (820x1180), desktop (1280x800), hd (1920x1080), or explicit '1920x1080'. Default: real window in headed mode, desktop in headless mode",
344
354
  )
345
355
  .option(
346
356
  "--color-scheme <scheme>",
@@ -349,6 +359,14 @@ export function registerBrowseCommand(
349
359
  "Absent = browser default (unchanged behavior).",
350
360
  )
351
361
  .option("--login", "Headed mode for one-time auth flow (cookies persist in profile)")
362
+ .option(
363
+ "--plain",
364
+ "With --login: open the URL in the installed Google Chrome with nothing attached (no DevTools " +
365
+ "protocol, no Playwright) on the same persistent profile. Use it for sign-in flows whose " +
366
+ "verification step detects automation itself (X does). Sign in, then close the window or " +
367
+ "create the --login-close-file; later browse and browse-session runs reuse the profile's cookies. " +
368
+ "Not compatible with --control-file, because nothing is attached to drive.",
369
+ )
352
370
  .option(
353
371
  "--login-close-file <path>",
354
372
  "With --login, wait for this file instead of terminal Enter, then remove it and close cleanly",
@@ -358,13 +376,27 @@ export function registerBrowseCommand(
358
376
  "With --login, publish an owner-only descriptor for repeated browse-session control",
359
377
  )
360
378
  .option("--headed", "Headed mode for one-off (no auth-flow framing)")
379
+ .option(
380
+ "--browser-channel <name>",
381
+ "Browser to launch: chrome | chrome-beta | msedge | chromium. Headed launches (--login, --headed) " +
382
+ "default to the installed Google Chrome with the automation signals removed, because the bundled " +
383
+ '"Chrome for Testing" build advertises itself and sign-in flows refuse clicks; chromium forces the ' +
384
+ "bundled build. HARNERY_BROWSER_CHANNEL sets the default machine-wide.",
385
+ )
386
+ .option(
387
+ "--user-agent <ua|auto|native>",
388
+ "User agent to present. Default: a normal Windows (or macOS on a Mac) Chrome user agent at the launched " +
389
+ "Chrome's major version, stored at ~/.cache/harnery/user-agent.json and reused by every surface; never " +
390
+ "Linux, never HeadlessChrome. A string rewrites the store, auto refreshes it, native uses the browser's own. " +
391
+ "HARNERY_BROWSER_UA overrides for one environment.",
392
+ )
361
393
  .option(
362
394
  "--browser-arg <flag>",
363
395
  "Extra Chromium launch flag, passed straight to the browser (repeatable). " +
364
396
  "e.g. --browser-arg --disable-gpu. Also settable machine-wide via the " +
365
- "HARNERY_BROWSER_ARGS env var (whitespace-separated). Under WSL, headed " +
366
- "launches auto-add --disable-gpu to fix blank-window paint; opt out with " +
367
- "HARNERY_BROWSER_NO_WSL_DEFAULTS=1.",
397
+ "HARNERY_BROWSER_ARGS env var (whitespace-separated). Under WSL, set " +
398
+ "HARNERY_BROWSER_WSL_DISABLE_GPU=1 to add --disable-gpu when a headed window paints blank; " +
399
+ "it is off by default because software WebGL is a bot tell.",
368
400
  (value: string, prev: string[] = []) => [...prev, value],
369
401
  [] as string[],
370
402
  )
@@ -376,6 +408,11 @@ export function registerBrowseCommand(
376
408
  "the expected IP is verified before the requested URL opens.",
377
409
  )
378
410
  .option("--no-cookies", "Skip cookie-jar attach and persist")
411
+ .option(
412
+ "--no-pace",
413
+ "Skip the human-pace gap (3 to 9 s) between page loads of the same site for this run. " +
414
+ "HARNERY_PACE=off disables it machine-wide; local and private hosts never wait.",
415
+ )
379
416
  .option("--store <path>", `Cookie store path (default ${DEFAULT_STORE})`)
380
417
  .option("--profile <dir>", `Persistent Chromium profile dir (default ${DEFAULT_PROFILE})`)
381
418
  .option(
@@ -901,20 +938,58 @@ async function runBrowse(
901
938
  );
902
939
  }
903
940
 
941
+ const pace = commandPaceGate(opts.pace !== false, (message) => emit.log(message, "info"));
942
+ if (opts.plain) {
943
+ if (!opts.login) throw new Error("--plain requires --login.");
944
+ if (opts.controlFile) {
945
+ throw new Error(
946
+ "--plain cannot take --control-file: nothing is attached to drive the window.",
947
+ );
948
+ }
949
+ const plainExecutable = installedChromePath();
950
+ const plainUa = resolveUserAgent({
951
+ requested: opts.userAgent,
952
+ env: process.env.HARNERY_BROWSER_UA,
953
+ chromeMajor: plainExecutable ? chromeMajorFromExecutable(plainExecutable) : undefined,
954
+ });
955
+ await pace?.before(url);
956
+ await runPlainLogin(url, opts.profile ?? DEFAULT_PROFILE, loginCloseFile, plainUa, emit);
957
+ return;
958
+ }
959
+
960
+ const channel = resolveBrowserChannel(opts, Boolean(headed));
961
+ const userAgent = resolveUserAgent({
962
+ requested: opts.userAgent,
963
+ env: process.env.HARNERY_BROWSER_UA,
964
+ chromeMajor: launchedChromeMajor(channel),
965
+ });
904
966
  const browser = new Browser({
905
967
  profileDir: opts.profile ?? DEFAULT_PROFILE,
906
968
  headed,
907
969
  jar,
908
- viewport,
970
+ viewport: headed && !opts.viewport ? null : viewport,
909
971
  ...(deviceScaleFactor !== undefined ? { deviceScaleFactor } : {}),
910
972
  ...(colorScheme ? { colorScheme } : {}),
911
973
  navigationTimeout: Number.parseInt(opts.timeout, 10),
912
974
  waitUntil: opts.waitUntil as BrowseOpts["waitUntil"] as never,
913
975
  recordHarPath: opts.networkHar ? resolve(opts.networkHar) : undefined,
914
976
  extraHeaders: context?.extraHeaders,
977
+ pace,
915
978
  launchArgs: resolveLaunchArgs(opts, Boolean(headed), Boolean(proxy)),
979
+ ...(channel ? { channel } : {}),
980
+ hideAutomation: Boolean(headed),
981
+ ...(userAgent ? { userAgent } : {}),
916
982
  proxy,
917
983
  });
984
+ if (userAgent) emit.log(`Presenting as: ${userAgent}`, "debug");
985
+ if (headed) {
986
+ emit.log(
987
+ channel && channel !== "chromium"
988
+ ? `Headed session uses the installed ${channel} channel with automation signals hidden.`
989
+ : "Headed session uses Playwright's bundled Chromium (no Google Chrome found); automation signals hidden.",
990
+ "info",
991
+ );
992
+ }
918
993
 
919
994
  // Print mode: --snapshot / --html / --json all suppress file writes.
920
995
  const printMode = opts.snapshot || opts.html || opts.json;
@@ -2967,15 +3042,57 @@ function summarizeDiagnostics(diag: Diagnostics): Record<string, unknown> {
2967
3042
 
2968
3043
  /**
2969
3044
  * Merge Chromium launch flags from three sources, in order, de-duped:
2970
- * 1. WSLg headed default (`--disable-gpu`) — auto-applied for headed launches
2971
- * under WSL so the window actually paints. Opt out with
2972
- * HARNERY_BROWSER_NO_WSL_DEFAULTS=1.
3045
+ * 1. WSLg `--disable-gpu`, only when HARNERY_BROWSER_WSL_DISABLE_GPU=1. It
3046
+ * was the default for headed launches, but software WebGL (SwiftShader)
3047
+ * is a bot tell that sign-in flows screen for, and current WSLg exposes
3048
+ * the host GPU through D3D12, so the flag is now opt-in for machines
3049
+ * that still paint a blank headed window without it.
2973
3050
  * 2. HARNERY_BROWSER_ARGS env (whitespace-separated) — a machine-wide default.
2974
3051
  * 3. --browser-arg flags on this invocation (repeatable).
2975
3052
  */
3053
+ const BROWSER_CHANNELS = new Set(["chrome", "chrome-beta", "msedge", "chromium"]);
3054
+
3055
+ /**
3056
+ * Pick the browser channel: `--browser-channel`, then `HARNERY_BROWSER_CHANNEL`,
3057
+ * then (headed only) the installed Google Chrome when one exists. Headless runs
3058
+ * keep the bundled Chromium unless told otherwise, so QA renders stay stable.
3059
+ */
3060
+ function resolveBrowserChannel(
3061
+ opts: BrowseOpts,
3062
+ headed: boolean,
3063
+ ): "chrome" | "chrome-beta" | "msedge" | "chromium" | undefined {
3064
+ const requested = (opts.browserChannel ?? process.env.HARNERY_BROWSER_CHANNEL)?.trim();
3065
+ if (requested) {
3066
+ if (!BROWSER_CHANNELS.has(requested)) {
3067
+ throw new Error(
3068
+ `Unknown --browser-channel "${requested}". Use chrome, chrome-beta, msedge, or chromium.`,
3069
+ );
3070
+ }
3071
+ return requested as "chrome" | "chrome-beta" | "msedge" | "chromium";
3072
+ }
3073
+ return headed ? installedChromeChannel() : undefined;
3074
+ }
3075
+
3076
+ /**
3077
+ * Major version of the Chrome that will launch: the installed Chrome for the
3078
+ * `chrome` channel, else Playwright's bundled Chromium. Unknown when neither
3079
+ * answers `--version`; the user-agent store then keeps its last value.
3080
+ */
3081
+ function launchedChromeMajor(channel: string | undefined): number | undefined {
3082
+ if (channel === "chrome") {
3083
+ const exe = installedChromePath();
3084
+ return exe ? chromeMajorFromExecutable(exe) : undefined;
3085
+ }
3086
+ try {
3087
+ return chromeMajorFromExecutable(chromium.executablePath());
3088
+ } catch {
3089
+ return undefined;
3090
+ }
3091
+ }
3092
+
2976
3093
  function resolveLaunchArgs(opts: BrowseOpts, headed: boolean, proxyEnabled: boolean): string[] {
2977
3094
  const args: string[] = [];
2978
- if (headed && !process.env.HARNERY_BROWSER_NO_WSL_DEFAULTS) {
3095
+ if (headed && process.env.HARNERY_BROWSER_WSL_DISABLE_GPU === "1") {
2979
3096
  args.push(...wslHeadedLaunchArgs());
2980
3097
  }
2981
3098
  const envArgs = process.env.HARNERY_BROWSER_ARGS?.trim();
@@ -3005,6 +3122,68 @@ async function verifyBrowserProxyGate(
3005
3122
  emit.log(`browser proxy gate: ${observedIp} · expected IP confirmed`, "info");
3006
3123
  }
3007
3124
 
3125
+ /**
3126
+ * `--login --plain`: spawn the installed Google Chrome directly on the shared
3127
+ * persistent profile, with no DevTools protocol attached. Playwright enables
3128
+ * its runtime hooks in every frame it drives, and sign-in verification vendors
3129
+ * (X's is the reported case) detect that and fail the flow with no explanation.
3130
+ * The person signs in here; cookies land in the same profile that later
3131
+ * `browse` and `browse-session` runs open, so read-only captures inherit the
3132
+ * session without ever repeating the sign-in under automation.
3133
+ */
3134
+ async function runPlainLogin(
3135
+ url: string,
3136
+ profileDir: string,
3137
+ loginCloseFile: string | null,
3138
+ userAgent: string | undefined,
3139
+ emit: { log: (message: string, level: "info" | "warn" | "error" | "debug") => void },
3140
+ ): Promise<void> {
3141
+ const executable = installedChromePath();
3142
+ if (!executable) {
3143
+ throw new Error(
3144
+ "--plain needs an installed Google Chrome at a standard path; none was found on this machine.",
3145
+ );
3146
+ }
3147
+ mkdirSync(profileDir, { recursive: true });
3148
+ const child = spawn(
3149
+ executable,
3150
+ [
3151
+ `--user-data-dir=${profileDir}`,
3152
+ "--no-first-run",
3153
+ "--no-default-browser-check",
3154
+ ...(userAgent ? [`--user-agent=${userAgent}`] : []),
3155
+ url,
3156
+ ],
3157
+ { stdio: "ignore" },
3158
+ );
3159
+ const exited = new Promise<void>((resolveExit) => {
3160
+ child.once("exit", () => resolveExit());
3161
+ child.once("error", () => resolveExit());
3162
+ });
3163
+ const lifecycleAbort = new AbortController();
3164
+ const waits: Promise<void>[] = [exited];
3165
+ if (loginCloseFile) {
3166
+ emit.log(
3167
+ `[--login --plain] Plain Google Chrome is open with nothing attached. Sign in, then close the window or create ${loginCloseFile}.`,
3168
+ "info",
3169
+ );
3170
+ waits.push(waitForLoginCloseFile(loginCloseFile, lifecycleAbort.signal));
3171
+ } else {
3172
+ emit.log(
3173
+ "[--login --plain] Plain Google Chrome is open with nothing attached. Sign in, then close the window or press Enter here.",
3174
+ "info",
3175
+ );
3176
+ waits.push(waitForTerminalEnter(lifecycleAbort.signal));
3177
+ }
3178
+ await Promise.race(waits);
3179
+ lifecycleAbort.abort();
3180
+ if (child.exitCode === null && child.signalCode === null) {
3181
+ child.kill("SIGTERM");
3182
+ await Promise.race([exited, new Promise((r) => setTimeout(r, 5000))]);
3183
+ }
3184
+ emit.log(`[--login --plain] Chrome closed; cookies persisted in ${profileDir}.`, "info");
3185
+ }
3186
+
3008
3187
  async function waitForLoginCloseFile(path: string, signal?: AbortSignal): Promise<void> {
3009
3188
  while (!existsSync(path) && !signal?.aborted) {
3010
3189
  await new Promise((resolve) => setTimeout(resolve, 250));
@@ -1,6 +1,6 @@
1
1
  import type { Command } from "commander";
2
2
  import type { EmitContext, HarneryProgramContext } from "../commander.ts";
3
- import type { Adapter } from "../core/adapter.ts";
3
+ import { ADAPTERS, type Adapter, normalizeAdapter } from "../core/adapter.ts";
4
4
  import { monorepoRoot, resolveOwner } from "../core/agents/index.ts";
5
5
  import { readLiveCoordinationRow } from "../core/agents/state/live-coordination-view.ts";
6
6
  import {
@@ -76,7 +76,7 @@ export function registerCheckpointCommand(
76
76
  .description("Create a durable context-continuity capsule for the current work")
77
77
  .option("--session <id>", "Session id (defaults to the current agent heartbeat)")
78
78
  .option("--instance <id>", "Agent instance id (defaults to the current owner)")
79
- .option("--adapter <id>", "claude-code, codex, or cursor (inferred from heartbeat)")
79
+ .option("--adapter <id>", `${ADAPTERS.join(", ")} (inferred from heartbeat)`)
80
80
  .option("--reason <reason>", "manual, pressure, pre_compact, or session_end", "manual")
81
81
  .option("--note <text>", "Short continuation note for the recovered agent")
82
82
  .option("--json", "Structured JSON output")
@@ -94,7 +94,7 @@ export function registerCheckpointCommand(
94
94
  const reason = parseCheckpointReason(opts.reason);
95
95
  const identity = resolveContinuityIdentity(context, opts);
96
96
  if (!identity.adapter) {
97
- throw new Error("could not infer the adapter; pass --adapter claude-code|codex|cursor");
97
+ throw new Error(`could not infer the adapter; pass --adapter ${ADAPTERS.join("|")}`);
98
98
  }
99
99
  const result = checkpointContext(identity.coordRoot, {
100
100
  sessionId: identity.sessionId,
@@ -166,15 +166,13 @@ function resolveContinuityIdentity(
166
166
  }
167
167
 
168
168
  function adapterFromPlatform(platform: string | undefined): Adapter | null {
169
- if (platform === "claude-code") return "claude-code";
170
- if (platform === "cursor") return "cursor";
171
- if (platform === "codex") return "codex";
172
- return null;
169
+ return normalizeAdapter(platform);
173
170
  }
174
171
 
175
172
  function parseAdapter(value: string): Adapter {
176
- if (value === "claude-code" || value === "codex" || value === "cursor") return value;
177
- throw new Error(`invalid adapter "${value}"; expected claude-code, codex, or cursor`);
173
+ const adapter = normalizeAdapter(value);
174
+ if (adapter) return adapter;
175
+ throw new Error(`invalid adapter "${value}"; expected one of ${ADAPTERS.join(", ")}`);
178
176
  }
179
177
 
180
178
  function parseCheckpointReason(value: string): CheckpointReason {
@@ -4,7 +4,7 @@
4
4
  * `init` makes two kinds of change outside the harnery package:
5
5
  * 1. Merges `agent-hook` entries into the adapter settings file
6
6
  * (Claude Code `.claude/settings.json`, Cursor `.cursor/hooks.json`, or
7
- * Codex `.codex/hooks.json`).
7
+ * Codex `.codex/hooks.json`), or installs the OpenCode plugin directory.
8
8
  * 2. Creates the `.harnery/` coord root (runtime state: events, councils,
9
9
  * identities, journal) and stamps the host bin name into
10
10
  * `.harnery/config.jsonc`.
@@ -34,6 +34,7 @@ import type { Command } from "commander";
34
34
  import type { EmitContext } from "../commander.ts";
35
35
  import { DEFAULT_BIN_NAME } from "../core/config.ts";
36
36
  import { ADAPTER_SPECS, type AdapterId } from "../core/hooks/adapter/events.ts";
37
+ import { removeOpenCodePlugin } from "../core/hooks/adapter/opencode-plugin.ts";
37
38
  import type { SettingsFile } from "../core/hooks/adapter/wiring.ts";
38
39
  import { removeIndexerExclusions } from "../lib/indexer-exclusions.ts";
39
40
  import { removeInstructions } from "../lib/instructions/apply.ts";
@@ -62,7 +63,7 @@ export function registerDeinitCommand(program: Command, emit: EmitContext, binNa
62
63
  ".harnery/ coord root (on a terminal it asks first). Idempotent; use " +
63
64
  "--dry-run to preview.",
64
65
  )
65
- .option("--adapter <id>", "claude-code | cursor | codex", "claude-code")
66
+ .option("--adapter <id>", "claude-code | cursor | codex | opencode", "claude-code")
66
67
  .option("--dry-run", "Show what would change without writing")
67
68
  .option("--project-root <path>", "Project root (default: git toplevel, else cwd)")
68
69
  .option("--purge-state", "Also delete the .harnery/ coord root (runtime state, destructive)")
@@ -70,7 +71,9 @@ export function registerDeinitCommand(program: Command, emit: EmitContext, binNa
70
71
  const adapter = opts.adapter as AdapterId;
71
72
  const spec = ADAPTER_SPECS[adapter];
72
73
  if (!spec) {
73
- emit.text(`Unknown adapter '${opts.adapter}'. Expected: claude-code | cursor | codex.`);
74
+ emit.text(
75
+ `Unknown adapter '${opts.adapter}'. Expected: claude-code | cursor | codex | opencode.`,
76
+ );
74
77
  emit.setExitCode(1);
75
78
  return;
76
79
  }
@@ -97,7 +100,9 @@ export function registerDeinitCommand(program: Command, emit: EmitContext, binNa
97
100
 
98
101
  // ── 1. unwire adapter hooks ────────────────────────────────────────────
99
102
  const settingsPath = resolve(projectRoot, spec.settingsFile);
100
- if (!existsSync(settingsPath)) {
103
+ if (spec.installMode === "opencode-plugin") {
104
+ actions.push(...removeOpenCodePlugin(projectRoot, dryRun));
105
+ } else if (!existsSync(settingsPath)) {
101
106
  actions.push(`· ${rel(projectRoot, settingsPath)} doesn't exist; no hooks to remove`);
102
107
  } else {
103
108
  let settings: SettingsFile;
@@ -6,6 +6,7 @@ import { initDocsContext as initDocsLinks, runLinks } from "../lib/docs-links.ts
6
6
  import { initDocsContext as initDocsLint, runLint } from "../lib/docs-lint.ts";
7
7
  import { readDocsMetadata, readDocsMetadataKey } from "../lib/docs-meta.ts";
8
8
  import { initDocsMetadataAuditContext, runDocsMetadataAudit } from "../lib/docs-metadata-audit.ts";
9
+ import { initDocsMetadataExclusions } from "../lib/docs-metadata-managed.ts";
9
10
  import { initDocsMetadataSyncContext, runDocsMetadataSync } from "../lib/docs-metadata-sync.ts";
10
11
  import { createDocsFile } from "../lib/docs-new.ts";
11
12
  import {
@@ -27,6 +28,7 @@ function ensureContext(context: HarneryProgramContext | undefined): void {
27
28
  docsRootAllowlist: context.docsRootAllowlist,
28
29
  });
29
30
  initDocsLinks({ ...opts, extraExcludedPrefixes: context.extraDocsExcludedPrefixes });
31
+ initDocsMetadataExclusions(context.extraDocsExcludedPrefixes);
30
32
  initDocsMetadataAuditContext(opts);
31
33
  initDocsMetadataSyncContext(opts);
32
34
  initDocsSweep(opts);
@@ -557,13 +557,22 @@ function checkAdapterHooks(installedAdapters: AdapterId[] = []): Check {
557
557
  if (d.invalidEventKeys.length > 0) {
558
558
  bits.push(`unsupported events (${d.invalidEventKeys.join(", ")})`);
559
559
  }
560
+ if (d.pluginIssues && d.pluginIssues.length > 0) {
561
+ // Plugin issues already name their file; render them as-is.
562
+ return d.pluginIssues.join("; ");
563
+ }
560
564
  return `${d.settingsFile}: ${bits.join("; ")}`;
561
565
  });
562
566
  for (const id of unwired) {
563
- parts.push(`${ADAPTER_SPECS[id].settingsFile}: ${id} CLI installed, no harnery hooks wired`);
567
+ const what = ADAPTER_SPECS[id].installMode === "opencode-plugin" ? "plugin" : "hooks";
568
+ parts.push(`${ADAPTER_SPECS[id].settingsFile}: ${id} CLI installed, no harnery ${what} wired`);
564
569
  }
565
570
  const needsManualRepair = drift.some(
566
- (d) => d.parseError || d.invalidTopLevelKeys.length > 0 || d.invalidEventKeys.length > 0,
571
+ (d) =>
572
+ d.parseError ||
573
+ d.invalidTopLevelKeys.length > 0 ||
574
+ d.invalidEventKeys.length > 0 ||
575
+ d.pluginIssues?.some((issue) => issue.includes("without harnery's ownership header")),
567
576
  );
568
577
  const wireHints = unwired.map((id) => `\`${bin} init --adapter ${id}\``);
569
578
  let hint: string;
@@ -3,8 +3,10 @@ import { homedir } from "node:os";
3
3
  import { resolve } from "node:path";
4
4
  import type { Command } from "commander";
5
5
  import type { EmitContext, HarneryProgramContext } from "../commander.ts";
6
+ import { resolveUserAgent } from "../lib/browser/user-agent.js";
6
7
  import { CookieJar } from "../lib/cookies/index.ts";
7
8
  import { fetchWithJar } from "../lib/http/index.ts";
9
+ import { commandPaceGate } from "../lib/pace/index.ts";
8
10
 
9
11
  /**
10
12
  * `harn fetch`: HTTP request with cookie-jar attach + persist.
@@ -23,6 +25,7 @@ interface FetchOpts {
23
25
  output?: string;
24
26
  store?: string;
25
27
  cookies?: boolean;
28
+ pace?: boolean;
26
29
  redirect: string;
27
30
  timeout: string;
28
31
  status?: boolean;
@@ -47,6 +50,11 @@ export function registerFetchCommand(
47
50
  .option("-o, --output <file>", "Write response body to file (default: stdout)")
48
51
  .option("--store <path>", `Cookie store path (default ${DEFAULT_STORE})`)
49
52
  .option("--no-cookies", "Skip cookie-jar attach + persist")
53
+ .option(
54
+ "--no-pace",
55
+ "Skip the human-pace gap (3 to 9 s) between requests to the same site for this run. " +
56
+ "HARNERY_PACE=off disables it machine-wide; local and private hosts never wait.",
57
+ )
50
58
  .option("--redirect <mode>", "Redirect handling: follow | error | manual", "follow")
51
59
  .option("--timeout <ms>", "Request timeout in milliseconds", "30000")
52
60
  .option("--status", "Print status to stderr")
@@ -70,6 +78,10 @@ async function runFetch(
70
78
  context: HarneryProgramContext | undefined,
71
79
  ): Promise<void> {
72
80
  const headers: Record<string, string> = {};
81
+ {
82
+ const ua = resolveUserAgent({ env: process.env.HARNERY_BROWSER_UA });
83
+ if (ua) headers["User-Agent"] = ua;
84
+ }
73
85
  for (const h of opts.header ?? []) {
74
86
  const idx = h.indexOf(":");
75
87
  if (idx < 0) {
@@ -83,6 +95,8 @@ async function runFetch(
83
95
  ? new CookieJar({ path: opts.store ?? DEFAULT_STORE, source: "harn-fetch" })
84
96
  : null;
85
97
 
98
+ await commandPaceGate(opts.pace !== false, (message) => emit.log(message, "info"))?.before(url);
99
+
86
100
  const timeoutMs = Number.parseInt(opts.timeout, 10);
87
101
  const ac = new AbortController();
88
102
  const timer = setTimeout(() => ac.abort(), timeoutMs);