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,13 @@
|
|
|
1
|
+
export {
|
|
2
|
+
type BunWebViewRuntime,
|
|
3
|
+
buildWebViewBackend,
|
|
4
|
+
parseWebViewTypeStep,
|
|
5
|
+
parseWebViewViewport,
|
|
6
|
+
type RunWebViewOptions,
|
|
7
|
+
runWebView,
|
|
8
|
+
type WebViewBackend,
|
|
9
|
+
type WebViewConsoleEvent,
|
|
10
|
+
type WebViewResult,
|
|
11
|
+
type WebViewTypeStep,
|
|
12
|
+
WebViewUnavailableError,
|
|
13
|
+
} from "./webview.ts";
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun.WebView probe: a lightweight headless page load through Bun's built-in
|
|
3
|
+
* browser API (Bun 1.4+). Uses the system WKWebView on macOS and a fresh
|
|
4
|
+
* headless Chrome-family process elsewhere. Always starts a fresh browser and
|
|
5
|
+
* ephemeral storage unless a profile directory is given, and never attaches to
|
|
6
|
+
* a user's running browser.
|
|
7
|
+
*
|
|
8
|
+
* This is a narrow probe, not a `browse` backend: no headed login, HAR, cookie
|
|
9
|
+
* jar sync, full-page capture, or page QA. Bun-only; `detectRuntime` fails
|
|
10
|
+
* with a clear message on Node.
|
|
11
|
+
*/
|
|
12
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
13
|
+
import { dirname } from "node:path";
|
|
14
|
+
import { installedChromePath } from "../browser/launch-args.ts";
|
|
15
|
+
import { chromeMajorFromExecutable, resolveUserAgent } from "../browser/user-agent.ts";
|
|
16
|
+
import { PaceGate, pacePolicyFromEnv } from "../pace/index.ts";
|
|
17
|
+
|
|
18
|
+
export type WebViewBackend = "auto" | "chrome" | "webkit";
|
|
19
|
+
|
|
20
|
+
type WebViewConsoleHandler = (type: string, ...args: unknown[]) => void;
|
|
21
|
+
|
|
22
|
+
interface WebViewBackendOptions {
|
|
23
|
+
type: "chrome";
|
|
24
|
+
url: false;
|
|
25
|
+
path?: string;
|
|
26
|
+
argv?: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface WebViewConstructorOptions {
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
backend?: "webkit" | WebViewBackendOptions;
|
|
33
|
+
console?: WebViewConsoleHandler;
|
|
34
|
+
dataStore?: "ephemeral" | { directory: string };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface WebViewLike {
|
|
38
|
+
readonly url: string;
|
|
39
|
+
readonly title: string;
|
|
40
|
+
readonly loading: boolean;
|
|
41
|
+
onNavigated: ((url: string, title: string) => void) | null;
|
|
42
|
+
onNavigationFailed: ((error: Error) => void) | null;
|
|
43
|
+
navigate(url: string): Promise<void>;
|
|
44
|
+
evaluate(script: string): Promise<unknown>;
|
|
45
|
+
screenshot(options: {
|
|
46
|
+
format: "png";
|
|
47
|
+
encoding: "buffer";
|
|
48
|
+
}): Promise<Blob | Buffer | string | { name: string; size: number }>;
|
|
49
|
+
click(selector: string, options?: { timeout?: number }): Promise<void>;
|
|
50
|
+
type(text: string): Promise<void>;
|
|
51
|
+
press(key: string): Promise<void>;
|
|
52
|
+
scrollTo(
|
|
53
|
+
selector: string,
|
|
54
|
+
options?: {
|
|
55
|
+
block?: "start" | "center" | "end" | "nearest";
|
|
56
|
+
timeout?: number;
|
|
57
|
+
},
|
|
58
|
+
): Promise<void>;
|
|
59
|
+
close(): void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface BunWebViewRuntime {
|
|
63
|
+
version?: string;
|
|
64
|
+
WebView: new (options: WebViewConstructorOptions) => WebViewLike;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface WebViewTypeStep {
|
|
68
|
+
selector: string;
|
|
69
|
+
text: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface RunWebViewOptions {
|
|
73
|
+
/** Explicit UA, "auto", or "native"; Chrome uses the shared store by default. */
|
|
74
|
+
userAgent?: string;
|
|
75
|
+
backend?: WebViewBackend;
|
|
76
|
+
viewport?: { width: number; height: number };
|
|
77
|
+
profileDir?: string;
|
|
78
|
+
chromePath?: string;
|
|
79
|
+
browserArgs?: string[];
|
|
80
|
+
timeoutMs?: number;
|
|
81
|
+
waitFor?: string;
|
|
82
|
+
typeSteps?: WebViewTypeStep[];
|
|
83
|
+
clicks?: string[];
|
|
84
|
+
presses?: string[];
|
|
85
|
+
evaluate?: string;
|
|
86
|
+
settleMs?: number;
|
|
87
|
+
screenshotPath?: string;
|
|
88
|
+
captureHtml?: boolean;
|
|
89
|
+
platform?: NodeJS.Platform;
|
|
90
|
+
runtime?: BunWebViewRuntime;
|
|
91
|
+
/**
|
|
92
|
+
* Human-pace gate applied before the load. Unset resolves the default from
|
|
93
|
+
* the `HARNERY_PACE*` environment; `null` disables pacing for this run.
|
|
94
|
+
*/
|
|
95
|
+
pace?: PaceGate | null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface WebViewConsoleEvent {
|
|
99
|
+
type: string;
|
|
100
|
+
args: unknown[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface WebViewResult {
|
|
104
|
+
backend: "chrome" | "webkit";
|
|
105
|
+
runtimeVersion: string | null;
|
|
106
|
+
url: string;
|
|
107
|
+
title: string;
|
|
108
|
+
text: string;
|
|
109
|
+
html?: string;
|
|
110
|
+
evaluation?: unknown;
|
|
111
|
+
screenshotPath?: string;
|
|
112
|
+
consoleEvents: WebViewConsoleEvent[];
|
|
113
|
+
elapsedMs: number;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export class WebViewUnavailableError extends Error {
|
|
117
|
+
readonly code = "webview_unavailable";
|
|
118
|
+
|
|
119
|
+
constructor(message: string) {
|
|
120
|
+
super(message);
|
|
121
|
+
this.name = "WebViewUnavailableError";
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function parseWebViewViewport(value: string): {
|
|
126
|
+
width: number;
|
|
127
|
+
height: number;
|
|
128
|
+
} {
|
|
129
|
+
const match = /^(\d+)x(\d+)$/.exec(value.trim());
|
|
130
|
+
if (!match) {
|
|
131
|
+
throw new Error(`Invalid viewport "${value}". Expected WxH, for example 1280x800.`);
|
|
132
|
+
}
|
|
133
|
+
const width = Number.parseInt(match[1], 10);
|
|
134
|
+
const height = Number.parseInt(match[2], 10);
|
|
135
|
+
if (width < 1 || width > 16_384 || height < 1 || height > 16_384) {
|
|
136
|
+
throw new Error(`Invalid viewport "${value}". Width and height must be between 1 and 16384.`);
|
|
137
|
+
}
|
|
138
|
+
return { width, height };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function parseWebViewTypeStep(value: string): WebViewTypeStep {
|
|
142
|
+
const separator = value.indexOf("=>");
|
|
143
|
+
const selector = value.slice(0, separator).trim();
|
|
144
|
+
if (separator <= 0 || selector.length === 0) {
|
|
145
|
+
throw new Error(`Invalid type step "${value}". Expected <selector>=><text>.`);
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
selector,
|
|
149
|
+
text: value.slice(separator + 2),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function buildWebViewBackend(
|
|
154
|
+
backend: WebViewBackend,
|
|
155
|
+
options: {
|
|
156
|
+
platform: NodeJS.Platform;
|
|
157
|
+
chromePath?: string;
|
|
158
|
+
browserArgs?: string[];
|
|
159
|
+
},
|
|
160
|
+
): {
|
|
161
|
+
backend?: "webkit" | WebViewBackendOptions;
|
|
162
|
+
resolved: "chrome" | "webkit";
|
|
163
|
+
} {
|
|
164
|
+
if (backend === "webkit") {
|
|
165
|
+
if (options.platform !== "darwin") {
|
|
166
|
+
throw new Error("The Bun.WebView WebKit backend is only available on macOS.");
|
|
167
|
+
}
|
|
168
|
+
if (options.chromePath || options.browserArgs?.length) {
|
|
169
|
+
throw new Error("--chrome-path and --browser-arg require --backend chrome.");
|
|
170
|
+
}
|
|
171
|
+
return { backend: "webkit", resolved: "webkit" };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (backend === "auto" && options.platform === "darwin") {
|
|
175
|
+
if (options.chromePath || options.browserArgs?.length) {
|
|
176
|
+
throw new Error("--chrome-path and --browser-arg require --backend chrome on macOS.");
|
|
177
|
+
}
|
|
178
|
+
return { resolved: "webkit" };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
backend: {
|
|
183
|
+
type: "chrome",
|
|
184
|
+
// Bun otherwise auto-connects to a Chrome profile with remote debugging
|
|
185
|
+
// enabled. A CLI read must never open an unexpected tab in a user's
|
|
186
|
+
// existing browser, so this command always spawns a fresh headless process.
|
|
187
|
+
url: false,
|
|
188
|
+
...(options.chromePath ? { path: options.chromePath } : {}),
|
|
189
|
+
...(options.browserArgs?.length ? { argv: options.browserArgs } : {}),
|
|
190
|
+
},
|
|
191
|
+
resolved: "chrome",
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export async function runWebView(
|
|
196
|
+
url: string,
|
|
197
|
+
options: RunWebViewOptions = {},
|
|
198
|
+
): Promise<WebViewResult> {
|
|
199
|
+
const runtime = options.runtime ?? detectRuntime();
|
|
200
|
+
const platform = options.platform ?? process.platform;
|
|
201
|
+
const backendChoice = options.backend ?? "auto";
|
|
202
|
+
const selected = buildWebViewBackend(backendChoice, {
|
|
203
|
+
platform,
|
|
204
|
+
chromePath: options.chromePath,
|
|
205
|
+
browserArgs: options.browserArgs,
|
|
206
|
+
});
|
|
207
|
+
if (typeof selected.backend === "object") {
|
|
208
|
+
const executable = options.chromePath ?? installedChromePath(platform);
|
|
209
|
+
const existingUa = options.browserArgs
|
|
210
|
+
?.find((arg) => arg.startsWith("--user-agent="))
|
|
211
|
+
?.slice(13);
|
|
212
|
+
const userAgent = resolveUserAgent({
|
|
213
|
+
requested: options.userAgent ?? existingUa,
|
|
214
|
+
env: process.env.HARNERY_BROWSER_UA,
|
|
215
|
+
chromeMajor: executable ? chromeMajorFromExecutable(executable) : undefined,
|
|
216
|
+
platform,
|
|
217
|
+
});
|
|
218
|
+
const argv = [
|
|
219
|
+
...(selected.backend.argv ?? []).filter((arg) => !arg.startsWith("--user-agent=")),
|
|
220
|
+
...(userAgent ? [`--user-agent=${userAgent}`] : []),
|
|
221
|
+
];
|
|
222
|
+
if (argv.length) selected.backend.argv = argv;
|
|
223
|
+
else delete selected.backend.argv;
|
|
224
|
+
}
|
|
225
|
+
const viewport = options.viewport ?? { width: 1280, height: 800 };
|
|
226
|
+
const timeoutMs = options.timeoutMs ?? 30_000;
|
|
227
|
+
const consoleEvents: WebViewConsoleEvent[] = [];
|
|
228
|
+
const startedAt = performance.now();
|
|
229
|
+
|
|
230
|
+
const gate = options.pace === undefined ? new PaceGate(pacePolicyFromEnv()) : options.pace;
|
|
231
|
+
await gate?.before(url);
|
|
232
|
+
|
|
233
|
+
const view = new runtime.WebView({
|
|
234
|
+
width: viewport.width,
|
|
235
|
+
height: viewport.height,
|
|
236
|
+
...(selected.backend ? { backend: selected.backend } : {}),
|
|
237
|
+
dataStore: options.profileDir ? { directory: options.profileDir } : "ephemeral",
|
|
238
|
+
console: (type, ...args) => consoleEvents.push({ type, args }),
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
await withTimeout(view.navigate(url), timeoutMs, `Navigation timed out after ${timeoutMs}ms.`);
|
|
243
|
+
|
|
244
|
+
if (options.waitFor) {
|
|
245
|
+
await waitForSelector(view, options.waitFor, timeoutMs);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (const step of options.typeSteps ?? []) {
|
|
249
|
+
await view.scrollTo(step.selector, {
|
|
250
|
+
block: "nearest",
|
|
251
|
+
timeout: timeoutMs,
|
|
252
|
+
});
|
|
253
|
+
await view.click(step.selector, { timeout: timeoutMs });
|
|
254
|
+
await view.type(step.text);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
for (const selector of options.clicks ?? []) {
|
|
258
|
+
// Unlike Playwright, Bun.WebView requires selector targets to already be
|
|
259
|
+
// inside the viewport. Scroll first so below-the-fold targets do not sit
|
|
260
|
+
// until the 30-second actionability timeout.
|
|
261
|
+
await view.scrollTo(selector, { block: "nearest", timeout: timeoutMs });
|
|
262
|
+
await runActionAndWaitForNavigation(
|
|
263
|
+
view,
|
|
264
|
+
() => view.click(selector, { timeout: timeoutMs }),
|
|
265
|
+
timeoutMs,
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
for (const key of options.presses ?? []) {
|
|
270
|
+
await runActionAndWaitForNavigation(view, () => view.press(key), timeoutMs);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const settleMs = options.settleMs ?? 0;
|
|
274
|
+
if (settleMs > 0) {
|
|
275
|
+
await sleep(settleMs);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const evaluation = options.evaluate ? await view.evaluate(options.evaluate) : undefined;
|
|
279
|
+
const text = String(await view.evaluate("document.body?.innerText ?? ''"));
|
|
280
|
+
const html = options.captureHtml
|
|
281
|
+
? String(await view.evaluate("document.documentElement?.outerHTML ?? ''"))
|
|
282
|
+
: undefined;
|
|
283
|
+
|
|
284
|
+
if (options.screenshotPath) {
|
|
285
|
+
const screenshot = await view.screenshot({
|
|
286
|
+
format: "png",
|
|
287
|
+
encoding: "buffer",
|
|
288
|
+
});
|
|
289
|
+
const bytes = await screenshotBytes(screenshot);
|
|
290
|
+
await mkdir(dirname(options.screenshotPath), { recursive: true });
|
|
291
|
+
await writeFile(options.screenshotPath, bytes);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
backend: selected.resolved,
|
|
296
|
+
runtimeVersion: runtime.version ?? null,
|
|
297
|
+
url: view.url,
|
|
298
|
+
title: view.title,
|
|
299
|
+
text,
|
|
300
|
+
...(html === undefined ? {} : { html }),
|
|
301
|
+
...(options.evaluate === undefined ? {} : { evaluation }),
|
|
302
|
+
...(options.screenshotPath ? { screenshotPath: options.screenshotPath } : {}),
|
|
303
|
+
consoleEvents,
|
|
304
|
+
elapsedMs: Math.round((performance.now() - startedAt) * 10) / 10,
|
|
305
|
+
};
|
|
306
|
+
} finally {
|
|
307
|
+
view.close();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function detectRuntime(): BunWebViewRuntime {
|
|
312
|
+
const runtime = (globalThis as typeof globalThis & { Bun?: Partial<BunWebViewRuntime> }).Bun;
|
|
313
|
+
if (!runtime || typeof runtime.WebView !== "function") {
|
|
314
|
+
throw new WebViewUnavailableError(
|
|
315
|
+
"Bun.WebView requires Bun 1.4 or newer. Every other command runs on Node; use the Playwright browse command for that path.",
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
return runtime as BunWebViewRuntime;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async function waitForSelector(
|
|
322
|
+
view: WebViewLike,
|
|
323
|
+
selector: string,
|
|
324
|
+
timeoutMs: number,
|
|
325
|
+
): Promise<void> {
|
|
326
|
+
const selectorJson = JSON.stringify(selector);
|
|
327
|
+
const timeoutJson = JSON.stringify(timeoutMs);
|
|
328
|
+
await withTimeout(
|
|
329
|
+
view.evaluate(`new Promise((resolve, reject) => {
|
|
330
|
+
const selector = ${selectorJson};
|
|
331
|
+
const deadline = performance.now() + ${timeoutJson};
|
|
332
|
+
const poll = () => {
|
|
333
|
+
if (document.querySelector(selector)) return resolve(true);
|
|
334
|
+
if (performance.now() >= deadline) return reject(new Error("timeout waiting for " + selector));
|
|
335
|
+
requestAnimationFrame(poll);
|
|
336
|
+
};
|
|
337
|
+
poll();
|
|
338
|
+
})`),
|
|
339
|
+
timeoutMs + 250,
|
|
340
|
+
`Timed out waiting for selector ${selector}.`,
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async function runActionAndWaitForNavigation(
|
|
345
|
+
view: WebViewLike,
|
|
346
|
+
action: () => Promise<void>,
|
|
347
|
+
timeoutMs: number,
|
|
348
|
+
): Promise<void> {
|
|
349
|
+
const beforeDocument = await readDocumentState(view);
|
|
350
|
+
const previousNavigated = view.onNavigated;
|
|
351
|
+
const previousFailed = view.onNavigationFailed;
|
|
352
|
+
let navigated = false;
|
|
353
|
+
let navigationError: Error | null = null;
|
|
354
|
+
|
|
355
|
+
view.onNavigated = (url, title) => {
|
|
356
|
+
previousNavigated?.(url, title);
|
|
357
|
+
navigated = true;
|
|
358
|
+
};
|
|
359
|
+
view.onNavigationFailed = (error) => {
|
|
360
|
+
previousFailed?.(error);
|
|
361
|
+
navigationError = error;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
try {
|
|
365
|
+
await action();
|
|
366
|
+
// Input completion does not include a navigation triggered by that input.
|
|
367
|
+
// Observe briefly for a URL/loading/callback change. Bun's Chrome backend
|
|
368
|
+
// can report onNavigated before the replacement DOM is ready, so the
|
|
369
|
+
// callback is a detection signal rather than the settle barrier itself.
|
|
370
|
+
await sleep(50);
|
|
371
|
+
const observed = await readDocumentState(view).catch(() => null);
|
|
372
|
+
if (!navigated && !view.loading && observed !== null && observed.href === beforeDocument.href) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
await withTimeout(
|
|
377
|
+
(async () => {
|
|
378
|
+
let priorSignature = "";
|
|
379
|
+
let stableSince = performance.now();
|
|
380
|
+
while (true) {
|
|
381
|
+
if (navigationError) throw navigationError;
|
|
382
|
+
const state = await readDocumentState(view).catch(() => null);
|
|
383
|
+
if (!state || view.loading) {
|
|
384
|
+
priorSignature = "";
|
|
385
|
+
stableSince = performance.now();
|
|
386
|
+
await sleep(10);
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
const signature = JSON.stringify(state);
|
|
390
|
+
if (signature !== priorSignature) {
|
|
391
|
+
priorSignature = signature;
|
|
392
|
+
stableSince = performance.now();
|
|
393
|
+
}
|
|
394
|
+
const changedDocument = navigated || state.href !== beforeDocument.href;
|
|
395
|
+
const hasMaterialDocument =
|
|
396
|
+
state.bodyHtmlLength > 0 || state.title !== beforeDocument.title;
|
|
397
|
+
const quietFor = performance.now() - stableSince;
|
|
398
|
+
if (
|
|
399
|
+
changedDocument &&
|
|
400
|
+
state.readyState === "complete" &&
|
|
401
|
+
quietFor >= (hasMaterialDocument ? 150 : 750)
|
|
402
|
+
) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
await sleep(10);
|
|
406
|
+
}
|
|
407
|
+
})(),
|
|
408
|
+
timeoutMs,
|
|
409
|
+
`Navigation triggered by an action timed out after ${timeoutMs}ms.`,
|
|
410
|
+
);
|
|
411
|
+
} finally {
|
|
412
|
+
view.onNavigated = previousNavigated;
|
|
413
|
+
view.onNavigationFailed = previousFailed;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
interface DocumentState {
|
|
418
|
+
href: string;
|
|
419
|
+
title: string;
|
|
420
|
+
readyState: string;
|
|
421
|
+
bodyHtmlLength: number;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
async function readDocumentState(view: WebViewLike): Promise<DocumentState> {
|
|
425
|
+
return (await view.evaluate(`({
|
|
426
|
+
href: location.href,
|
|
427
|
+
title: document.title,
|
|
428
|
+
readyState: document.readyState,
|
|
429
|
+
bodyHtmlLength: document.body?.innerHTML.length ?? -1
|
|
430
|
+
})`)) as DocumentState;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
async function screenshotBytes(
|
|
434
|
+
value: Blob | Buffer | string | { name: string; size: number },
|
|
435
|
+
): Promise<Buffer> {
|
|
436
|
+
if (Buffer.isBuffer(value)) return value;
|
|
437
|
+
if (value instanceof Blob) return Buffer.from(await value.arrayBuffer());
|
|
438
|
+
throw new Error("Bun.WebView returned an unexpected screenshot encoding.");
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
async function withTimeout<T>(promise: Promise<T>, timeoutMs: number, message: string): Promise<T> {
|
|
442
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
443
|
+
try {
|
|
444
|
+
return await Promise.race([
|
|
445
|
+
promise,
|
|
446
|
+
new Promise<never>((_, reject) => {
|
|
447
|
+
timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
448
|
+
}),
|
|
449
|
+
]);
|
|
450
|
+
} finally {
|
|
451
|
+
if (timer) clearTimeout(timer);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function sleep(ms: number): Promise<void> {
|
|
456
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
457
|
+
}
|