@openagt/dashboard 0.0.0-stage → 0.9.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/LICENSE +21 -0
- package/README.md +125 -2
- package/dist/agent-id.d.ts +13 -0
- package/dist/agent-id.d.ts.map +1 -0
- package/dist/agent-id.js +20 -0
- package/dist/agent-id.js.map +1 -0
- package/dist/agent-locks.d.ts +3 -0
- package/dist/agent-locks.d.ts.map +1 -0
- package/dist/agent-locks.js +40 -0
- package/dist/agent-locks.js.map +1 -0
- package/dist/agent-view.d.ts +39 -0
- package/dist/agent-view.d.ts.map +1 -0
- package/dist/agent-view.js +45 -0
- package/dist/agent-view.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +11 -0
- package/dist/bin.js.map +1 -0
- package/dist/branch-name.d.ts +8 -0
- package/dist/branch-name.d.ts.map +1 -0
- package/dist/branch-name.js +20 -0
- package/dist/branch-name.js.map +1 -0
- package/dist/bridge-browser.d.ts +217 -0
- package/dist/bridge-browser.d.ts.map +1 -0
- package/dist/bridge-browser.js +520 -0
- package/dist/bridge-browser.js.map +1 -0
- package/dist/browser-stream.d.ts +20 -0
- package/dist/browser-stream.d.ts.map +1 -0
- package/dist/browser-stream.js +51 -0
- package/dist/browser-stream.js.map +1 -0
- package/dist/browser.d.ts +16 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +38 -0
- package/dist/browser.js.map +1 -0
- package/dist/built-in.d.ts +38 -0
- package/dist/built-in.d.ts.map +1 -0
- package/dist/built-in.js +119 -0
- package/dist/built-in.js.map +1 -0
- package/dist/chrome-extension/background.js +532 -0
- package/dist/chrome-extension/content.js +1475 -0
- package/dist/chrome-extension/driver-plan.js +41 -0
- package/dist/chrome-extension/fingerprint.js +43 -0
- package/dist/chrome-extension/manifest.json +31 -0
- package/dist/chrome-extension/options.html +48 -0
- package/dist/chrome-extension/options.js +122 -0
- package/dist/cli.d.ts +43 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +186 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +30 -0
- package/dist/client.js.map +1 -0
- package/dist/cloud-run-state.d.ts +27 -0
- package/dist/cloud-run-state.d.ts.map +1 -0
- package/dist/cloud-run-state.js +36 -0
- package/dist/cloud-run-state.js.map +1 -0
- package/dist/cloud-scratch-refs.d.ts +85 -0
- package/dist/cloud-scratch-refs.d.ts.map +1 -0
- package/dist/cloud-scratch-refs.js +275 -0
- package/dist/cloud-scratch-refs.js.map +1 -0
- package/dist/cloud-work.d.ts +66 -0
- package/dist/cloud-work.d.ts.map +1 -0
- package/dist/cloud-work.js +204 -0
- package/dist/cloud-work.js.map +1 -0
- package/dist/daemon-runtime.d.ts +42 -0
- package/dist/daemon-runtime.d.ts.map +1 -0
- package/dist/daemon-runtime.js +183 -0
- package/dist/daemon-runtime.js.map +1 -0
- package/dist/daemon-services.d.ts +37 -0
- package/dist/daemon-services.d.ts.map +1 -0
- package/dist/daemon-services.js +126 -0
- package/dist/daemon-services.js.map +1 -0
- package/dist/daemon-tick.d.ts +68 -0
- package/dist/daemon-tick.d.ts.map +1 -0
- package/dist/daemon-tick.js +97 -0
- package/dist/daemon-tick.js.map +1 -0
- package/dist/daemon.d.ts +65 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +202 -0
- package/dist/daemon.js.map +1 -0
- package/dist/dashboard/activity.d.ts +41 -0
- package/dist/dashboard/activity.d.ts.map +1 -0
- package/dist/dashboard/activity.js +56 -0
- package/dist/dashboard/activity.js.map +1 -0
- package/dist/dashboard/agent-handoff.d.ts +244 -0
- package/dist/dashboard/agent-handoff.d.ts.map +1 -0
- package/dist/dashboard/agent-handoff.js +310 -0
- package/dist/dashboard/agent-handoff.js.map +1 -0
- package/dist/dashboard/bridge-endpoints.d.ts +158 -0
- package/dist/dashboard/bridge-endpoints.d.ts.map +1 -0
- package/dist/dashboard/bridge-endpoints.js +382 -0
- package/dist/dashboard/bridge-endpoints.js.map +1 -0
- package/dist/dashboard/bridge-question.d.ts +33 -0
- package/dist/dashboard/bridge-question.d.ts.map +1 -0
- package/dist/dashboard/bridge-question.js +20 -0
- package/dist/dashboard/bridge-question.js.map +1 -0
- package/dist/dashboard/bridge-sessions.d.ts +25 -0
- package/dist/dashboard/bridge-sessions.d.ts.map +1 -0
- package/dist/dashboard/bridge-sessions.js +46 -0
- package/dist/dashboard/bridge-sessions.js.map +1 -0
- package/dist/dashboard/bridge-starts.d.ts +61 -0
- package/dist/dashboard/bridge-starts.d.ts.map +1 -0
- package/dist/dashboard/bridge-starts.js +94 -0
- package/dist/dashboard/bridge-starts.js.map +1 -0
- package/dist/dashboard/bridge-store.d.ts +179 -0
- package/dist/dashboard/bridge-store.d.ts.map +1 -0
- package/dist/dashboard/bridge-store.js +262 -0
- package/dist/dashboard/bridge-store.js.map +1 -0
- package/dist/dashboard/bundle.d.ts +12 -0
- package/dist/dashboard/bundle.d.ts.map +1 -0
- package/dist/dashboard/bundle.js +22 -0
- package/dist/dashboard/bundle.js.map +1 -0
- package/dist/dashboard/cache.d.ts +47 -0
- package/dist/dashboard/cache.d.ts.map +1 -0
- package/dist/dashboard/cache.js +87 -0
- package/dist/dashboard/cache.js.map +1 -0
- package/dist/dashboard/content-type.d.ts +3 -0
- package/dist/dashboard/content-type.d.ts.map +1 -0
- package/dist/dashboard/content-type.js +31 -0
- package/dist/dashboard/content-type.js.map +1 -0
- package/dist/dashboard/dashboard.d.ts +38 -0
- package/dist/dashboard/dashboard.d.ts.map +1 -0
- package/dist/dashboard/dashboard.js +42 -0
- package/dist/dashboard/dashboard.js.map +1 -0
- package/dist/dashboard/docs.d.ts +39 -0
- package/dist/dashboard/docs.d.ts.map +1 -0
- package/dist/dashboard/docs.js +59 -0
- package/dist/dashboard/docs.js.map +1 -0
- package/dist/dashboard/git-status.d.ts +44 -0
- package/dist/dashboard/git-status.d.ts.map +1 -0
- package/dist/dashboard/git-status.js +37 -0
- package/dist/dashboard/git-status.js.map +1 -0
- package/dist/dashboard/http.d.ts +29 -0
- package/dist/dashboard/http.d.ts.map +1 -0
- package/dist/dashboard/http.js +74 -0
- package/dist/dashboard/http.js.map +1 -0
- package/dist/dashboard/index.d.ts +24 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +23 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/dashboard/interventions.d.ts +67 -0
- package/dist/dashboard/interventions.d.ts.map +1 -0
- package/dist/dashboard/interventions.js +169 -0
- package/dist/dashboard/interventions.js.map +1 -0
- package/dist/dashboard/keyed-watcher.d.ts +29 -0
- package/dist/dashboard/keyed-watcher.d.ts.map +1 -0
- package/dist/dashboard/keyed-watcher.js +42 -0
- package/dist/dashboard/keyed-watcher.js.map +1 -0
- package/dist/dashboard/keys.d.ts +31 -0
- package/dist/dashboard/keys.d.ts.map +1 -0
- package/dist/dashboard/keys.js +37 -0
- package/dist/dashboard/keys.js.map +1 -0
- package/dist/dashboard/models.d.ts +25 -0
- package/dist/dashboard/models.d.ts.map +1 -0
- package/dist/dashboard/models.js +30 -0
- package/dist/dashboard/models.js.map +1 -0
- package/dist/dashboard/module-host.d.ts +44 -0
- package/dist/dashboard/module-host.d.ts.map +1 -0
- package/dist/dashboard/module-host.js +91 -0
- package/dist/dashboard/module-host.js.map +1 -0
- package/dist/dashboard/module-serve.d.ts +15 -0
- package/dist/dashboard/module-serve.d.ts.map +1 -0
- package/dist/dashboard/module-serve.js +45 -0
- package/dist/dashboard/module-serve.js.map +1 -0
- package/dist/dashboard/open-in-app.d.ts +43 -0
- package/dist/dashboard/open-in-app.d.ts.map +1 -0
- package/dist/dashboard/open-in-app.js +98 -0
- package/dist/dashboard/open-in-app.js.map +1 -0
- package/dist/dashboard/open-questions.d.ts +45 -0
- package/dist/dashboard/open-questions.d.ts.map +1 -0
- package/dist/dashboard/open-questions.js +62 -0
- package/dist/dashboard/open-questions.js.map +1 -0
- package/dist/dashboard/overview.d.ts +78 -0
- package/dist/dashboard/overview.d.ts.map +1 -0
- package/dist/dashboard/overview.js +87 -0
- package/dist/dashboard/overview.js.map +1 -0
- package/dist/dashboard/projects.d.ts +101 -0
- package/dist/dashboard/projects.d.ts.map +1 -0
- package/dist/dashboard/projects.js +63 -0
- package/dist/dashboard/projects.js.map +1 -0
- package/dist/dashboard/pull-requests.d.ts +127 -0
- package/dist/dashboard/pull-requests.d.ts.map +1 -0
- package/dist/dashboard/pull-requests.js +137 -0
- package/dist/dashboard/pull-requests.js.map +1 -0
- package/dist/dashboard/queue.d.ts +17 -0
- package/dist/dashboard/queue.d.ts.map +1 -0
- package/dist/dashboard/queue.js +19 -0
- package/dist/dashboard/queue.js.map +1 -0
- package/dist/dashboard/quota.d.ts +53 -0
- package/dist/dashboard/quota.d.ts.map +1 -0
- package/dist/dashboard/quota.js +42 -0
- package/dist/dashboard/quota.js.map +1 -0
- package/dist/dashboard/relay-endpoints.d.ts +32 -0
- package/dist/dashboard/relay-endpoints.d.ts.map +1 -0
- package/dist/dashboard/relay-endpoints.js +115 -0
- package/dist/dashboard/relay-endpoints.js.map +1 -0
- package/dist/dashboard/remote-run.d.ts +95 -0
- package/dist/dashboard/remote-run.d.ts.map +1 -0
- package/dist/dashboard/remote-run.js +235 -0
- package/dist/dashboard/remote-run.js.map +1 -0
- package/dist/dashboard/rpc-serve.d.ts +106 -0
- package/dist/dashboard/rpc-serve.d.ts.map +1 -0
- package/dist/dashboard/rpc-serve.js +180 -0
- package/dist/dashboard/rpc-serve.js.map +1 -0
- package/dist/dashboard/run-inbox.d.ts +31 -0
- package/dist/dashboard/run-inbox.d.ts.map +1 -0
- package/dist/dashboard/run-inbox.js +51 -0
- package/dist/dashboard/run-inbox.js.map +1 -0
- package/dist/dashboard/server.d.ts +105 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.js +231 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/dashboard/static.d.ts +9 -0
- package/dist/dashboard/static.d.ts.map +1 -0
- package/dist/dashboard/static.js +54 -0
- package/dist/dashboard/static.js.map +1 -0
- package/dist/dashboard/types.d.ts +135 -0
- package/dist/dashboard/types.d.ts.map +1 -0
- package/dist/dashboard/types.js +2 -0
- package/dist/dashboard/types.js.map +1 -0
- package/dist/dashboard/web-start-endpoints.d.ts +32 -0
- package/dist/dashboard/web-start-endpoints.d.ts.map +1 -0
- package/dist/dashboard/web-start-endpoints.js +75 -0
- package/dist/dashboard/web-start-endpoints.js.map +1 -0
- package/dist/dashboard-bundle/assets/client-CbBRB9m4.js +9 -0
- package/dist/dashboard-bundle/assets/jsx-runtime-By8HlURe.js +1 -0
- package/dist/dashboard-bundle/assets/main-B98UOA3_.js +140 -0
- package/dist/dashboard-bundle/assets/main-ByRjbCiA.css +2 -0
- package/dist/dashboard-bundle/assets/module-v213KWfH.js +21 -0
- package/dist/dashboard-bundle/assets/react-CZI7_Jkm.js +1 -0
- package/dist/dashboard-bundle/assets/react-dom-cJyBB_A4.js +1 -0
- package/dist/dashboard-bundle/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/dist/dashboard-bundle/host/module.js +1 -0
- package/dist/dashboard-bundle/host/react-dom-client.js +1 -0
- package/dist/dashboard-bundle/host/react-dom.js +1 -0
- package/dist/dashboard-bundle/host/react-jsx-runtime.js +1 -0
- package/dist/dashboard-bundle/host/react.js +1 -0
- package/dist/dashboard-bundle/index.html +42 -0
- package/dist/dashboard-bundle/logo-animated.svg +34 -0
- package/dist/dashboard-bundle/logo.svg +16 -0
- package/dist/dashboard-rpc/context.d.ts +56 -0
- package/dist/dashboard-rpc/context.d.ts.map +1 -0
- package/dist/dashboard-rpc/context.js +106 -0
- package/dist/dashboard-rpc/context.js.map +1 -0
- package/dist/dashboard-rpc/control.d.ts +124 -0
- package/dist/dashboard-rpc/control.d.ts.map +1 -0
- package/dist/dashboard-rpc/control.js +284 -0
- package/dist/dashboard-rpc/control.js.map +1 -0
- package/dist/dashboard-rpc/devices.d.ts +9 -0
- package/dist/dashboard-rpc/devices.d.ts.map +1 -0
- package/dist/dashboard-rpc/devices.js +12 -0
- package/dist/dashboard-rpc/devices.js.map +1 -0
- package/dist/dashboard-rpc/events-tail.d.ts +68 -0
- package/dist/dashboard-rpc/events-tail.d.ts.map +1 -0
- package/dist/dashboard-rpc/events-tail.js +257 -0
- package/dist/dashboard-rpc/events-tail.js.map +1 -0
- package/dist/dashboard-rpc/events.d.ts +39 -0
- package/dist/dashboard-rpc/events.d.ts.map +1 -0
- package/dist/dashboard-rpc/events.js +47 -0
- package/dist/dashboard-rpc/events.js.map +1 -0
- package/dist/dashboard-rpc/index.d.ts +29 -0
- package/dist/dashboard-rpc/index.d.ts.map +1 -0
- package/dist/dashboard-rpc/index.js +40 -0
- package/dist/dashboard-rpc/index.js.map +1 -0
- package/dist/dashboard-rpc/models.d.ts +4 -0
- package/dist/dashboard-rpc/models.d.ts.map +1 -0
- package/dist/dashboard-rpc/models.js +8 -0
- package/dist/dashboard-rpc/models.js.map +1 -0
- package/dist/dashboard-rpc/modules.d.ts +45 -0
- package/dist/dashboard-rpc/modules.d.ts.map +1 -0
- package/dist/dashboard-rpc/modules.js +79 -0
- package/dist/dashboard-rpc/modules.js.map +1 -0
- package/dist/dashboard-rpc/preferences.d.ts +41 -0
- package/dist/dashboard-rpc/preferences.d.ts.map +1 -0
- package/dist/dashboard-rpc/preferences.js +65 -0
- package/dist/dashboard-rpc/preferences.js.map +1 -0
- package/dist/dashboard-rpc/projects.d.ts +85 -0
- package/dist/dashboard-rpc/projects.d.ts.map +1 -0
- package/dist/dashboard-rpc/projects.js +129 -0
- package/dist/dashboard-rpc/projects.js.map +1 -0
- package/dist/dashboard-rpc/quota.d.ts +4 -0
- package/dist/dashboard-rpc/quota.d.ts.map +1 -0
- package/dist/dashboard-rpc/quota.js +15 -0
- package/dist/dashboard-rpc/quota.js.map +1 -0
- package/dist/dashboard-rpc/reads.d.ts +185 -0
- package/dist/dashboard-rpc/reads.d.ts.map +1 -0
- package/dist/dashboard-rpc/reads.js +370 -0
- package/dist/dashboard-rpc/reads.js.map +1 -0
- package/dist/dashboard-rpc/relay-agent.d.ts +9 -0
- package/dist/dashboard-rpc/relay-agent.d.ts.map +1 -0
- package/dist/dashboard-rpc/relay-agent.js +21 -0
- package/dist/dashboard-rpc/relay-agent.js.map +1 -0
- package/dist/dashboard-rpc/relay-dispatch.d.ts +9 -0
- package/dist/dashboard-rpc/relay-dispatch.d.ts.map +1 -0
- package/dist/dashboard-rpc/relay-dispatch.js +24 -0
- package/dist/dashboard-rpc/relay-dispatch.js.map +1 -0
- package/dist/dashboard-rpc/stream-forward.d.ts +17 -0
- package/dist/dashboard-rpc/stream-forward.d.ts.map +1 -0
- package/dist/dashboard-rpc/stream-forward.js +38 -0
- package/dist/dashboard-rpc/stream-forward.js.map +1 -0
- package/dist/dashboard-rpc/test-context.d.ts +23 -0
- package/dist/dashboard-rpc/test-context.d.ts.map +1 -0
- package/dist/dashboard-rpc/test-context.js +43 -0
- package/dist/dashboard-rpc/test-context.js.map +1 -0
- package/dist/driver-names.d.ts +22 -0
- package/dist/driver-names.d.ts.map +1 -0
- package/dist/driver-names.js +29 -0
- package/dist/driver-names.js.map +1 -0
- package/dist/error-message.d.ts +8 -0
- package/dist/error-message.d.ts.map +1 -0
- package/dist/error-message.js +10 -0
- package/dist/error-message.js.map +1 -0
- package/dist/event-stream.d.ts +33 -0
- package/dist/event-stream.d.ts.map +1 -0
- package/dist/event-stream.js +104 -0
- package/dist/event-stream.js.map +1 -0
- package/dist/events.d.ts +236 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +5 -0
- package/dist/events.js.map +1 -0
- package/dist/format-bytes.d.ts +3 -0
- package/dist/format-bytes.d.ts.map +1 -0
- package/dist/format-bytes.js +18 -0
- package/dist/format-bytes.js.map +1 -0
- package/dist/has-remote.d.ts +8 -0
- package/dist/has-remote.d.ts.map +1 -0
- package/dist/has-remote.js +10 -0
- package/dist/has-remote.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +31 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +54 -0
- package/dist/install.js.map +1 -0
- package/dist/jsonl-tail.d.ts +59 -0
- package/dist/jsonl-tail.d.ts.map +1 -0
- package/dist/jsonl-tail.js +152 -0
- package/dist/jsonl-tail.js.map +1 -0
- package/dist/loopback-host.d.ts +20 -0
- package/dist/loopback-host.d.ts.map +1 -0
- package/dist/loopback-host.js +31 -0
- package/dist/loopback-host.js.map +1 -0
- package/dist/module-server.d.ts +56 -0
- package/dist/module-types/dashboard/components/DiffStat.d.ts +6 -0
- package/dist/module-types/dashboard/components/DriverModelMenu.d.ts +23 -0
- package/dist/module-types/dashboard/components/LinkActions.d.ts +26 -0
- package/dist/module-types/dashboard/components/Markdown.d.ts +4 -0
- package/dist/module-types/dashboard/components/SettingsRows.d.ts +37 -0
- package/dist/module-types/dashboard/components/StartAgentButton.d.ts +39 -0
- package/dist/module-types/dashboard/components/ui/badge.d.ts +2 -0
- package/dist/module-types/dashboard/components/ui/button.d.ts +10 -0
- package/dist/module-types/dashboard/components/ui/card.d.ts +5 -0
- package/dist/module-types/dashboard/components/ui/checkbox.d.ts +7 -0
- package/dist/module-types/dashboard/components/ui/dropdown-menu.d.ts +16 -0
- package/dist/module-types/dashboard/components/ui/input.d.ts +2 -0
- package/dist/module-types/dashboard/components/ui/option-label.d.ts +4 -0
- package/dist/module-types/dashboard/components/ui/popover.d.ts +8 -0
- package/dist/module-types/dashboard/components/ui/scroll-area.d.ts +10 -0
- package/dist/module-types/dashboard/components/ui/separator.d.ts +3 -0
- package/dist/module-types/dashboard/components/ui/skeleton.d.ts +2 -0
- package/dist/module-types/dashboard/components/ui/slider.d.ts +9 -0
- package/dist/module-types/dashboard/components/ui/tooltip.d.ts +11 -0
- package/dist/module-types/dashboard/lib/agent-settings.d.ts +2 -0
- package/dist/module-types/dashboard/lib/draft-handoff.d.ts +15 -0
- package/dist/module-types/dashboard/lib/format-date.d.ts +51 -0
- package/dist/module-types/dashboard/lib/host-services.d.ts +12 -0
- package/dist/module-types/dashboard/lib/models.d.ts +24 -0
- package/dist/module-types/dashboard/lib/route.d.ts +38 -0
- package/dist/module-types/dashboard/lib/rpc.d.ts +31 -0
- package/dist/module-types/dashboard/lib/use-action.d.ts +25 -0
- package/dist/module-types/dashboard/lib/use-async.d.ts +45 -0
- package/dist/module-types/dashboard/lib/use-modules.d.ts +79 -0
- package/dist/module-types/dashboard/lib/utils.d.ts +3 -0
- package/dist/module-types/dashboard/module/index.d.ts +335 -0
- package/dist/module-types/dashboard/rpc/models.d.ts +2 -0
- package/dist/module-types/dashboard/rpc/modules.d.ts +5 -0
- package/dist/module-types/src/agent-id.d.ts +12 -0
- package/dist/module-types/src/agent-locks.d.ts +2 -0
- package/dist/module-types/src/agent-view.d.ts +38 -0
- package/dist/module-types/src/bridge-browser.d.ts +216 -0
- package/dist/module-types/src/browser-stream.d.ts +19 -0
- package/dist/module-types/src/browser.d.ts +15 -0
- package/dist/module-types/src/built-in.d.ts +37 -0
- package/dist/module-types/src/client.d.ts +15 -0
- package/dist/module-types/src/cloud-run-state.d.ts +26 -0
- package/dist/module-types/src/dashboard/activity.d.ts +40 -0
- package/dist/module-types/src/dashboard/agent-handoff.d.ts +243 -0
- package/dist/module-types/src/dashboard/bridge-endpoints.d.ts +157 -0
- package/dist/module-types/src/dashboard/bridge-question.d.ts +32 -0
- package/dist/module-types/src/dashboard/bridge-store.d.ts +178 -0
- package/dist/module-types/src/dashboard/cache.d.ts +46 -0
- package/dist/module-types/src/dashboard/content-type.d.ts +2 -0
- package/dist/module-types/src/dashboard/dashboard.d.ts +37 -0
- package/dist/module-types/src/dashboard/docs.d.ts +38 -0
- package/dist/module-types/src/dashboard/git-status.d.ts +43 -0
- package/dist/module-types/src/dashboard/http.d.ts +28 -0
- package/dist/module-types/src/dashboard/interventions.d.ts +66 -0
- package/dist/module-types/src/dashboard/keyed-watcher.d.ts +28 -0
- package/dist/module-types/src/dashboard/keys.d.ts +30 -0
- package/dist/module-types/src/dashboard/models.d.ts +24 -0
- package/dist/module-types/src/dashboard/module-host.d.ts +43 -0
- package/dist/module-types/src/dashboard/module-serve.d.ts +14 -0
- package/dist/module-types/src/dashboard/open-in-app.d.ts +42 -0
- package/dist/module-types/src/dashboard/open-questions.d.ts +44 -0
- package/dist/module-types/src/dashboard/overview.d.ts +77 -0
- package/dist/module-types/src/dashboard/projects.d.ts +100 -0
- package/dist/module-types/src/dashboard/pull-requests.d.ts +126 -0
- package/dist/module-types/src/dashboard/queue.d.ts +16 -0
- package/dist/module-types/src/dashboard/quota.d.ts +52 -0
- package/dist/module-types/src/dashboard/remote-run.d.ts +94 -0
- package/dist/module-types/src/dashboard/rpc-serve.d.ts +105 -0
- package/dist/module-types/src/dashboard/run-inbox.d.ts +30 -0
- package/dist/module-types/src/dashboard/types.d.ts +134 -0
- package/dist/module-types/src/dashboard-rpc/context.d.ts +55 -0
- package/dist/module-types/src/dashboard-rpc/control.d.ts +123 -0
- package/dist/module-types/src/dashboard-rpc/devices.d.ts +8 -0
- package/dist/module-types/src/dashboard-rpc/events-tail.d.ts +67 -0
- package/dist/module-types/src/dashboard-rpc/events.d.ts +38 -0
- package/dist/module-types/src/dashboard-rpc/index.d.ts +28 -0
- package/dist/module-types/src/dashboard-rpc/models.d.ts +3 -0
- package/dist/module-types/src/dashboard-rpc/modules.d.ts +44 -0
- package/dist/module-types/src/dashboard-rpc/preferences.d.ts +40 -0
- package/dist/module-types/src/dashboard-rpc/projects.d.ts +84 -0
- package/dist/module-types/src/dashboard-rpc/quota.d.ts +3 -0
- package/dist/module-types/src/dashboard-rpc/reads.d.ts +184 -0
- package/dist/module-types/src/dashboard-rpc/relay-agent.d.ts +8 -0
- package/dist/module-types/src/dashboard-rpc/stream-forward.d.ts +16 -0
- package/dist/module-types/src/driver-names.d.ts +21 -0
- package/dist/module-types/src/error-message.d.ts +7 -0
- package/dist/module-types/src/event-stream.d.ts +32 -0
- package/dist/module-types/src/events.d.ts +235 -0
- package/dist/module-types/src/format-bytes.d.ts +2 -0
- package/dist/module-types/src/has-remote.d.ts +7 -0
- package/dist/module-types/src/index.d.ts +41 -0
- package/dist/module-types/src/jsonl-tail.d.ts +58 -0
- package/dist/module-types/src/loopback-host.d.ts +19 -0
- package/dist/module-types/src/node-fs.d.ts +32 -0
- package/dist/module-types/src/open-choices.d.ts +14 -0
- package/dist/module-types/src/openagent-dir.d.ts +10 -0
- package/dist/module-types/src/openagent-gitignore.d.ts +11 -0
- package/dist/module-types/src/pick-directory.d.ts +29 -0
- package/dist/module-types/src/preference-defaults.d.ts +42 -0
- package/dist/module-types/src/project-commands.d.ts +23 -0
- package/dist/module-types/src/project-errors.d.ts +59 -0
- package/dist/module-types/src/project-hooks.d.ts +129 -0
- package/dist/module-types/src/project-modules.d.ts +49 -0
- package/dist/module-types/src/project-presets.d.ts +29 -0
- package/dist/module-types/src/project.d.ts +28 -0
- package/dist/module-types/src/publish-levels.d.ts +32 -0
- package/dist/module-types/src/quota-boundary.d.ts +64 -0
- package/dist/module-types/src/quota-poller.d.ts +82 -0
- package/dist/module-types/src/registry.d.ts +226 -0
- package/dist/module-types/src/store/agent-checkout.d.ts +53 -0
- package/dist/module-types/src/store/agent-store.d.ts +266 -0
- package/dist/module-types/src/store/branches.d.ts +163 -0
- package/dist/module-types/src/store/git-host.d.ts +113 -0
- package/dist/module-types/src/store/index.d.ts +9 -0
- package/dist/module-types/src/store/provided.d.ts +16 -0
- package/dist/module-types/src/store/queue.d.ts +45 -0
- package/dist/module-types/src/store/repository.d.ts +32 -0
- package/dist/module-types/src/store/run-record.d.ts +21 -0
- package/dist/module-types/src/store/runs.d.ts +107 -0
- package/dist/module-types/src/store/tickets.d.ts +72 -0
- package/dist/module-types/src/terminal.d.ts +3 -0
- package/dist/module-types/src/worktrees.d.ts +89 -0
- package/dist/module.css +50 -0
- package/dist/node-fs.d.ts +33 -0
- package/dist/node-fs.d.ts.map +1 -0
- package/dist/node-fs.js +57 -0
- package/dist/node-fs.js.map +1 -0
- package/dist/open-choices.d.ts +15 -0
- package/dist/open-choices.d.ts.map +1 -0
- package/dist/open-choices.js +31 -0
- package/dist/open-choices.js.map +1 -0
- package/dist/openagent-dir.d.ts +11 -0
- package/dist/openagent-dir.d.ts.map +1 -0
- package/dist/openagent-dir.js +11 -0
- package/dist/openagent-dir.js.map +1 -0
- package/dist/openagent-gitignore.d.ts +12 -0
- package/dist/openagent-gitignore.d.ts.map +1 -0
- package/dist/openagent-gitignore.js +19 -0
- package/dist/openagent-gitignore.js.map +1 -0
- package/dist/pick-directory.d.ts +30 -0
- package/dist/pick-directory.d.ts.map +1 -0
- package/dist/pick-directory.js +102 -0
- package/dist/pick-directory.js.map +1 -0
- package/dist/preference-defaults.d.ts +43 -0
- package/dist/preference-defaults.d.ts.map +1 -0
- package/dist/preference-defaults.js +34 -0
- package/dist/preference-defaults.js.map +1 -0
- package/dist/project-commands.d.ts +24 -0
- package/dist/project-commands.d.ts.map +1 -0
- package/dist/project-commands.js +57 -0
- package/dist/project-commands.js.map +1 -0
- package/dist/project-errors.d.ts +60 -0
- package/dist/project-errors.d.ts.map +1 -0
- package/dist/project-errors.js +51 -0
- package/dist/project-errors.js.map +1 -0
- package/dist/project-hooks.d.ts +130 -0
- package/dist/project-hooks.d.ts.map +1 -0
- package/dist/project-hooks.js +232 -0
- package/dist/project-hooks.js.map +1 -0
- package/dist/project-modules.d.ts +50 -0
- package/dist/project-modules.d.ts.map +1 -0
- package/dist/project-modules.js +110 -0
- package/dist/project-modules.js.map +1 -0
- package/dist/project-pass.d.ts +32 -0
- package/dist/project-pass.d.ts.map +1 -0
- package/dist/project-pass.js +45 -0
- package/dist/project-pass.js.map +1 -0
- package/dist/project-presets.d.ts +30 -0
- package/dist/project-presets.d.ts.map +1 -0
- package/dist/project-presets.js +74 -0
- package/dist/project-presets.js.map +1 -0
- package/dist/project.d.ts +29 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +41 -0
- package/dist/project.js.map +1 -0
- package/dist/publish-levels.d.ts +33 -0
- package/dist/publish-levels.d.ts.map +1 -0
- package/dist/publish-levels.js +53 -0
- package/dist/publish-levels.js.map +1 -0
- package/dist/quota-boundary.d.ts +65 -0
- package/dist/quota-boundary.d.ts.map +1 -0
- package/dist/quota-boundary.js +135 -0
- package/dist/quota-boundary.js.map +1 -0
- package/dist/quota-poller.d.ts +83 -0
- package/dist/quota-poller.d.ts.map +1 -0
- package/dist/quota-poller.js +118 -0
- package/dist/quota-poller.js.map +1 -0
- package/dist/registry.d.ts +227 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +364 -0
- package/dist/registry.js.map +1 -0
- package/dist/remove-files.d.ts +24 -0
- package/dist/remove-files.d.ts.map +1 -0
- package/dist/remove-files.js +98 -0
- package/dist/remove-files.js.map +1 -0
- package/dist/request-path.d.ts +10 -0
- package/dist/request-path.d.ts.map +1 -0
- package/dist/request-path.js +16 -0
- package/dist/request-path.js.map +1 -0
- package/dist/store/agent-checkout.d.ts +54 -0
- package/dist/store/agent-checkout.d.ts.map +1 -0
- package/dist/store/agent-checkout.js +61 -0
- package/dist/store/agent-checkout.js.map +1 -0
- package/dist/store/agent-store.d.ts +267 -0
- package/dist/store/agent-store.d.ts.map +1 -0
- package/dist/store/agent-store.js +190 -0
- package/dist/store/agent-store.js.map +1 -0
- package/dist/store/branches.d.ts +164 -0
- package/dist/store/branches.d.ts.map +1 -0
- package/dist/store/branches.js +187 -0
- package/dist/store/branches.js.map +1 -0
- package/dist/store/git-host.d.ts +114 -0
- package/dist/store/git-host.d.ts.map +1 -0
- package/dist/store/git-host.js +103 -0
- package/dist/store/git-host.js.map +1 -0
- package/dist/store/index.d.ts +10 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +10 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/provided.d.ts +17 -0
- package/dist/store/provided.d.ts.map +1 -0
- package/dist/store/provided.js +37 -0
- package/dist/store/provided.js.map +1 -0
- package/dist/store/queue.d.ts +46 -0
- package/dist/store/queue.d.ts.map +1 -0
- package/dist/store/queue.js +61 -0
- package/dist/store/queue.js.map +1 -0
- package/dist/store/repository.d.ts +33 -0
- package/dist/store/repository.d.ts.map +1 -0
- package/dist/store/repository.js +25 -0
- package/dist/store/repository.js.map +1 -0
- package/dist/store/run-record.d.ts +22 -0
- package/dist/store/run-record.d.ts.map +1 -0
- package/dist/store/run-record.js +108 -0
- package/dist/store/run-record.js.map +1 -0
- package/dist/store/runs.d.ts +108 -0
- package/dist/store/runs.d.ts.map +1 -0
- package/dist/store/runs.js +146 -0
- package/dist/store/runs.js.map +1 -0
- package/dist/store/test-branches.d.ts +18 -0
- package/dist/store/test-branches.d.ts.map +1 -0
- package/dist/store/test-branches.js +59 -0
- package/dist/store/test-branches.js.map +1 -0
- package/dist/store/test-runs.d.ts +15 -0
- package/dist/store/test-runs.d.ts.map +1 -0
- package/dist/store/test-runs.js +37 -0
- package/dist/store/test-runs.js.map +1 -0
- package/dist/store/tickets.d.ts +73 -0
- package/dist/store/tickets.d.ts.map +1 -0
- package/dist/store/tickets.js +67 -0
- package/dist/store/tickets.js.map +1 -0
- package/dist/terminal.d.ts +4 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +97 -0
- package/dist/terminal.js.map +1 -0
- package/dist/update-check.d.ts +44 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +71 -0
- package/dist/update-check.js.map +1 -0
- package/dist/worktrees.d.ts +90 -0
- package/dist/worktrees.d.ts.map +1 -0
- package/dist/worktrees.js +123 -0
- package/dist/worktrees.js.map +1 -0
- package/package.json +103 -3
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
// The half that talks to the daemon.
|
|
2
|
+
//
|
|
3
|
+
// **Why the fetch lives here and not in the content script.** A content script's fetch carries
|
|
4
|
+
// the page's origin, so it would be a cross-origin request and the daemon deliberately answers
|
|
5
|
+
// no CORS headers: a wildcard there would let any site the user visits post to their dashboard.
|
|
6
|
+
// A service worker holding `host_permissions` is not subject to CORS, so the same request works
|
|
7
|
+
// from here and only from here.
|
|
8
|
+
//
|
|
9
|
+
// It also keeps the token out of the page. A content script shares a tab with claude.ai, and
|
|
10
|
+
// nothing on that page should ever be able to read the secret that talks to a daemon.
|
|
11
|
+
|
|
12
|
+
importScripts('driver-plan.js', 'fingerprint.js')
|
|
13
|
+
|
|
14
|
+
const DEFAULT_DAEMON = 'http://localhost:4200'
|
|
15
|
+
|
|
16
|
+
// Every daemon call states this extension's version, and a daemon expecting another refuses it
|
|
17
|
+
// outright (#1519): a version-skewed extension half-works in ways that read as dashboard bugs,
|
|
18
|
+
// so the daemon blocks rather than degrades, and the error it answers names both versions.
|
|
19
|
+
const VERSION_HEADER = { 'x-oa-extension-version': chrome.runtime.getManifest().version }
|
|
20
|
+
|
|
21
|
+
/** What we last successfully reported per session, so a re-render does not re-post. */
|
|
22
|
+
const lastSent = new Map()
|
|
23
|
+
|
|
24
|
+
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
25
|
+
// Run a cycle on demand, so the options page can prove it works without waiting on an alarm.
|
|
26
|
+
if (message?.type === 'oa-open-now') {
|
|
27
|
+
void openDriverNow()
|
|
28
|
+
.then(sendResponse)
|
|
29
|
+
.catch(err => sendResponse({ ok: false, reason: String(err?.message ?? err) }))
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
if (message?.type === 'oa-hello') {
|
|
33
|
+
// The reply says whether the page asking is the Driver tab, so it draws its overlay the
|
|
34
|
+
// moment it loads rather than when the first cycle reaches it.
|
|
35
|
+
void Promise.all([post('/_bridge/hello', { version: message.version, sessionId: message.sessionId, note: message.note }), driverTabId()])
|
|
36
|
+
.then(([reply, driver]) => sendResponse({ ...reply, driver: sender.tab?.id != null && sender.tab.id === driver }))
|
|
37
|
+
.catch(() => sendResponse({ ok: false }))
|
|
38
|
+
return true
|
|
39
|
+
}
|
|
40
|
+
if (message?.type === 'oa-driver-log') {
|
|
41
|
+
// Receiving it is the point: a cycle in the page can run for minutes, and each message
|
|
42
|
+
// resets the idle clock that would otherwise end this worker mid-cycle.
|
|
43
|
+
sendResponse({ ok: true })
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
if (message?.type === 'oa-events') {
|
|
47
|
+
void postEvents(message)
|
|
48
|
+
.then(sendResponse)
|
|
49
|
+
.catch(err => sendResponse({ ok: false, error: String(err?.message ?? err) }))
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
52
|
+
if (message?.type !== 'oa-question') return false
|
|
53
|
+
void report(message.question)
|
|
54
|
+
.then(sendResponse)
|
|
55
|
+
.catch(err => sendResponse({ ok: false, error: String(err?.message ?? err) }))
|
|
56
|
+
// Keep the message channel open for the async reply.
|
|
57
|
+
return true
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
async function report(question) {
|
|
61
|
+
if (!question?.sessionId) return { ok: false, error: 'no session id' }
|
|
62
|
+
const { daemonUrl, token } = await chrome.storage.local.get(['daemonUrl', 'token'])
|
|
63
|
+
if (!token) return { ok: false, error: 'no token set: open the extension options' }
|
|
64
|
+
|
|
65
|
+
// Same question, same session: say so and spend nothing. The content script re-surveys on every
|
|
66
|
+
// DOM change, and a parked question can sit there for an hour.
|
|
67
|
+
const fingerprint = JSON.stringify([question.title, question.options, question.recommended])
|
|
68
|
+
if (lastSent.get(question.sessionId) === fingerprint) return { ok: true, skipped: 'unchanged' }
|
|
69
|
+
|
|
70
|
+
const base = (daemonUrl || DEFAULT_DAEMON).replace(/\/+$/, '')
|
|
71
|
+
const res = await fetch(`${base}/_bridge/question`, {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${token}`, ...VERSION_HEADER },
|
|
74
|
+
body: JSON.stringify(question),
|
|
75
|
+
})
|
|
76
|
+
if (!res.ok) {
|
|
77
|
+
// Do not remember a failure, so the next DOM change retries rather than going quiet.
|
|
78
|
+
return { ok: false, error: `daemon answered ${res.status}: ${(await res.text()).slice(0, 200)}` }
|
|
79
|
+
}
|
|
80
|
+
lastSent.set(question.sessionId, fingerprint)
|
|
81
|
+
return { ok: true }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Answers travelling back (#1237): the dashboard queues a pick, the cycle collects it, the Driver
|
|
86
|
+
// tab types it into the session, and the outcome is reported.
|
|
87
|
+
|
|
88
|
+
/** Answer ids already handed to the Driver, so a slow ack cannot double-submit into the session. */
|
|
89
|
+
const deliveredAnswers = new Set()
|
|
90
|
+
|
|
91
|
+
/** Acks that failed to reach the daemon, retried on the next cycle rather than dropped. */
|
|
92
|
+
const pendingAcks = new Map()
|
|
93
|
+
|
|
94
|
+
/** Tell the daemon what a delivery did. A failed ack is kept and retried, never dropped: an
|
|
95
|
+
* unacked delivered answer would sit `queued` in the dashboard after being typed into the page. */
|
|
96
|
+
async function ack(base, token, body) {
|
|
97
|
+
try {
|
|
98
|
+
const res = await fetch(`${base}/_bridge/answered`, {
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${token}`, ...VERSION_HEADER },
|
|
101
|
+
body: JSON.stringify(body),
|
|
102
|
+
})
|
|
103
|
+
if (res.ok || res.status === 400) {
|
|
104
|
+
pendingAcks.delete(body.id)
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
} catch {
|
|
108
|
+
// Fall through to the retry queue.
|
|
109
|
+
}
|
|
110
|
+
pendingAcks.set(body.id, body)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** The answer the dashboard queued for that session, or undefined. */
|
|
114
|
+
async function fetchAnswer(base, token, sessionId) {
|
|
115
|
+
try {
|
|
116
|
+
const res = await fetch(`${base}/_bridge/answer?sessionId=${sessionId}`, {
|
|
117
|
+
headers: { authorization: `Bearer ${token}`, ...VERSION_HEADER },
|
|
118
|
+
})
|
|
119
|
+
if (!res.ok) return undefined
|
|
120
|
+
const answer = (await res.json())?.answer
|
|
121
|
+
return answer?.id && typeof answer.text === 'string' ? answer : undefined
|
|
122
|
+
} catch {
|
|
123
|
+
return undefined
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The next session the daemon wants created, claimed by this read (#1328), or undefined. */
|
|
128
|
+
async function claimStart(base, token) {
|
|
129
|
+
try {
|
|
130
|
+
const res = await fetch(`${base}/_bridge/start`, { headers: { authorization: `Bearer ${token}`, ...VERSION_HEADER } })
|
|
131
|
+
if (!res.ok) return undefined
|
|
132
|
+
const start = (await res.json())?.start
|
|
133
|
+
return start?.id && typeof start.repo === 'string' && typeof start.branch === 'string' && typeof start.prompt === 'string' ? start : undefined
|
|
134
|
+
} catch {
|
|
135
|
+
return undefined
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** One authenticated POST to the daemon. */
|
|
140
|
+
async function post(path, body) {
|
|
141
|
+
const { daemonUrl, token } = await chrome.storage.local.get(['daemonUrl', 'token'])
|
|
142
|
+
if (!token) return { ok: false, error: 'no token set' }
|
|
143
|
+
const base = (daemonUrl || DEFAULT_DAEMON).replace(/\/+$/, '')
|
|
144
|
+
const res = await fetch(`${base}${path}`, {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${token}`, ...VERSION_HEADER },
|
|
147
|
+
body: JSON.stringify(body),
|
|
148
|
+
})
|
|
149
|
+
if (!res.ok) return { ok: false, error: `daemon answered ${res.status}: ${(await res.text()).slice(0, 200)}` }
|
|
150
|
+
return { ok: true }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Send a batch of transcript entries. Same token and same discipline as the question. */
|
|
154
|
+
async function postEvents({ sessionId, events }) {
|
|
155
|
+
const { daemonUrl, token } = await chrome.storage.local.get(['daemonUrl', 'token'])
|
|
156
|
+
if (!token) return { ok: false, error: 'no token set: open the extension options' }
|
|
157
|
+
const base = (daemonUrl || DEFAULT_DAEMON).replace(/\/+$/, '')
|
|
158
|
+
const res = await fetch(`${base}/_bridge/events`, {
|
|
159
|
+
method: 'POST',
|
|
160
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${token}`, ...VERSION_HEADER },
|
|
161
|
+
body: JSON.stringify({ sessionId, events }),
|
|
162
|
+
})
|
|
163
|
+
if (!res.ok) return { ok: false, error: `daemon answered ${res.status}: ${(await res.text()).slice(0, 200)}` }
|
|
164
|
+
return { ok: true }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
// The Driver tab (#1332): one pinned background tab that serves every watched session.
|
|
169
|
+
//
|
|
170
|
+
// The extension cannot know a cloud run started: it only sees pages it is injected into. So the
|
|
171
|
+
// daemon publishes which sessions are ours, and this keeps one tab open on claude.ai whose content
|
|
172
|
+
// script reads claude.ai's own session list — the status icon beside each session says whether it
|
|
173
|
+
// stopped for its user — and visits only the sessions that need it, navigating inside the app.
|
|
174
|
+
// One tab for fifty sessions, where there used to be a tab each, capped at three.
|
|
175
|
+
|
|
176
|
+
const DRIVER_URL = 'https://claude.ai/code'
|
|
177
|
+
|
|
178
|
+
/** How often a cycle runs; the floor Chrome allows for an alarm. */
|
|
179
|
+
const CYCLE_MINUTES = 0.5
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* How often the Driver's page is reloaded before its list is read. The list refreshes only on a
|
|
183
|
+
* page load — after an in-app navigation it still shows what it showed before (measured
|
|
184
|
+
* 2026-08-25) — so a fresh read costs one load, at the rate the old tab sweep used to poll.
|
|
185
|
+
*/
|
|
186
|
+
const LIST_REFRESH_MS = 60_000
|
|
187
|
+
|
|
188
|
+
/** How long to give the Driver's page to load and its content script to answer. */
|
|
189
|
+
const TAB_LOAD_MS = 30_000
|
|
190
|
+
const SCRIPT_RETRIES = 10
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Most visits handed to the Driver in one cycle, answers first. One drive is one message this
|
|
194
|
+
* worker waits on, and Chrome ends a worker whose single call has run five minutes — the cycle
|
|
195
|
+
* log lines reset only the separate idle clock. Four visits and a creation keep well under it
|
|
196
|
+
* even on a slow page; the rest wait for the next beat.
|
|
197
|
+
*/
|
|
198
|
+
const MAX_VISITS = 4
|
|
199
|
+
|
|
200
|
+
/** A cycle in flight, so the next alarm does not start a second one over it. */
|
|
201
|
+
let cycling = false
|
|
202
|
+
/** When the Driver's page was last loaded fresh. In memory: a new worker reloads once, which is fine. */
|
|
203
|
+
let lastReloadAt = 0
|
|
204
|
+
/** What the list said and when the session was last visited, per session — the sticky-state memory `planVisits` reads. */
|
|
205
|
+
const seen = new Map()
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The Driver's bookkeeping that is only good for one browser session — its tab id, and the pause
|
|
209
|
+
* that closing it leaves — is kept in session storage: Chrome empties it on a browser restart and
|
|
210
|
+
* keeps it across worker restarts. A tab id from an earlier browser session would name whatever
|
|
211
|
+
* tab happens to carry that number now, which is not a tab to drive.
|
|
212
|
+
*/
|
|
213
|
+
const driverState = chrome.storage.session
|
|
214
|
+
|
|
215
|
+
/** The tab id the Driver runs in, or undefined. Stored, so a restarted worker finds its tab again. */
|
|
216
|
+
async function driverTabId() {
|
|
217
|
+
const { driverTabId } = await driverState.get('driverTabId')
|
|
218
|
+
return driverTabId ?? undefined
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Record what the last cycle did, so the options page can show it.
|
|
223
|
+
*
|
|
224
|
+
* Every early return used to be silent, which is how "the bridge is doing nothing" became
|
|
225
|
+
* unanswerable without reading a service worker console. Each one now says which it was.
|
|
226
|
+
*/
|
|
227
|
+
async function note(state) {
|
|
228
|
+
await chrome.storage.local.set({ lastCycle: { ...state, at: new Date().toISOString() } })
|
|
229
|
+
return state
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Resolve once the tab reports `complete`, or after {@link TAB_LOAD_MS}. */
|
|
233
|
+
function tabLoaded(tabId) {
|
|
234
|
+
return new Promise(resolve => {
|
|
235
|
+
const done = () => {
|
|
236
|
+
chrome.tabs.onUpdated.removeListener(listener)
|
|
237
|
+
resolve()
|
|
238
|
+
}
|
|
239
|
+
const listener = (id, info) => {
|
|
240
|
+
if (id === tabId && info.status === 'complete') done()
|
|
241
|
+
}
|
|
242
|
+
chrome.tabs.onUpdated.addListener(listener)
|
|
243
|
+
setTimeout(done, TAB_LOAD_MS)
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The Driver tab, opened if there is none. A stored tab that is gone, or that someone moved off
|
|
249
|
+
* claude.ai, is forgotten and replaced — whoever moved it keeps it; a tab is never navigated to
|
|
250
|
+
* make it ours. On a browser restart Chrome restores pinned tabs under new ids and the stored id
|
|
251
|
+
* is gone with the session, so a lone pinned claude.ai/code tab is adopted rather than doubled; a
|
|
252
|
+
* restored tab carries no other mark, so this cannot tell it from one the user pinned themselves.
|
|
253
|
+
*/
|
|
254
|
+
async function ensureDriverTab() {
|
|
255
|
+
const stored = await driverTabId()
|
|
256
|
+
if (stored != null) {
|
|
257
|
+
const tab = await chrome.tabs.get(stored).catch(() => undefined)
|
|
258
|
+
if (tab && (tab.url ?? '').startsWith('https://claude.ai/')) return tab
|
|
259
|
+
await driverState.set({ driverTabId: null })
|
|
260
|
+
}
|
|
261
|
+
const pinned = await chrome.tabs.query({ url: `${DRIVER_URL}*`, pinned: true })
|
|
262
|
+
let tab = pinned.length === 1 ? pinned[0] : undefined
|
|
263
|
+
if (!tab) {
|
|
264
|
+
tab = await chrome.tabs.create({ url: DRIVER_URL, active: false, pinned: true })
|
|
265
|
+
await tabLoaded(tab.id)
|
|
266
|
+
lastReloadAt = Date.now()
|
|
267
|
+
}
|
|
268
|
+
await driverState.set({ driverTabId: tab.id })
|
|
269
|
+
return tab
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Load the Driver's page fresh, so its session list is current. */
|
|
273
|
+
async function reloadDriver(tabId) {
|
|
274
|
+
await chrome.tabs.reload(tabId)
|
|
275
|
+
await tabLoaded(tabId)
|
|
276
|
+
lastReloadAt = Date.now()
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Hand a message to the Driver's content script, retrying while it is still being injected.
|
|
281
|
+
* A script orphaned by an extension reload cannot hear us at all; the tab is ours, so one reload
|
|
282
|
+
* revives it before the retries continue. A tab that is gone, or a drive whose page was torn
|
|
283
|
+
* down after taking the message, is a failure rather than a throw or a re-send: the answers
|
|
284
|
+
* handed over must still be accounted for, and a drive is not idempotent.
|
|
285
|
+
*/
|
|
286
|
+
async function askDriver(tabId, message) {
|
|
287
|
+
let lastErr
|
|
288
|
+
let reloaded = false
|
|
289
|
+
for (let i = 0; i < SCRIPT_RETRIES; i++) {
|
|
290
|
+
try {
|
|
291
|
+
const outcome = await chrome.tabs.sendMessage(tabId, message)
|
|
292
|
+
if (outcome) return outcome
|
|
293
|
+
} catch (err) {
|
|
294
|
+
lastErr = err
|
|
295
|
+
// A port that closed after the page took the message means the page acted and was then
|
|
296
|
+
// torn down — a reload under it, a sign-in bounce. The answer may already be typed.
|
|
297
|
+
if (message.type === 'oa-drive' && /port closed/i.test(String(err?.message ?? ''))) {
|
|
298
|
+
return { ok: false, tornDown: true, note: 'the Driver page was torn down mid-drive; an answer handed over may or may not have been typed — check the session before picking again' }
|
|
299
|
+
}
|
|
300
|
+
if (i >= 2 && !reloaded) {
|
|
301
|
+
reloaded = true
|
|
302
|
+
try {
|
|
303
|
+
await reloadDriver(tabId)
|
|
304
|
+
} catch (reloadErr) {
|
|
305
|
+
return { ok: false, note: `the Driver tab is gone: ${String(reloadErr?.message ?? reloadErr)}` }
|
|
306
|
+
}
|
|
307
|
+
continue
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
311
|
+
}
|
|
312
|
+
return { ok: false, note: `the Driver tab never answered: ${String(lastErr?.message ?? lastErr ?? 'no reply')}` }
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** One cycle, guarded: an alarm landing mid-cycle does nothing. */
|
|
316
|
+
async function cycle() {
|
|
317
|
+
if (cycling) return { ok: false, reason: 'a cycle is already running' }
|
|
318
|
+
cycling = true
|
|
319
|
+
try {
|
|
320
|
+
return await note(await runCycle())
|
|
321
|
+
} catch (err) {
|
|
322
|
+
return note({ ok: false, reason: String(err?.message ?? err) })
|
|
323
|
+
} finally {
|
|
324
|
+
cycling = false
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function runCycle() {
|
|
329
|
+
const { daemonUrl, token, autoOpen } = await chrome.storage.local.get(['daemonUrl', 'token', 'autoOpen'])
|
|
330
|
+
if (!token) return { ok: false, reason: 'no token set' }
|
|
331
|
+
const base = (daemonUrl || DEFAULT_DAEMON).replace(/\/+$/, '')
|
|
332
|
+
// Whatever the Driver's state, what is owed to the daemon is paid first: acknowledgements that
|
|
333
|
+
// never landed, and — with the Driver off or paused — an honest failure for any session request,
|
|
334
|
+
// since one left queued would be created hours later, for a run long gone.
|
|
335
|
+
for (const body of [...pendingAcks.values()]) await ack(base, token, body)
|
|
336
|
+
const { driverPaused } = await driverState.get('driverPaused')
|
|
337
|
+
// Opt-in: driving a tab on someone's behalf should be asked for, not assumed.
|
|
338
|
+
const stopped =
|
|
339
|
+
autoOpen === false ? 'the Driver tab is switched off' : driverPaused ? 'the Driver tab was closed; "Open the Driver tab" on the options page resumes it' : undefined
|
|
340
|
+
if (stopped) {
|
|
341
|
+
const start = await claimStart(base, token)
|
|
342
|
+
if (start) await reportStarted(base, token, start.id, { ok: false, note: stopped })
|
|
343
|
+
return { ok: false, reason: stopped }
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
let sessions
|
|
347
|
+
try {
|
|
348
|
+
const res = await fetch(`${base}/_bridge/sessions`, { headers: { authorization: `Bearer ${token}`, ...VERSION_HEADER } })
|
|
349
|
+
if (!res.ok) return { ok: false, reason: `daemon answered ${res.status} listing sessions` }
|
|
350
|
+
sessions = (await res.json())?.sessions
|
|
351
|
+
} catch (err) {
|
|
352
|
+
return { ok: false, reason: `could not reach ${base}: ${String(err?.message ?? err)}` }
|
|
353
|
+
}
|
|
354
|
+
sessions = (Array.isArray(sessions) ? sessions : []).filter(s => s?.id)
|
|
355
|
+
|
|
356
|
+
// A queued answer forces a visit whatever the list says: it is the one thing the list cannot know.
|
|
357
|
+
const answers = new Map()
|
|
358
|
+
for (const session of sessions) {
|
|
359
|
+
if (!session.answerQueued) continue
|
|
360
|
+
const answer = await fetchAnswer(base, token, session.id)
|
|
361
|
+
if (answer && !deliveredAnswers.has(answer.id)) answers.set(session.id, answer)
|
|
362
|
+
}
|
|
363
|
+
// Claim-on-read (#1328): from here on the request is ours to report, success or failure.
|
|
364
|
+
const start = await claimStart(base, token)
|
|
365
|
+
if (!sessions.length && !start) return { ok: true, reason: 'nothing to drive: no recent cloud sessions, no session to create' }
|
|
366
|
+
|
|
367
|
+
const tab = await ensureDriverTab()
|
|
368
|
+
const ids = sessions.map(s => s.id)
|
|
369
|
+
if (ids.length && Date.now() - lastReloadAt >= LIST_REFRESH_MS) await reloadDriver(tab.id)
|
|
370
|
+
const read = ids.length ? await askDriver(tab.id, { type: 'oa-read-list', ids }) : { ok: true, statuses: [] }
|
|
371
|
+
if (!read.ok) {
|
|
372
|
+
// A Driver still busy with an earlier cycle's drive is left alone, claim included: the claim
|
|
373
|
+
// expires on the daemon and the request is offered again once the page is free.
|
|
374
|
+
if (start && !read.busy) await reportStarted(base, token, start.id, { ok: false, note: read.note })
|
|
375
|
+
return { ok: false, reason: read.note ?? 'the Driver could not read the session list' }
|
|
376
|
+
}
|
|
377
|
+
const statuses = Array.isArray(read.statuses) ? read.statuses : []
|
|
378
|
+
if (statuses.length) {
|
|
379
|
+
await post('/_bridge/statuses', { statuses: statuses.map(({ sessionId, status, label }) => ({ sessionId, status, ...(label ? { label } : {}) })) })
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const now = Date.now()
|
|
383
|
+
const planned = planVisits(statuses, answers, seen, now)
|
|
384
|
+
// Answers first, then a bounded handful of the due sessions; what is cut waits for the next
|
|
385
|
+
// beat, with the change that made it due kept pending below.
|
|
386
|
+
const visits = [...planned.filter(v => v.answer), ...planned.filter(v => !v.answer)].slice(0, MAX_VISITS)
|
|
387
|
+
for (const visit of visits) if (visit.answer) deliveredAnswers.add(visit.answer.id)
|
|
388
|
+
const driven =
|
|
389
|
+
visits.length || start
|
|
390
|
+
? await askDriver(tab.id, {
|
|
391
|
+
type: 'oa-drive',
|
|
392
|
+
visits,
|
|
393
|
+
...(start ? { start: { repo: start.repo, branch: start.branch, prompt: start.prompt, ...(typeof start.model === 'string' ? { model: start.model } : {}) } } : {}),
|
|
394
|
+
})
|
|
395
|
+
: { ok: true, visited: [], delivered: [] }
|
|
396
|
+
if (driven.busy) {
|
|
397
|
+
// The page is still on an earlier cycle's drive — a worker that ended mid-cycle leaves the
|
|
398
|
+
// page driving. Nothing was handed over, so nothing is claimed, acknowledged or reported; the
|
|
399
|
+
// next beat tries again, and the daemon's claim on the session request expires on its own.
|
|
400
|
+
for (const visit of visits) if (visit.answer) deliveredAnswers.delete(visit.answer.id)
|
|
401
|
+
return { ok: false, reason: driven.note ?? 'the Driver is still busy with an earlier cycle' }
|
|
402
|
+
}
|
|
403
|
+
const visited = Array.isArray(driven.visited) ? driven.visited : []
|
|
404
|
+
const delivered = Array.isArray(driven.delivered) ? driven.delivered : []
|
|
405
|
+
// A session planned but not reached this beat — cut by the cap, or a visit that failed — keeps
|
|
406
|
+
// its earlier status, so the change that made it due is still a change next time.
|
|
407
|
+
const unreached = id => planned.some(v => v.id === id) && !visited.some(v => v.id === id && v.ok)
|
|
408
|
+
for (const { sessionId, status } of statuses) {
|
|
409
|
+
if (unreached(sessionId)) continue
|
|
410
|
+
const before = seen.get(sessionId)
|
|
411
|
+
seen.set(sessionId, { status, visitedAt: visited.some(v => v.id === sessionId && v.ok) ? now : (before?.visitedAt ?? 0) })
|
|
412
|
+
}
|
|
413
|
+
// Every answer handed over is accounted for. A delivery the page attempted is acknowledged as
|
|
414
|
+
// it reported it, sent or failed. One the visit never got to — the session not on the list,
|
|
415
|
+
// the page not becoming it, a Driver that did not answer — stays queued on the daemon and is
|
|
416
|
+
// released here, so the next beat tries again. The one exception is a page torn down
|
|
417
|
+
// mid-drive: its answer may already be typed, so that is acknowledged as failed with a note
|
|
418
|
+
// saying to check the session before picking again.
|
|
419
|
+
for (const visit of visits) {
|
|
420
|
+
if (!visit.answer) continue
|
|
421
|
+
const outcome = delivered.find(d => d.id === visit.answer.id)
|
|
422
|
+
if (!outcome && !driven.tornDown) {
|
|
423
|
+
deliveredAnswers.delete(visit.answer.id)
|
|
424
|
+
continue
|
|
425
|
+
}
|
|
426
|
+
const report = outcome ?? { sessionId: visit.id, id: visit.answer.id, ok: false, note: driven.note }
|
|
427
|
+
if (!report.ok) deliveredAnswers.delete(visit.answer.id)
|
|
428
|
+
await ack(base, token, { sessionId: report.sessionId, id: report.id, ok: Boolean(report.ok), ...(report.note ? { note: String(report.note).slice(0, 300) } : {}) })
|
|
429
|
+
}
|
|
430
|
+
if (start) await reportStarted(base, token, start.id, driven.started ?? { ok: false, note: driven.note ?? 'the Driver did not create the session' })
|
|
431
|
+
|
|
432
|
+
const counts = {
|
|
433
|
+
awaiting: statuses.filter(s => s.status === 'awaiting').length,
|
|
434
|
+
unread: statuses.filter(s => s.status === 'unread').length,
|
|
435
|
+
missing: statuses.filter(s => s.status === 'missing').length,
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
ok: driven.ok !== false,
|
|
439
|
+
reason: `read ${statuses.length} of ${ids.length} (${counts.awaiting} awaiting, ${counts.unread} unread, ${counts.missing} missing), visited ${visited.length}${planned.length > visits.length ? ` of ${planned.length} due` : ''}, typed ${delivered.filter(d => d.ok).length}${start ? `, created ${driven.started?.ok ? driven.started.sessionId : 'nothing: ' + (driven.started?.note ?? driven.note ?? 'unknown')}` : ''}${driven.note ? `; ${driven.note}` : ''}`,
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/** Report what a creation attempt did (#1328); the daemon's claim expires on its own if this never lands. */
|
|
444
|
+
async function reportStarted(base, token, id, outcome) {
|
|
445
|
+
const ok = Boolean(outcome?.ok && outcome?.sessionId)
|
|
446
|
+
try {
|
|
447
|
+
await fetch(`${base}/_bridge/started`, {
|
|
448
|
+
method: 'POST',
|
|
449
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${token}`, ...VERSION_HEADER },
|
|
450
|
+
body: JSON.stringify({
|
|
451
|
+
id,
|
|
452
|
+
ok,
|
|
453
|
+
...(ok ? { sessionId: outcome.sessionId } : {}),
|
|
454
|
+
...(outcome?.note ? { note: String(outcome.note).slice(0, 1500) } : {}),
|
|
455
|
+
}),
|
|
456
|
+
})
|
|
457
|
+
} catch {
|
|
458
|
+
// The claim expires on the daemon, and the request is offered again.
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** The options page's button: resume a paused Driver and run a cycle now. */
|
|
463
|
+
async function openDriverNow() {
|
|
464
|
+
await driverState.set({ driverPaused: false })
|
|
465
|
+
return cycle()
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Closing the Driver tab is the user saying stop: the bridge pauses until they reopen it from
|
|
469
|
+
// the options page or restart the browser, rather than the tab reappearing half a minute later.
|
|
470
|
+
// Closing the window it sits in is not that — Chrome keeps running without a window — so the
|
|
471
|
+
// tab is merely forgotten and reopened in the next one.
|
|
472
|
+
chrome.tabs.onRemoved.addListener(async (tabId, info) => {
|
|
473
|
+
if (tabId !== (await driverTabId())) return
|
|
474
|
+
await driverState.set({ driverTabId: null, driverPaused: !info.isWindowClosing })
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
// An alarm rather than setInterval: an MV3 service worker is terminated when idle, and a timer
|
|
478
|
+
// dies with it. Alarms wake it back up. One beat for everything: a person may be sitting at the
|
|
479
|
+
// dashboard watching an answer's spinner, and a run may be waiting for its session.
|
|
480
|
+
chrome.alarms.create('oa-cycle', { periodInMinutes: CYCLE_MINUTES })
|
|
481
|
+
chrome.alarms.onAlarm.addListener(alarm => {
|
|
482
|
+
if (alarm.name === 'oa-cycle') void beat()
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
// ---------------------------------------------------------------------------
|
|
486
|
+
// Reloading itself when its files change (#1711). The extension is unpacked and edited in place,
|
|
487
|
+
// and Chrome re-reads its files only on a reload; that used to be a click on chrome://extensions
|
|
488
|
+
// after every change. The worker can read its own files as they are on disk, so it takes their
|
|
489
|
+
// fingerprint at start and compares each beat. Reloading orphans the content script in the
|
|
490
|
+
// Driver tab, which the next cycle's page load replaces, as after a manual reload.
|
|
491
|
+
//
|
|
492
|
+
// One thing to know: with developer mode switched off on chrome://extensions, Chrome (137 and
|
|
493
|
+
// later) disables an unpacked extension on reload instead of reloading it, and only a click on
|
|
494
|
+
// chrome://extensions brings it back. The mode is on for anyone who loaded the extension
|
|
495
|
+
// unpacked; leave it on.
|
|
496
|
+
|
|
497
|
+
/** The files' hashes when this worker started, or undefined until the first read succeeds. */
|
|
498
|
+
let filesAtStart
|
|
499
|
+
|
|
500
|
+
/** The extension's own file as it is on disk now. */
|
|
501
|
+
const readOwnFile = file => fetch(chrome.runtime.getURL(file)).then(res => res.text())
|
|
502
|
+
|
|
503
|
+
/** The watched files that changed since this worker started; none while a read fails. */
|
|
504
|
+
async function filesChanged() {
|
|
505
|
+
try {
|
|
506
|
+
const now = await fingerprint(readOwnFile)
|
|
507
|
+
if (!filesAtStart) {
|
|
508
|
+
filesAtStart = now
|
|
509
|
+
return []
|
|
510
|
+
}
|
|
511
|
+
return changedFiles(filesAtStart, now)
|
|
512
|
+
} catch {
|
|
513
|
+
return []
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* One beat: reload the extension if its files changed, else run a cycle. Never mid-cycle — a
|
|
519
|
+
* reload would kill a drive with answers handed over and unaccounted for — so a beat that lands
|
|
520
|
+
* on a running cycle merely does nothing, and the next one checks again. The reload is recorded
|
|
521
|
+
* as the last cycle's outcome, so the options page can say why the worker restarted.
|
|
522
|
+
*/
|
|
523
|
+
async function beat() {
|
|
524
|
+
if (cycling) return
|
|
525
|
+
const changed = await filesChanged()
|
|
526
|
+
if (changed.length === 0 || cycling) return cycle()
|
|
527
|
+
await note({ ok: true, reason: `reloading the extension: ${changed.join(', ')} changed on disk` })
|
|
528
|
+
chrome.runtime.reload()
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
void filesChanged()
|
|
532
|
+
void cycle()
|