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
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type DurableHistoryFaultBoundary,
|
|
6
6
|
readDurableHistorySync,
|
|
7
7
|
} from "../storage/durable-history.ts";
|
|
8
|
+
import { stateDirMode, stateFileMode } from "../storage/modes.ts";
|
|
8
9
|
import type {
|
|
9
10
|
HarneryConversationAccessMode,
|
|
10
11
|
HarneryConversationArchiveAuthorityMode,
|
|
@@ -69,10 +70,10 @@ export async function captureProviderConversation(
|
|
|
69
70
|
provider.capabilities.provider_id,
|
|
70
71
|
options.conversation_id,
|
|
71
72
|
);
|
|
72
|
-
mkdirSync(objectDir, { recursive: true, mode:
|
|
73
|
+
mkdirSync(objectDir, { recursive: true, mode: stateDirMode() });
|
|
73
74
|
const lease = join(objectDir, ".capture.lease");
|
|
74
75
|
try {
|
|
75
|
-
mkdirSync(lease, { mode:
|
|
76
|
+
mkdirSync(lease, { mode: stateDirMode() });
|
|
76
77
|
} catch {
|
|
77
78
|
throw new Error(`conversation capture lease busy: ${options.conversation_id}`);
|
|
78
79
|
}
|
|
@@ -223,7 +224,7 @@ function manifestFor(
|
|
|
223
224
|
function publishManifest(objectDir: string, manifest: HarneryConversationArchiveManifest): void {
|
|
224
225
|
const path = join(objectDir, "manifest.json");
|
|
225
226
|
const temp = `${path}.tmp-${process.pid}`;
|
|
226
|
-
writeFileSync(temp, `${JSON.stringify(manifest, null, 2)}\n`, { mode:
|
|
227
|
+
writeFileSync(temp, `${JSON.stringify(manifest, null, 2)}\n`, { mode: stateFileMode() });
|
|
227
228
|
renameSync(temp, path);
|
|
228
229
|
}
|
|
229
230
|
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
} from "../artifacts/index.ts";
|
|
26
26
|
import { currentHarneryRuntimeBuild } from "../events/v3/runtime-build.ts";
|
|
27
27
|
import { writePrivateJsonAtomic } from "../storage/atomic-json.ts";
|
|
28
|
+
import { stateDirMode } from "../storage/modes.ts";
|
|
28
29
|
import {
|
|
29
30
|
SUPERVISOR_DIAGNOSTIC_LIMITS,
|
|
30
31
|
SUPERVISOR_EXPLANATION_SCHEMA_VERSION,
|
|
@@ -171,8 +172,8 @@ export function captureDiagnosticBundle(
|
|
|
171
172
|
now,
|
|
172
173
|
});
|
|
173
174
|
const inputsPath = join(created.path, "inputs");
|
|
174
|
-
mkdirSync(inputsPath, { recursive: true, mode:
|
|
175
|
-
tryChmod(inputsPath,
|
|
175
|
+
mkdirSync(inputsPath, { recursive: true, mode: stateDirMode() });
|
|
176
|
+
tryChmod(inputsPath, stateDirMode());
|
|
176
177
|
|
|
177
178
|
const payloads: Record<(typeof PAYLOAD_FILES)[number], unknown> = {
|
|
178
179
|
"inputs/observations.json": observations,
|
|
@@ -4,6 +4,7 @@ import { chmod, lstat, mkdir, open, rename, rm } from "node:fs/promises";
|
|
|
4
4
|
import { basename, join, resolve } from "node:path";
|
|
5
5
|
import { pipeline } from "node:stream/promises";
|
|
6
6
|
import { createGzip } from "node:zlib";
|
|
7
|
+
import { stateDirMode, stateFileMode } from "../../storage/modes.ts";
|
|
7
8
|
import { canonicalJsonV3 } from "../v3/canonical.ts";
|
|
8
9
|
import { verifyLegacyV1HardFence } from "./fence.ts";
|
|
9
10
|
import { type LegacyV1SegmentManifest, validateLegacyV1SegmentManifest } from "./manifest.ts";
|
|
@@ -46,8 +47,8 @@ export async function writeLegacyV1Canary(input: {
|
|
|
46
47
|
.digest("hex")
|
|
47
48
|
.slice(0, 32)}` as const;
|
|
48
49
|
const outputDirectory = resolve(input.output_directory);
|
|
49
|
-
await mkdir(outputDirectory, { recursive: true, mode:
|
|
50
|
-
await chmod(outputDirectory,
|
|
50
|
+
await mkdir(outputDirectory, { recursive: true, mode: stateDirMode() });
|
|
51
|
+
await chmod(outputDirectory, stateDirMode());
|
|
51
52
|
const payloadPath = join(outputDirectory, `${segmentId}.ndjson.gz`);
|
|
52
53
|
const manifestPath = join(outputDirectory, `${segmentId}.manifest.json`);
|
|
53
54
|
const partialPayload = `${payloadPath}.partial`;
|
|
@@ -57,7 +58,7 @@ export async function writeLegacyV1Canary(input: {
|
|
|
57
58
|
await pipeline(
|
|
58
59
|
createReadStream(source),
|
|
59
60
|
createGzip({ level: 9 }),
|
|
60
|
-
createWriteStream(partialPayload, { flags: "wx", mode:
|
|
61
|
+
createWriteStream(partialPayload, { flags: "wx", mode: stateFileMode() }),
|
|
61
62
|
);
|
|
62
63
|
await rename(partialPayload, payloadPath);
|
|
63
64
|
const payloadStat = await lstat(payloadPath);
|
|
@@ -85,7 +86,7 @@ export async function writeLegacyV1Canary(input: {
|
|
|
85
86
|
const handle = await open(
|
|
86
87
|
partialManifest,
|
|
87
88
|
constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL,
|
|
88
|
-
|
|
89
|
+
stateFileMode(),
|
|
89
90
|
);
|
|
90
91
|
try {
|
|
91
92
|
await handle.writeFile(`${canonicalJsonV3(manifest)}\n`, "utf8");
|
|
@@ -5,6 +5,7 @@ import { chmod, lstat, rename, rm } from "node:fs/promises";
|
|
|
5
5
|
import { basename } from "node:path";
|
|
6
6
|
import { pipeline } from "node:stream/promises";
|
|
7
7
|
import { createGzip } from "node:zlib";
|
|
8
|
+
import { stateFileMode } from "../../storage/modes.ts";
|
|
8
9
|
import { verifyLegacyV1HardFence } from "./fence.ts";
|
|
9
10
|
import { inventoryLegacyV1Segments } from "./inventory.ts";
|
|
10
11
|
import { streamLegacyV1Rows } from "./reader.ts";
|
|
@@ -84,7 +85,7 @@ export async function compressSealedLegacyV1Segments(
|
|
|
84
85
|
await pipeline(
|
|
85
86
|
createReadStream(row.path),
|
|
86
87
|
createGzip({ level: 9 }),
|
|
87
|
-
createWriteStream(temporary, { flags: "wx", mode:
|
|
88
|
+
createWriteStream(temporary, { flags: "wx", mode: stateFileMode() }),
|
|
88
89
|
);
|
|
89
90
|
await proveRowParity(row.path, temporary);
|
|
90
91
|
const unchanged = (await inventoryLegacyV1Segments(coordRoot)).find(
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
type Adapter,
|
|
3
|
+
type AdapterFallbackOptions,
|
|
4
|
+
DEFAULT_ADAPTER,
|
|
5
|
+
normalizeAdapterId,
|
|
6
|
+
resolveAdapterId,
|
|
7
|
+
} from "../../adapter.ts";
|
|
2
8
|
|
|
3
9
|
/** Harness identities that may produce or describe Event Ledger V3 evidence. */
|
|
4
10
|
export type EventAdapterIdV3 = Adapter | "openclaw";
|
|
@@ -8,5 +14,27 @@ export const EVENT_ADAPTER_IDS_V3 = [
|
|
|
8
14
|
"claude-code",
|
|
9
15
|
"codex",
|
|
10
16
|
"cursor",
|
|
17
|
+
"opencode",
|
|
11
18
|
"openclaw",
|
|
12
19
|
] as const satisfies readonly EventAdapterIdV3[];
|
|
20
|
+
|
|
21
|
+
type MissingEventAdapterId = Exclude<EventAdapterIdV3, (typeof EVENT_ADAPTER_IDS_V3)[number]>;
|
|
22
|
+
const eventAdapterIdsComplete: [MissingEventAdapterId] extends [never] ? true : never = true;
|
|
23
|
+
void eventAdapterIdsComplete;
|
|
24
|
+
|
|
25
|
+
/** Strict event-adapter normalizer: a known id or `null`. */
|
|
26
|
+
export function normalizeEventAdapterIdV3(value: unknown): EventAdapterIdV3 | null {
|
|
27
|
+
return normalizeAdapterId(value, EVENT_ADAPTER_IDS_V3);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Heartbeat `platform` to an event adapter id, substituting `DEFAULT_ADAPTER`
|
|
32
|
+
* and reporting the substitution. Use this wherever a row must be attributed
|
|
33
|
+
* to some adapter; use `normalizeEventAdapterIdV3` when `null` is acceptable.
|
|
34
|
+
*/
|
|
35
|
+
export function eventAdapterIdV3FromPlatform(
|
|
36
|
+
value: unknown,
|
|
37
|
+
options?: AdapterFallbackOptions,
|
|
38
|
+
): EventAdapterIdV3 {
|
|
39
|
+
return resolveAdapterId(value, EVENT_ADAPTER_IDS_V3, DEFAULT_ADAPTER, options);
|
|
40
|
+
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
writeFileSync,
|
|
12
12
|
} from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
+
import { stateFileMode } from "../../storage/modes.ts";
|
|
14
15
|
import { fsyncParentDirectory } from "../../workflow/durable-record.ts";
|
|
15
16
|
import { canonicalJsonV3, sha256V3 } from "./canonical.ts";
|
|
16
17
|
import type { EventV3 } from "./contract.ts";
|
|
@@ -540,7 +541,7 @@ function publishExclusive(path: string, serialized: string): void {
|
|
|
540
541
|
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
541
542
|
let fd: number | undefined;
|
|
542
543
|
try {
|
|
543
|
-
fd = openSync(temporary, "wx",
|
|
544
|
+
fd = openSync(temporary, "wx", stateFileMode());
|
|
544
545
|
writeFileSync(fd, serialized, "utf8");
|
|
545
546
|
fsyncSync(fd);
|
|
546
547
|
closeSync(fd);
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { hostname } from "node:os";
|
|
17
17
|
import { dirname, join, resolve } from "node:path";
|
|
18
18
|
import { fileURLToPath } from "node:url";
|
|
19
|
+
import { stateDirMode, stateFileMode } from "../../storage/modes.ts";
|
|
19
20
|
import { fsyncParentDirectory } from "../../workflow/durable-record.ts";
|
|
20
21
|
import { acquireNoClobberLease } from "../../workflow/workspaces/leases.ts";
|
|
21
22
|
import { canonicalJsonV3, sha256V3 } from "./canonical.ts";
|
|
@@ -524,7 +525,7 @@ function archiveCurrentEpoch(root: string, createdAt: string): string | undefine
|
|
|
524
525
|
const current = join(root, ".harnery", "ledgers", "v3");
|
|
525
526
|
if (!existsSync(current)) return undefined;
|
|
526
527
|
const archives = join(root, ".harnery", "ledgers", "v3-archives");
|
|
527
|
-
mkdirSync(archives, { recursive: true, mode:
|
|
528
|
+
mkdirSync(archives, { recursive: true, mode: stateDirMode() });
|
|
528
529
|
const stamp = createdAt.replace(/[^0-9]/g, "");
|
|
529
530
|
let target = join(archives, `epoch-${stamp}`);
|
|
530
531
|
let suffix = 0;
|
|
@@ -535,20 +536,20 @@ function archiveCurrentEpoch(root: string, createdAt: string): string | undefine
|
|
|
535
536
|
}
|
|
536
537
|
|
|
537
538
|
function publishControlFile(path: string, value: unknown): void {
|
|
538
|
-
mkdirSync(dirname(path), { recursive: true, mode:
|
|
539
|
+
mkdirSync(dirname(path), { recursive: true, mode: stateDirMode() });
|
|
539
540
|
const temp = `${path}.tmp.${process.pid}`;
|
|
540
541
|
// A prior failed publish by this same pid would otherwise make every retry
|
|
541
542
|
// fail on the exclusive create, which is exactly how one transient error
|
|
542
543
|
// turns into a permanently stranded epoch.
|
|
543
544
|
if (existsSync(temp)) unlinkSync(temp);
|
|
544
|
-
const fd = openSync(temp, "wx",
|
|
545
|
+
const fd = openSync(temp, "wx", stateFileMode());
|
|
545
546
|
try {
|
|
546
547
|
writeFileSync(fd, `${canonicalJsonV3(value)}\n`, "utf8");
|
|
547
548
|
fsyncSync(fd);
|
|
548
549
|
} finally {
|
|
549
550
|
closeSync(fd);
|
|
550
551
|
}
|
|
551
|
-
chmodSync(temp,
|
|
552
|
+
chmodSync(temp, stateFileMode());
|
|
552
553
|
renameSync(temp, path);
|
|
553
554
|
fsyncParentDirectory(path);
|
|
554
555
|
}
|
|
@@ -115,6 +115,19 @@ const BASE_SIGNAL_SUPPORT: Record<
|
|
|
115
115
|
post_compaction: "unsupported",
|
|
116
116
|
context_usage: "conditional",
|
|
117
117
|
},
|
|
118
|
+
opencode: {
|
|
119
|
+
...SHARED_SIGNAL_SUPPORT,
|
|
120
|
+
// OpenCode sessions are persistent server objects; the plugin observes a
|
|
121
|
+
// turn boundary (session.idle) rather than a clean session close, so end is
|
|
122
|
+
// conditional. Turns group by messageID without a first-class turn id.
|
|
123
|
+
session_end: "conditional",
|
|
124
|
+
turn_id: "conditional",
|
|
125
|
+
permission: "native",
|
|
126
|
+
// Compaction is intercepted (session.hook("compaction")); post-compaction
|
|
127
|
+
// recovery and SQLite-backed context usage are not yet certified.
|
|
128
|
+
post_compaction: "unsupported",
|
|
129
|
+
context_usage: "unsupported",
|
|
130
|
+
},
|
|
118
131
|
openclaw: {
|
|
119
132
|
session_start: "conditional",
|
|
120
133
|
session_end: "native",
|
|
@@ -169,6 +182,10 @@ export const ADAPTER_CAPABILITY_PROFILES_V3: Record<EventAdapterIdV3, AdapterCap
|
|
|
169
182
|
model_usage: "unsupported",
|
|
170
183
|
inference_timing: "unsupported",
|
|
171
184
|
}),
|
|
185
|
+
opencode: profile("opencode", {
|
|
186
|
+
model_usage: "conditional",
|
|
187
|
+
inference_timing: "unsupported",
|
|
188
|
+
}),
|
|
172
189
|
openclaw: profile(
|
|
173
190
|
"openclaw",
|
|
174
191
|
{
|
|
@@ -123,8 +123,15 @@ export const TurnCompletedV3Schema = eventV3("turn.completed", {
|
|
|
123
123
|
}),
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
+
export const ToolLineChangesV3Schema = StrictObject({
|
|
127
|
+
added: Type.Integer({ minimum: 0 }),
|
|
128
|
+
removed: Type.Integer({ minimum: 0 }),
|
|
129
|
+
});
|
|
130
|
+
|
|
126
131
|
export const ToolCompletedV3Schema = eventV3("tool.completed", {
|
|
127
|
-
payload: terminalPayloadV3("tool.completed"
|
|
132
|
+
payload: terminalPayloadV3("tool.completed", {
|
|
133
|
+
line_changes: Type.Optional(ObservationV3Schema(ToolLineChangesV3Schema)),
|
|
134
|
+
}),
|
|
128
135
|
});
|
|
129
136
|
|
|
130
137
|
export const CommandCompletedV3Schema = eventV3("command.completed", {
|
|
@@ -260,6 +267,7 @@ type ToolCompletedEventV3 = ReplaceEventV3<
|
|
|
260
267
|
Omit<EventOfTypeV3Base<"tool.completed">["payload"], "duration_ms"> & {
|
|
261
268
|
duration_ms: SpanSummaryValueV3["duration_ms"];
|
|
262
269
|
span: SpanSummaryValueV3;
|
|
270
|
+
line_changes?: Static<ReturnType<typeof ObservationV3Schema<typeof ToolLineChangesV3Schema>>>;
|
|
263
271
|
}
|
|
264
272
|
>;
|
|
265
273
|
type CommandCompletedEventV3 = ReplaceEventV3<
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
unlinkSync,
|
|
11
11
|
writeFileSync,
|
|
12
12
|
} from "node:fs";
|
|
13
|
+
import { stateFileMode } from "../../storage/modes.ts";
|
|
13
14
|
import { fsyncParentDirectory } from "../../workflow/durable-record.ts";
|
|
14
15
|
import { canonicalJsonV3, type FingerprintV3, fingerprintV3, sha256V3 } from "./canonical.ts";
|
|
15
16
|
import type { ActivationManifestV3, CandidateGenesisManifestV3 } from "./control.ts";
|
|
@@ -332,12 +333,12 @@ function publishCanonicalFileV3(path: string, value: unknown): boolean {
|
|
|
332
333
|
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
333
334
|
let fd: number | undefined;
|
|
334
335
|
try {
|
|
335
|
-
fd = openSync(temporary, "wx",
|
|
336
|
+
fd = openSync(temporary, "wx", stateFileMode());
|
|
336
337
|
writeFileSync(fd, `${canonicalJsonV3(value)}\n`, "utf8");
|
|
337
338
|
fsyncSync(fd);
|
|
338
339
|
closeSync(fd);
|
|
339
340
|
fd = undefined;
|
|
340
|
-
chmodSync(temporary,
|
|
341
|
+
chmodSync(temporary, stateFileMode());
|
|
341
342
|
renameSync(temporary, path);
|
|
342
343
|
fsyncParentDirectory(path);
|
|
343
344
|
return true;
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
writeFileSync,
|
|
14
14
|
} from "node:fs";
|
|
15
15
|
import { join } from "node:path";
|
|
16
|
+
import { stateDirMode, stateFileMode } from "../../storage/modes.ts";
|
|
16
17
|
import { fsyncParentDirectory } from "../../workflow/durable-record.ts";
|
|
17
18
|
import {
|
|
18
19
|
type AuthorityTransactionV3,
|
|
@@ -306,8 +307,8 @@ function recoveryPaths(coordRoot: string, transactionId: string) {
|
|
|
306
307
|
|
|
307
308
|
function ensureRecoveryLayout(paths: ReturnType<typeof recoveryPaths>): void {
|
|
308
309
|
for (const path of [paths.root, paths.quarantineRoot]) {
|
|
309
|
-
mkdirSync(path, { recursive: true, mode:
|
|
310
|
-
chmodSync(path,
|
|
310
|
+
mkdirSync(path, { recursive: true, mode: stateDirMode() });
|
|
311
|
+
chmodSync(path, stateDirMode());
|
|
311
312
|
}
|
|
312
313
|
}
|
|
313
314
|
|
|
@@ -325,7 +326,7 @@ function publishSerializedExclusive(path: string, serialized: string): void {
|
|
|
325
326
|
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
326
327
|
let fd: number | undefined;
|
|
327
328
|
try {
|
|
328
|
-
fd = openSync(temporary, "wx",
|
|
329
|
+
fd = openSync(temporary, "wx", stateFileMode());
|
|
329
330
|
writeFileSync(fd, serialized, "utf8");
|
|
330
331
|
fsyncSync(fd);
|
|
331
332
|
closeSync(fd);
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "node:fs";
|
|
15
15
|
import { hostname } from "node:os";
|
|
16
16
|
import { join, resolve } from "node:path";
|
|
17
|
+
import { stateDirMode, stateFileMode, stateModeTooOpen } from "../../storage/modes.ts";
|
|
17
18
|
import { fsyncParentDirectory } from "../../workflow/durable-record.ts";
|
|
18
19
|
import { acquireNoClobberLease } from "../../workflow/workspaces/leases.ts";
|
|
19
20
|
import type { FingerprintContextV3 } from "./canonical.ts";
|
|
@@ -78,8 +79,8 @@ export function readFingerprintKeyStoreV3(coordRoot: string): FingerprintKeyStor
|
|
|
78
79
|
|
|
79
80
|
function readKeyStoreValue(path: string): unknown {
|
|
80
81
|
const mode = statSync(path).mode & 0o777;
|
|
81
|
-
if ((mode
|
|
82
|
-
throw new Error("fingerprint key store
|
|
82
|
+
if (stateModeTooOpen(mode)) {
|
|
83
|
+
throw new Error("fingerprint key store is open to other users");
|
|
83
84
|
}
|
|
84
85
|
let parsed: unknown;
|
|
85
86
|
try {
|
|
@@ -135,8 +136,8 @@ export function fingerprintContextV3(
|
|
|
135
136
|
|
|
136
137
|
function withKeyStoreLock<T>(coordRoot: string, operation: () => T): T {
|
|
137
138
|
const privateDir = join(resolve(coordRoot), ".harnery/private");
|
|
138
|
-
mkdirSync(privateDir, { recursive: true, mode:
|
|
139
|
-
chmodSync(privateDir,
|
|
139
|
+
mkdirSync(privateDir, { recursive: true, mode: stateDirMode() });
|
|
140
|
+
chmodSync(privateDir, stateDirMode());
|
|
140
141
|
const leasePath = join(privateDir, "fingerprint-key-lease");
|
|
141
142
|
const authority = createHash("sha256").update(resolve(coordRoot)).digest("hex");
|
|
142
143
|
let lease: ReturnType<typeof acquireNoClobberLease> | undefined;
|
|
@@ -178,12 +179,12 @@ function publishKeyStore(path: string, store: FingerprintKeyStoreV3, replacing:
|
|
|
178
179
|
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
179
180
|
let fd: number | undefined;
|
|
180
181
|
try {
|
|
181
|
-
fd = openSync(temporary, "wx",
|
|
182
|
+
fd = openSync(temporary, "wx", stateFileMode());
|
|
182
183
|
writeFileSync(fd, `${JSON.stringify(store)}\n`, "utf8");
|
|
183
184
|
fsyncSync(fd);
|
|
184
185
|
closeSync(fd);
|
|
185
186
|
fd = undefined;
|
|
186
|
-
chmodSync(temporary,
|
|
187
|
+
chmodSync(temporary, stateFileMode());
|
|
187
188
|
if (!replacing && existsSync(path)) throw new Error("fingerprint key store already exists");
|
|
188
189
|
renameSync(temporary, path);
|
|
189
190
|
fsyncParentDirectory(path);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Generated by scripts/generate-event-v3-contract.ts. Do not edit. */
|
|
2
2
|
export const EVENT_V3_SCHEMA_DIGEST =
|
|
3
|
-
"sha256:
|
|
3
|
+
"sha256:07137e2cdf5eaed58d55a34e4036c87aa1f375d45c88274d07ad1cc69a6fe6f7" as const;
|
|
4
4
|
export const EVENT_V3_GENERATED_CORE_TYPES = [
|
|
5
5
|
"ledger.genesis",
|
|
6
6
|
"ledger.activated",
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
writeSync,
|
|
13
13
|
} from "node:fs";
|
|
14
14
|
import { basename, join, resolve } from "node:path";
|
|
15
|
+
import { stateDirMode, stateFileMode } from "../../storage/modes.ts";
|
|
15
16
|
|
|
16
17
|
const DEFAULT_TTL_MS = 15 * 60 * 1_000;
|
|
17
18
|
const HARD_MAX_TTL_MS = 60 * 60 * 1_000;
|
|
@@ -92,16 +93,16 @@ export function writeLiveDisplayV3(
|
|
|
92
93
|
throw new Error("V3 live-display row exceeds its bounded size");
|
|
93
94
|
}
|
|
94
95
|
const root = liveRoot(coordRoot);
|
|
95
|
-
mkdirSync(root, { recursive: true, mode:
|
|
96
|
-
chmodSync(root,
|
|
96
|
+
mkdirSync(root, { recursive: true, mode: stateDirMode() });
|
|
97
|
+
chmodSync(root, stateDirMode());
|
|
97
98
|
const path = join(root, `${input.generation_id}.ndjson`);
|
|
98
|
-
const fd = openSync(path, "a",
|
|
99
|
+
const fd = openSync(path, "a", stateFileMode());
|
|
99
100
|
try {
|
|
100
101
|
writeSync(fd, serialized, undefined, "utf8");
|
|
101
102
|
} finally {
|
|
102
103
|
closeSync(fd);
|
|
103
104
|
}
|
|
104
|
-
chmodSync(path,
|
|
105
|
+
chmodSync(path, stateFileMode());
|
|
105
106
|
return row;
|
|
106
107
|
}
|
|
107
108
|
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "node:fs";
|
|
16
16
|
import { hostname } from "node:os";
|
|
17
17
|
import { join, resolve } from "node:path";
|
|
18
|
+
import { stateDirMode, stateFileMode, stateModeTooOpen } from "../../../storage/modes.ts";
|
|
18
19
|
import { fsyncParentDirectory } from "../../../workflow/durable-record.ts";
|
|
19
20
|
import { acquireNoClobberLease } from "../../../workflow/workspaces/leases.ts";
|
|
20
21
|
import { selectCommandParentSpan } from "../../span-parent.ts";
|
|
@@ -502,9 +503,9 @@ function commandStatePath(coordRoot: string, commandSource: `hid_${string}`): st
|
|
|
502
503
|
function acquireCommandLease(coordRoot: string, statePath: string) {
|
|
503
504
|
const directory = join(statePath, "..");
|
|
504
505
|
const producerRoot = join(resolve(coordRoot), EVENT_V3_LEDGER_RELATIVE_ROOT, "private-producers");
|
|
505
|
-
mkdirSync(directory, { recursive: true, mode:
|
|
506
|
-
chmodSync(producerRoot,
|
|
507
|
-
chmodSync(directory,
|
|
506
|
+
mkdirSync(directory, { recursive: true, mode: stateDirMode() });
|
|
507
|
+
chmodSync(producerRoot, stateDirMode());
|
|
508
|
+
chmodSync(directory, stateDirMode());
|
|
508
509
|
return acquireNoClobberLease({
|
|
509
510
|
path: `${statePath}.lease`,
|
|
510
511
|
scope: "event-v3-command-producer",
|
|
@@ -522,13 +523,13 @@ function publishCommandState(path: string, state: CommandRecorderStateV3): void
|
|
|
522
523
|
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
523
524
|
let fd: number | undefined;
|
|
524
525
|
try {
|
|
525
|
-
fd = openSync(temporary, "wx",
|
|
526
|
+
fd = openSync(temporary, "wx", stateFileMode());
|
|
526
527
|
writeFileSync(fd, `${JSON.stringify(state)}\n`, "utf8");
|
|
527
528
|
fsyncSync(fd);
|
|
528
529
|
closeSync(fd);
|
|
529
530
|
fd = undefined;
|
|
530
531
|
renameSync(temporary, path);
|
|
531
|
-
chmodSync(path,
|
|
532
|
+
chmodSync(path, stateFileMode());
|
|
532
533
|
fsyncParentDirectory(path);
|
|
533
534
|
} finally {
|
|
534
535
|
if (fd !== undefined) closeSync(fd);
|
|
@@ -537,7 +538,8 @@ function publishCommandState(path: string, state: CommandRecorderStateV3): void
|
|
|
537
538
|
}
|
|
538
539
|
|
|
539
540
|
function readCommandState(path: string): CommandRecorderStateV3 {
|
|
540
|
-
if ((statSync(path).mode
|
|
541
|
+
if (stateModeTooOpen(statSync(path).mode))
|
|
542
|
+
throw new Error("V3 command state is open to other users");
|
|
541
543
|
let parsed: unknown;
|
|
542
544
|
try {
|
|
543
545
|
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "node:fs";
|
|
16
16
|
import { hostname } from "node:os";
|
|
17
17
|
import { basename, join, resolve } from "node:path";
|
|
18
|
+
import { stateDirMode, stateFileMode, stateModeTooOpen } from "../../../storage/modes.ts";
|
|
18
19
|
import { fsyncParentDirectory } from "../../../workflow/durable-record.ts";
|
|
19
20
|
import { acquireNoClobberLease } from "../../../workflow/workspaces/leases.ts";
|
|
20
21
|
import { EVENT_ADAPTER_IDS_V3, type EventAdapterIdV3 } from "../adapter-id.ts";
|
|
@@ -488,9 +489,9 @@ function coordinationProducerDirectory(coordRoot: string): string {
|
|
|
488
489
|
function acquireCoordinationLease(coordRoot: string, statePath: string) {
|
|
489
490
|
const directory = join(statePath, "..");
|
|
490
491
|
const producerRoot = join(resolve(coordRoot), EVENT_V3_LEDGER_RELATIVE_ROOT, "private-producers");
|
|
491
|
-
mkdirSync(directory, { recursive: true, mode:
|
|
492
|
-
chmodSync(producerRoot,
|
|
493
|
-
chmodSync(directory,
|
|
492
|
+
mkdirSync(directory, { recursive: true, mode: stateDirMode() });
|
|
493
|
+
chmodSync(producerRoot, stateDirMode());
|
|
494
|
+
chmodSync(directory, stateDirMode());
|
|
494
495
|
return acquireNoClobberLease({
|
|
495
496
|
path: `${statePath}.lease`,
|
|
496
497
|
scope: "event-v3-coordination-producer",
|
|
@@ -508,13 +509,13 @@ function publishCoordinationState(path: string, state: CoordinationRecorderState
|
|
|
508
509
|
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
509
510
|
let fd: number | undefined;
|
|
510
511
|
try {
|
|
511
|
-
fd = openSync(temporary, "wx",
|
|
512
|
+
fd = openSync(temporary, "wx", stateFileMode());
|
|
512
513
|
writeFileSync(fd, `${JSON.stringify(state)}\n`, "utf8");
|
|
513
514
|
fsyncSync(fd);
|
|
514
515
|
closeSync(fd);
|
|
515
516
|
fd = undefined;
|
|
516
517
|
renameSync(temporary, path);
|
|
517
|
-
chmodSync(path,
|
|
518
|
+
chmodSync(path, stateFileMode());
|
|
518
519
|
fsyncParentDirectory(path);
|
|
519
520
|
} finally {
|
|
520
521
|
if (fd !== undefined) closeSync(fd);
|
|
@@ -523,8 +524,8 @@ function publishCoordinationState(path: string, state: CoordinationRecorderState
|
|
|
523
524
|
}
|
|
524
525
|
|
|
525
526
|
function readCoordinationState(path: string): CoordinationRecorderStateV3 {
|
|
526
|
-
if ((statSync(path).mode
|
|
527
|
-
throw new Error("V3 coordination state is
|
|
527
|
+
if (stateModeTooOpen(statSync(path).mode)) {
|
|
528
|
+
throw new Error("V3 coordination state is open to other users");
|
|
528
529
|
}
|
|
529
530
|
let parsed: unknown;
|
|
530
531
|
try {
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import { hostname } from "node:os";
|
|
20
20
|
import { join, resolve } from "node:path";
|
|
21
21
|
import { coordEnv } from "../../../../lib/env.ts";
|
|
22
|
+
import { stateDirMode, stateFileMode } from "../../../storage/modes.ts";
|
|
22
23
|
import { fsyncParentDirectory } from "../../../workflow/durable-record.ts";
|
|
23
24
|
import { acquireNoClobberLease } from "../../../workflow/workspaces/leases.ts";
|
|
24
25
|
import { EVENT_V3_LEDGER_RELATIVE_ROOT } from "../writer.ts";
|
|
@@ -189,8 +190,8 @@ function summaryPath(root: string, category: string, window: string, digest: str
|
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
function ensureOwnerOnlyDirectory(path: string): void {
|
|
192
|
-
mkdirSync(path, { recursive: true, mode:
|
|
193
|
-
chmodSync(path,
|
|
193
|
+
mkdirSync(path, { recursive: true, mode: stateDirMode() });
|
|
194
|
+
chmodSync(path, stateDirMode());
|
|
194
195
|
}
|
|
195
196
|
|
|
196
197
|
function publishOwnerOnlyJson(path: string, value: unknown, durable: boolean): void {
|
|
@@ -201,7 +202,7 @@ function publishOwnerOnlyJson(path: string, value: unknown, durable: boolean): v
|
|
|
201
202
|
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
202
203
|
let fd: number | undefined;
|
|
203
204
|
try {
|
|
204
|
-
fd = openSync(temporary, "wx",
|
|
205
|
+
fd = openSync(temporary, "wx", stateFileMode());
|
|
205
206
|
writeFileSync(fd, contents, "utf8");
|
|
206
207
|
if (durable) fsyncSync(fd);
|
|
207
208
|
closeSync(fd);
|
|
@@ -401,7 +402,7 @@ function recordFailOpen(root: string, stage: string, nowMs: number): void {
|
|
|
401
402
|
// Missing log starts fresh.
|
|
402
403
|
}
|
|
403
404
|
const line = JSON.stringify({ at: new Date(nowMs).toISOString(), stage, pid: process.pid });
|
|
404
|
-
appendFileSync(path, `${line}\n`, { mode:
|
|
405
|
+
appendFileSync(path, `${line}\n`, { mode: stateFileMode() });
|
|
405
406
|
} catch {
|
|
406
407
|
// The emergency log may undercount when storage is unavailable; it is a
|
|
407
408
|
// signal, not accounting, and must never throw into the producer path.
|
|
@@ -85,6 +85,7 @@ export interface TurnRitualEvidenceV3 {
|
|
|
85
85
|
status_box_present_strict: boolean;
|
|
86
86
|
session_name_required: boolean;
|
|
87
87
|
session_name_present: boolean;
|
|
88
|
+
session_name_unavailable_reason?: string;
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
type TurnRitualObservationV3 = NonNullable<
|
|
@@ -478,10 +479,16 @@ function turnRitualObservation(
|
|
|
478
479
|
return {
|
|
479
480
|
status_box_present: observed(evidence.status_box_present),
|
|
480
481
|
status_box_present_strict: observed(evidence.status_box_present_strict),
|
|
481
|
-
session_name:
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
482
|
+
session_name: evidence.session_name_unavailable_reason
|
|
483
|
+
? {
|
|
484
|
+
state: "expected_but_missing",
|
|
485
|
+
capability: "assistant_reply_text",
|
|
486
|
+
reason: evidence.session_name_unavailable_reason,
|
|
487
|
+
}
|
|
488
|
+
: observed({
|
|
489
|
+
required: evidence.session_name_required,
|
|
490
|
+
present: evidence.session_name_present,
|
|
491
|
+
}),
|
|
485
492
|
};
|
|
486
493
|
}
|
|
487
494
|
|
|
@@ -4,6 +4,7 @@ import { adapterDurationSupportV3, adapterSignalSupportV3 } from "../capabilitie
|
|
|
4
4
|
import type { EventOfTypeV3, EventTypeV3, SpanSummaryV3 } from "../contract.ts";
|
|
5
5
|
import { EVENT_V3_CONTRACT_MAJOR, EVENT_V3_CONTRACT_NAME } from "../contract.ts";
|
|
6
6
|
import { EVENT_V3_SCHEMA_DIGEST } from "../generated.ts";
|
|
7
|
+
import type { LineChanges } from "../tool-line-changes.ts";
|
|
7
8
|
import {
|
|
8
9
|
emptyHarnessTimingV3,
|
|
9
10
|
extractTurnTelemetryV3,
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
} from "./hook-base.ts";
|
|
20
21
|
|
|
21
22
|
export interface HookProducerContextV3 extends HookProducerContextV3Base {
|
|
23
|
+
tool_line_changes?: LineChanges;
|
|
22
24
|
/** Required for terminal events; captured when the corresponding span opens. */
|
|
23
25
|
terminal_span?: SpanSummaryV3;
|
|
24
26
|
/** Required by V3 delegation starts so the child span is anchored in its parent tree. */
|
|
@@ -111,7 +113,23 @@ function terminalPayload(
|
|
|
111
113
|
const span =
|
|
112
114
|
duration === sourceSpan.duration_ms ? sourceSpan : { ...sourceSpan, duration_ms: duration };
|
|
113
115
|
if (eventType === "tool.completed") {
|
|
114
|
-
|
|
116
|
+
const counts = context.tool_line_changes;
|
|
117
|
+
const response = source.tool_response as { isError?: boolean } | undefined;
|
|
118
|
+
return {
|
|
119
|
+
...basePayload,
|
|
120
|
+
duration_ms: duration,
|
|
121
|
+
span,
|
|
122
|
+
line_changes:
|
|
123
|
+
counts &&
|
|
124
|
+
(basePayload as { outcome?: string }).outcome === "succeeded" &&
|
|
125
|
+
response?.isError !== true
|
|
126
|
+
? { state: "observed", value: counts, attestation: "derived", confidence: "high" }
|
|
127
|
+
: {
|
|
128
|
+
state: "expected_but_missing",
|
|
129
|
+
reason: "tool_line_changes_unmeasured",
|
|
130
|
+
capability: "tool_line_changes",
|
|
131
|
+
},
|
|
132
|
+
};
|
|
115
133
|
}
|
|
116
134
|
if (eventType !== "turn.completed") return { ...basePayload, span };
|
|
117
135
|
|