harnery 0.39.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 (445) 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 +30 -19
  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/names.d.ts +4 -4
  69. package/dist/core/agents/state/names.d.ts.map +1 -1
  70. package/dist/core/agents/state/names.js +5 -7
  71. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  72. package/dist/core/agents/state/stale-sweep.js +2 -10
  73. package/dist/core/agents/turn-changes.d.ts +17 -0
  74. package/dist/core/agents/turn-changes.d.ts.map +1 -0
  75. package/dist/core/agents/turn-changes.js +76 -0
  76. package/dist/core/artifacts/delivery-card.d.ts.map +1 -1
  77. package/dist/core/artifacts/delivery-card.js +2 -1
  78. package/dist/core/artifacts/index.d.ts.map +1 -1
  79. package/dist/core/artifacts/index.js +4 -3
  80. package/dist/core/config.d.ts +5 -0
  81. package/dist/core/config.d.ts.map +1 -1
  82. package/dist/core/config.js +14 -0
  83. package/dist/core/context/index.d.ts.map +1 -1
  84. package/dist/core/context/index.js +2 -1
  85. package/dist/core/conversations/archive.d.ts.map +1 -1
  86. package/dist/core/conversations/archive.js +4 -3
  87. package/dist/core/diagnostics/bundle.d.ts.map +1 -1
  88. package/dist/core/diagnostics/bundle.js +3 -2
  89. package/dist/core/events/legacy-storage/canary.d.ts.map +1 -1
  90. package/dist/core/events/legacy-storage/canary.js +5 -4
  91. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -1
  92. package/dist/core/events/legacy-storage/compression.js +2 -1
  93. package/dist/core/events/v3/adapter-id.d.ts +10 -2
  94. package/dist/core/events/v3/adapter-id.d.ts.map +1 -1
  95. package/dist/core/events/v3/adapter-id.js +16 -0
  96. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
  97. package/dist/core/events/v3/authority-outbox.js +2 -1
  98. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  99. package/dist/core/events/v3/bootstrap.js +5 -4
  100. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  101. package/dist/core/events/v3/capabilities.js +17 -0
  102. package/dist/core/events/v3/contract.d.ts +5 -0
  103. package/dist/core/events/v3/contract.d.ts.map +1 -1
  104. package/dist/core/events/v3/contract.js +7 -1
  105. package/dist/core/events/v3/control-witness.d.ts.map +1 -1
  106. package/dist/core/events/v3/control-witness.js +3 -2
  107. package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -1
  108. package/dist/core/events/v3/coordination-transaction-recovery.js +4 -3
  109. package/dist/core/events/v3/fingerprint-keys.d.ts.map +1 -1
  110. package/dist/core/events/v3/fingerprint-keys.js +7 -6
  111. package/dist/core/events/v3/generated.d.ts +1 -1
  112. package/dist/core/events/v3/generated.js +1 -1
  113. package/dist/core/events/v3/live-feed.d.ts.map +1 -1
  114. package/dist/core/events/v3/live-feed.js +5 -4
  115. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  116. package/dist/core/events/v3/producers/command-recorder.js +8 -7
  117. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  118. package/dist/core/events/v3/producers/coordination-recorder.js +8 -7
  119. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -1
  120. package/dist/core/events/v3/producers/diagnostic-summaries.js +5 -4
  121. package/dist/core/events/v3/producers/hook-base.d.ts +1 -0
  122. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  123. package/dist/core/events/v3/producers/hook-base.js +10 -4
  124. package/dist/core/events/v3/producers/hook.d.ts +2 -0
  125. package/dist/core/events/v3/producers/hook.d.ts.map +1 -1
  126. package/dist/core/events/v3/producers/hook.js +16 -1
  127. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  128. package/dist/core/events/v3/producers/intake.js +16 -6
  129. package/dist/core/events/v3/producers/recorder.d.ts +2 -4
  130. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  131. package/dist/core/events/v3/producers/recorder.js +109 -101
  132. package/dist/core/events/v3/recovery.d.ts.map +1 -1
  133. package/dist/core/events/v3/recovery.js +4 -3
  134. package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -1
  135. package/dist/core/events/v3/support-storage/inventory.js +2 -1
  136. package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -1
  137. package/dist/core/events/v3/support-storage/maintenance.js +4 -3
  138. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -1
  139. package/dist/core/events/v3/support-storage/pack-reader.js +4 -3
  140. package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -1
  141. package/dist/core/events/v3/support-storage/pack-writer.js +6 -5
  142. package/dist/core/events/v3/tool-line-changes.d.ts +8 -0
  143. package/dist/core/events/v3/tool-line-changes.d.ts.map +1 -0
  144. package/dist/core/events/v3/tool-line-changes.js +135 -0
  145. package/dist/core/events/v3/writer.d.ts.map +1 -1
  146. package/dist/core/events/v3/writer.js +8 -7
  147. package/dist/core/governor/planning.d.ts.map +1 -1
  148. package/dist/core/governor/planning.js +6 -5
  149. package/dist/core/governor/service.d.ts.map +1 -1
  150. package/dist/core/governor/service.js +12 -11
  151. package/dist/core/governor/state.d.ts.map +1 -1
  152. package/dist/core/governor/state.js +7 -6
  153. package/dist/core/guard/evaluator.js +1 -0
  154. package/dist/core/guard/storage.d.ts.map +1 -1
  155. package/dist/core/guard/storage.js +3 -2
  156. package/dist/core/hooks/adapter/behaviors/claude-code.d.ts +4 -0
  157. package/dist/core/hooks/adapter/behaviors/claude-code.d.ts.map +1 -0
  158. package/dist/core/hooks/adapter/behaviors/claude-code.js +31 -0
  159. package/dist/core/hooks/adapter/behaviors/codex.d.ts +15 -0
  160. package/dist/core/hooks/adapter/behaviors/codex.d.ts.map +1 -0
  161. package/dist/core/hooks/adapter/behaviors/codex.js +82 -0
  162. package/dist/core/hooks/adapter/behaviors/cursor.d.ts +7 -0
  163. package/dist/core/hooks/adapter/behaviors/cursor.d.ts.map +1 -0
  164. package/dist/core/hooks/adapter/behaviors/cursor.js +35 -0
  165. package/dist/core/hooks/adapter/behaviors/index.d.ts +11 -0
  166. package/dist/core/hooks/adapter/behaviors/index.d.ts.map +1 -0
  167. package/dist/core/hooks/adapter/behaviors/index.js +20 -0
  168. package/dist/core/hooks/adapter/behaviors/openclaw.d.ts +7 -0
  169. package/dist/core/hooks/adapter/behaviors/openclaw.d.ts.map +1 -0
  170. package/dist/core/hooks/adapter/behaviors/openclaw.js +34 -0
  171. package/dist/core/hooks/adapter/behaviors/opencode.d.ts +7 -0
  172. package/dist/core/hooks/adapter/behaviors/opencode.d.ts.map +1 -0
  173. package/dist/core/hooks/adapter/behaviors/opencode.js +34 -0
  174. package/dist/core/hooks/adapter/behaviors/types.d.ts +89 -0
  175. package/dist/core/hooks/adapter/behaviors/types.d.ts.map +1 -0
  176. package/dist/core/hooks/adapter/behaviors/types.js +1 -0
  177. package/dist/core/hooks/adapter/detect.d.ts +1 -1
  178. package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
  179. package/dist/core/hooks/adapter/detect.js +2 -3
  180. package/dist/core/hooks/adapter/events.d.ts +29 -1
  181. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  182. package/dist/core/hooks/adapter/events.js +31 -0
  183. package/dist/core/hooks/adapter/opencode-plugin.d.ts +60 -0
  184. package/dist/core/hooks/adapter/opencode-plugin.d.ts.map +1 -0
  185. package/dist/core/hooks/adapter/opencode-plugin.js +129 -0
  186. package/dist/core/hooks/adapter/output.d.ts +7 -0
  187. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  188. package/dist/core/hooks/adapter/output.js +8 -1
  189. package/dist/core/hooks/adapter/wiring.d.ts +15 -1
  190. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  191. package/dist/core/hooks/adapter/wiring.js +74 -11
  192. package/dist/core/hooks/cli.js +640 -531
  193. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  194. package/dist/core/hooks/effects/image-capture.js +2 -1
  195. package/dist/core/hooks/prompt-context/contract.d.ts.map +1 -1
  196. package/dist/core/hooks/prompt-context/contract.js +1 -0
  197. package/dist/core/hooks/resolve/transcript.d.ts +1 -1
  198. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  199. package/dist/core/hooks/resolve/transcript.js +35 -4
  200. package/dist/core/hooks/session-name-presence.d.ts +3 -1
  201. package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
  202. package/dist/core/hooks/session-name-presence.js +7 -2
  203. package/dist/core/hooks/shell-waiter.d.ts +2 -0
  204. package/dist/core/hooks/shell-waiter.d.ts.map +1 -0
  205. package/dist/core/hooks/shell-waiter.js +173 -0
  206. package/dist/core/resources/service.d.ts.map +1 -1
  207. package/dist/core/resources/service.js +5 -4
  208. package/dist/core/semantic/review.d.ts.map +1 -1
  209. package/dist/core/semantic/review.js +5 -4
  210. package/dist/core/semantic/service.d.ts.map +1 -1
  211. package/dist/core/semantic/service.js +15 -14
  212. package/dist/core/semantic/storage.d.ts.map +1 -1
  213. package/dist/core/semantic/storage.js +5 -4
  214. package/dist/core/storage/atomic-json.d.ts.map +1 -1
  215. package/dist/core/storage/atomic-json.js +7 -3
  216. package/dist/core/storage/durable-history.d.ts.map +1 -1
  217. package/dist/core/storage/durable-history.js +6 -5
  218. package/dist/core/storage/maintenance-providers.d.ts.map +1 -1
  219. package/dist/core/storage/maintenance-providers.js +2 -1
  220. package/dist/core/storage/maintenance.d.ts.map +1 -1
  221. package/dist/core/storage/maintenance.js +7 -6
  222. package/dist/core/storage/metrics.d.ts.map +1 -1
  223. package/dist/core/storage/metrics.js +5 -1
  224. package/dist/core/storage/modes.d.ts +17 -0
  225. package/dist/core/storage/modes.d.ts.map +1 -0
  226. package/dist/core/storage/modes.js +47 -0
  227. package/dist/core/storage/process-log.d.ts.map +1 -1
  228. package/dist/core/storage/process-log.js +3 -2
  229. package/dist/core/storage/receipts.d.ts.map +1 -1
  230. package/dist/core/storage/receipts.js +4 -3
  231. package/dist/core/storage/segments.d.ts.map +1 -1
  232. package/dist/core/storage/segments.js +7 -6
  233. package/dist/core/supervisor/hook-health.d.ts +2 -1
  234. package/dist/core/supervisor/hook-health.d.ts.map +1 -1
  235. package/dist/core/supervisor/hook-health.js +4 -3
  236. package/dist/core/supervisor/service.d.ts.map +1 -1
  237. package/dist/core/supervisor/service.js +7 -6
  238. package/dist/core/work/state.d.ts.map +1 -1
  239. package/dist/core/work/state.js +8 -7
  240. package/dist/core/workflow/adapters.d.ts +7 -0
  241. package/dist/core/workflow/adapters.d.ts.map +1 -1
  242. package/dist/core/workflow/adapters.js +9 -0
  243. package/dist/core/workflow/approvals.d.ts.map +1 -1
  244. package/dist/core/workflow/approvals.js +6 -5
  245. package/dist/core/workflow/billing.d.ts.map +1 -1
  246. package/dist/core/workflow/billing.js +33 -4
  247. package/dist/core/workflow/durable-record.d.ts.map +1 -1
  248. package/dist/core/workflow/durable-record.js +4 -3
  249. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  250. package/dist/core/workflow/live-session-v3.js +6 -4
  251. package/dist/core/workflow/run-state.d.ts.map +1 -1
  252. package/dist/core/workflow/run-state.js +3 -2
  253. package/dist/core/workflow/spawn-opencode.d.ts +36 -0
  254. package/dist/core/workflow/spawn-opencode.d.ts.map +1 -0
  255. package/dist/core/workflow/spawn-opencode.js +132 -0
  256. package/dist/core/workflow/transcript.d.ts.map +1 -1
  257. package/dist/core/workflow/transcript.js +3 -2
  258. package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
  259. package/dist/core/workflow/workspaces/leases.js +5 -4
  260. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  261. package/dist/core/workflow/workspaces/local-git.js +3 -2
  262. package/dist/core/workflow/workspaces/paths.d.ts.map +1 -1
  263. package/dist/core/workflow/workspaces/paths.js +2 -1
  264. package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
  265. package/dist/core/workflow/workspaces/state.js +10 -9
  266. package/dist/lazy-commands.js +8 -1
  267. package/dist/lib/agent-browser/client.d.ts +9 -0
  268. package/dist/lib/agent-browser/client.d.ts.map +1 -1
  269. package/dist/lib/agent-browser/client.js +13 -0
  270. package/dist/lib/browser/client.d.ts +35 -1
  271. package/dist/lib/browser/client.d.ts.map +1 -1
  272. package/dist/lib/browser/client.js +117 -8
  273. package/dist/lib/browser/identity.d.ts +25 -0
  274. package/dist/lib/browser/identity.d.ts.map +1 -0
  275. package/dist/lib/browser/identity.js +66 -0
  276. package/dist/lib/browser/index.d.ts +2 -1
  277. package/dist/lib/browser/index.d.ts.map +1 -1
  278. package/dist/lib/browser/index.js +2 -1
  279. package/dist/lib/browser/launch-args.d.ts +26 -0
  280. package/dist/lib/browser/launch-args.d.ts.map +1 -1
  281. package/dist/lib/browser/launch-args.js +41 -1
  282. package/dist/lib/browser/user-agent.d.ts +53 -0
  283. package/dist/lib/browser/user-agent.d.ts.map +1 -0
  284. package/dist/lib/browser/user-agent.js +79 -0
  285. package/dist/lib/docs-metadata-managed.d.ts +1 -0
  286. package/dist/lib/docs-metadata-managed.d.ts.map +1 -1
  287. package/dist/lib/docs-metadata-managed.js +17 -1
  288. package/dist/lib/identities/assume.d.ts.map +1 -1
  289. package/dist/lib/identities/assume.js +4 -9
  290. package/dist/lib/instructions/apply.d.ts.map +1 -1
  291. package/dist/lib/instructions/apply.js +2 -0
  292. package/dist/lib/pace/index.d.ts +2 -0
  293. package/dist/lib/pace/index.d.ts.map +1 -0
  294. package/dist/lib/pace/index.js +1 -0
  295. package/dist/lib/pace/pace.d.ts +95 -0
  296. package/dist/lib/pace/pace.d.ts.map +1 -0
  297. package/dist/lib/pace/pace.js +313 -0
  298. package/dist/lib/tunnel/forward-headers.d.ts +11 -0
  299. package/dist/lib/tunnel/forward-headers.d.ts.map +1 -0
  300. package/dist/lib/tunnel/forward-headers.js +17 -0
  301. package/dist/lib/tunnel/gate.js +15 -10
  302. package/dist/lib/webview/index.d.ts +2 -0
  303. package/dist/lib/webview/index.d.ts.map +1 -0
  304. package/dist/lib/webview/index.js +1 -0
  305. package/dist/lib/webview/webview.d.ts +116 -0
  306. package/dist/lib/webview/webview.d.ts.map +1 -0
  307. package/dist/lib/webview/webview.js +289 -0
  308. package/opencode-plugin/package.json +19 -0
  309. package/opencode-plugin/src/index.ts +791 -0
  310. package/package.json +11 -4
  311. package/schemas/config.schema.json +13 -0
  312. package/schemas/event-v3.schema.json +164 -0
  313. package/src/commander.ts +7 -0
  314. package/src/commands/agents.ts +33 -18
  315. package/src/commands/browse-ai.ts +8 -0
  316. package/src/commands/browse.ts +189 -10
  317. package/src/commands/checkpoint.ts +7 -9
  318. package/src/commands/deinit.ts +9 -4
  319. package/src/commands/docs.ts +2 -0
  320. package/src/commands/doctor.ts +11 -2
  321. package/src/commands/fetch.ts +14 -0
  322. package/src/commands/init.ts +281 -119
  323. package/src/commands/instructions.ts +8 -4
  324. package/src/commands/ledger-v3.ts +2 -1
  325. package/src/commands/webview.ts +159 -0
  326. package/src/core/adapter.ts +102 -1
  327. package/src/core/adapters/attestation.ts +3 -2
  328. package/src/core/adapters/profiles.ts +42 -1
  329. package/src/core/adapters/registry.ts +37 -0
  330. package/src/core/agents/canonical-emit.ts +2 -5
  331. package/src/core/agents/cli.ts +31 -20
  332. package/src/core/agents/coord-client.ts +9 -3
  333. package/src/core/agents/rules/claim-conflict.ts +3 -8
  334. package/src/core/agents/rules/commit-conflict.ts +2 -7
  335. package/src/core/agents/rules/stop-hook.ts +3 -1
  336. package/src/core/agents/session-events.ts +120 -26
  337. package/src/core/agents/session-finalization-state-v3.ts +2 -1
  338. package/src/core/agents/session-finalizer-v3.ts +5 -4
  339. package/src/core/agents/session-name-display.ts +48 -0
  340. package/src/core/agents/state/heartbeat-reader.ts +7 -0
  341. package/src/core/agents/state/heartbeat-writer.ts +24 -2
  342. package/src/core/agents/state/live-coordination-view.ts +1 -0
  343. package/src/core/agents/state/live-coordination-writer.ts +3 -0
  344. package/src/core/agents/state/names.ts +7 -9
  345. package/src/core/agents/state/stale-sweep.ts +2 -9
  346. package/src/core/agents/turn-changes.ts +97 -0
  347. package/src/core/artifacts/delivery-card.ts +2 -1
  348. package/src/core/artifacts/index.ts +4 -3
  349. package/src/core/config.ts +23 -0
  350. package/src/core/context/index.ts +2 -1
  351. package/src/core/conversations/archive.ts +4 -3
  352. package/src/core/diagnostics/bundle.ts +3 -2
  353. package/src/core/events/legacy-storage/canary.ts +5 -4
  354. package/src/core/events/legacy-storage/compression.ts +2 -1
  355. package/src/core/events/v3/adapter-id.ts +29 -1
  356. package/src/core/events/v3/authority-outbox.ts +2 -1
  357. package/src/core/events/v3/bootstrap.ts +5 -4
  358. package/src/core/events/v3/capabilities.ts +17 -0
  359. package/src/core/events/v3/contract.ts +9 -1
  360. package/src/core/events/v3/control-witness.ts +3 -2
  361. package/src/core/events/v3/coordination-transaction-recovery.ts +4 -3
  362. package/src/core/events/v3/fingerprint-keys.ts +7 -6
  363. package/src/core/events/v3/generated.ts +1 -1
  364. package/src/core/events/v3/live-feed.ts +5 -4
  365. package/src/core/events/v3/producers/command-recorder.ts +8 -6
  366. package/src/core/events/v3/producers/coordination-recorder.ts +8 -7
  367. package/src/core/events/v3/producers/diagnostic-summaries.ts +5 -4
  368. package/src/core/events/v3/producers/hook-base.ts +11 -4
  369. package/src/core/events/v3/producers/hook.ts +19 -1
  370. package/src/core/events/v3/producers/intake.ts +18 -6
  371. package/src/core/events/v3/producers/recorder.ts +123 -114
  372. package/src/core/events/v3/recovery.ts +4 -3
  373. package/src/core/events/v3/support-storage/inventory.ts +2 -1
  374. package/src/core/events/v3/support-storage/maintenance.ts +8 -3
  375. package/src/core/events/v3/support-storage/pack-reader.ts +4 -3
  376. package/src/core/events/v3/support-storage/pack-writer.ts +6 -5
  377. package/src/core/events/v3/tool-line-changes.ts +139 -0
  378. package/src/core/events/v3/writer.ts +8 -7
  379. package/src/core/governor/planning.ts +6 -5
  380. package/src/core/governor/service.ts +12 -11
  381. package/src/core/governor/state.ts +7 -6
  382. package/src/core/guard/evaluator.ts +1 -0
  383. package/src/core/guard/storage.ts +3 -2
  384. package/src/core/hooks/adapter/behaviors/claude-code.ts +33 -0
  385. package/src/core/hooks/adapter/behaviors/codex.ts +96 -0
  386. package/src/core/hooks/adapter/behaviors/cursor.ts +37 -0
  387. package/src/core/hooks/adapter/behaviors/index.ts +31 -0
  388. package/src/core/hooks/adapter/behaviors/openclaw.ts +36 -0
  389. package/src/core/hooks/adapter/behaviors/opencode.ts +36 -0
  390. package/src/core/hooks/adapter/behaviors/types.ts +110 -0
  391. package/src/core/hooks/adapter/detect.ts +2 -3
  392. package/src/core/hooks/adapter/events.ts +53 -1
  393. package/src/core/hooks/adapter/opencode-plugin.ts +177 -0
  394. package/src/core/hooks/adapter/output.ts +8 -1
  395. package/src/core/hooks/adapter/wiring.ts +85 -11
  396. package/src/core/hooks/cli.ts +738 -538
  397. package/src/core/hooks/effects/image-capture.ts +2 -1
  398. package/src/core/hooks/prompt-context/contract.ts +1 -0
  399. package/src/core/hooks/resolve/transcript.ts +42 -5
  400. package/src/core/hooks/session-name-presence.ts +10 -3
  401. package/src/core/hooks/shell-waiter.ts +166 -0
  402. package/src/core/resources/service.ts +5 -4
  403. package/src/core/semantic/review.ts +5 -4
  404. package/src/core/semantic/service.ts +15 -14
  405. package/src/core/semantic/storage.ts +5 -4
  406. package/src/core/storage/atomic-json.ts +7 -3
  407. package/src/core/storage/durable-history.ts +6 -5
  408. package/src/core/storage/maintenance-providers.ts +2 -1
  409. package/src/core/storage/maintenance.ts +7 -6
  410. package/src/core/storage/metrics.ts +5 -1
  411. package/src/core/storage/modes.ts +53 -0
  412. package/src/core/storage/process-log.ts +3 -2
  413. package/src/core/storage/receipts.ts +4 -3
  414. package/src/core/storage/segments.ts +7 -6
  415. package/src/core/supervisor/hook-health.ts +4 -4
  416. package/src/core/supervisor/service.ts +7 -6
  417. package/src/core/work/state.ts +8 -7
  418. package/src/core/workflow/adapters.ts +15 -0
  419. package/src/core/workflow/approvals.ts +6 -5
  420. package/src/core/workflow/billing.ts +34 -4
  421. package/src/core/workflow/durable-record.ts +4 -3
  422. package/src/core/workflow/live-session-v3.ts +6 -4
  423. package/src/core/workflow/run-state.ts +3 -2
  424. package/src/core/workflow/spawn-opencode.ts +150 -0
  425. package/src/core/workflow/transcript.ts +3 -2
  426. package/src/core/workflow/workspaces/leases.ts +5 -4
  427. package/src/core/workflow/workspaces/local-git.ts +3 -2
  428. package/src/core/workflow/workspaces/paths.ts +2 -1
  429. package/src/core/workflow/workspaces/state.ts +10 -9
  430. package/src/lazy-commands.ts +11 -1
  431. package/src/lib/agent-browser/client.ts +18 -0
  432. package/src/lib/browser/client.ts +147 -9
  433. package/src/lib/browser/identity.ts +64 -0
  434. package/src/lib/browser/index.ts +15 -1
  435. package/src/lib/browser/launch-args.ts +53 -1
  436. package/src/lib/browser/user-agent.ts +130 -0
  437. package/src/lib/docs-metadata-managed.ts +21 -0
  438. package/src/lib/identities/assume.ts +7 -7
  439. package/src/lib/instructions/apply.ts +2 -0
  440. package/src/lib/pace/index.ts +14 -0
  441. package/src/lib/pace/pace.ts +370 -0
  442. package/src/lib/tunnel/forward-headers.ts +16 -0
  443. package/src/lib/tunnel/gate.ts +18 -10
  444. package/src/lib/webview/index.ts +13 -0
  445. package/src/lib/webview/webview.ts +457 -0
