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.
- package/README.md +1 -1
- package/dist/commander.js +1 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +25 -19
- package/dist/commands/browse-ai.d.ts.map +1 -1
- package/dist/commands/browse-ai.js +4 -0
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +141 -10
- package/dist/commands/checkpoint.js +8 -12
- package/dist/commands/deinit.d.ts +1 -1
- package/dist/commands/deinit.d.ts.map +1 -1
- package/dist/commands/deinit.js +8 -4
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +2 -0
- package/dist/commands/doctor.js +10 -2
- package/dist/commands/fetch.d.ts.map +1 -1
- package/dist/commands/fetch.js +10 -0
- package/dist/commands/init.d.ts +19 -3
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +232 -104
- package/dist/commands/instructions.js +5 -4
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +2 -1
- package/dist/commands/webview.d.ts +4 -0
- package/dist/commands/webview.d.ts.map +1 -0
- package/dist/commands/webview.js +94 -0
- package/dist/core/adapter.d.ts +50 -1
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +59 -1
- package/dist/core/adapters/attestation.d.ts.map +1 -1
- package/dist/core/adapters/attestation.js +3 -2
- package/dist/core/adapters/profiles.d.ts +20 -3
- package/dist/core/adapters/profiles.d.ts.map +1 -1
- package/dist/core/adapters/profiles.js +32 -1
- package/dist/core/adapters/registry.d.ts.map +1 -1
- package/dist/core/adapters/registry.js +33 -0
- package/dist/core/agents/canonical-emit.d.ts +1 -1
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +2 -7
- package/dist/core/agents/cli.js +18 -16
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +7 -2
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +3 -9
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +2 -8
- package/dist/core/agents/rules/stop-hook.d.ts +2 -0
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +1 -1
- package/dist/core/agents/session-events.d.ts +6 -2
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +105 -26
- package/dist/core/agents/session-finalization-state-v3.d.ts.map +1 -1
- package/dist/core/agents/session-finalization-state-v3.js +2 -1
- package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -1
- package/dist/core/agents/session-finalizer-v3.js +5 -4
- package/dist/core/agents/session-name-display.d.ts +28 -0
- package/dist/core/agents/session-name-display.d.ts.map +1 -1
- package/dist/core/agents/session-name-display.js +43 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts +7 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.d.ts +10 -0
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +21 -2
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +1 -0
- package/dist/core/agents/state/live-coordination-writer.js +3 -0
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +2 -10
- package/dist/core/agents/turn-changes.d.ts +17 -0
- package/dist/core/agents/turn-changes.d.ts.map +1 -0
- package/dist/core/agents/turn-changes.js +76 -0
- package/dist/core/artifacts/delivery-card.d.ts.map +1 -1
- package/dist/core/artifacts/delivery-card.js +2 -1
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +4 -3
- package/dist/core/config.d.ts +5 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +14 -0
- package/dist/core/context/index.d.ts.map +1 -1
- package/dist/core/context/index.js +2 -1
- package/dist/core/conversations/archive.d.ts.map +1 -1
- package/dist/core/conversations/archive.js +4 -3
- package/dist/core/diagnostics/bundle.d.ts.map +1 -1
- package/dist/core/diagnostics/bundle.js +3 -2
- package/dist/core/events/legacy-storage/canary.d.ts.map +1 -1
- package/dist/core/events/legacy-storage/canary.js +5 -4
- package/dist/core/events/legacy-storage/compression.d.ts.map +1 -1
- package/dist/core/events/legacy-storage/compression.js +2 -1
- package/dist/core/events/v3/adapter-id.d.ts +10 -2
- package/dist/core/events/v3/adapter-id.d.ts.map +1 -1
- package/dist/core/events/v3/adapter-id.js +16 -0
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
- package/dist/core/events/v3/authority-outbox.js +2 -1
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
- package/dist/core/events/v3/bootstrap.js +5 -4
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +17 -0
- package/dist/core/events/v3/contract.d.ts +5 -0
- package/dist/core/events/v3/contract.d.ts.map +1 -1
- package/dist/core/events/v3/contract.js +7 -1
- package/dist/core/events/v3/control-witness.d.ts.map +1 -1
- package/dist/core/events/v3/control-witness.js +3 -2
- package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -1
- package/dist/core/events/v3/coordination-transaction-recovery.js +4 -3
- package/dist/core/events/v3/fingerprint-keys.d.ts.map +1 -1
- package/dist/core/events/v3/fingerprint-keys.js +7 -6
- package/dist/core/events/v3/generated.d.ts +1 -1
- package/dist/core/events/v3/generated.js +1 -1
- package/dist/core/events/v3/live-feed.d.ts.map +1 -1
- package/dist/core/events/v3/live-feed.js +5 -4
- package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/command-recorder.js +8 -7
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +8 -7
- package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -1
- package/dist/core/events/v3/producers/diagnostic-summaries.js +5 -4
- package/dist/core/events/v3/producers/hook-base.d.ts +1 -0
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +10 -4
- package/dist/core/events/v3/producers/hook.d.ts +2 -0
- package/dist/core/events/v3/producers/hook.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook.js +16 -1
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +16 -6
- package/dist/core/events/v3/producers/recorder.d.ts +2 -4
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +109 -101
- package/dist/core/events/v3/recovery.d.ts.map +1 -1
- package/dist/core/events/v3/recovery.js +4 -3
- package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -1
- package/dist/core/events/v3/support-storage/inventory.js +2 -1
- package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -1
- package/dist/core/events/v3/support-storage/maintenance.js +4 -3
- package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -1
- package/dist/core/events/v3/support-storage/pack-reader.js +4 -3
- package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -1
- package/dist/core/events/v3/support-storage/pack-writer.js +6 -5
- package/dist/core/events/v3/tool-line-changes.d.ts +8 -0
- package/dist/core/events/v3/tool-line-changes.d.ts.map +1 -0
- package/dist/core/events/v3/tool-line-changes.js +135 -0
- package/dist/core/events/v3/writer.d.ts.map +1 -1
- package/dist/core/events/v3/writer.js +8 -7
- package/dist/core/governor/planning.d.ts.map +1 -1
- package/dist/core/governor/planning.js +6 -5
- package/dist/core/governor/service.d.ts.map +1 -1
- package/dist/core/governor/service.js +12 -11
- package/dist/core/governor/state.d.ts.map +1 -1
- package/dist/core/governor/state.js +7 -6
- package/dist/core/guard/evaluator.js +1 -0
- package/dist/core/guard/storage.d.ts.map +1 -1
- package/dist/core/guard/storage.js +3 -2
- package/dist/core/hooks/adapter/behaviors/claude-code.d.ts +4 -0
- package/dist/core/hooks/adapter/behaviors/claude-code.d.ts.map +1 -0
- package/dist/core/hooks/adapter/behaviors/claude-code.js +31 -0
- package/dist/core/hooks/adapter/behaviors/codex.d.ts +15 -0
- package/dist/core/hooks/adapter/behaviors/codex.d.ts.map +1 -0
- package/dist/core/hooks/adapter/behaviors/codex.js +82 -0
- package/dist/core/hooks/adapter/behaviors/cursor.d.ts +7 -0
- package/dist/core/hooks/adapter/behaviors/cursor.d.ts.map +1 -0
- package/dist/core/hooks/adapter/behaviors/cursor.js +35 -0
- package/dist/core/hooks/adapter/behaviors/index.d.ts +11 -0
- package/dist/core/hooks/adapter/behaviors/index.d.ts.map +1 -0
- package/dist/core/hooks/adapter/behaviors/index.js +20 -0
- package/dist/core/hooks/adapter/behaviors/openclaw.d.ts +7 -0
- package/dist/core/hooks/adapter/behaviors/openclaw.d.ts.map +1 -0
- package/dist/core/hooks/adapter/behaviors/openclaw.js +34 -0
- package/dist/core/hooks/adapter/behaviors/opencode.d.ts +7 -0
- package/dist/core/hooks/adapter/behaviors/opencode.d.ts.map +1 -0
- package/dist/core/hooks/adapter/behaviors/opencode.js +34 -0
- package/dist/core/hooks/adapter/behaviors/types.d.ts +89 -0
- package/dist/core/hooks/adapter/behaviors/types.d.ts.map +1 -0
- package/dist/core/hooks/adapter/behaviors/types.js +1 -0
- package/dist/core/hooks/adapter/detect.d.ts +1 -1
- package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
- package/dist/core/hooks/adapter/detect.js +2 -3
- package/dist/core/hooks/adapter/events.d.ts +29 -1
- package/dist/core/hooks/adapter/events.d.ts.map +1 -1
- package/dist/core/hooks/adapter/events.js +31 -0
- package/dist/core/hooks/adapter/opencode-plugin.d.ts +60 -0
- package/dist/core/hooks/adapter/opencode-plugin.d.ts.map +1 -0
- package/dist/core/hooks/adapter/opencode-plugin.js +129 -0
- package/dist/core/hooks/adapter/output.d.ts +7 -0
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +8 -1
- package/dist/core/hooks/adapter/wiring.d.ts +15 -1
- package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
- package/dist/core/hooks/adapter/wiring.js +74 -11
- package/dist/core/hooks/cli.js +635 -529
- package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
- package/dist/core/hooks/effects/image-capture.js +2 -1
- package/dist/core/hooks/prompt-context/contract.d.ts.map +1 -1
- package/dist/core/hooks/prompt-context/contract.js +1 -0
- package/dist/core/hooks/resolve/transcript.d.ts +1 -1
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +35 -4
- package/dist/core/hooks/session-name-presence.d.ts +3 -1
- package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
- package/dist/core/hooks/session-name-presence.js +7 -2
- package/dist/core/hooks/shell-waiter.d.ts +2 -0
- package/dist/core/hooks/shell-waiter.d.ts.map +1 -0
- package/dist/core/hooks/shell-waiter.js +173 -0
- package/dist/core/resources/service.d.ts.map +1 -1
- package/dist/core/resources/service.js +5 -4
- package/dist/core/semantic/review.d.ts.map +1 -1
- package/dist/core/semantic/review.js +5 -4
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +15 -14
- package/dist/core/semantic/storage.d.ts.map +1 -1
- package/dist/core/semantic/storage.js +5 -4
- package/dist/core/storage/atomic-json.d.ts.map +1 -1
- package/dist/core/storage/atomic-json.js +7 -3
- package/dist/core/storage/durable-history.d.ts.map +1 -1
- package/dist/core/storage/durable-history.js +6 -5
- package/dist/core/storage/maintenance-providers.d.ts.map +1 -1
- package/dist/core/storage/maintenance-providers.js +2 -1
- package/dist/core/storage/maintenance.d.ts.map +1 -1
- package/dist/core/storage/maintenance.js +7 -6
- package/dist/core/storage/metrics.d.ts.map +1 -1
- package/dist/core/storage/metrics.js +5 -1
- package/dist/core/storage/modes.d.ts +17 -0
- package/dist/core/storage/modes.d.ts.map +1 -0
- package/dist/core/storage/modes.js +47 -0
- package/dist/core/storage/process-log.d.ts.map +1 -1
- package/dist/core/storage/process-log.js +3 -2
- package/dist/core/storage/receipts.d.ts.map +1 -1
- package/dist/core/storage/receipts.js +4 -3
- package/dist/core/storage/segments.d.ts.map +1 -1
- package/dist/core/storage/segments.js +7 -6
- package/dist/core/supervisor/hook-health.d.ts +2 -1
- package/dist/core/supervisor/hook-health.d.ts.map +1 -1
- package/dist/core/supervisor/hook-health.js +4 -3
- package/dist/core/supervisor/service.d.ts.map +1 -1
- package/dist/core/supervisor/service.js +7 -6
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +8 -7
- package/dist/core/workflow/adapters.d.ts +7 -0
- package/dist/core/workflow/adapters.d.ts.map +1 -1
- package/dist/core/workflow/adapters.js +9 -0
- package/dist/core/workflow/approvals.d.ts.map +1 -1
- package/dist/core/workflow/approvals.js +6 -5
- package/dist/core/workflow/billing.d.ts.map +1 -1
- package/dist/core/workflow/billing.js +33 -4
- package/dist/core/workflow/durable-record.d.ts.map +1 -1
- package/dist/core/workflow/durable-record.js +4 -3
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +2 -3
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +3 -2
- package/dist/core/workflow/spawn-opencode.d.ts +36 -0
- package/dist/core/workflow/spawn-opencode.d.ts.map +1 -0
- package/dist/core/workflow/spawn-opencode.js +132 -0
- package/dist/core/workflow/transcript.d.ts.map +1 -1
- package/dist/core/workflow/transcript.js +3 -2
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +5 -4
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.js +3 -2
- package/dist/core/workflow/workspaces/paths.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/paths.js +2 -1
- package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/state.js +10 -9
- package/dist/lazy-commands.js +8 -1
- package/dist/lib/agent-browser/client.d.ts +9 -0
- package/dist/lib/agent-browser/client.d.ts.map +1 -1
- package/dist/lib/agent-browser/client.js +13 -0
- package/dist/lib/browser/client.d.ts +35 -1
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +117 -8
- package/dist/lib/browser/identity.d.ts +25 -0
- package/dist/lib/browser/identity.d.ts.map +1 -0
- package/dist/lib/browser/identity.js +66 -0
- package/dist/lib/browser/index.d.ts +2 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +2 -1
- package/dist/lib/browser/launch-args.d.ts +26 -0
- package/dist/lib/browser/launch-args.d.ts.map +1 -1
- package/dist/lib/browser/launch-args.js +41 -1
- package/dist/lib/browser/user-agent.d.ts +53 -0
- package/dist/lib/browser/user-agent.d.ts.map +1 -0
- package/dist/lib/browser/user-agent.js +79 -0
- package/dist/lib/docs-metadata-managed.d.ts +1 -0
- package/dist/lib/docs-metadata-managed.d.ts.map +1 -1
- package/dist/lib/docs-metadata-managed.js +17 -1
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +4 -9
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +2 -0
- package/dist/lib/pace/index.d.ts +2 -0
- package/dist/lib/pace/index.d.ts.map +1 -0
- package/dist/lib/pace/index.js +1 -0
- package/dist/lib/pace/pace.d.ts +95 -0
- package/dist/lib/pace/pace.d.ts.map +1 -0
- package/dist/lib/pace/pace.js +313 -0
- package/dist/lib/tunnel/forward-headers.d.ts +11 -0
- package/dist/lib/tunnel/forward-headers.d.ts.map +1 -0
- package/dist/lib/tunnel/forward-headers.js +17 -0
- package/dist/lib/tunnel/gate.js +15 -10
- package/dist/lib/webview/index.d.ts +2 -0
- package/dist/lib/webview/index.d.ts.map +1 -0
- package/dist/lib/webview/index.js +1 -0
- package/dist/lib/webview/webview.d.ts +116 -0
- package/dist/lib/webview/webview.d.ts.map +1 -0
- package/dist/lib/webview/webview.js +289 -0
- package/opencode-plugin/package.json +19 -0
- package/opencode-plugin/src/index.ts +791 -0
- package/package.json +11 -4
- package/schemas/config.schema.json +13 -0
- package/schemas/event-v3.schema.json +164 -0
- package/src/commander.ts +7 -0
- package/src/commands/agents.ts +33 -18
- package/src/commands/browse-ai.ts +8 -0
- package/src/commands/browse.ts +189 -10
- package/src/commands/checkpoint.ts +7 -9
- package/src/commands/deinit.ts +9 -4
- package/src/commands/docs.ts +2 -0
- package/src/commands/doctor.ts +11 -2
- package/src/commands/fetch.ts +14 -0
- package/src/commands/init.ts +281 -119
- package/src/commands/instructions.ts +8 -4
- package/src/commands/ledger-v3.ts +2 -1
- package/src/commands/webview.ts +159 -0
- package/src/core/adapter.ts +102 -1
- package/src/core/adapters/attestation.ts +3 -2
- package/src/core/adapters/profiles.ts +42 -1
- package/src/core/adapters/registry.ts +37 -0
- package/src/core/agents/canonical-emit.ts +2 -5
- package/src/core/agents/cli.ts +18 -17
- package/src/core/agents/coord-client.ts +9 -3
- package/src/core/agents/rules/claim-conflict.ts +3 -8
- package/src/core/agents/rules/commit-conflict.ts +2 -7
- package/src/core/agents/rules/stop-hook.ts +3 -1
- package/src/core/agents/session-events.ts +120 -26
- package/src/core/agents/session-finalization-state-v3.ts +2 -1
- package/src/core/agents/session-finalizer-v3.ts +5 -4
- package/src/core/agents/session-name-display.ts +48 -0
- package/src/core/agents/state/heartbeat-reader.ts +7 -0
- package/src/core/agents/state/heartbeat-writer.ts +24 -2
- package/src/core/agents/state/live-coordination-view.ts +1 -0
- package/src/core/agents/state/live-coordination-writer.ts +3 -0
- package/src/core/agents/state/stale-sweep.ts +2 -9
- package/src/core/agents/turn-changes.ts +97 -0
- package/src/core/artifacts/delivery-card.ts +2 -1
- package/src/core/artifacts/index.ts +4 -3
- package/src/core/config.ts +23 -0
- package/src/core/context/index.ts +2 -1
- package/src/core/conversations/archive.ts +4 -3
- package/src/core/diagnostics/bundle.ts +3 -2
- package/src/core/events/legacy-storage/canary.ts +5 -4
- package/src/core/events/legacy-storage/compression.ts +2 -1
- package/src/core/events/v3/adapter-id.ts +29 -1
- package/src/core/events/v3/authority-outbox.ts +2 -1
- package/src/core/events/v3/bootstrap.ts +5 -4
- package/src/core/events/v3/capabilities.ts +17 -0
- package/src/core/events/v3/contract.ts +9 -1
- package/src/core/events/v3/control-witness.ts +3 -2
- package/src/core/events/v3/coordination-transaction-recovery.ts +4 -3
- package/src/core/events/v3/fingerprint-keys.ts +7 -6
- package/src/core/events/v3/generated.ts +1 -1
- package/src/core/events/v3/live-feed.ts +5 -4
- package/src/core/events/v3/producers/command-recorder.ts +8 -6
- package/src/core/events/v3/producers/coordination-recorder.ts +8 -7
- package/src/core/events/v3/producers/diagnostic-summaries.ts +5 -4
- package/src/core/events/v3/producers/hook-base.ts +11 -4
- package/src/core/events/v3/producers/hook.ts +19 -1
- package/src/core/events/v3/producers/intake.ts +18 -6
- package/src/core/events/v3/producers/recorder.ts +123 -114
- package/src/core/events/v3/recovery.ts +4 -3
- package/src/core/events/v3/support-storage/inventory.ts +2 -1
- package/src/core/events/v3/support-storage/maintenance.ts +8 -3
- package/src/core/events/v3/support-storage/pack-reader.ts +4 -3
- package/src/core/events/v3/support-storage/pack-writer.ts +6 -5
- package/src/core/events/v3/tool-line-changes.ts +139 -0
- package/src/core/events/v3/writer.ts +8 -7
- package/src/core/governor/planning.ts +6 -5
- package/src/core/governor/service.ts +12 -11
- package/src/core/governor/state.ts +7 -6
- package/src/core/guard/evaluator.ts +1 -0
- package/src/core/guard/storage.ts +3 -2
- package/src/core/hooks/adapter/behaviors/claude-code.ts +33 -0
- package/src/core/hooks/adapter/behaviors/codex.ts +96 -0
- package/src/core/hooks/adapter/behaviors/cursor.ts +37 -0
- package/src/core/hooks/adapter/behaviors/index.ts +31 -0
- package/src/core/hooks/adapter/behaviors/openclaw.ts +36 -0
- package/src/core/hooks/adapter/behaviors/opencode.ts +36 -0
- package/src/core/hooks/adapter/behaviors/types.ts +110 -0
- package/src/core/hooks/adapter/detect.ts +2 -3
- package/src/core/hooks/adapter/events.ts +53 -1
- package/src/core/hooks/adapter/opencode-plugin.ts +177 -0
- package/src/core/hooks/adapter/output.ts +8 -1
- package/src/core/hooks/adapter/wiring.ts +85 -11
- package/src/core/hooks/cli.ts +733 -537
- package/src/core/hooks/effects/image-capture.ts +2 -1
- package/src/core/hooks/prompt-context/contract.ts +1 -0
- package/src/core/hooks/resolve/transcript.ts +42 -5
- package/src/core/hooks/session-name-presence.ts +10 -3
- package/src/core/hooks/shell-waiter.ts +166 -0
- package/src/core/resources/service.ts +5 -4
- package/src/core/semantic/review.ts +5 -4
- package/src/core/semantic/service.ts +15 -14
- package/src/core/semantic/storage.ts +5 -4
- package/src/core/storage/atomic-json.ts +7 -3
- package/src/core/storage/durable-history.ts +6 -5
- package/src/core/storage/maintenance-providers.ts +2 -1
- package/src/core/storage/maintenance.ts +7 -6
- package/src/core/storage/metrics.ts +5 -1
- package/src/core/storage/modes.ts +53 -0
- package/src/core/storage/process-log.ts +3 -2
- package/src/core/storage/receipts.ts +4 -3
- package/src/core/storage/segments.ts +7 -6
- package/src/core/supervisor/hook-health.ts +4 -4
- package/src/core/supervisor/service.ts +7 -6
- package/src/core/work/state.ts +8 -7
- package/src/core/workflow/adapters.ts +15 -0
- package/src/core/workflow/approvals.ts +6 -5
- package/src/core/workflow/billing.ts +34 -4
- package/src/core/workflow/durable-record.ts +4 -3
- package/src/core/workflow/live-session-v3.ts +2 -3
- package/src/core/workflow/run-state.ts +3 -2
- package/src/core/workflow/spawn-opencode.ts +150 -0
- package/src/core/workflow/transcript.ts +3 -2
- package/src/core/workflow/workspaces/leases.ts +5 -4
- package/src/core/workflow/workspaces/local-git.ts +3 -2
- package/src/core/workflow/workspaces/paths.ts +2 -1
- package/src/core/workflow/workspaces/state.ts +10 -9
- package/src/lazy-commands.ts +11 -1
- package/src/lib/agent-browser/client.ts +18 -0
- package/src/lib/browser/client.ts +147 -9
- package/src/lib/browser/identity.ts +64 -0
- package/src/lib/browser/index.ts +15 -1
- package/src/lib/browser/launch-args.ts +53 -1
- package/src/lib/browser/user-agent.ts +130 -0
- package/src/lib/docs-metadata-managed.ts +21 -0
- package/src/lib/identities/assume.ts +7 -7
- package/src/lib/instructions/apply.ts +2 -0
- package/src/lib/pace/index.ts +14 -0
- package/src/lib/pace/pace.ts +370 -0
- package/src/lib/tunnel/forward-headers.ts +16 -0
- package/src/lib/tunnel/gate.ts +18 -10
- package/src/lib/webview/index.ts +13 -0
- package/src/lib/webview/webview.ts +457 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install-side owner of the OpenCode plugin files: what `harn init --adapter
|
|
3
|
+
* opencode` writes, what `--check`/`doctor` compare against, and what `deinit`
|
|
4
|
+
* removes. The plugin itself lives in `opencode-plugin/src/index.ts` and is
|
|
5
|
+
* copied verbatim under a hash-stamped ownership header, the same fully-owned
|
|
6
|
+
* file contract as the shipped skills (`lib/instructions/splice.ts`).
|
|
7
|
+
*
|
|
8
|
+
* Layout under the project root (`ADAPTER_SPECS.opencode.settingsFile` names
|
|
9
|
+
* the entry file):
|
|
10
|
+
*
|
|
11
|
+
* .opencode/plugins/harnery/index.ts # the plugin, header + verbatim source
|
|
12
|
+
* .opencode/plugins/harnery/harnery.json # { schema, agentHook } written by init
|
|
13
|
+
*
|
|
14
|
+
* OpenCode auto-discovers every directory under `.opencode/plugins/`, so no
|
|
15
|
+
* `opencode.json` edit is needed and a configured-plugin entry is never
|
|
16
|
+
* written (OpenCode also refuses a configured local *file*; only directories
|
|
17
|
+
* load that way).
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
20
|
+
import { dirname, resolve } from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import { shortHash } from "../../../lib/instructions/splice.js";
|
|
23
|
+
import { ADAPTER_SPECS } from "./events.js";
|
|
24
|
+
export const OPENCODE_PLUGIN_ENTRY = ADAPTER_SPECS.opencode.settingsFile;
|
|
25
|
+
export const OPENCODE_PLUGIN_DIR = dirname(OPENCODE_PLUGIN_ENTRY);
|
|
26
|
+
export const OPENCODE_PLUGIN_CONFIG = `${OPENCODE_PLUGIN_DIR}/harnery.json`;
|
|
27
|
+
export const OPENCODE_PLUGIN_CONFIG_SCHEMA = "harnery-opencode-plugin/v1";
|
|
28
|
+
const HEADER_RE = /^\/\/ harnery:generated opencode-plugin v=([0-9a-f]{8});[^\n]*\n/;
|
|
29
|
+
/** Package-relative path of the shipped plugin source (also listed in `files`). */
|
|
30
|
+
const PLUGIN_SOURCE = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "..", "opencode-plugin", "src", "index.ts");
|
|
31
|
+
/** The plugin source as shipped, trimmed so header + body hashing is stable. */
|
|
32
|
+
export function openCodePluginSource() {
|
|
33
|
+
return readFileSync(PLUGIN_SOURCE, "utf8").trim();
|
|
34
|
+
}
|
|
35
|
+
/** Render the installed entry file: ownership header, then the verbatim source. */
|
|
36
|
+
export function renderOpenCodePluginEntry(binName, source = openCodePluginSource()) {
|
|
37
|
+
const body = source.trim();
|
|
38
|
+
const header = `// harnery:generated opencode-plugin v=${shortHash(body)}; machine-owned; ` +
|
|
39
|
+
`regenerated by \`${binName} init --adapter opencode\`, removed by \`${binName} deinit --adapter opencode\`. ` +
|
|
40
|
+
"Edit harnery's opencode-plugin/src/index.ts, not this file.";
|
|
41
|
+
return `${header}\n${body}\n`;
|
|
42
|
+
}
|
|
43
|
+
/** Render the sibling config the plugin reads to find the `agent-hook` launcher. */
|
|
44
|
+
export function renderOpenCodePluginConfig(agentHook) {
|
|
45
|
+
return `${JSON.stringify({ schema: OPENCODE_PLUGIN_CONFIG_SCHEMA, agentHook }, null, 2)}\n`;
|
|
46
|
+
}
|
|
47
|
+
/** True when the content carries harnery's plugin ownership header. */
|
|
48
|
+
export function isOwnedOpenCodePlugin(content) {
|
|
49
|
+
return HEADER_RE.test(content);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Compare the installed plugin files with what init would write now. Pure
|
|
53
|
+
* except for reads; never writes. `foreign` means an entry file exists at the
|
|
54
|
+
* harnery path without harnery's header, which init refuses to overwrite.
|
|
55
|
+
*/
|
|
56
|
+
export function checkOpenCodePlugin(projectRoot, expected) {
|
|
57
|
+
const entryPath = resolve(projectRoot, OPENCODE_PLUGIN_ENTRY);
|
|
58
|
+
const configPath = resolve(projectRoot, OPENCODE_PLUGIN_CONFIG);
|
|
59
|
+
if (!existsSync(entryPath))
|
|
60
|
+
return { status: "missing", issues: [] };
|
|
61
|
+
const content = readFileSync(entryPath, "utf8");
|
|
62
|
+
const match = HEADER_RE.exec(content);
|
|
63
|
+
if (!match) {
|
|
64
|
+
return {
|
|
65
|
+
status: "foreign",
|
|
66
|
+
issues: [`${OPENCODE_PLUGIN_ENTRY}: exists without harnery's ownership header`],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const issues = [];
|
|
70
|
+
const body = content.slice(match[0].length).trim();
|
|
71
|
+
const fresh = (expected.source ?? openCodePluginSource()).trim();
|
|
72
|
+
if (match[1] !== shortHash(fresh) || body !== fresh) {
|
|
73
|
+
issues.push(`${OPENCODE_PLUGIN_ENTRY}: plugin source is stale (re-run init)`);
|
|
74
|
+
}
|
|
75
|
+
if (!existsSync(configPath)) {
|
|
76
|
+
issues.push(`${OPENCODE_PLUGIN_CONFIG}: missing`);
|
|
77
|
+
}
|
|
78
|
+
else if (readFileSync(configPath, "utf8") !== renderOpenCodePluginConfig(expected.agentHook)) {
|
|
79
|
+
issues.push(`${OPENCODE_PLUGIN_CONFIG}: stale agent-hook launcher (re-run init)`);
|
|
80
|
+
}
|
|
81
|
+
return { status: issues.length === 0 ? "fresh" : "stale", issues };
|
|
82
|
+
}
|
|
83
|
+
/** Write (or refresh) the plugin directory. Idempotent; a fresh install is a no-op. */
|
|
84
|
+
export function installOpenCodePlugin(projectRoot, opts) {
|
|
85
|
+
const check = checkOpenCodePlugin(projectRoot, opts);
|
|
86
|
+
if (check.status === "foreign") {
|
|
87
|
+
return {
|
|
88
|
+
actions: [],
|
|
89
|
+
error: `✗ ${OPENCODE_PLUGIN_ENTRY} exists but is not harnery's plugin; refusing to overwrite. ` +
|
|
90
|
+
"Move it aside and re-run.",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (check.status === "fresh") {
|
|
94
|
+
return { actions: [`· opencode plugin already installed at ${OPENCODE_PLUGIN_DIR}/`] };
|
|
95
|
+
}
|
|
96
|
+
const verb = check.status === "missing" ? "install" : "refresh";
|
|
97
|
+
if (opts.dryRun) {
|
|
98
|
+
return {
|
|
99
|
+
actions: [
|
|
100
|
+
`+ would ${verb} the opencode plugin at ${OPENCODE_PLUGIN_DIR}/ (index.ts + harnery.json)`,
|
|
101
|
+
...check.issues.map((issue) => ` · ${issue}`),
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const dir = resolve(projectRoot, OPENCODE_PLUGIN_DIR);
|
|
106
|
+
mkdirSync(dir, { recursive: true });
|
|
107
|
+
writeFileSync(resolve(projectRoot, OPENCODE_PLUGIN_ENTRY), renderOpenCodePluginEntry(opts.binName));
|
|
108
|
+
writeFileSync(resolve(projectRoot, OPENCODE_PLUGIN_CONFIG), renderOpenCodePluginConfig(opts.agentHook));
|
|
109
|
+
return {
|
|
110
|
+
actions: [
|
|
111
|
+
`+ ${verb === "install" ? "installed" : "refreshed"} the opencode plugin at ${OPENCODE_PLUGIN_DIR}/ (index.ts + harnery.json)`,
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/** Remove the plugin directory when harnery owns it. Leaves a foreign file alone. */
|
|
116
|
+
export function removeOpenCodePlugin(projectRoot, dryRun) {
|
|
117
|
+
const dir = resolve(projectRoot, OPENCODE_PLUGIN_DIR);
|
|
118
|
+
const entryPath = resolve(projectRoot, OPENCODE_PLUGIN_ENTRY);
|
|
119
|
+
if (!existsSync(entryPath)) {
|
|
120
|
+
return [`· ${OPENCODE_PLUGIN_DIR}/ doesn't exist; no plugin to remove`];
|
|
121
|
+
}
|
|
122
|
+
if (!isOwnedOpenCodePlugin(readFileSync(entryPath, "utf8"))) {
|
|
123
|
+
return [`· ${OPENCODE_PLUGIN_ENTRY} is not harnery's plugin; left in place`];
|
|
124
|
+
}
|
|
125
|
+
if (dryRun)
|
|
126
|
+
return [`+ would remove ${OPENCODE_PLUGIN_DIR}/ (harnery-owned plugin)`];
|
|
127
|
+
rmSync(dir, { recursive: true, force: true });
|
|
128
|
+
return [`+ removed ${OPENCODE_PLUGIN_DIR}/ (harnery-owned plugin)`];
|
|
129
|
+
}
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
* - **Codex**: structurally identical to Claude Code for context and tool
|
|
15
15
|
* denials. Stop blocks are deliberately suppressed because their automatic
|
|
16
16
|
* continuation can replace a completed user-facing answer.
|
|
17
|
+
* - **OpenCode**: the Harnery OpenCode plugin reads the Claude Code envelope
|
|
18
|
+
* (`hookSpecificOutput.additionalContext` / `permissionDecision`) and feeds
|
|
19
|
+
* it back through OpenCode's own channels. Stop blocks are suppressed.
|
|
17
20
|
*
|
|
18
21
|
* Every helper writes to process.stdout + newline-terminates so callers can
|
|
19
22
|
* fire-and-forget. Empty text is a no-op.
|
|
@@ -46,6 +49,10 @@ export declare function emitDeny(adapter: Adapter, reason: string): void;
|
|
|
46
49
|
* answer in clients that retain only the final continuation response. Return
|
|
47
50
|
* success without output as a defense in depth behind the observe-only
|
|
48
51
|
* verdict in `agents/rules/stop-hook.ts`.
|
|
52
|
+
* - **OpenCode** has no blocking Stop channel at all: the plugin observes
|
|
53
|
+
* `session.execution.succeeded` after the turn has already completed, so a
|
|
54
|
+
* block could only arrive as a new message. Return success without output;
|
|
55
|
+
* the verdict is still recorded in the ledger.
|
|
49
56
|
* - **Cursor** ignores stop-hook exit codes (non-zero = fail-open, the turn
|
|
50
57
|
* proceeds) and re-prompts ONLY via a `followup_message` field in stdout
|
|
51
58
|
* JSON, which it auto-submits as the next user message: the sanctioned
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/output.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAIhD,MAAM,MAAM,WAAW,GACnB,cAAc,GACd,kBAAkB,GAClB,eAAe,GACf,YAAY,GACZ,aAAa,CAAC;AAElB,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKvF;AAED,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC1C,SAAS,CAAC,EAAE,MAAM,GACjB,CAAC,GAAG,CAAC,CAEP;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,iBAAiB,EAC1B,SAAS,CAAC,EAAE,MAAM,GACjB,CAAC,GAAG,CAAC,CAuBP"}
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
* - **Codex**: structurally identical to Claude Code for context and tool
|
|
15
15
|
* denials. Stop blocks are deliberately suppressed because their automatic
|
|
16
16
|
* continuation can replace a completed user-facing answer.
|
|
17
|
+
* - **OpenCode**: the Harnery OpenCode plugin reads the Claude Code envelope
|
|
18
|
+
* (`hookSpecificOutput.additionalContext` / `permissionDecision`) and feeds
|
|
19
|
+
* it back through OpenCode's own channels. Stop blocks are suppressed.
|
|
17
20
|
*
|
|
18
21
|
* Every helper writes to process.stdout + newline-terminates so callers can
|
|
19
22
|
* fire-and-forget. Empty text is a no-op.
|
|
@@ -50,6 +53,10 @@ export function emitDeny(adapter, reason) {
|
|
|
50
53
|
* answer in clients that retain only the final continuation response. Return
|
|
51
54
|
* success without output as a defense in depth behind the observe-only
|
|
52
55
|
* verdict in `agents/rules/stop-hook.ts`.
|
|
56
|
+
* - **OpenCode** has no blocking Stop channel at all: the plugin observes
|
|
57
|
+
* `session.execution.succeeded` after the turn has already completed, so a
|
|
58
|
+
* block could only arrive as a new message. Return success without output;
|
|
59
|
+
* the verdict is still recorded in the ledger.
|
|
53
60
|
* - **Cursor** ignores stop-hook exit codes (non-zero = fail-open, the turn
|
|
54
61
|
* proceeds) and re-prompts ONLY via a `followup_message` field in stdout
|
|
55
62
|
* JSON, which it auto-submits as the next user message: the sanctioned
|
|
@@ -64,7 +71,7 @@ export function emitStopBlock(adapter, verdict, coordRoot) {
|
|
|
64
71
|
* Emit the adapter-specific response for one Stop outcome.
|
|
65
72
|
*/
|
|
66
73
|
export function emitStopOutcome(adapter, options, coordRoot) {
|
|
67
|
-
if (adapter === "codex")
|
|
74
|
+
if (adapter === "codex" || adapter === "opencode")
|
|
68
75
|
return 0;
|
|
69
76
|
const verdict = options.verdict;
|
|
70
77
|
if (!verdict)
|
|
@@ -24,8 +24,12 @@ export interface CursorHookGroup {
|
|
|
24
24
|
command: string;
|
|
25
25
|
type?: string;
|
|
26
26
|
matcher?: string;
|
|
27
|
+
/** Cursor Stop followup cap. Harnery pins 2; Cursor's own default is 5. */
|
|
28
|
+
loop_limit?: number;
|
|
27
29
|
}
|
|
28
30
|
export type HookGroup = ClaudeHookGroup | CursorHookGroup;
|
|
31
|
+
/** Bound Cursor Stop `followup_message` retries so a missed ritual cannot loop 5 times. */
|
|
32
|
+
export declare const CURSOR_STOP_FOLLOWUP_LOOP_LIMIT = 2;
|
|
29
33
|
export interface SettingsFile {
|
|
30
34
|
version?: number;
|
|
31
35
|
description?: string;
|
|
@@ -33,7 +37,11 @@ export interface SettingsFile {
|
|
|
33
37
|
[k: string]: unknown;
|
|
34
38
|
}
|
|
35
39
|
/** Build a hook entry in the adapter's shape. */
|
|
36
|
-
export declare function makeEntry(shape: HookEntryShape, command: string
|
|
40
|
+
export declare function makeEntry(shape: HookEntryShape, command: string, extras?: {
|
|
41
|
+
loop_limit?: number;
|
|
42
|
+
}): HookGroup;
|
|
43
|
+
/** Pin Cursor Stop followups to Harnery's loop cap. Returns true when the entry changed. */
|
|
44
|
+
export declare function applyCursorStopLoopLimit(group: HookGroup, subcommand: string): boolean;
|
|
37
45
|
/** Pull every command string out of a hook entry, regardless of shape. */
|
|
38
46
|
export declare function groupCommands(group: HookGroup): string[];
|
|
39
47
|
/**
|
|
@@ -95,6 +103,12 @@ export interface AdapterWiringStatus {
|
|
|
95
103
|
invalidTopLevelKeys: string[];
|
|
96
104
|
invalidEventKeys: string[];
|
|
97
105
|
parseError?: string;
|
|
106
|
+
/**
|
|
107
|
+
* `opencode-plugin` install mode only: why the installed plugin differs from
|
|
108
|
+
* what init writes now (stale source, missing/stale `harnery.json`, or a
|
|
109
|
+
* foreign file at the harnery path). Hook-map fields stay empty for it.
|
|
110
|
+
*/
|
|
111
|
+
pluginIssues?: string[];
|
|
98
112
|
}
|
|
99
113
|
/**
|
|
100
114
|
* Inspect every adapter whose settings file exists under `projectRoot` and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wiring.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/wiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"wiring.d.ts","sourceRoot":"","sources":["../../../../src/core/hooks/adapter/wiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAGrB,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C;AACD,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AACD,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,eAAe,CAAC;AAE1D,2FAA2F;AAC3F,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAEjD,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,iDAAiD;AACjD,wBAAgB,SAAS,CACvB,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/B,SAAS,CAKX;AAED,4FAA4F;AAC5F,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAMtF;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAMxD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAGnF;AAQD,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,6DAA6D;AAC7D,wBAAgB,WAAW,CACzB,IAAI,EAAE,WAAW,EACjB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,SAAS,GACjB,MAAM,CAMR;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAOxF;AAED,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,iCAAiC;IACjC,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sEAAsE;IACtE,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,yEAAyE;IACzE,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,mFAAmF;IACnF,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,4EAA4E;IAC5E,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,WAAW,EACjB,QAAQ,CAAC,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,CAAA;CAAE,GACvD,UAAU,CAoEZ;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,SAAS,CAAC;IACnB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAsCD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAwD5E;AAED,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB;;;;OAIG;IACH,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,oBAAoB,CA8BhF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAUvC;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAkBlD"}
|
|
@@ -13,10 +13,29 @@
|
|
|
13
13
|
import { existsSync, readFileSync } from "node:fs";
|
|
14
14
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { resolveBinName } from "../../config.js";
|
|
16
17
|
import { ADAPTER_SPECS, } from "./events.js";
|
|
18
|
+
import { checkOpenCodePlugin, isOwnedOpenCodePlugin } from "./opencode-plugin.js";
|
|
19
|
+
/** Bound Cursor Stop `followup_message` retries so a missed ritual cannot loop 5 times. */
|
|
20
|
+
export const CURSOR_STOP_FOLLOWUP_LOOP_LIMIT = 2;
|
|
17
21
|
/** Build a hook entry in the adapter's shape. */
|
|
18
|
-
export function makeEntry(shape, command) {
|
|
19
|
-
|
|
22
|
+
export function makeEntry(shape, command, extras) {
|
|
23
|
+
if (shape !== "cursor")
|
|
24
|
+
return { hooks: [{ type: "command", command }] };
|
|
25
|
+
return extras?.loop_limit !== undefined
|
|
26
|
+
? { command, loop_limit: extras.loop_limit }
|
|
27
|
+
: { command };
|
|
28
|
+
}
|
|
29
|
+
/** Pin Cursor Stop followups to Harnery's loop cap. Returns true when the entry changed. */
|
|
30
|
+
export function applyCursorStopLoopLimit(group, subcommand) {
|
|
31
|
+
if (subcommand !== "stop")
|
|
32
|
+
return false;
|
|
33
|
+
if (!("command" in group) || typeof group.command !== "string")
|
|
34
|
+
return false;
|
|
35
|
+
if (group.loop_limit === CURSOR_STOP_FOLLOWUP_LOOP_LIMIT)
|
|
36
|
+
return false;
|
|
37
|
+
group.loop_limit = CURSOR_STOP_FOLLOWUP_LOOP_LIMIT;
|
|
38
|
+
return true;
|
|
20
39
|
}
|
|
21
40
|
/** Pull every command string out of a hook entry, regardless of shape. */
|
|
22
41
|
export function groupCommands(group) {
|
|
@@ -131,6 +150,39 @@ export function diffWiring(settings, spec, expected) {
|
|
|
131
150
|
invalidEventKeys,
|
|
132
151
|
};
|
|
133
152
|
}
|
|
153
|
+
function emptyWiringStatus(adapter, settingsFile) {
|
|
154
|
+
return {
|
|
155
|
+
adapter,
|
|
156
|
+
settingsFile,
|
|
157
|
+
missing: [],
|
|
158
|
+
orphans: [],
|
|
159
|
+
duplicates: [],
|
|
160
|
+
misplaced: [],
|
|
161
|
+
stale: [],
|
|
162
|
+
invalidTopLevelKeys: [],
|
|
163
|
+
invalidEventKeys: [],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Plugin-mode drift: the installed entry exists but is not what init would
|
|
168
|
+
* write now. Absent entry → not opted in → null (mirrors the hook-map rule).
|
|
169
|
+
* Without a resolvable package root the launcher cannot be compared, so only
|
|
170
|
+
* the source freshness is judged.
|
|
171
|
+
*/
|
|
172
|
+
function pluginDrift(projectRoot, id, spec) {
|
|
173
|
+
if (!existsSync(resolve(projectRoot, spec.settingsFile)))
|
|
174
|
+
return null;
|
|
175
|
+
const packageRoot = harneryPackageRoot();
|
|
176
|
+
const check = checkOpenCodePlugin(projectRoot, {
|
|
177
|
+
binName: resolveBinName(projectRoot),
|
|
178
|
+
agentHook: packageRoot ? agentHookPathForProject(projectRoot, packageRoot) : "agent-hook",
|
|
179
|
+
});
|
|
180
|
+
if (check.status === "fresh")
|
|
181
|
+
return null;
|
|
182
|
+
if (check.status === "missing")
|
|
183
|
+
return null;
|
|
184
|
+
return { ...emptyWiringStatus(id, spec.settingsFile), pluginIssues: check.issues };
|
|
185
|
+
}
|
|
134
186
|
/**
|
|
135
187
|
* Inspect every adapter whose settings file exists under `projectRoot` and
|
|
136
188
|
* return only those with *drift*. Read-only; never writes.
|
|
@@ -145,6 +197,12 @@ export function diffWiring(settings, spec, expected) {
|
|
|
145
197
|
export function loadAdapterWiring(projectRoot) {
|
|
146
198
|
const out = [];
|
|
147
199
|
for (const [id, spec] of Object.entries(ADAPTER_SPECS)) {
|
|
200
|
+
if (spec.installMode === "opencode-plugin") {
|
|
201
|
+
const drift = pluginDrift(projectRoot, id, spec);
|
|
202
|
+
if (drift)
|
|
203
|
+
out.push(drift);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
148
206
|
const settingsPath = resolve(projectRoot, spec.settingsFile);
|
|
149
207
|
if (!existsSync(settingsPath))
|
|
150
208
|
continue;
|
|
@@ -154,15 +212,7 @@ export function loadAdapterWiring(projectRoot) {
|
|
|
154
212
|
}
|
|
155
213
|
catch (error) {
|
|
156
214
|
out.push({
|
|
157
|
-
|
|
158
|
-
settingsFile: spec.settingsFile,
|
|
159
|
-
missing: [],
|
|
160
|
-
orphans: [],
|
|
161
|
-
duplicates: [],
|
|
162
|
-
misplaced: [],
|
|
163
|
-
stale: [],
|
|
164
|
-
invalidTopLevelKeys: [],
|
|
165
|
-
invalidEventKeys: [],
|
|
215
|
+
...emptyWiringStatus(id, spec.settingsFile),
|
|
166
216
|
parseError: error.message,
|
|
167
217
|
});
|
|
168
218
|
continue;
|
|
@@ -220,6 +270,19 @@ export function summarizeAdapterWiring(projectRoot) {
|
|
|
220
270
|
unwired.push(id);
|
|
221
271
|
continue;
|
|
222
272
|
}
|
|
273
|
+
if (spec.installMode === "opencode-plugin") {
|
|
274
|
+
// The entry counts as wired only when harnery owns it; a foreign file at
|
|
275
|
+
// that path is drift (surfaced by loadAdapterWiring), not a wiring.
|
|
276
|
+
let content;
|
|
277
|
+
try {
|
|
278
|
+
content = readFileSync(settingsPath, "utf8");
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
(isOwnedOpenCodePlugin(content) ? wired : unwired).push(id);
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
223
286
|
let settings;
|
|
224
287
|
try {
|
|
225
288
|
settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|