@@ -1,8 +1,10 @@
1
1
  import { writeFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { resolve } from "node:path";
4
+ import { resolveUserAgent } from "../lib/browser/user-agent.js";
4
5
  import { CookieJar } from "../lib/cookies/index.js";
5
6
  import { fetchWithJar } from "../lib/http/index.js";
7
+ import { commandPaceGate } from "../lib/pace/index.js";
6
8
  /**
7
9
  * `harn fetch`: HTTP request with cookie-jar attach + persist.
8
10
  *
@@ -22,6 +24,8 @@ export function registerFetchCommand(program, emit, context) {
22
24
  .option("-o, --output <file>", "Write response body to file (default: stdout)")
23
25
  .option("--store <path>", `Cookie store path (default ${DEFAULT_STORE})`)
24
26
  .option("--no-cookies", "Skip cookie-jar attach + persist")
27
+ .option("--no-pace", "Skip the human-pace gap (3 to 9 s) between requests to the same site for this run. " +
28
+ "HARNERY_PACE=off disables it machine-wide; local and private hosts never wait.")
25
29
  .option("--redirect <mode>", "Redirect handling: follow | error | manual", "follow")
26
30
  .option("--timeout <ms>", "Request timeout in milliseconds", "30000")
27
31
  .option("--status", "Print status to stderr")
@@ -40,6 +44,11 @@ export function registerFetchCommand(program, emit, context) {
40
44
  }
41
45
  async function runFetch(url, opts, emit, context) {
42
46
  const headers = {};
47
+ {
48
+ const ua = resolveUserAgent({ env: process.env.HARNERY_BROWSER_UA });
49
+ if (ua)
50
+ headers["User-Agent"] = ua;
51
+ }
43
52
  for (const h of opts.header ?? []) {
44
53
  const idx = h.indexOf(":");
45
54
  if (idx < 0) {
@@ -50,6 +59,7 @@ async function runFetch(url, opts, emit, context) {
50
59
  const jar = opts.cookies !== false
51
60
  ? new CookieJar({ path: opts.store ?? DEFAULT_STORE, source: "harn-fetch" })
52
61
  : null;
62
+ await commandPaceGate(opts.pace !== false, (message) => emit.log(message, "info"))?.before(url);
53
63
  const timeoutMs = Number.parseInt(opts.timeout, 10);
54
64
  const ac = new AbortController();
55
65
  const timer = setTimeout(() => ac.abort(), timeoutMs);
@@ -7,9 +7,13 @@
7
7
  * null and every hook no-ops forever.
8
8
  * 2. Register the agent-hook entries in the adapter settings file.
9
9
  *
10
- * Wires whichever adapter `--adapter` names (Claude Code `.claude/settings.json`,
11
- * Cursor `.cursor/hooks.json`, or Codex `.codex/hooks.json`): the per-adapter
12
- * file path, event list, and hook-entry shape all come from ADAPTER_SPECS.
10
+ * Wires every adapter in the resolved set (Claude Code `.claude/settings.json`,
11
+ * Cursor `.cursor/hooks.json`, Codex `.codex/hooks.json`, or the OpenCode plugin
12
+ * directory `.opencode/plugins/harnery/`): the per-adapter file path, event list,
13
+ * and hook-entry shape all come from ADAPTER_SPECS. `--adapter` is repeatable (or
14
+ * comma-separated, or `all`); with no flag, init wires every adapter whose CLI is
15
+ * installed on this machine, plus any adapter the project already has wired, else
16
+ * claude-code.
13
17
  *
14
18
  * `harn init` does both, non-destructively: it merges hook entries into an
15
19
  * existing settings file (preserving any other hooks) and skips entries that are
@@ -20,6 +24,18 @@ import type { EmitContext } from "../commander.js";
20
24
  import type { EventV3ControlState } from "../core/events/v3/control.js";
21
25
  import { type AdapterId, type AdapterSpec } from "../core/hooks/adapter/events.js";
22
26
  import { type SettingsFile } from "../core/hooks/adapter/wiring.js";
27
+ /**
28
+ * Which adapters `init` should wire. An explicit `--adapter` wins. Without one:
29
+ * every adapter whose CLI is installed on this machine, plus every adapter the
30
+ * project already has wired (committed wiring stays current on a box whose CLI is
31
+ * absent, e.g. CI). A machine with neither falls back to the historical
32
+ * claude-code default. `installed` is injectable so tests never key on the host's
33
+ * toolchain.
34
+ */
35
+ export declare function resolveInitAdapters(projectRoot: string, requested: string[], installed?: AdapterId[]): {
36
+ adapters: AdapterId[];
37
+ error?: string;
38
+ };
23
39
  export declare function registerInitCommand(program: Command, emit: EmitContext, binName?: string): void;
24
40
  /**
25
41
  * Runtime contracts bound into an immutable V3 epoch. `init` replaces the
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAInD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAOxE,OAAO,EAAiB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAClG,OAAO,EASL,KAAK,YAAY,EAClB,MAAM,iCAAiC,CAAC;AAqBzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAgT/F;AAiBD;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAiBjF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAOvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,SAAS,GACjB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CA8CvE;AAwFD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAa1F;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAmDhG;AASD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAkCxF"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAOH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAInD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAOxE,OAAO,EAAiB,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAKlG,OAAO,EAWL,KAAK,YAAY,EAElB,MAAM,iCAAiC,CAAC;AA0CzC;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,CAAC,EAAE,SAAS,EAAE,GACtB;IAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAM3C;AAyFD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CA8T/F;AAiBD;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAiBjF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAOvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,SAAS,GACjB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAsDvE;AAyFD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAa1F;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAmDhG;AASD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAkCxF"}
@@ -7,9 +7,13 @@
7
7
  * null and every hook no-ops forever.
8
8
  * 2. Register the agent-hook entries in the adapter settings file.
9
9
  *
10
- * Wires whichever adapter `--adapter` names (Claude Code `.claude/settings.json`,
11
- * Cursor `.cursor/hooks.json`, or Codex `.codex/hooks.json`): the per-adapter
12
- * file path, event list, and hook-entry shape all come from ADAPTER_SPECS.
10
+ * Wires every adapter in the resolved set (Claude Code `.claude/settings.json`,
11
+ * Cursor `.cursor/hooks.json`, Codex `.codex/hooks.json`, or the OpenCode plugin
12
+ * directory `.opencode/plugins/harnery/`): the per-adapter file path, event list,
13
+ * and hook-entry shape all come from ADAPTER_SPECS. `--adapter` is repeatable (or
14
+ * comma-separated, or `all`); with no flag, init wires every adapter whose CLI is
15
+ * installed on this machine, plus any adapter the project already has wired, else
16
+ * claude-code.
13
17
  *
14
18
  * `harn init` does both, non-destructively: it merges hook entries into an
15
19
  * existing settings file (preserving any other hooks) and skips entries that are
@@ -26,13 +30,122 @@ import { ADAPTER_CAPABILITY_PROFILES_V3 } from "../core/events/v3/capabilities.j
26
30
  import { EVENT_V3_SCHEMA_DIGEST } from "../core/events/v3/generated.js";
27
31
  import { initializeEventLedgerV3, readEventV3ControlState, sha256V3, } from "../core/events/v3/index.js";
28
32
  import { ADAPTER_SPECS } from "../core/hooks/adapter/events.js";
29
- import { agentHookPathForProject, commandWiresSubcommand, diffWiring, groupCommands, hookCommand, isAgentHookCommand, makeEntry, } from "../core/hooks/adapter/wiring.js";
33
+ import { checkOpenCodePlugin, installOpenCodePlugin, } from "../core/hooks/adapter/opencode-plugin.js";
34
+ import { agentHookPathForProject, applyCursorStopLoopLimit, CURSOR_STOP_FOLLOWUP_LOOP_LIMIT, commandWiresSubcommand, diffWiring, groupCommands, hookCommand, isAgentHookCommand, makeEntry, summarizeAdapterWiring, } from "../core/hooks/adapter/wiring.js";
35
+ import { detectInstalledAdapters } from "../core/workflow/adapters.js";
30
36
  import { applyIndexerExclusions } from "../lib/indexer-exclusions.js";
31
37
  import { applyInstructions, checkInstructions, } from "../lib/instructions/apply.js";
32
38
  import { applyGitHooks, checkGitHooks } from "../lib/instructions/git-hooks.js";
33
39
  import { HostAddendumError } from "../lib/instructions/host-addendum.js";
34
40
  // This file is src/commands/init.ts → harnery package root is two levels up.
35
41
  const HARNERY_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
42
+ const ADAPTER_IDS = Object.keys(ADAPTER_SPECS);
43
+ /** Parse explicit `--adapter` values; `all` expands and order is preserved, deduplicated. */
44
+ function parseAdapterIds(requested) {
45
+ const adapters = [];
46
+ for (const raw of requested) {
47
+ const ids = raw === "all" ? ADAPTER_IDS : [raw];
48
+ for (const id of ids) {
49
+ if (!(id in ADAPTER_SPECS)) {
50
+ return {
51
+ adapters: [],
52
+ error: `Unknown adapter '${raw}'. Expected: ${ADAPTER_IDS.join(" | ")} | all.`,
53
+ };
54
+ }
55
+ if (!adapters.includes(id))
56
+ adapters.push(id);
57
+ }
58
+ }
59
+ return { adapters };
60
+ }
61
+ /**
62
+ * Which adapters `init` should wire. An explicit `--adapter` wins. Without one:
63
+ * every adapter whose CLI is installed on this machine, plus every adapter the
64
+ * project already has wired (committed wiring stays current on a box whose CLI is
65
+ * absent, e.g. CI). A machine with neither falls back to the historical
66
+ * claude-code default. `installed` is injectable so tests never key on the host's
67
+ * toolchain.
68
+ */
69
+ export function resolveInitAdapters(projectRoot, requested, installed) {
70
+ if (requested.length > 0)
71
+ return parseAdapterIds(requested);
72
+ const detected = installed ?? detectInstalledAdapters();
73
+ const wired = summarizeAdapterWiring(projectRoot).wired;
74
+ const adapters = ADAPTER_IDS.filter((id) => detected.includes(id) || wired.includes(id));
75
+ return { adapters: adapters.length > 0 ? adapters : ["claude-code"] };
76
+ }
77
+ /** Drift check for one adapter's runtime wiring (settings hooks or the OpenCode plugin). */
78
+ function checkAdapterHooks(projectRoot, adapter, bin) {
79
+ const spec = ADAPTER_SPECS[adapter];
80
+ const agentHook = agentHookPathForProject(projectRoot, HARNERY_ROOT);
81
+ if (spec.installMode === "opencode-plugin") {
82
+ // No hooks map to diff: the plugin directory is the wiring.
83
+ const plugin = checkOpenCodePlugin(projectRoot, { binName: bin, agentHook });
84
+ if (plugin.status === "missing") {
85
+ return {
86
+ drift: true,
87
+ error: false,
88
+ issues: [`${spec.settingsFile}: missing (re-run \`init --adapter opencode\`)`],
89
+ };
90
+ }
91
+ if (plugin.status === "foreign")
92
+ return { drift: false, error: true, issues: plugin.issues };
93
+ if (plugin.status === "stale")
94
+ return { drift: true, error: false, issues: plugin.issues };
95
+ return { drift: false, error: false, issues: [] };
96
+ }
97
+ const settingsPath = resolve(projectRoot, spec.settingsFile);
98
+ if (!existsSync(settingsPath)) {
99
+ return { drift: true, error: false, issues: [`${spec.settingsFile}: missing (re-run init)`] };
100
+ }
101
+ const issues = [];
102
+ let drift = false;
103
+ try {
104
+ const settings = JSON.parse(readFileSync(settingsPath, "utf8"));
105
+ const hookDiff = diffWiring(settings, spec, { agentHookPath: agentHook, adapter });
106
+ drift =
107
+ hookDiff.missing.length > 0 ||
108
+ hookDiff.stale.length > 0 ||
109
+ hookDiff.duplicates.length > 0 ||
110
+ hookDiff.misplaced.length > 0 ||
111
+ hookDiff.orphans.length > 0 ||
112
+ hookDiff.invalidTopLevelKeys.length > 0 ||
113
+ hookDiff.invalidEventKeys.length > 0;
114
+ if (hookDiff.missing.length > 0) {
115
+ issues.push(`${spec.settingsFile}: missing hooks (${hookDiff.missing.map((e) => e.settingsKey).join(", ")})`);
116
+ }
117
+ if (hookDiff.stale.length > 0) {
118
+ issues.push(`${spec.settingsFile}: stale hook commands (${hookDiff.stale.map((e) => e.settingsKey).join(", ")})`);
119
+ }
120
+ if (hookDiff.duplicates.length > 0) {
121
+ issues.push(`${spec.settingsFile}: duplicate hooks (${hookDiff.duplicates.map((e) => e.settingsKey).join(", ")})`);
122
+ }
123
+ if (hookDiff.misplaced.length > 0) {
124
+ issues.push(`${spec.settingsFile}: hooks under the wrong event (${hookDiff.misplaced.map((e) => e.subcommand).join(", ")})`);
125
+ }
126
+ if (hookDiff.orphans.length > 0) {
127
+ issues.push(`${spec.settingsFile}: obsolete hooks (${hookDiff.orphans.join(", ")})`);
128
+ }
129
+ if (hookDiff.invalidTopLevelKeys.length > 0) {
130
+ issues.push(`${spec.settingsFile}: invalid fields (${hookDiff.invalidTopLevelKeys.join(", ")})`);
131
+ }
132
+ if (hookDiff.invalidEventKeys.length > 0) {
133
+ issues.push(`${spec.settingsFile}: unsupported events (${hookDiff.invalidEventKeys.join(", ")})`);
134
+ }
135
+ }
136
+ catch (error) {
137
+ return {
138
+ drift: false,
139
+ error: true,
140
+ issues: [`${spec.settingsFile}: invalid JSON (${error.message})`],
141
+ };
142
+ }
143
+ return { drift, error: false, issues };
144
+ }
145
+ /** Preserve first-seen order while dropping repeats (one pass per adapter repeats lines). */
146
+ function dedupe(values) {
147
+ return [...new Set(values)];
148
+ }
36
149
  export function registerInitCommand(program, emit, binName) {
37
150
  program
38
151
  .command("init")
@@ -40,19 +153,16 @@ export function registerInitCommand(program, emit, binName) {
40
153
  "hooks, and inject the agent-facing instructions block + skills " +
41
154
  "(idempotent; safe to re-run). Use --dry-run to preview, --check to " +
42
155
  "report drift without writing (exit 0 fresh / 2 drift / 1 error).")
43
- .option("--adapter <id>", "claude-code | cursor | codex", "claude-code")
156
+ .option("--adapter <id>", "claude-code | cursor | codex | opencode | all; repeatable or comma-separated. " +
157
+ "Default: every adapter installed on this machine plus every adapter already wired, else claude-code", (value, previous) => previous.concat(value
158
+ .split(",")
159
+ .map((id) => id.trim())
160
+ .filter(Boolean)), [])
44
161
  .option("--dry-run", "Show what would change without writing")
45
162
  .option("--check", "Report managed-surface drift without writing; exit 0/2/1")
46
163
  .option("--instructions-only", "Refresh only AGENTS.md regions and Harnery-owned skills; leave runtime wiring untouched")
47
164
  .option("--project-root <path>", "Project root (default: git toplevel, else cwd)")
48
165
  .action((opts) => {
49
- const adapter = opts.adapter;
50
- const spec = ADAPTER_SPECS[adapter];
51
- if (!spec) {
52
- emit.text(`Unknown adapter '${opts.adapter}'. Expected: claude-code | cursor | codex.`);
53
- emit.setExitCode(1);
54
- return;
55
- }
56
166
  const projectRoot = resolve(opts.projectRoot ?? gitTopLevel() ?? process.cwd());
57
167
  // A binName already pinned in this project's config.jsonc beats the
58
168
  // invoking CLI's name: the pin is a committed, deliberate declaration;
@@ -66,6 +176,15 @@ export function registerInitCommand(program, emit, binName) {
66
176
  // before every coord-root, config, ledger, adapter-settings, and Git-hook
67
177
  // operation so its no-runtime-writes contract is structural.
68
178
  if (opts.instructionsOnly === true) {
179
+ // Narrow by design: host sync tooling depends on one deterministic
180
+ // guidance layout, so this mode stays single-adapter and never detects.
181
+ const parsed = parseAdapterIds(opts.adapter);
182
+ if (parsed.error) {
183
+ emit.text(parsed.error);
184
+ emit.setExitCode(1);
185
+ return;
186
+ }
187
+ const adapter = parsed.adapters[0] ?? "claude-code";
69
188
  if (opts.check === true) {
70
189
  const { status, issues } = checkInstructions(projectRoot, { binName: bin, adapter });
71
190
  const head = status === "fresh"
@@ -95,55 +214,31 @@ export function registerInitCommand(program, emit, binName) {
95
214
  emit.text(renderInstructionsOnly(projectRoot, bin, dryRun, applied.actions, applied.warnings));
96
215
  return;
97
216
  }
217
+ const resolved = resolveInitAdapters(projectRoot, opts.adapter);
218
+ if (resolved.error) {
219
+ emit.text(resolved.error);
220
+ emit.setExitCode(1);
221
+ return;
222
+ }
223
+ const adapters = resolved.adapters;
98
224
  // ── --check: read-only drift report on every init-managed surface ─────
99
225
  if (opts.check === true) {
100
- const { status, issues } = checkInstructions(projectRoot, { binName: bin, adapter });
226
+ const issues = [];
227
+ let instructionStatus = "fresh";
101
228
  let hookCheckError = false;
102
229
  let hookDrift = false;
103
- const settingsPath = resolve(projectRoot, spec.settingsFile);
104
- const agentHook = agentHookPathForProject(projectRoot, HARNERY_ROOT);
105
- if (!existsSync(settingsPath)) {
106
- hookDrift = true;
107
- issues.push(`${spec.settingsFile}: missing (re-run init)`);
108
- }
109
- else {
110
- try {
111
- const settings = JSON.parse(readFileSync(settingsPath, "utf8"));
112
- const hookDiff = diffWiring(settings, spec, { agentHookPath: agentHook, adapter });
113
- hookDrift =
114
- hookDiff.missing.length > 0 ||
115
- hookDiff.stale.length > 0 ||
116
- hookDiff.duplicates.length > 0 ||
117
- hookDiff.misplaced.length > 0 ||
118
- hookDiff.orphans.length > 0 ||
119
- hookDiff.invalidTopLevelKeys.length > 0 ||
120
- hookDiff.invalidEventKeys.length > 0;
121
- if (hookDiff.missing.length > 0) {
122
- issues.push(`${spec.settingsFile}: missing hooks (${hookDiff.missing.map((e) => e.settingsKey).join(", ")})`);
123
- }
124
- if (hookDiff.stale.length > 0) {
125
- issues.push(`${spec.settingsFile}: stale hook commands (${hookDiff.stale.map((e) => e.settingsKey).join(", ")})`);
126
- }
127
- if (hookDiff.duplicates.length > 0) {
128
- issues.push(`${spec.settingsFile}: duplicate hooks (${hookDiff.duplicates.map((e) => e.settingsKey).join(", ")})`);
129
- }
130
- if (hookDiff.misplaced.length > 0) {
131
- issues.push(`${spec.settingsFile}: hooks under the wrong event (${hookDiff.misplaced.map((e) => e.subcommand).join(", ")})`);
132
- }
133
- if (hookDiff.orphans.length > 0) {
134
- issues.push(`${spec.settingsFile}: obsolete hooks (${hookDiff.orphans.join(", ")})`);
135
- }
136
- if (hookDiff.invalidTopLevelKeys.length > 0) {
137
- issues.push(`${spec.settingsFile}: invalid fields (${hookDiff.invalidTopLevelKeys.join(", ")})`);
138
- }
139
- if (hookDiff.invalidEventKeys.length > 0) {
140
- issues.push(`${spec.settingsFile}: unsupported events (${hookDiff.invalidEventKeys.join(", ")})`);
141
- }
142
- }
143
- catch (error) {
144
- hookCheckError = true;
145
- issues.push(`${spec.settingsFile}: invalid JSON (${error.message})`);
230
+ for (const adapter of adapters) {
231
+ const instructions = checkInstructions(projectRoot, { binName: bin, adapter });
232
+ if (instructions.status === "error")
233
+ instructionStatus = "error";
234
+ else if (instructions.status === "drift" && instructionStatus !== "error") {
235
+ instructionStatus = "drift";
146
236
  }
237
+ issues.push(...instructions.issues);
238
+ const hooks = checkAdapterHooks(projectRoot, adapter, bin);
239
+ hookCheckError = hookCheckError || hooks.error;
240
+ hookDrift = hookDrift || hooks.drift;
241
+ issues.push(...hooks.issues);
147
242
  }
148
243
  const gitHooks = checkGitHooks(projectRoot);
149
244
  if (gitHooks.status !== "fresh")
@@ -155,20 +250,25 @@ export function registerInitCommand(program, emit, binName) {
155
250
  if (ledgerRuntimeIssues.length > 0) {
156
251
  issues.push(`event ledger V3 is runtime-stale (${ledgerRuntimeIssues.join(", ")})`);
157
252
  }
158
- const merged = status === "error" || hookCheckError
253
+ const merged = instructionStatus === "error" || hookCheckError
159
254
  ? "error"
160
255
  : hookDrift ||
256
+ instructionStatus === "drift" ||
161
257
  gitHooks.status !== "fresh" ||
162
258
  ledger.state !== "active" ||
163
259
  ledgerRuntimeIssues.length > 0
164
260
  ? "drift"
165
- : status;
261
+ : "fresh";
166
262
  const head = merged === "fresh"
167
263
  ? "harn init --check: hooks + instructions + skills + event ledger V3 are current"
168
264
  : merged === "drift"
169
265
  ? "harn init --check: drift found (re-run `init` to refresh)"
170
266
  : "harn init --check: error";
171
- const lines = issues.length ? `\n${issues.map((i) => ` ✗ ${i}`).join("\n")}` : "";
267
+ const lines = issues.length
268
+ ? `\n${dedupe(issues)
269
+ .map((i) => ` ✗ ${i}`)
270
+ .join("\n")}`
271
+ : "";
172
272
  emit.text(`${head}${lines}`);
173
273
  emit.setExitCode(merged === "fresh" ? 0 : merged === "drift" ? 2 : 1);
174
274
  return;
@@ -247,63 +347,87 @@ export function registerInitCommand(program, emit, binName) {
247
347
  : "· event ledger V3 already active");
248
348
  }
249
349
  // ── 2. adapter hooks ───────────────────────────────────────────────────
250
- const settingsPath = resolve(projectRoot, spec.settingsFile);
251
- const agentHook = agentHookPathForProject(projectRoot, HARNERY_ROOT);
252
- let settings;
253
- if (existsSync(settingsPath)) {
350
+ for (const adapter of adapters) {
351
+ const spec = ADAPTER_SPECS[adapter];
352
+ const settingsPath = resolve(projectRoot, spec.settingsFile);
353
+ const agentHook = agentHookPathForProject(projectRoot, HARNERY_ROOT);
354
+ if (spec.installMode === "opencode-plugin") {
355
+ // OpenCode has no hooks map. Install the plugin directory instead; the
356
+ // instructions + skills step below still runs (AGENTS.md and
357
+ // .agents/skills are read natively, so no shim or mirror is needed).
358
+ const plugin = installOpenCodePlugin(projectRoot, { binName: bin, agentHook, dryRun });
359
+ if (plugin.error) {
360
+ emit.text(plugin.error);
361
+ emit.setExitCode(1);
362
+ return;
363
+ }
364
+ actions.push(...plugin.actions);
365
+ }
366
+ else {
367
+ let settings;
368
+ if (existsSync(settingsPath)) {
369
+ try {
370
+ settings = JSON.parse(readFileSync(settingsPath, "utf8"));
371
+ }
372
+ catch (err) {
373
+ emit.text(`✗ ${rel(projectRoot, settingsPath)} exists but isn't valid JSON; refusing to ` +
374
+ `overwrite. Fix it and re-run.\n (${err.message})`);
375
+ emit.setExitCode(1);
376
+ return;
377
+ }
378
+ }
379
+ else {
380
+ settings = {};
381
+ }
382
+ const { wired, already, removed, upgraded } = wireHooks(settings, spec, agentHook, adapter);
383
+ if (wired === 0 && removed === 0 && upgraded === 0) {
384
+ actions.push(`· all ${spec.events.length} ${adapter} hooks already wired in ${rel(projectRoot, settingsPath)}`);
385
+ }
386
+ else if (dryRun) {
387
+ actions.push(`+ would wire ${wired} hook(s), upgrade ${upgraded} stale command(s), and remove ` +
388
+ `${removed} obsolete/duplicate command(s) in ${rel(projectRoot, settingsPath)} (${already} already present)`);
389
+ }
390
+ else {
391
+ mkdirSync(dirname(settingsPath), { recursive: true });
392
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`);
393
+ actions.push(`+ wired ${wired} hook(s), upgraded ${upgraded} stale command(s), and removed ` +
394
+ `${removed} obsolete/duplicate command(s) in ${rel(projectRoot, settingsPath)} (${already} already present)`);
395
+ }
396
+ const authorizationReview = codexHookReviewAction(adapter);
397
+ if (authorizationReview)
398
+ actions.push(authorizationReview);
399
+ }
400
+ }
401
+ // ── 3. agent-facing instructions block + skills ────────────────────────
402
+ // Idempotent per adapter: the AGENTS.md block is adapter-independent, the
403
+ // harn-* skills land in each adapter's directory, and the CLAUDE.md shim and
404
+ // Cursor rule exist only for their own adapter. A misconfigured host addendum
405
+ // aborts here rather than half-writing: the apply step validates the
406
+ // configured source before it touches a file, so a bad path leaves the repo
407
+ // exactly as it found it.
408
+ const warnings = [];
409
+ for (const adapter of adapters) {
410
+ let applied;
254
411
  try {
255
- settings = JSON.parse(readFileSync(settingsPath, "utf8"));
412
+ applied = applyInstructions(projectRoot, { binName: bin, adapter, dryRun });
256
413
  }
257
414
  catch (err) {
258
- emit.text(`✗ ${rel(projectRoot, settingsPath)} exists but isn't valid JSON; refusing to ` +
259
- `overwrite. Fix it and re-run.\n (${err.message})`);
415
+ if (!(err instanceof HostAddendumError))
416
+ throw err;
417
+ emit.text(`${bin} init: ${err.message}`);
260
418
  emit.setExitCode(1);
261
419
  return;
262
420
  }
421
+ actions.push(...applied.actions);
422
+ warnings.push(...applied.warnings);
263
423
  }
264
- else {
265
- settings = {};
266
- }
267
- const { wired, already, removed, upgraded } = wireHooks(settings, spec, agentHook, adapter);
268
- if (wired === 0 && removed === 0 && upgraded === 0) {
269
- actions.push(`· all ${spec.events.length} ${adapter} hooks already wired in ${rel(projectRoot, settingsPath)}`);
270
- }
271
- else if (dryRun) {
272
- actions.push(`+ would wire ${wired} hook(s), upgrade ${upgraded} stale command(s), and remove ` +
273
- `${removed} obsolete/duplicate command(s) in ${rel(projectRoot, settingsPath)} (${already} already present)`);
274
- }
275
- else {
276
- mkdirSync(dirname(settingsPath), { recursive: true });
277
- writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`);
278
- actions.push(`+ wired ${wired} hook(s), upgraded ${upgraded} stale command(s), and removed ` +
279
- `${removed} obsolete/duplicate command(s) in ${rel(projectRoot, settingsPath)} (${already} already present)`);
280
- }
281
- const authorizationReview = codexHookReviewAction(adapter);
282
- if (authorizationReview)
283
- actions.push(authorizationReview);
284
- // ── 3. agent-facing instructions block + skills ────────────────────────
285
- // A misconfigured host addendum aborts here rather than half-writing: the
286
- // apply step validates the configured source before it touches a file, so
287
- // a bad path leaves the repo exactly as it found it.
288
- let applied;
289
- try {
290
- applied = applyInstructions(projectRoot, { binName: bin, adapter, dryRun });
291
- }
292
- catch (err) {
293
- if (!(err instanceof HostAddendumError))
294
- throw err;
295
- emit.text(`${bin} init: ${err.message}`);
296
- emit.setExitCode(1);
297
- return;
298
- }
299
- actions.push(...applied.actions);
300
424
  // ── 4. git-hook managed regions ────────────────────────────────────────
301
425
  // Same lifecycle contract as the instructions block: the coordination
302
426
  // content of the consumer's git hooks is machine-owned and versioned;
303
427
  // everything else in those files belongs to the host.
304
428
  const gitHooks = applyGitHooks(projectRoot, { dryRun });
305
429
  actions.push(...gitHooks.actions);
306
- emit.text(render(projectRoot, dryRun, actions, [...applied.warnings, ...gitHooks.warnings]));
430
+ emit.text(render(projectRoot, dryRun, dedupe(actions), dedupe([...warnings, ...gitHooks.warnings])));
307
431
  });
308
432
  }
309
433
  function gitBuild(root) {
@@ -400,7 +524,9 @@ export function wireHooks(settings, spec, agentHookPath, adapter) {
400
524
  continue;
401
525
  }
402
526
  const current = settings.hooks[settingsKey] ?? [];
403
- current.push(makeEntry(spec.entryShape, command));
527
+ current.push(makeEntry(spec.entryShape, command, spec.entryShape === "cursor" && subcommand === "stop"
528
+ ? { loop_limit: CURSOR_STOP_FOLLOWUP_LOOP_LIMIT }
529
+ : undefined));
404
530
  settings.hooks[settingsKey] = current;
405
531
  wired++;
406
532
  }
@@ -429,6 +555,8 @@ function normalizeEventGroup(group, subcommand, canonical, alreadyFound) {
429
555
  group.command = canonical;
430
556
  upgraded++;
431
557
  }
558
+ if (applyCursorStopLoopLimit(group, subcommand))
559
+ upgraded++;
432
560
  }
433
561
  }
434
562
  if ("hooks" in group && Array.isArray(group.hooks)) {
@@ -11,7 +11,7 @@ export function registerInstructionsCommand(program, emit) {
11
11
  command
12
12
  .command("manifest [paths...]")
13
13
  .description("Emit a machine-readable bundle manifest for one or more working paths")
14
- .option("--adapter <adapter>", "claude-code, cursor, codex, or all", "all")
14
+ .option("--adapter <adapter>", "claude-code, cursor, codex, opencode, or all", "all")
15
15
  .option("--format <type>", "Output format: json or table", "json")
16
16
  .option("-o, --output <file>", "Write the complete JSON manifest to a file")
17
17
  .action((paths, options) => {
@@ -49,10 +49,11 @@ export function registerInstructionsCommand(program, emit) {
49
49
  }
50
50
  function parseAdapters(value) {
51
51
  if (value === "all")
52
- return ["claude-code", "cursor", "codex"];
53
- if (value === "claude-code" || value === "cursor" || value === "codex")
52
+ return ["claude-code", "cursor", "codex", "opencode"];
53
+ if (value === "claude-code" || value === "cursor" || value === "codex" || value === "opencode") {
54
54
  return [value];
55
- throw new Error(`unsupported adapter '${value}' (expected claude-code, cursor, codex, or all)`);
55
+ }
56
+ throw new Error(`unsupported adapter '${value}' (expected claude-code, cursor, codex, opencode, or all)`);
56
57
  }
57
58
  function enrichBundle(bundle, coordRoot) {
58
59
  const components = bundle.components.map((component) => enrichComponent(component, coordRoot));
@@ -1 +1 @@
1
- {"version":3,"file":"ledger-v3.d.ts","sourceRoot":"","sources":["../../src/commands/ledger-v3.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAuC1E,2DAA2D;AAC3D,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAgbN"}
1
+ {"version":3,"file":"ledger-v3.d.ts","sourceRoot":"","sources":["../../src/commands/ledger-v3.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAwC1E,2DAA2D;AAC3D,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAgbN"}
@@ -5,6 +5,7 @@ import { resolve } from "node:path";
5
5
  import { compressSealedLegacyV1Segments, inventoryLegacyV1Segments, streamLegacyV1Rows, verifyLegacyV1HardFence, writeLegacyV1Canary, } from "../core/events/legacy-storage/index.js";
6
6
  import { cleanEventV3Archives, initializeEventLedgerV3, inventoryEventV3Archives, listHookProducerStateRecordsV3, readEventV3ControlState, recoverInvalidEventLedgerV3, sha256V3, } from "../core/events/v3/index.js";
7
7
  import { authorizeEventV3SupportReplacement, inventoryEventV3Support, planEventV3SupportReplacement, planEventV3SupportTransaction, readEventV3SupportPackManifest, readEventV3SupportTransaction, streamEventV3SupportPackRecords, unpackEventV3SupportPack, verifyEventV3SupportTransactionShadow, writeEventV3SupportTransactionShadow, } from "../core/events/v3/support-storage/index.js";
8
+ import { stateDirMode } from "../core/storage/modes.js";
8
9
  /** Inspect or initialize the universal V3 event ledger. */
9
10
  export function registerLedgerV3Command(program, emit, context) {
10
11
  const command = program
@@ -210,7 +211,7 @@ export function registerLedgerV3Command(program, emit, context) {
210
211
  }
211
212
  const root = resolve(options.root ?? coordRoot(context));
212
213
  const transactions = transactionRoot(root);
213
- mkdirSync(transactions, { recursive: true, mode: 0o700 });
214
+ mkdirSync(transactions, { recursive: true, mode: stateDirMode() });
214
215
  emit.data(await planEventV3SupportTransaction({
215
216
  transaction_root: transactions,
216
217
  authority_root: resolve(options.authorityRoot),
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { EmitContext } from "../commander.js";
3
+ export declare function registerWebviewCommand(program: Command, emit: EmitContext, binName: string): void;
4
+ //# sourceMappingURL=webview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webview.d.ts","sourceRoot":"","sources":["../../src/commands/webview.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAyCnD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CA2DjG"}