@withbuddi/buddi 0.1.0-pre.37 → 0.1.0-pre.39
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/extension/background.js +764 -32
- package/extension/manifest.json +2 -2
- package/node_modules/@buddi/cli/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/cli/dist/access-cmd.d.ts +10 -0
- package/node_modules/@buddi/cli/dist/access-cmd.d.ts.map +1 -0
- package/node_modules/@buddi/cli/dist/access-cmd.js +180 -0
- package/node_modules/@buddi/cli/dist/access-cmd.js.map +1 -0
- package/node_modules/@buddi/cli/dist/args.d.ts +10 -0
- package/node_modules/@buddi/cli/dist/args.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/args.js +34 -1
- package/node_modules/@buddi/cli/dist/args.js.map +1 -1
- package/node_modules/@buddi/cli/dist/commands.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/commands.js +39 -2
- package/node_modules/@buddi/cli/dist/commands.js.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor-probes.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor-probes.js +54 -29
- package/node_modules/@buddi/cli/dist/doctor-probes.js.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor.d.ts +36 -12
- package/node_modules/@buddi/cli/dist/doctor.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor.js +32 -9
- package/node_modules/@buddi/cli/dist/doctor.js.map +1 -1
- package/node_modules/@buddi/cli/dist/main.d.ts +2 -0
- package/node_modules/@buddi/cli/dist/main.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/main.js +20 -2
- package/node_modules/@buddi/cli/dist/main.js.map +1 -1
- package/node_modules/@buddi/core/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/core/dist/agents/catalog.d.ts +2 -0
- package/node_modules/@buddi/core/dist/agents/catalog.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/catalog.js +1 -0
- package/node_modules/@buddi/core/dist/agents/catalog.js.map +1 -1
- package/node_modules/@buddi/core/dist/agents/edit.d.ts +2 -0
- package/node_modules/@buddi/core/dist/agents/edit.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/edit.js +3 -1
- package/node_modules/@buddi/core/dist/agents/edit.js.map +1 -1
- package/node_modules/@buddi/core/dist/agents/frontmatter.d.ts +11 -0
- package/node_modules/@buddi/core/dist/agents/frontmatter.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/frontmatter.js +7 -0
- package/node_modules/@buddi/core/dist/agents/frontmatter.js.map +1 -1
- package/node_modules/@buddi/core/dist/index.d.ts +1 -0
- package/node_modules/@buddi/core/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/index.js +1 -0
- package/node_modules/@buddi/core/dist/index.js.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/index.d.ts +3 -0
- package/node_modules/@buddi/core/dist/plugin/index.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/index.js +3 -0
- package/node_modules/@buddi/core/dist/plugin/index.js.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/version.d.ts +1 -1
- package/node_modules/@buddi/core/dist/plugin/version.js +1 -1
- package/node_modules/@buddi/core/dist/questions/store.d.ts +12 -0
- package/node_modules/@buddi/core/dist/questions/store.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/questions/store.js +11 -1
- package/node_modules/@buddi/core/dist/questions/store.js.map +1 -1
- package/node_modules/@buddi/core/dist/questions/types.d.ts +8 -0
- package/node_modules/@buddi/core/dist/questions/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/questions/types.js +15 -0
- package/node_modules/@buddi/core/dist/questions/types.js.map +1 -1
- package/node_modules/@buddi/core/dist/queue/jobs.d.ts +8 -0
- package/node_modules/@buddi/core/dist/queue/jobs.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/queue/jobs.js +9 -3
- package/node_modules/@buddi/core/dist/queue/jobs.js.map +1 -1
- package/node_modules/@buddi/core/dist/queue/worker.d.ts +2 -0
- package/node_modules/@buddi/core/dist/queue/worker.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/queue/worker.js +2 -1
- package/node_modules/@buddi/core/dist/queue/worker.js.map +1 -1
- package/node_modules/@buddi/core/dist/registry.d.ts +7 -1
- package/node_modules/@buddi/core/dist/registry.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/registry.js +73 -11
- package/node_modules/@buddi/core/dist/registry.js.map +1 -1
- package/node_modules/@buddi/core/dist/routes.d.ts +153 -0
- package/node_modules/@buddi/core/dist/routes.d.ts.map +1 -0
- package/node_modules/@buddi/core/dist/routes.js +47 -0
- package/node_modules/@buddi/core/dist/routes.js.map +1 -0
- package/node_modules/@buddi/core/dist/scheduler/missions.d.ts +5 -3
- package/node_modules/@buddi/core/dist/scheduler/missions.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/missions.js +9 -7
- package/node_modules/@buddi/core/dist/scheduler/missions.js.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/types.d.ts +7 -0
- package/node_modules/@buddi/core/dist/scheduler/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/scheduler/types.js +1 -0
- package/node_modules/@buddi/core/dist/scheduler/types.js.map +1 -1
- package/node_modules/@buddi/core/dist/tools.d.ts +59 -2
- package/node_modules/@buddi/core/dist/tools.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/tools.js.map +1 -1
- package/node_modules/@buddi/core/migrations/075_access_providers.sql +43 -0
- package/node_modules/@buddi/core/migrations/076_mission_browser.sql +7 -0
- package/node_modules/@buddi/gateway/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/gateway/dist/agents/canvas.d.ts +12 -12
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.d.ts +38 -20
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.js +6 -0
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/delegation.d.ts +10 -0
- package/node_modules/@buddi/gateway/dist/agents/delegation.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/delegation.js +1 -0
- package/node_modules/@buddi/gateway/dist/agents/delegation.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.d.ts +7 -1
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.js +15 -6
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/bootstrap.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/bootstrap.js +8 -0
- package/node_modules/@buddi/gateway/dist/bootstrap.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/browser-host.d.ts +30 -1
- package/node_modules/@buddi/gateway/dist/browser-host.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/browser-host.js +56 -1
- package/node_modules/@buddi/gateway/dist/browser-host.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/chat/session.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/chat/session.js +9 -5
- package/node_modules/@buddi/gateway/dist/chat/session.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.d.ts +2 -1
- package/node_modules/@buddi/gateway/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.js +2 -1
- package/node_modules/@buddi/gateway/dist/index.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/ask-cap.d.ts +26 -0
- package/node_modules/@buddi/gateway/dist/missions/ask-cap.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions/ask-cap.js +83 -0
- package/node_modules/@buddi/gateway/dist/missions/ask-cap.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions/execute.d.ts +45 -1
- package/node_modules/@buddi/gateway/dist/missions/execute.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/execute.js +156 -10
- package/node_modules/@buddi/gateway/dist/missions/execute.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/parked.d.ts +139 -0
- package/node_modules/@buddi/gateway/dist/missions/parked.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions/parked.js +255 -0
- package/node_modules/@buddi/gateway/dist/missions/parked.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/serve.d.ts +7 -0
- package/node_modules/@buddi/gateway/dist/serve.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/serve.js +49 -9
- package/node_modules/@buddi/gateway/dist/serve.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.d.ts +18 -0
- package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.js +42 -0
- package/node_modules/@buddi/gateway/dist/surfaces/browser-cards.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/surfaces/browser-continuation.js +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/browser-continuation.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/owner-request.d.ts +6 -0
- package/node_modules/@buddi/gateway/dist/surfaces/owner-request.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/surfaces/owner-request.js +7 -1
- package/node_modules/@buddi/gateway/dist/surfaces/owner-request.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/system-context.d.ts +7 -0
- package/node_modules/@buddi/gateway/dist/system-context.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/system-context.js +14 -7
- package/node_modules/@buddi/gateway/dist/system-context.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/browser-view.d.ts +17 -17
- package/node_modules/@buddi/gateway/dist/telegram/browser-view.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/browser-view.js +33 -37
- package/node_modules/@buddi/gateway/dist/telegram/browser-view.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/channel.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/channel.js +17 -1
- package/node_modules/@buddi/gateway/dist/telegram/channel.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/main.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/main.js +11 -3
- package/node_modules/@buddi/gateway/dist/telegram/main.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/surface.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/surface.js +10 -0
- package/node_modules/@buddi/gateway/dist/telegram/surface.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/tips/facts.d.ts +8 -0
- package/node_modules/@buddi/gateway/dist/tips/facts.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/tips/facts.js +8 -2
- package/node_modules/@buddi/gateway/dist/tips/facts.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/tips/rules.d.ts +2 -0
- package/node_modules/@buddi/gateway/dist/tips/rules.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/tips/rules.js +15 -0
- package/node_modules/@buddi/gateway/dist/tips/rules.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/access/arrival.d.ts +24 -0
- package/node_modules/@buddi/gateway/dist/web/access/arrival.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/arrival.js +18 -0
- package/node_modules/@buddi/gateway/dist/web/access/arrival.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.d.ts +124 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.js +206 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-api.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.d.ts +163 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.js +438 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-setup.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.d.ts +31 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.js +74 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare-token.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare.d.ts +145 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare.js +474 -0
- package/node_modules/@buddi/gateway/dist/web/access/cloudflare.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/index.d.ts +9 -0
- package/node_modules/@buddi/gateway/dist/web/access/index.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/index.js +9 -0
- package/node_modules/@buddi/gateway/dist/web/access/index.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/ingress.d.ts +30 -0
- package/node_modules/@buddi/gateway/dist/web/access/ingress.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/ingress.js +76 -0
- package/node_modules/@buddi/gateway/dist/web/access/ingress.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/provider.d.ts +173 -0
- package/node_modules/@buddi/gateway/dist/web/access/provider.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/provider.js +11 -0
- package/node_modules/@buddi/gateway/dist/web/access/provider.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/registry.d.ts +33 -0
- package/node_modules/@buddi/gateway/dist/web/access/registry.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/access/registry.js +32 -0
- package/node_modules/@buddi/gateway/dist/web/access/registry.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/{tailscale.d.ts → access/tailscale.d.ts} +27 -0
- package/node_modules/@buddi/gateway/dist/web/access/tailscale.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/{tailscale.js → access/tailscale.js} +118 -3
- package/node_modules/@buddi/gateway/dist/web/access/tailscale.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/agents.d.ts +2 -0
- package/node_modules/@buddi/gateway/dist/web/agents.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/agents.js +19 -1
- package/node_modules/@buddi/gateway/dist/web/agents.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts +4 -3
- package/node_modules/@buddi/gateway/dist/web/api-routes.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/api-routes.js +106 -19
- package/node_modules/@buddi/gateway/dist/web/api-routes.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/attention.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/attention.js +11 -3
- package/node_modules/@buddi/gateway/dist/web/attention.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/chat.d.ts +23 -0
- package/node_modules/@buddi/gateway/dist/web/chat.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/chat.js +62 -2
- package/node_modules/@buddi/gateway/dist/web/chat.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/client-key.d.ts +3 -0
- package/node_modules/@buddi/gateway/dist/web/client-key.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/client-key.js +8 -1
- package/node_modules/@buddi/gateway/dist/web/client-key.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/extension.d.ts +21 -1
- package/node_modules/@buddi/gateway/dist/web/extension.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/extension.js +183 -3
- package/node_modules/@buddi/gateway/dist/web/extension.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/http.d.ts +7 -0
- package/node_modules/@buddi/gateway/dist/web/http.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/http.js +15 -1
- package/node_modules/@buddi/gateway/dist/web/http.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/index.d.ts +1 -1
- package/node_modules/@buddi/gateway/dist/web/index.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/index.js +1 -1
- package/node_modules/@buddi/gateway/dist/web/index.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/onboarding.js +1 -1
- package/node_modules/@buddi/gateway/dist/web/onboarding.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/remote-hand.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/remote-hand.js +45 -2
- package/node_modules/@buddi/gateway/dist/web/remote-hand.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/secrets.d.ts +26 -1
- package/node_modules/@buddi/gateway/dist/web/secrets.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/secrets.js +66 -3
- package/node_modules/@buddi/gateway/dist/web/secrets.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/server.d.ts +38 -2
- package/node_modules/@buddi/gateway/dist/web/server.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/server.js +634 -147
- package/node_modules/@buddi/gateway/dist/web/server.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/sessions.d.ts +24 -14
- package/node_modules/@buddi/gateway/dist/web/sessions.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/sessions.js +42 -14
- package/node_modules/@buddi/gateway/dist/web/sessions.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/signed-out.d.ts +10 -0
- package/node_modules/@buddi/gateway/dist/web/signed-out.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/signed-out.js +47 -0
- package/node_modules/@buddi/gateway/dist/web/signed-out.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/version.d.ts +2 -0
- package/node_modules/@buddi/gateway/dist/web/version.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/version.js +5 -1
- package/node_modules/@buddi/gateway/dist/web/version.js.map +1 -1
- package/node_modules/@buddi/install/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/install/dist/app-layout.d.ts +127 -0
- package/node_modules/@buddi/install/dist/app-layout.d.ts.map +1 -0
- package/node_modules/@buddi/install/dist/app-layout.js +323 -0
- package/node_modules/@buddi/install/dist/app-layout.js.map +1 -0
- package/node_modules/@buddi/install/dist/index.d.ts +1 -0
- package/node_modules/@buddi/install/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/install/dist/index.js +1 -0
- package/node_modules/@buddi/install/dist/index.js.map +1 -1
- package/node_modules/@buddi/install/dist/launcher.d.ts.map +1 -1
- package/node_modules/@buddi/install/dist/launcher.js +18 -4
- package/node_modules/@buddi/install/dist/launcher.js.map +1 -1
- package/node_modules/@buddi/install/dist/provenance.d.ts +34 -0
- package/node_modules/@buddi/install/dist/provenance.d.ts.map +1 -0
- package/node_modules/@buddi/install/dist/provenance.js +200 -0
- package/node_modules/@buddi/install/dist/provenance.js.map +1 -0
- package/node_modules/@buddi/install/dist/supervisor.d.ts.map +1 -1
- package/node_modules/@buddi/install/dist/supervisor.js +9 -4
- package/node_modules/@buddi/install/dist/supervisor.js.map +1 -1
- package/node_modules/@buddi/install/dist/upgrade.d.ts +77 -3
- package/node_modules/@buddi/install/dist/upgrade.d.ts.map +1 -1
- package/node_modules/@buddi/install/dist/upgrade.js +325 -43
- package/node_modules/@buddi/install/dist/upgrade.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/runtime/dist/delegate.d.ts +8 -0
- package/node_modules/@buddi/runtime/dist/delegate.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/delegate.js +19 -1
- package/node_modules/@buddi/runtime/dist/delegate.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/loop.d.ts +2 -0
- package/node_modules/@buddi/runtime/dist/loop.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/loop.js +18 -4
- package/node_modules/@buddi/runtime/dist/loop.js.map +1 -1
- package/node_modules/@buddi/tool-artifacts/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-browser/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-browser/dist/availability.d.ts +2 -2
- package/node_modules/@buddi/tool-browser/dist/availability.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/availability.js +2 -2
- package/node_modules/@buddi/tool-browser/dist/availability.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/controller.d.ts +82 -58
- package/node_modules/@buddi/tool-browser/dist/controller.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/controller.js +823 -217
- package/node_modules/@buddi/tool-browser/dist/controller.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/driver.d.ts +3 -1
- package/node_modules/@buddi/tool-browser/dist/driver.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/driver.js +82 -1
- package/node_modules/@buddi/tool-browser/dist/driver.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/extension.d.ts +70 -5
- package/node_modules/@buddi/tool-browser/dist/extension.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/extension.js +94 -9
- package/node_modules/@buddi/tool-browser/dist/extension.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/index.d.ts +17 -7
- package/node_modules/@buddi/tool-browser/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/index.js +35 -15
- package/node_modules/@buddi/tool-browser/dist/index.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/logins.d.ts +150 -0
- package/node_modules/@buddi/tool-browser/dist/logins.d.ts.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/logins.js +476 -0
- package/node_modules/@buddi/tool-browser/dist/logins.js.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/manager.d.ts +39 -21
- package/node_modules/@buddi/tool-browser/dist/manager.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/manager.js +229 -136
- package/node_modules/@buddi/tool-browser/dist/manager.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/routes.d.ts +151 -0
- package/node_modules/@buddi/tool-browser/dist/routes.d.ts.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/routes.js +331 -0
- package/node_modules/@buddi/tool-browser/dist/routes.js.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/secrets.d.ts +3 -1
- package/node_modules/@buddi/tool-browser/dist/secrets.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/secrets.js +10 -6
- package/node_modules/@buddi/tool-browser/dist/secrets.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/service.d.ts +182 -115
- package/node_modules/@buddi/tool-browser/dist/service.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/service.js +491 -388
- package/node_modules/@buddi/tool-browser/dist/service.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/settings.d.ts +88 -0
- package/node_modules/@buddi/tool-browser/dist/settings.d.ts.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/settings.js +86 -0
- package/node_modules/@buddi/tool-browser/dist/settings.js.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/telemetry.d.ts +203 -0
- package/node_modules/@buddi/tool-browser/dist/telemetry.d.ts.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/telemetry.js +142 -0
- package/node_modules/@buddi/tool-browser/dist/telemetry.js.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/types.d.ts +102 -3
- package/node_modules/@buddi/tool-browser/dist/types.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/types.js +27 -9
- package/node_modules/@buddi/tool-browser/dist/types.js.map +1 -1
- package/node_modules/@buddi/tool-email/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-host/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-mcp/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-memory/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-web/dist/.tsbuildinfo +1 -1
- package/node_modules/hono/dist/cjs/hono-base.js +2 -0
- package/node_modules/hono/dist/cjs/middleware/language/language.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/mount/index.js +71 -0
- package/node_modules/hono/dist/cjs/request.js +4 -4
- package/node_modules/hono/dist/hono-base.js +2 -0
- package/node_modules/hono/dist/middleware/mount/index.js +70 -0
- package/node_modules/hono/dist/request.js +4 -4
- package/node_modules/hono/dist/types/hono-base.d.ts +2 -0
- package/node_modules/hono/dist/types/jsx/base.d.ts +1 -1
- package/node_modules/hono/dist/types/middleware/mount/index.d.ts +46 -0
- package/node_modules/hono/dist/types/request.d.ts +4 -4
- package/node_modules/hono/package.json +9 -1
- package/node_modules/imapflow/CHANGELOG.md +15 -0
- package/node_modules/imapflow/dist/cjs/package-info.d.ts +1 -1
- package/node_modules/imapflow/dist/cjs/package-info.js +1 -1
- package/node_modules/imapflow/dist/cjs/search-compiler.js +21 -31
- package/node_modules/imapflow/dist/esm/package-info.d.ts +1 -1
- package/node_modules/imapflow/dist/esm/package-info.js +1 -1
- package/node_modules/imapflow/dist/esm/search-compiler.js +21 -31
- package/node_modules/imapflow/package.json +2 -2
- package/node_modules/pino/CONTRIBUTING.md +1 -5
- package/node_modules/pino/LICENSE +1 -1
- package/node_modules/pino/README.md +1 -1
- package/node_modules/pino/SECURITY.md +2 -18
- package/node_modules/pino/browser.js +8 -68
- package/node_modules/pino/docs/api.md +4 -75
- package/node_modules/pino/docs/asynchronous.md +3 -18
- package/node_modules/pino/docs/browser.md +0 -63
- package/node_modules/pino/docs/child-loggers.md +1 -22
- package/node_modules/pino/docs/ecosystem.md +0 -1
- package/node_modules/pino/docs/help.md +3 -11
- package/node_modules/pino/docs/lts.md +0 -29
- package/node_modules/pino/docs/pretty.md +0 -3
- package/node_modules/pino/docs/redaction.md +8 -3
- package/node_modules/pino/docs/transports.md +0 -71
- package/node_modules/pino/docs/web.md +14 -11
- package/node_modules/pino/eslint.config.js +7 -15
- package/node_modules/pino/lib/caller.js +0 -10
- package/node_modules/pino/lib/meta.js +1 -1
- package/node_modules/pino/lib/multistream.js +7 -15
- package/node_modules/pino/lib/redaction.js +3 -8
- package/node_modules/pino/lib/symbols.js +1 -3
- package/node_modules/pino/lib/tools.js +2 -2
- package/node_modules/pino/lib/transport.js +1 -14
- package/node_modules/pino/lib/worker.js +1 -4
- package/node_modules/pino/package.json +22 -14
- package/node_modules/pino/pino.d.ts +736 -709
- package/node_modules/pino/pino.js +2 -27
- package/node_modules/pino/test/basic.test.js +0 -66
- package/node_modules/pino/test/escaping.test.js +0 -17
- package/node_modules/pino/test/fixtures/ts/transpile.cjs +3 -3
- package/node_modules/pino/test/helper.js +2 -6
- package/node_modules/pino/test/multistream.test.js +0 -64
- package/node_modules/pino/test/redact.test.js +0 -30
- package/node_modules/pino/test/transport/core.test.js +0 -85
- package/node_modules/pino/test/transport/sync-false.test.js +0 -12
- package/node_modules/pino/test/transport/uses-pino-config.test.js +4 -4
- package/node_modules/pino/test/types/pino-import.test-d.cts +30 -0
- package/node_modules/pino/test/types/pino-multistream.test-d.ts +28 -0
- package/node_modules/pino/test/types/pino-top-export.test-d.ts +34 -0
- package/node_modules/pino/test/types/{pino-transport.tst.ts → pino-transport.test-d.ts} +70 -85
- package/node_modules/pino/test/types/pino-type-only.test-d.ts +75 -0
- package/node_modules/pino/test/types/{pino.tst.ts → pino.test-d.ts} +137 -135
- package/node_modules/pino/test/types/pino.ts +7 -14
- package/node_modules/pino/tsconfig.json +6 -6
- package/node_modules/real-require/README.md +6 -6
- package/node_modules/real-require/package.json +21 -10
- package/node_modules/real-require/src/index.js +2 -2
- package/node_modules/thread-stream/node_modules/real-require/LICENSE.md +21 -0
- package/node_modules/thread-stream/node_modules/real-require/README.md +51 -0
- package/node_modules/thread-stream/node_modules/real-require/package.json +38 -0
- package/node_modules/thread-stream/node_modules/real-require/src/index.js +14 -0
- package/package.json +2 -2
- package/packages/cli/dist/.tsbuildinfo +1 -1
- package/packages/cli/dist/access-cmd.d.ts +10 -0
- package/packages/cli/dist/access-cmd.d.ts.map +1 -0
- package/packages/cli/dist/access-cmd.js +180 -0
- package/packages/cli/dist/access-cmd.js.map +1 -0
- package/packages/cli/dist/args.d.ts +10 -0
- package/packages/cli/dist/args.d.ts.map +1 -1
- package/packages/cli/dist/args.js +34 -1
- package/packages/cli/dist/args.js.map +1 -1
- package/packages/cli/dist/commands.d.ts.map +1 -1
- package/packages/cli/dist/commands.js +39 -2
- package/packages/cli/dist/commands.js.map +1 -1
- package/packages/cli/dist/doctor-probes.d.ts.map +1 -1
- package/packages/cli/dist/doctor-probes.js +54 -29
- package/packages/cli/dist/doctor-probes.js.map +1 -1
- package/packages/cli/dist/doctor.d.ts +36 -12
- package/packages/cli/dist/doctor.d.ts.map +1 -1
- package/packages/cli/dist/doctor.js +32 -9
- package/packages/cli/dist/doctor.js.map +1 -1
- package/packages/cli/dist/main.d.ts +2 -0
- package/packages/cli/dist/main.d.ts.map +1 -1
- package/packages/cli/dist/main.js +20 -2
- package/packages/cli/dist/main.js.map +1 -1
- package/packages/core/dist/.tsbuildinfo +1 -1
- package/packages/core/dist/agents/catalog.d.ts +2 -0
- package/packages/core/dist/agents/catalog.d.ts.map +1 -1
- package/packages/core/dist/agents/catalog.js +1 -0
- package/packages/core/dist/agents/catalog.js.map +1 -1
- package/packages/core/dist/agents/edit.d.ts +2 -0
- package/packages/core/dist/agents/edit.d.ts.map +1 -1
- package/packages/core/dist/agents/edit.js +3 -1
- package/packages/core/dist/agents/edit.js.map +1 -1
- package/packages/core/dist/agents/frontmatter.d.ts +11 -0
- package/packages/core/dist/agents/frontmatter.d.ts.map +1 -1
- package/packages/core/dist/agents/frontmatter.js +7 -0
- package/packages/core/dist/agents/frontmatter.js.map +1 -1
- package/packages/core/dist/index.d.ts +1 -0
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +1 -0
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/plugin/index.d.ts +3 -0
- package/packages/core/dist/plugin/index.d.ts.map +1 -1
- package/packages/core/dist/plugin/index.js +3 -0
- package/packages/core/dist/plugin/index.js.map +1 -1
- package/packages/core/dist/plugin/version.d.ts +1 -1
- package/packages/core/dist/plugin/version.js +1 -1
- package/packages/core/dist/questions/store.d.ts +12 -0
- package/packages/core/dist/questions/store.d.ts.map +1 -1
- package/packages/core/dist/questions/store.js +11 -1
- package/packages/core/dist/questions/store.js.map +1 -1
- package/packages/core/dist/questions/types.d.ts +8 -0
- package/packages/core/dist/questions/types.d.ts.map +1 -1
- package/packages/core/dist/questions/types.js +15 -0
- package/packages/core/dist/questions/types.js.map +1 -1
- package/packages/core/dist/queue/jobs.d.ts +8 -0
- package/packages/core/dist/queue/jobs.d.ts.map +1 -1
- package/packages/core/dist/queue/jobs.js +9 -3
- package/packages/core/dist/queue/jobs.js.map +1 -1
- package/packages/core/dist/queue/worker.d.ts +2 -0
- package/packages/core/dist/queue/worker.d.ts.map +1 -1
- package/packages/core/dist/queue/worker.js +2 -1
- package/packages/core/dist/queue/worker.js.map +1 -1
- package/packages/core/dist/registry.d.ts +7 -1
- package/packages/core/dist/registry.d.ts.map +1 -1
- package/packages/core/dist/registry.js +73 -11
- package/packages/core/dist/registry.js.map +1 -1
- package/packages/core/dist/routes.d.ts +153 -0
- package/packages/core/dist/routes.d.ts.map +1 -0
- package/packages/core/dist/routes.js +47 -0
- package/packages/core/dist/routes.js.map +1 -0
- package/packages/core/dist/scheduler/missions.d.ts +5 -3
- package/packages/core/dist/scheduler/missions.d.ts.map +1 -1
- package/packages/core/dist/scheduler/missions.js +9 -7
- package/packages/core/dist/scheduler/missions.js.map +1 -1
- package/packages/core/dist/scheduler/types.d.ts +7 -0
- package/packages/core/dist/scheduler/types.d.ts.map +1 -1
- package/packages/core/dist/scheduler/types.js +1 -0
- package/packages/core/dist/scheduler/types.js.map +1 -1
- package/packages/core/dist/tools.d.ts +59 -2
- package/packages/core/dist/tools.d.ts.map +1 -1
- package/packages/core/dist/tools.js.map +1 -1
- package/packages/core/migrations/075_access_providers.sql +43 -0
- package/packages/core/migrations/076_mission_browser.sql +7 -0
- package/packages/gateway/dist/.tsbuildinfo +1 -1
- package/packages/gateway/dist/agents/canvas.d.ts +12 -12
- package/packages/gateway/dist/agents/catalogue-package.d.ts +38 -20
- package/packages/gateway/dist/agents/catalogue-package.d.ts.map +1 -1
- package/packages/gateway/dist/agents/catalogue-package.js +6 -0
- package/packages/gateway/dist/agents/catalogue-package.js.map +1 -1
- package/packages/gateway/dist/agents/delegation.d.ts +10 -0
- package/packages/gateway/dist/agents/delegation.d.ts.map +1 -1
- package/packages/gateway/dist/agents/delegation.js +1 -0
- package/packages/gateway/dist/agents/delegation.js.map +1 -1
- package/packages/gateway/dist/agents/platform-catalogue.d.ts +7 -1
- package/packages/gateway/dist/agents/platform-catalogue.d.ts.map +1 -1
- package/packages/gateway/dist/agents/platform-catalogue.js +15 -6
- package/packages/gateway/dist/agents/platform-catalogue.js.map +1 -1
- package/packages/gateway/dist/bootstrap.d.ts.map +1 -1
- package/packages/gateway/dist/bootstrap.js +8 -0
- package/packages/gateway/dist/bootstrap.js.map +1 -1
- package/packages/gateway/dist/browser-host.d.ts +30 -1
- package/packages/gateway/dist/browser-host.d.ts.map +1 -1
- package/packages/gateway/dist/browser-host.js +56 -1
- package/packages/gateway/dist/browser-host.js.map +1 -1
- package/packages/gateway/dist/chat/session.d.ts.map +1 -1
- package/packages/gateway/dist/chat/session.js +9 -5
- package/packages/gateway/dist/chat/session.js.map +1 -1
- package/packages/gateway/dist/index.d.ts +2 -1
- package/packages/gateway/dist/index.d.ts.map +1 -1
- package/packages/gateway/dist/index.js +2 -1
- package/packages/gateway/dist/index.js.map +1 -1
- package/packages/gateway/dist/missions/ask-cap.d.ts +26 -0
- package/packages/gateway/dist/missions/ask-cap.d.ts.map +1 -0
- package/packages/gateway/dist/missions/ask-cap.js +83 -0
- package/packages/gateway/dist/missions/ask-cap.js.map +1 -0
- package/packages/gateway/dist/missions/execute.d.ts +45 -1
- package/packages/gateway/dist/missions/execute.d.ts.map +1 -1
- package/packages/gateway/dist/missions/execute.js +156 -10
- package/packages/gateway/dist/missions/execute.js.map +1 -1
- package/packages/gateway/dist/missions/parked.d.ts +139 -0
- package/packages/gateway/dist/missions/parked.d.ts.map +1 -0
- package/packages/gateway/dist/missions/parked.js +255 -0
- package/packages/gateway/dist/missions/parked.js.map +1 -0
- package/packages/gateway/dist/serve.d.ts +7 -0
- package/packages/gateway/dist/serve.d.ts.map +1 -1
- package/packages/gateway/dist/serve.js +49 -9
- package/packages/gateway/dist/serve.js.map +1 -1
- package/packages/gateway/dist/surfaces/browser-cards.d.ts +18 -0
- package/packages/gateway/dist/surfaces/browser-cards.d.ts.map +1 -0
- package/packages/gateway/dist/surfaces/browser-cards.js +42 -0
- package/packages/gateway/dist/surfaces/browser-cards.js.map +1 -0
- package/packages/gateway/dist/surfaces/browser-continuation.js +1 -1
- package/packages/gateway/dist/surfaces/browser-continuation.js.map +1 -1
- package/packages/gateway/dist/surfaces/owner-request.d.ts +6 -0
- package/packages/gateway/dist/surfaces/owner-request.d.ts.map +1 -1
- package/packages/gateway/dist/surfaces/owner-request.js +7 -1
- package/packages/gateway/dist/surfaces/owner-request.js.map +1 -1
- package/packages/gateway/dist/system-context.d.ts +7 -0
- package/packages/gateway/dist/system-context.d.ts.map +1 -1
- package/packages/gateway/dist/system-context.js +14 -7
- package/packages/gateway/dist/system-context.js.map +1 -1
- package/packages/gateway/dist/telegram/browser-view.d.ts +17 -17
- package/packages/gateway/dist/telegram/browser-view.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/browser-view.js +33 -37
- package/packages/gateway/dist/telegram/browser-view.js.map +1 -1
- package/packages/gateway/dist/telegram/channel.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/channel.js +17 -1
- package/packages/gateway/dist/telegram/channel.js.map +1 -1
- package/packages/gateway/dist/telegram/main.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/main.js +11 -3
- package/packages/gateway/dist/telegram/main.js.map +1 -1
- package/packages/gateway/dist/telegram/surface.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/surface.js +10 -0
- package/packages/gateway/dist/telegram/surface.js.map +1 -1
- package/packages/gateway/dist/tips/facts.d.ts +8 -0
- package/packages/gateway/dist/tips/facts.d.ts.map +1 -1
- package/packages/gateway/dist/tips/facts.js +8 -2
- package/packages/gateway/dist/tips/facts.js.map +1 -1
- package/packages/gateway/dist/tips/rules.d.ts +2 -0
- package/packages/gateway/dist/tips/rules.d.ts.map +1 -1
- package/packages/gateway/dist/tips/rules.js +15 -0
- package/packages/gateway/dist/tips/rules.js.map +1 -1
- package/packages/gateway/dist/web/access/arrival.d.ts +24 -0
- package/packages/gateway/dist/web/access/arrival.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/arrival.js +18 -0
- package/packages/gateway/dist/web/access/arrival.js.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-api.d.ts +124 -0
- package/packages/gateway/dist/web/access/cloudflare-api.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-api.js +206 -0
- package/packages/gateway/dist/web/access/cloudflare-api.js.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-setup.d.ts +163 -0
- package/packages/gateway/dist/web/access/cloudflare-setup.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-setup.js +438 -0
- package/packages/gateway/dist/web/access/cloudflare-setup.js.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-token.d.ts +31 -0
- package/packages/gateway/dist/web/access/cloudflare-token.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare-token.js +74 -0
- package/packages/gateway/dist/web/access/cloudflare-token.js.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare.d.ts +145 -0
- package/packages/gateway/dist/web/access/cloudflare.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/cloudflare.js +474 -0
- package/packages/gateway/dist/web/access/cloudflare.js.map +1 -0
- package/packages/gateway/dist/web/access/index.d.ts +9 -0
- package/packages/gateway/dist/web/access/index.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/index.js +9 -0
- package/packages/gateway/dist/web/access/index.js.map +1 -0
- package/packages/gateway/dist/web/access/ingress.d.ts +30 -0
- package/packages/gateway/dist/web/access/ingress.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/ingress.js +76 -0
- package/packages/gateway/dist/web/access/ingress.js.map +1 -0
- package/packages/gateway/dist/web/access/provider.d.ts +173 -0
- package/packages/gateway/dist/web/access/provider.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/provider.js +11 -0
- package/packages/gateway/dist/web/access/provider.js.map +1 -0
- package/packages/gateway/dist/web/access/registry.d.ts +33 -0
- package/packages/gateway/dist/web/access/registry.d.ts.map +1 -0
- package/packages/gateway/dist/web/access/registry.js +32 -0
- package/packages/gateway/dist/web/access/registry.js.map +1 -0
- package/packages/gateway/dist/web/{tailscale.d.ts → access/tailscale.d.ts} +27 -0
- package/packages/gateway/dist/web/access/tailscale.d.ts.map +1 -0
- package/packages/gateway/dist/web/{tailscale.js → access/tailscale.js} +118 -3
- package/packages/gateway/dist/web/access/tailscale.js.map +1 -0
- package/packages/gateway/dist/web/agents.d.ts +2 -0
- package/packages/gateway/dist/web/agents.d.ts.map +1 -1
- package/packages/gateway/dist/web/agents.js +19 -1
- package/packages/gateway/dist/web/agents.js.map +1 -1
- package/packages/gateway/dist/web/api-routes.d.ts +4 -3
- package/packages/gateway/dist/web/api-routes.d.ts.map +1 -1
- package/packages/gateway/dist/web/api-routes.js +106 -19
- package/packages/gateway/dist/web/api-routes.js.map +1 -1
- package/packages/gateway/dist/web/attention.d.ts.map +1 -1
- package/packages/gateway/dist/web/attention.js +11 -3
- package/packages/gateway/dist/web/attention.js.map +1 -1
- package/packages/gateway/dist/web/chat.d.ts +23 -0
- package/packages/gateway/dist/web/chat.d.ts.map +1 -1
- package/packages/gateway/dist/web/chat.js +62 -2
- package/packages/gateway/dist/web/chat.js.map +1 -1
- package/packages/gateway/dist/web/client-key.d.ts +3 -0
- package/packages/gateway/dist/web/client-key.d.ts.map +1 -1
- package/packages/gateway/dist/web/client-key.js +8 -1
- package/packages/gateway/dist/web/client-key.js.map +1 -1
- package/packages/gateway/dist/web/extension.d.ts +21 -1
- package/packages/gateway/dist/web/extension.d.ts.map +1 -1
- package/packages/gateway/dist/web/extension.js +183 -3
- package/packages/gateway/dist/web/extension.js.map +1 -1
- package/packages/gateway/dist/web/http.d.ts +7 -0
- package/packages/gateway/dist/web/http.d.ts.map +1 -1
- package/packages/gateway/dist/web/http.js +15 -1
- package/packages/gateway/dist/web/http.js.map +1 -1
- package/packages/gateway/dist/web/index.d.ts +1 -1
- package/packages/gateway/dist/web/index.d.ts.map +1 -1
- package/packages/gateway/dist/web/index.js +1 -1
- package/packages/gateway/dist/web/index.js.map +1 -1
- package/packages/gateway/dist/web/onboarding.js +1 -1
- package/packages/gateway/dist/web/onboarding.js.map +1 -1
- package/packages/gateway/dist/web/remote-hand.d.ts.map +1 -1
- package/packages/gateway/dist/web/remote-hand.js +45 -2
- package/packages/gateway/dist/web/remote-hand.js.map +1 -1
- package/packages/gateway/dist/web/secrets.d.ts +26 -1
- package/packages/gateway/dist/web/secrets.d.ts.map +1 -1
- package/packages/gateway/dist/web/secrets.js +66 -3
- package/packages/gateway/dist/web/secrets.js.map +1 -1
- package/packages/gateway/dist/web/server.d.ts +38 -2
- package/packages/gateway/dist/web/server.d.ts.map +1 -1
- package/packages/gateway/dist/web/server.js +634 -147
- package/packages/gateway/dist/web/server.js.map +1 -1
- package/packages/gateway/dist/web/sessions.d.ts +24 -14
- package/packages/gateway/dist/web/sessions.d.ts.map +1 -1
- package/packages/gateway/dist/web/sessions.js +42 -14
- package/packages/gateway/dist/web/sessions.js.map +1 -1
- package/packages/gateway/dist/web/signed-out.d.ts +10 -0
- package/packages/gateway/dist/web/signed-out.d.ts.map +1 -1
- package/packages/gateway/dist/web/signed-out.js +47 -0
- package/packages/gateway/dist/web/signed-out.js.map +1 -1
- package/packages/gateway/dist/web/version.d.ts +2 -0
- package/packages/gateway/dist/web/version.d.ts.map +1 -1
- package/packages/gateway/dist/web/version.js +5 -1
- package/packages/gateway/dist/web/version.js.map +1 -1
- package/packages/install/dist/.tsbuildinfo +1 -1
- package/packages/install/dist/app-layout.d.ts +127 -0
- package/packages/install/dist/app-layout.d.ts.map +1 -0
- package/packages/install/dist/app-layout.js +323 -0
- package/packages/install/dist/app-layout.js.map +1 -0
- package/packages/install/dist/index.d.ts +1 -0
- package/packages/install/dist/index.d.ts.map +1 -1
- package/packages/install/dist/index.js +1 -0
- package/packages/install/dist/index.js.map +1 -1
- package/packages/install/dist/launcher.d.ts.map +1 -1
- package/packages/install/dist/launcher.js +18 -4
- package/packages/install/dist/launcher.js.map +1 -1
- package/packages/install/dist/provenance.d.ts +34 -0
- package/packages/install/dist/provenance.d.ts.map +1 -0
- package/packages/install/dist/provenance.js +200 -0
- package/packages/install/dist/provenance.js.map +1 -0
- package/packages/install/dist/supervisor.d.ts.map +1 -1
- package/packages/install/dist/supervisor.js +9 -4
- package/packages/install/dist/supervisor.js.map +1 -1
- package/packages/install/dist/upgrade.d.ts +77 -3
- package/packages/install/dist/upgrade.d.ts.map +1 -1
- package/packages/install/dist/upgrade.js +325 -43
- package/packages/install/dist/upgrade.js.map +1 -1
- package/packages/runtime/dist/.tsbuildinfo +1 -1
- package/packages/runtime/dist/delegate.d.ts +8 -0
- package/packages/runtime/dist/delegate.d.ts.map +1 -1
- package/packages/runtime/dist/delegate.js +19 -1
- package/packages/runtime/dist/delegate.js.map +1 -1
- package/packages/runtime/dist/loop.d.ts +2 -0
- package/packages/runtime/dist/loop.d.ts.map +1 -1
- package/packages/runtime/dist/loop.js +18 -4
- package/packages/runtime/dist/loop.js.map +1 -1
- package/packages/tools/artifacts/dist/.tsbuildinfo +1 -1
- package/packages/tools/browser/dist/.tsbuildinfo +1 -1
- package/packages/tools/browser/dist/availability.d.ts +2 -2
- package/packages/tools/browser/dist/availability.d.ts.map +1 -1
- package/packages/tools/browser/dist/availability.js +2 -2
- package/packages/tools/browser/dist/availability.js.map +1 -1
- package/packages/tools/browser/dist/controller.d.ts +82 -58
- package/packages/tools/browser/dist/controller.d.ts.map +1 -1
- package/packages/tools/browser/dist/controller.js +823 -217
- package/packages/tools/browser/dist/controller.js.map +1 -1
- package/packages/tools/browser/dist/driver.d.ts +3 -1
- package/packages/tools/browser/dist/driver.d.ts.map +1 -1
- package/packages/tools/browser/dist/driver.js +82 -1
- package/packages/tools/browser/dist/driver.js.map +1 -1
- package/packages/tools/browser/dist/extension.d.ts +70 -5
- package/packages/tools/browser/dist/extension.d.ts.map +1 -1
- package/packages/tools/browser/dist/extension.js +94 -9
- package/packages/tools/browser/dist/extension.js.map +1 -1
- package/packages/tools/browser/dist/index.d.ts +17 -7
- package/packages/tools/browser/dist/index.d.ts.map +1 -1
- package/packages/tools/browser/dist/index.js +35 -15
- package/packages/tools/browser/dist/index.js.map +1 -1
- package/packages/tools/browser/dist/logins.d.ts +150 -0
- package/packages/tools/browser/dist/logins.d.ts.map +1 -0
- package/packages/tools/browser/dist/logins.js +476 -0
- package/packages/tools/browser/dist/logins.js.map +1 -0
- package/packages/tools/browser/dist/manager.d.ts +39 -21
- package/packages/tools/browser/dist/manager.d.ts.map +1 -1
- package/packages/tools/browser/dist/manager.js +229 -136
- package/packages/tools/browser/dist/manager.js.map +1 -1
- package/packages/tools/browser/dist/routes.d.ts +151 -0
- package/packages/tools/browser/dist/routes.d.ts.map +1 -0
- package/packages/tools/browser/dist/routes.js +331 -0
- package/packages/tools/browser/dist/routes.js.map +1 -0
- package/packages/tools/browser/dist/secrets.d.ts +3 -1
- package/packages/tools/browser/dist/secrets.d.ts.map +1 -1
- package/packages/tools/browser/dist/secrets.js +10 -6
- package/packages/tools/browser/dist/secrets.js.map +1 -1
- package/packages/tools/browser/dist/service.d.ts +182 -115
- package/packages/tools/browser/dist/service.d.ts.map +1 -1
- package/packages/tools/browser/dist/service.js +491 -388
- package/packages/tools/browser/dist/service.js.map +1 -1
- package/packages/tools/browser/dist/settings.d.ts +88 -0
- package/packages/tools/browser/dist/settings.d.ts.map +1 -0
- package/packages/tools/browser/dist/settings.js +86 -0
- package/packages/tools/browser/dist/settings.js.map +1 -0
- package/packages/tools/browser/dist/telemetry.d.ts +203 -0
- package/packages/tools/browser/dist/telemetry.d.ts.map +1 -0
- package/packages/tools/browser/dist/telemetry.js +142 -0
- package/packages/tools/browser/dist/telemetry.js.map +1 -0
- package/packages/tools/browser/dist/types.d.ts +102 -3
- package/packages/tools/browser/dist/types.d.ts.map +1 -1
- package/packages/tools/browser/dist/types.js +27 -9
- package/packages/tools/browser/dist/types.js.map +1 -1
- package/packages/tools/email/dist/.tsbuildinfo +1 -1
- package/packages/tools/host/dist/.tsbuildinfo +1 -1
- package/packages/tools/mcp/dist/.tsbuildinfo +1 -1
- package/packages/tools/memory/dist/.tsbuildinfo +1 -1
- package/packages/tools/web/dist/.tsbuildinfo +1 -1
- package/packages/web/dist/assets/index-DYfeUW-0.css +1 -0
- package/packages/web/dist/assets/index-vpc904_b.js +146 -0
- package/packages/web/dist/assets/{lottie_light-CKJ88Yuk.js → lottie_light-BFAMYgLA.js} +1 -1
- package/packages/web/dist/build.json +1 -1
- package/packages/web/dist/index.html +2 -2
- package/packages/web/dist/precache.json +4 -4
- package/node_modules/@buddi/gateway/dist/web/apps.d.ts +0 -18
- package/node_modules/@buddi/gateway/dist/web/apps.d.ts.map +0 -1
- package/node_modules/@buddi/gateway/dist/web/apps.js +0 -84
- package/node_modules/@buddi/gateway/dist/web/apps.js.map +0 -1
- package/node_modules/@buddi/gateway/dist/web/tailscale.d.ts.map +0 -1
- package/node_modules/@buddi/gateway/dist/web/tailscale.js.map +0 -1
- package/node_modules/@buddi/tool-browser/dist/computer.d.ts +0 -153
- package/node_modules/@buddi/tool-browser/dist/computer.d.ts.map +0 -1
- package/node_modules/@buddi/tool-browser/dist/computer.js +0 -392
- package/node_modules/@buddi/tool-browser/dist/computer.js.map +0 -1
- package/node_modules/@buddi/tool-browser/dist/native/buddi-computer +0 -0
- package/node_modules/pino/test/browser-bindings.test.js +0 -114
- package/node_modules/pino/test/browser-redaction.test.js +0 -264
- package/node_modules/pino/test/browser-set-bindings.test.js +0 -99
- package/node_modules/pino/test/caller.test.js +0 -20
- package/node_modules/pino/test/fixtures/caller-loop.js +0 -6
- package/node_modules/pino/test/smoke.js +0 -59
- package/node_modules/pino/test/types/pino-import.tst.cts +0 -30
- package/node_modules/pino/test/types/pino-import.tst.js +0 -73
- package/node_modules/pino/test/types/pino-multistream.tst.ts +0 -49
- package/node_modules/pino/test/types/pino-top-export.tst.ts +0 -32
- package/node_modules/pino/test/types/pino-type-only.tst.ts +0 -77
- package/node_modules/pino/test/types/tsconfig.json +0 -10
- package/packages/gateway/dist/web/apps.d.ts +0 -18
- package/packages/gateway/dist/web/apps.d.ts.map +0 -1
- package/packages/gateway/dist/web/apps.js +0 -84
- package/packages/gateway/dist/web/apps.js.map +0 -1
- package/packages/gateway/dist/web/tailscale.d.ts.map +0 -1
- package/packages/gateway/dist/web/tailscale.js.map +0 -1
- package/packages/tools/browser/dist/computer.d.ts +0 -153
- package/packages/tools/browser/dist/computer.d.ts.map +0 -1
- package/packages/tools/browser/dist/computer.js +0 -392
- package/packages/tools/browser/dist/computer.js.map +0 -1
- package/packages/tools/browser/dist/native/buddi-computer +0 -0
- package/packages/web/dist/assets/index-CN1AXMI1.css +0 -1
- package/packages/web/dist/assets/index-CQRE9LJX.js +0 -145
|
@@ -1,51 +1,55 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { mkdir, readFile, writeFile, rename } from 'node:fs/promises';
|
|
3
|
-
import path from 'node:path';
|
|
4
2
|
import { FORM_KIND, NATIVE_KIND, fieldBoundTo, secretKindFor, takeDelivered } from './secrets.js';
|
|
5
|
-
import { APP_BEHIND, BrowserPreconditionError, UNTRUSTED, observedLine } from './types.js';
|
|
3
|
+
import { LOGIN_GONE, LOGIN_GRACE_MS, APP_BEHIND, BrowserOpenedError, BrowserPreconditionError, UNTRUSTED, observedLine } from './types.js';
|
|
4
|
+
import { ownerCard, siteOf } from './routes.js';
|
|
5
|
+
import { missionMark } from './telemetry.js';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* is already on the tool context (`ctx.surface`), so the plugin says it rather
|
|
11
|
-
* than leaving a relay to guess. On Telegram the way back is a command in the
|
|
12
|
-
* same chat; everywhere else it is the dashboard's own Settings page, which is
|
|
13
|
-
* where the Stop button lives.
|
|
7
|
+
* Said when the owner has stopped agents' browsing. On Telegram the way back
|
|
8
|
+
* is a command in the same chat; everywhere else the Resume card in the chat
|
|
9
|
+
* itself, or Settings.
|
|
14
10
|
*/
|
|
15
|
-
|
|
11
|
+
export function browserStoppedMessage(surface) {
|
|
12
|
+
return surface?.id === 'telegram'
|
|
13
|
+
? 'The owner stopped agents\' browsing. Tap Resume on the card, or send /browser resume here.'
|
|
14
|
+
: 'The owner stopped agents\' browsing. Tap Resume on the card in this chat to let agents look again.';
|
|
15
|
+
}
|
|
16
|
+
/** Kept for the surfaces that still name it: the owner has the page in their hands. */
|
|
16
17
|
export function browserPausedMessage(surface) {
|
|
17
18
|
return surface?.id === 'telegram'
|
|
18
|
-
? '
|
|
19
|
-
: '
|
|
19
|
+
? 'You have the page. Give it back from the dashboard, or send /browser resume here.'
|
|
20
|
+
: 'You have the page. Give it back when you are done and the agent carries on.';
|
|
20
21
|
}
|
|
21
|
-
/**
|
|
22
|
-
* Said when an observation did not answer and control stays with the agent.
|
|
23
|
-
* A slow page is something the model can wait out itself, so there is nothing
|
|
24
|
-
* for the owner to do and the wording is the same on every surface.
|
|
25
|
-
*/
|
|
22
|
+
/** A page that did not answer after every retry: said once, never as an instruction to retry. */
|
|
26
23
|
export function browserWaitMessage(_surface) {
|
|
27
|
-
return 'The page
|
|
24
|
+
return 'The page did not answer after several tries.';
|
|
28
25
|
}
|
|
29
|
-
/**
|
|
30
|
-
const SCREEN_GONE = /\b(tab|window)\b[^.]*\b(closed|gone)\b|has been closed|target closed/i;
|
|
31
|
-
/** A gone tab the driver can replace by itself ("observe again to continue in a new one") is not a screen lost. */
|
|
32
|
-
const SCREEN_REPLACEABLE = /observe again to continue in a new one/i;
|
|
33
|
-
/** The extension's refusal to act in the tab the owner is viewing (extension commands.ts, `WATCHED`). */
|
|
26
|
+
/** The extension's last word after waiting for the owner to leave their tab (extension commands.ts, `WATCHED`). */
|
|
34
27
|
const OWNER_WATCHING = /You are looking at this tab/i;
|
|
35
|
-
/** What the
|
|
36
|
-
export const OWNER_WATCHING_MESSAGE = 'The owner is looking at that tab
|
|
37
|
-
/**
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
28
|
+
/** What the agent is told instead: no ask, no retry loop; the bar in the tab already asks the owner. */
|
|
29
|
+
export const OWNER_WATCHING_MESSAGE = 'The owner is looking at that tab, and the bar in it asks them whether you may carry on there. Nothing was done. Work on something else for a moment, then try again.';
|
|
30
|
+
/** An observation failure no waiting fixes: the tab or window it was reading is gone. */
|
|
31
|
+
const SCREEN_GONE = /\b(tab|window)\b[^.]*\b(closed|gone)\b|has been closed|target closed/i;
|
|
32
|
+
/** The waits before each re-read when the page gave no answer: 0.5, 1, 2, 4 and 8 seconds (six attempts in all). */
|
|
33
|
+
export const RETRY_DELAYS_MS = [500, 1_000, 2_000, 4_000, 8_000];
|
|
34
|
+
/** Targeting refusals in a row before the task asks the owner whether to keep going. */
|
|
35
|
+
export const MAX_TARGETING_FAILURES = 8;
|
|
36
|
+
/** The task's budget: actions and minutes, renewed by any owner touch in the conversation. */
|
|
37
|
+
export const DEFAULT_MAX_STEPS = 200;
|
|
38
|
+
export const DEFAULT_LIFETIME_MS = 60 * 60_000;
|
|
39
|
+
/** How long a run stays parked on its page waiting for the owner's card. */
|
|
40
|
+
export const PARK_MS = 60 * 60_000;
|
|
41
|
+
/** A route by the mode name the dashboard and Telegram already know. */
|
|
42
|
+
export function modeOf(route) {
|
|
43
|
+
return route === 'chrome' ? 'extension' : route === 'apps' ? 'computer' : 'playwright';
|
|
46
44
|
}
|
|
47
|
-
/**
|
|
48
|
-
*
|
|
45
|
+
/**
|
|
46
|
+
* One conversation's page on one route.
|
|
47
|
+
*
|
|
48
|
+
* Every action returns the page as it is afterwards. Refusals that used to
|
|
49
|
+
* stop the task are retried here (a slow page, a stale ref, a redirect) or
|
|
50
|
+
* become one card the owner answers (an input that may not have landed, the
|
|
51
|
+
* budget). Only the owner's own take-over pauses a page.
|
|
52
|
+
*/
|
|
49
53
|
export class BrowserService {
|
|
50
54
|
driver;
|
|
51
55
|
options;
|
|
@@ -55,81 +59,112 @@ export class BrowserService {
|
|
|
55
59
|
#observation;
|
|
56
60
|
#picture;
|
|
57
61
|
#busy = false;
|
|
58
|
-
/**
|
|
59
|
-
* The screen this session had is gone.
|
|
60
|
-
*
|
|
61
|
-
* Set when a take-over had to close the driver to end the action in flight,
|
|
62
|
-
* and cleared by resume. Belt to `handReady`'s braces: a hand offered over
|
|
63
|
-
* nothing is a live view that never paints its first frame, and the owner
|
|
64
|
-
* has no way to tell that from a slow link.
|
|
65
|
-
*/
|
|
66
62
|
#handless = false;
|
|
63
|
+
/** The owner holds the page in place (their Chrome brought it forward): no frames, no hand. */
|
|
64
|
+
#held = false;
|
|
65
|
+
/** The page the owner last held in place, and until when a Save they tapped there still counts (the driver's grace). */
|
|
66
|
+
#lastHeld;
|
|
67
|
+
/** Who waits for the action in flight to settle (a Give it back pressed while it stops). */
|
|
68
|
+
#settleWaiters = [];
|
|
67
69
|
#controller;
|
|
68
70
|
#expiry;
|
|
69
71
|
#lastAction;
|
|
70
72
|
#message;
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
#
|
|
73
|
+
#targetingFailures = 0;
|
|
74
|
+
#card;
|
|
75
|
+
/** Where the page last was, so a closed tab or a new request re-opens it rather than stopping. */
|
|
76
|
+
#lastUrl;
|
|
77
|
+
#lastActivity = 0;
|
|
78
|
+
#tail = Promise.resolve();
|
|
75
79
|
#controlTail = Promise.resolve();
|
|
76
|
-
#diskTail = Promise.resolve();
|
|
77
80
|
constructor(driver, options = {}) {
|
|
78
81
|
this.driver = driver;
|
|
79
82
|
this.options = options;
|
|
80
83
|
}
|
|
81
84
|
#now() { return this.options.now?.() ?? Date.now(); }
|
|
82
|
-
|
|
83
|
-
#
|
|
84
|
-
|
|
85
|
+
get #route() { return this.options.route ?? (this.options.allowOpen ? 'apps' : 'own'); }
|
|
86
|
+
#sleep(ms) { return this.options.sleep ? this.options.sleep(ms) : new Promise((resolve) => setTimeout(resolve, ms)); }
|
|
87
|
+
#stamp(observation) { return { ...observation, observedAt: new Date(this.#now()).toISOString() }; }
|
|
88
|
+
#stop(cause, ctx, recovered) {
|
|
89
|
+
this.options.telemetry?.stop(cause, { route: this.#route, ...(ctx?.agentId ? { agent: ctx.agentId } : {}), ...(ctx?.surface?.id ? { surface: ctx.surface.id } : {}), ...missionMark(ctx),
|
|
90
|
+
...(siteOf(this.#observation?.url ?? this.#lastUrl) ? { host: siteOf(this.#observation?.url ?? this.#lastUrl) } : {}), ...(recovered ? { recovered } : {}) });
|
|
85
91
|
}
|
|
86
92
|
async enable() {
|
|
87
93
|
if (this.#enabled)
|
|
88
94
|
return;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
this
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
// Take over pressed in the page's own bar is the Canvas button.
|
|
96
|
+
this.driver.onOwnerTakeover?.(() => {
|
|
97
|
+
const id = this.#session?.id;
|
|
98
|
+
if (!id)
|
|
99
|
+
return;
|
|
100
|
+
if (this.options.requestTakeover)
|
|
101
|
+
this.options.requestTakeover(id);
|
|
102
|
+
else
|
|
103
|
+
void this.control('takeover').catch(() => undefined);
|
|
104
|
+
});
|
|
105
|
+
// Give it back pressed in the held tab's bar is the Canvas's Give it back.
|
|
106
|
+
this.driver.onOwnerGiveBack?.(() => {
|
|
107
|
+
const id = this.#session?.id;
|
|
108
|
+
if (!id || this.#state !== 'paused')
|
|
109
|
+
return;
|
|
110
|
+
if (this.options.requestResume)
|
|
111
|
+
this.options.requestResume(id);
|
|
112
|
+
else
|
|
113
|
+
void this.control('resume').catch(() => undefined);
|
|
114
|
+
});
|
|
115
|
+
// A sign-in the owner made on the page they hold: the keeper asks them, never a model.
|
|
116
|
+
// A Save the owner tapped in their Chrome a beat after Give it back still counts, for the page they held, within the driver's grace.
|
|
117
|
+
this.driver.onLoginSeen?.((login) => {
|
|
118
|
+
const live = this.#state === 'paused' ? this.#session?.id : undefined;
|
|
119
|
+
if (login.decision === 'check' && !live)
|
|
120
|
+
return Promise.resolve({ ask: 'none' });
|
|
121
|
+
const recent = !live && login.decision && this.#lastHeld && this.#now() < this.#lastHeld.until ? this.#lastHeld.id : undefined;
|
|
122
|
+
const id = live ?? recent;
|
|
123
|
+
if (!id)
|
|
124
|
+
return login.decision ? Promise.resolve({ saved: false, reason: LOGIN_GONE }) : undefined;
|
|
125
|
+
return this.options.loginSeen?.(id, login);
|
|
126
|
+
});
|
|
127
|
+
this.#state = 'idle';
|
|
102
128
|
this.#enabled = true;
|
|
103
129
|
}
|
|
104
130
|
status(_scope) {
|
|
105
131
|
const { tree: _tree, targets: _targets, ...page } = this.#observation ?? {};
|
|
106
|
-
const { ownerId:
|
|
132
|
+
const session = this.#session ? (({ ownerId: _o, startedAt: _s, actions: _a, cards: _c, ...rest }) => rest)(this.#session) : undefined;
|
|
107
133
|
return { state: this.#state, enabled: this.#enabled, busy: this.#busy,
|
|
108
|
-
...(
|
|
134
|
+
...(session ? { session: { ...session, route: this.#route }, route: this.#route, mode: modeOf(this.#route) } : {}),
|
|
109
135
|
...(this.#observation ? { page: page } : {}),
|
|
136
|
+
...(this.#card ? { needsOwner: this.#card } : {}),
|
|
137
|
+
...(this.#state === 'paused' && this.#held && this.driver.holdsInPlace ? { held: { by: 'owner', where: this.driver.holdsInPlace } } : {}),
|
|
110
138
|
lastAction: this.#lastAction, message: this.#message, hasScreenshot: !!this.#picture };
|
|
111
139
|
}
|
|
112
140
|
screenshot(_sessionId) { return this.#picture; }
|
|
141
|
+
/** The card this page waits on, if any. */
|
|
142
|
+
get card() { return this.#card; }
|
|
143
|
+
/** Where this page is, or was. */
|
|
144
|
+
get lastUrl() { return this.#observation?.url ?? this.#lastUrl; }
|
|
145
|
+
/** The latest page, with its tree: what the route's post-processing reads. */
|
|
146
|
+
get observation() { return this.#observation; }
|
|
147
|
+
get busy() { return this.#busy; }
|
|
148
|
+
/** Where this conversation's page was before it was let go, so the next action opens it again there. */
|
|
149
|
+
seed(url) { this.#lastUrl ??= url; }
|
|
150
|
+
/** No action for this long: a page a waiting conversation may take over. */
|
|
151
|
+
idleFor() { return this.#busy || this.#state === 'paused' || this.#card ? 0 : this.#now() - this.#lastActivity; }
|
|
113
152
|
/**
|
|
114
|
-
* The remote hand, and only while the owner holds this screen.
|
|
115
|
-
*
|
|
116
|
-
* Paused is the take-over state, so it is also the only state in which a
|
|
117
|
-
* dashboard may drive: an agent mid-action and a hand on the same page would
|
|
118
|
-
* be two drivers, and the evidence rules here assume exactly one.
|
|
153
|
+
* The remote hand, and only while the owner holds this screen. Paused is the
|
|
154
|
+
* take-over state, the only one in which a dashboard may drive.
|
|
119
155
|
*/
|
|
120
156
|
hand(_scope) {
|
|
157
|
+
if (this.#held && this.#state === 'paused')
|
|
158
|
+
return { supported: false, message: 'The page is in front of you in your Chrome.' };
|
|
121
159
|
if (this.driver.supportsHand === false || !this.driver.hand) {
|
|
122
|
-
return { supported: false, message: this.driver.handMessage ?? 'Take over at the computer for this
|
|
160
|
+
return { supported: false, message: this.driver.handMessage ?? 'Take over at the computer for this route.' };
|
|
123
161
|
}
|
|
124
162
|
if (!this.#session)
|
|
125
|
-
return { supported: true, message: 'No agent is
|
|
163
|
+
return { supported: true, message: 'No agent is looking at this page.' };
|
|
126
164
|
if (this.#state !== 'paused')
|
|
127
165
|
return { supported: true, message: 'Take over first, then you can drive.' };
|
|
128
|
-
// Paused is not the same as paintable. A take-over that interrupted an
|
|
129
|
-
// action closed the screen that action was on, and a hand offered over
|
|
130
|
-
// nothing is a live view that never draws its first frame.
|
|
131
166
|
if (this.#handless || this.driver.handReady?.() === false) {
|
|
132
|
-
return { supported: true, message: this.#message ?? 'There is no screen to drive.
|
|
167
|
+
return { supported: true, message: this.#message ?? 'There is no screen to drive. Give it back and the agent opens the page again.' };
|
|
133
168
|
}
|
|
134
169
|
return { supported: true, hand: this.driver.hand };
|
|
135
170
|
}
|
|
@@ -138,120 +173,195 @@ export class BrowserService {
|
|
|
138
173
|
if (!session || session.ownerId !== input.ownerId || session.agentId !== input.agentId || session.conversationId !== input.previousConversationId)
|
|
139
174
|
return false;
|
|
140
175
|
if (!this.#enabled || this.#busy || !['running', 'paused'].includes(this.#state))
|
|
141
|
-
throw new Error('Wait for
|
|
142
|
-
if (Date.parse(session.expiresAt) <= this.#now())
|
|
143
|
-
return false;
|
|
144
|
-
this.#spent.add(session.requestId);
|
|
176
|
+
throw new Error('Wait for the page to settle before continuing the conversation.');
|
|
145
177
|
session.conversationId = input.conversationId;
|
|
146
178
|
this.#observation = undefined;
|
|
147
179
|
this.#picture = undefined;
|
|
148
|
-
this.#
|
|
149
|
-
this.#message = 'Task continued after conversation rollover. Observe the current page before acting. Human takeover, if active, still requires owner resume.';
|
|
180
|
+
this.#message = 'Task continued after conversation rollover. The next action returns the current page.';
|
|
150
181
|
return true;
|
|
151
182
|
}
|
|
152
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Put the page on a card and wait for the owner. The run stops (the tool's
|
|
185
|
+
* result carries the card) and the page stays open for at least an hour.
|
|
186
|
+
*/
|
|
187
|
+
park(kind, facts = {}) {
|
|
188
|
+
const card = ownerCard(kind, { site: siteOf(this.lastUrl), ...facts });
|
|
189
|
+
this.#card = card;
|
|
190
|
+
if (this.#session)
|
|
191
|
+
this.#session.cards++;
|
|
192
|
+
this.#schedule(Math.max(Date.parse(this.#session?.expiresAt ?? '') || 0, this.#now()) + Math.max(this.options.parkMs ?? PARK_MS, PARK_MS) - this.#now());
|
|
193
|
+
return card;
|
|
194
|
+
}
|
|
195
|
+
#cardResult(card, dispatched, message) {
|
|
196
|
+
return { completed: false, dispatched, needsOwner: card, notice: UNTRUSTED,
|
|
197
|
+
message: message ?? `Waiting for the owner: "${card.title}" Say that in one sentence and stop; the card in the chat has the buttons. The page stays open; you continue when they answer.`,
|
|
198
|
+
...(this.#observation ? { observation: this.#observation } : {}) };
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The owner spoke or tapped in this conversation: the budget renews (200
|
|
202
|
+
* actions, an hour) and a waiting card is cleared. Returns the card it
|
|
203
|
+
* cleared, so the caller can act on the answer (take over, use Chrome).
|
|
204
|
+
*/
|
|
205
|
+
renew() {
|
|
206
|
+
const card = this.#card;
|
|
207
|
+
this.#card = undefined;
|
|
208
|
+
this.#targetingFailures = 0;
|
|
209
|
+
if (this.#session) {
|
|
210
|
+
this.#session.steps = 0;
|
|
211
|
+
this.#session.maxSteps = this.options.maxSteps ?? DEFAULT_MAX_STEPS;
|
|
212
|
+
const expiresAt = this.#now() + (this.options.lifetimeMs ?? DEFAULT_LIFETIME_MS);
|
|
213
|
+
this.#session.expiresAt = new Date(expiresAt).toISOString();
|
|
214
|
+
this.#schedule(expiresAt - this.#now() + Math.max(this.options.parkMs ?? PARK_MS, PARK_MS));
|
|
215
|
+
}
|
|
216
|
+
return card;
|
|
217
|
+
}
|
|
218
|
+
#schedule(ms) {
|
|
219
|
+
clearTimeout(this.#expiry);
|
|
220
|
+
this.#expiry = setTimeout(() => { void this.#release('expired'); }, Math.max(1, ms));
|
|
221
|
+
this.#expiry.unref?.();
|
|
222
|
+
}
|
|
223
|
+
#open(request, ctx) {
|
|
224
|
+
const lifetime = this.options.lifetimeMs ?? DEFAULT_LIFETIME_MS;
|
|
225
|
+
if (!this.#session) {
|
|
226
|
+
const expiresAt = this.#now() + lifetime;
|
|
227
|
+
this.#session = { id: randomUUID(), ownerId: ctx.buddi.owner.id, agentId: ctx.agentId, conversationId: ctx.conversationId,
|
|
228
|
+
requestId: request?.id ?? 'unattended', task: (request?.text ?? 'An unattended task').slice(0, 4000),
|
|
229
|
+
expiresAt: new Date(expiresAt).toISOString(), steps: 0, maxSteps: this.options.maxSteps ?? DEFAULT_MAX_STEPS,
|
|
230
|
+
startedAt: this.#now(), actions: 0, cards: 0 };
|
|
231
|
+
this.#schedule(lifetime + Math.max(this.options.parkMs ?? PARK_MS, PARK_MS));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
// A new owner message is an owner touch: the same page, a fresh budget.
|
|
235
|
+
if (request && this.#session.requestId !== request.id) {
|
|
236
|
+
this.#session.requestId = request.id;
|
|
237
|
+
this.#session.task = request.text.slice(0, 4000);
|
|
238
|
+
this.renew();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** One action at a time per page: a second call waits for the first rather than being refused. */
|
|
242
|
+
#serial(run) {
|
|
243
|
+
const next = this.#tail.then(run, run);
|
|
244
|
+
this.#tail = next.catch(() => { });
|
|
245
|
+
return next;
|
|
246
|
+
}
|
|
247
|
+
execute(command, ctx) {
|
|
248
|
+
return this.#serial(() => this.#execute(command, ctx));
|
|
249
|
+
}
|
|
250
|
+
async #execute(command, ctx) {
|
|
153
251
|
ctx.signal?.throwIfAborted();
|
|
154
252
|
const request = ctx.ownerRequest;
|
|
155
|
-
if (!
|
|
156
|
-
|
|
157
|
-
throw new Error('A current authenticated owner request is required.');
|
|
158
|
-
}
|
|
253
|
+
if (!ctx.agentId || !ctx.conversationId)
|
|
254
|
+
throw new Error('A browser action belongs to an agent and a conversation.');
|
|
159
255
|
if (!this.#enabled)
|
|
160
256
|
throw new Error('Browser driving is available through buddi serve (dashboard or Telegram), not a separate CLI process.');
|
|
161
257
|
if (this.#state === 'stopped')
|
|
162
258
|
throw new Error(browserStoppedMessage(ctx.surface));
|
|
163
|
-
if (this.#busy)
|
|
164
|
-
throw new Error('Browser is busy; overlapping actions are refused.');
|
|
165
259
|
if (this.#session && (this.#session.ownerId !== ctx.buddi.owner.id || this.#session.agentId !== ctx.agentId || this.#session.conversationId !== ctx.conversationId)) {
|
|
166
|
-
throw new Error('Another
|
|
260
|
+
throw new Error('Another conversation owns this page.');
|
|
167
261
|
}
|
|
168
|
-
if (this.#spent.has(request.id))
|
|
169
|
-
throw new Error('This browser request has ended. A new owner message is required.');
|
|
170
262
|
if (command.action === 'close') {
|
|
171
|
-
this.#spent.add(request.id);
|
|
172
263
|
await this.#release('idle');
|
|
173
264
|
return { closed: true, notice: UNTRUSTED };
|
|
174
265
|
}
|
|
175
|
-
if (this.#state === 'paused')
|
|
176
|
-
throw new Error('
|
|
177
|
-
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
266
|
+
if (this.#state === 'paused') {
|
|
267
|
+
throw new Error('The owner has this page in their hands. Wait for them to give it back; you continue when they do.');
|
|
268
|
+
}
|
|
269
|
+
// Parked on a card: nothing is done until the owner answers it.
|
|
270
|
+
if (this.#card) {
|
|
271
|
+
this.#open(request, ctx);
|
|
272
|
+
if (this.#card)
|
|
273
|
+
return this.#cardResult(this.#card, false);
|
|
274
|
+
}
|
|
275
|
+
let run = command;
|
|
276
|
+
let reopened = false;
|
|
277
|
+
if (!this.#session && command.action !== 'navigate' && command.action !== 'open') {
|
|
278
|
+
// No page yet, or the last one was let go: open it again where it was.
|
|
279
|
+
if (!this.#lastUrl || this.#route === 'apps') {
|
|
280
|
+
this.#stop('start-with-navigate', ctx);
|
|
281
|
+
return { completed: false, dispatched: false, notice: UNTRUSTED, message: 'No page is open in this conversation yet. Navigate to the website first.' };
|
|
282
|
+
}
|
|
283
|
+
this.#stop('request-ended', ctx);
|
|
284
|
+
run = { action: 'navigate', url: this.#lastUrl };
|
|
285
|
+
reopened = true;
|
|
186
286
|
}
|
|
287
|
+
this.#open(request, ctx);
|
|
187
288
|
const active = this.#session;
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
289
|
+
if (active.steps >= active.maxSteps || Date.parse(active.expiresAt) <= this.#now()) {
|
|
290
|
+
this.#stop('budget', ctx);
|
|
291
|
+
return this.#cardResult(this.park('budget'), false);
|
|
292
|
+
}
|
|
293
|
+
// The observation is the latest one unless the agent named another.
|
|
294
|
+
if (['click', 'fill', 'select', 'press', 'scroll'].includes(run.action) && run.observation === undefined && this.#observation) {
|
|
295
|
+
run = { ...run, observation: this.#observation.id };
|
|
191
296
|
}
|
|
192
297
|
++active.steps;
|
|
298
|
+
++active.actions;
|
|
193
299
|
this.#busy = true;
|
|
194
|
-
this.#lastAction =
|
|
300
|
+
this.#lastAction = run.action; // Never record form values here.
|
|
301
|
+
this.#lastActivity = this.#now();
|
|
195
302
|
this.#message = undefined;
|
|
196
303
|
const controller = new AbortController();
|
|
197
304
|
this.#controller = controller;
|
|
198
305
|
const cancel = () => {
|
|
199
306
|
controller.abort(ctx.signal?.reason ?? new Error('Browser action stopped.'));
|
|
200
|
-
this.#
|
|
201
|
-
void this.#release('stopped');
|
|
202
|
-
void this.#persistStop(true).catch(() => { });
|
|
307
|
+
void this.#release('idle');
|
|
203
308
|
};
|
|
204
309
|
ctx.signal?.addEventListener('abort', cancel, { once: true });
|
|
205
310
|
try {
|
|
206
311
|
this.#state = 'starting';
|
|
207
312
|
await this.driver.start();
|
|
208
313
|
controller.signal.throwIfAborted();
|
|
209
|
-
ctx.signal?.throwIfAborted();
|
|
210
314
|
this.#state = 'running';
|
|
211
|
-
await this.driver.perform(
|
|
212
|
-
|
|
213
|
-
|
|
315
|
+
await this.driver.perform(run);
|
|
316
|
+
const note = this.driver.takeNote?.();
|
|
317
|
+
if (note)
|
|
318
|
+
this.#message = note;
|
|
319
|
+
if (run.action !== 'observe')
|
|
320
|
+
this.#targetingFailures = 0;
|
|
214
321
|
controller.signal.throwIfAborted();
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
controller.signal.throwIfAborted();
|
|
221
|
-
this.#observation = this.#stamp(observation);
|
|
222
|
-
this.#picture = picture;
|
|
223
|
-
this.#needsObservation = false;
|
|
224
|
-
this.#observationFailures = 0;
|
|
322
|
+
const seen = await this.#look(controller, ctx);
|
|
323
|
+
if (!seen) {
|
|
324
|
+
// Six reads over fifteen seconds and nothing: one card, not a loop.
|
|
325
|
+
this.#stop('observation-failures', ctx, 'card');
|
|
326
|
+
return this.#cardResult(this.park('uncertain'), run.action !== 'observe');
|
|
225
327
|
}
|
|
226
|
-
catch (error) {
|
|
227
|
-
controller.signal.throwIfAborted();
|
|
228
|
-
const cause = error instanceof Error ? error.message : String(error);
|
|
229
|
-
const paused = this.#observationFailed(cause);
|
|
230
|
-
// The extension's final error already says to wait and observe again; do not say it twice.
|
|
231
|
-
// The app pushed behind already says how to bring it back.
|
|
232
|
-
const recovery = paused ? browserPausedMessage(ctx.surface) : APP_BEHIND.test(cause) || /observe again\.?$/i.test(cause.trim()) ? '' : browserWaitMessage(ctx.surface);
|
|
233
|
-
this.#message = `${command.action === 'observe' ? 'Observation failed' : 'Action completed, but observation failed'}: ${cause.replace(/\.$/, '')}.${recovery ? ` ${recovery}` : ''}${command.action === 'observe' ? '' : ' Do not repeat the action; its effect may already have happened.'}`;
|
|
234
|
-
const result = { completed: command.action !== 'observe', observed: false, error: cause,
|
|
235
|
-
state: this.#state, recovery, message: this.#message, notice: UNTRUSTED };
|
|
236
|
-
if (command.action === 'observe')
|
|
237
|
-
throw new ObservationFailure(JSON.stringify(result));
|
|
238
|
-
return result;
|
|
239
|
-
}
|
|
240
|
-
controller.signal.throwIfAborted();
|
|
241
328
|
const observed = observedLine(this.#observation.observedAt);
|
|
329
|
+
if (reopened) {
|
|
330
|
+
const asked = command.action;
|
|
331
|
+
return { completed: false, dispatched: false, notice: UNTRUSTED, observation: this.#observation,
|
|
332
|
+
message: `${observed} No page was open, so I opened ${siteOf(this.#lastUrl) ?? 'the last page'} again. Nothing else was done; ${asked === 'observe' ? 'here it is' : 'act on this page now'}.` };
|
|
333
|
+
}
|
|
242
334
|
return { completed: true, notice: UNTRUSTED, observation: this.#observation, message: this.#message ? `${observed} ${this.#message}` : observed };
|
|
243
335
|
}
|
|
244
336
|
catch (error) {
|
|
245
|
-
if (
|
|
337
|
+
if (controller.signal.aborted)
|
|
246
338
|
throw error;
|
|
247
|
-
|
|
248
|
-
|
|
339
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
340
|
+
if (error instanceof BrowserPreconditionError)
|
|
341
|
+
return await this.#precondition(controller, error, ctx);
|
|
342
|
+
this.#state = 'running';
|
|
343
|
+
if (error instanceof BrowserOpenedError) {
|
|
344
|
+
// The page opened and a later step failed: hand back the page, not just the error.
|
|
345
|
+
const site = siteOf(error.page.url) ?? 'the page';
|
|
346
|
+
const failed = message.replace(/\.$/, '');
|
|
347
|
+
if (error.page.url)
|
|
348
|
+
this.#lastUrl = error.page.url;
|
|
349
|
+
const seen = await this.#look(controller, ctx).catch(() => false);
|
|
350
|
+
if (seen) {
|
|
351
|
+
return { completed: false, dispatched: true, notice: UNTRUSTED, observation: this.#observation,
|
|
352
|
+
message: `${observedLine(this.#observation.observedAt)} Opened ${site}, then this failed: ${failed}. Carry on from this page; don't open it again.` };
|
|
353
|
+
}
|
|
354
|
+
this.#message = `Opened ${site} in a tab, then this failed: ${failed}.`;
|
|
355
|
+
throw new Error(this.#message);
|
|
249
356
|
}
|
|
250
|
-
if (
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
this.#
|
|
357
|
+
if (['click', 'fill', 'select', 'press'].includes(run.action)) {
|
|
358
|
+
// The input may have landed part-way: the owner looks, or tells the agent to judge from the page.
|
|
359
|
+
this.#stop('uncertain-input', ctx, 'card');
|
|
360
|
+
this.#observation = undefined;
|
|
361
|
+
this.#picture = undefined;
|
|
362
|
+
return this.#cardResult(this.park('uncertain'), true, `${message.replace(/\.$/, '')}. I'm not sure that went through. Say so in one sentence and stop; the card asks the owner whether to look.`);
|
|
254
363
|
}
|
|
364
|
+
this.#message = message;
|
|
255
365
|
throw error;
|
|
256
366
|
}
|
|
257
367
|
finally {
|
|
@@ -259,204 +369,177 @@ export class BrowserService {
|
|
|
259
369
|
if (this.#controller === controller)
|
|
260
370
|
this.#controller = undefined;
|
|
261
371
|
this.#busy = false;
|
|
372
|
+
this.#settled();
|
|
262
373
|
}
|
|
263
374
|
}
|
|
264
375
|
/**
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* Returns whether it paused.
|
|
376
|
+
* Read the page, re-reading at 0.5, 1, 2, 4 and 8 seconds when it does not
|
|
377
|
+
* answer. A closed tab is opened again at its last address once. False when
|
|
378
|
+
* all six reads failed. The app pushed behind the owner's window is said
|
|
379
|
+
* straight away: open brings it back and no wait helps.
|
|
270
380
|
*/
|
|
271
|
-
#
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
381
|
+
async #look(controller, ctx) {
|
|
382
|
+
const delays = this.options.retryDelays ?? RETRY_DELAYS_MS;
|
|
383
|
+
let reopened = false;
|
|
384
|
+
let counted = false;
|
|
385
|
+
for (let attempt = 0; attempt <= delays.length; attempt++) {
|
|
386
|
+
if (attempt > 0)
|
|
387
|
+
await this.#sleep(delays[attempt - 1]);
|
|
388
|
+
controller.signal.throwIfAborted();
|
|
389
|
+
try {
|
|
390
|
+
const observation = await this.driver.observe();
|
|
391
|
+
const picture = await this.driver.screenshot();
|
|
392
|
+
controller.signal.throwIfAborted();
|
|
393
|
+
this.#observation = this.#stamp(observation);
|
|
394
|
+
this.#picture = picture;
|
|
395
|
+
if (observation.url)
|
|
396
|
+
this.#lastUrl = observation.url;
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
controller.signal.throwIfAborted();
|
|
401
|
+
const cause = error instanceof Error ? error.message : String(error);
|
|
402
|
+
this.#observation = undefined;
|
|
403
|
+
this.#picture = undefined;
|
|
404
|
+
if (APP_BEHIND.test(cause)) {
|
|
405
|
+
this.#stop('app-behind', ctx);
|
|
406
|
+
throw new BrowserPreconditionError(cause);
|
|
407
|
+
}
|
|
408
|
+
if (SCREEN_GONE.test(cause) && !reopened && this.#lastUrl && this.#route !== 'apps') {
|
|
409
|
+
reopened = true;
|
|
410
|
+
this.#stop('screen-gone', ctx);
|
|
411
|
+
try {
|
|
412
|
+
await this.driver.perform({ action: 'navigate', url: this.#lastUrl });
|
|
413
|
+
}
|
|
414
|
+
catch { /* the next read says */ }
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
if (!counted) {
|
|
418
|
+
counted = true;
|
|
419
|
+
this.#stop('page-not-answered', ctx);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
280
422
|
}
|
|
281
|
-
|
|
282
|
-
this.#state = paused ? 'paused' : 'running';
|
|
283
|
-
return paused;
|
|
423
|
+
return false;
|
|
284
424
|
}
|
|
285
425
|
/**
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
426
|
+
* Refused before anything was dispatched: a stale observation, a ref that
|
|
427
|
+
* no longer matches, a page that moved. The tool looks again and answers
|
|
428
|
+
* with the fresh page; nothing pauses. Eight in a row asks the owner
|
|
429
|
+
* whether to keep going. The owner looking at the tab and the app behind
|
|
430
|
+
* their window are said as what they are.
|
|
290
431
|
*/
|
|
291
|
-
#
|
|
292
|
-
|
|
293
|
-
if (this.#session)
|
|
294
|
-
this.#spent.add(this.#session.requestId);
|
|
295
|
-
this.#preconditionFailures = 0;
|
|
296
|
-
this.#session = { id: this.#session?.id ?? randomUUID(), ownerId, agentId,
|
|
297
|
-
conversationId, requestId: request.id, task: request.text.slice(0, 4000),
|
|
298
|
-
expiresAt: new Date(expiresAt).toISOString(), steps: 0, maxSteps: this.options.maxSteps ?? 80 };
|
|
299
|
-
clearTimeout(this.#expiry);
|
|
300
|
-
this.#expiry = setTimeout(() => { void this.#release('expired'); }, Math.max(1, expiresAt - this.#now()));
|
|
301
|
-
this.#expiry.unref?.();
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* The precondition path every refused action takes, `browser.act`'s and the
|
|
305
|
-
* secret tools' alike: count the failure, pause on the third, and recover
|
|
306
|
-
* fresh evidence so the next call acts on what the page now shows rather
|
|
307
|
-
* than on the stale arguments. Nothing was dispatched for any of these.
|
|
308
|
-
*/
|
|
309
|
-
async #precondition(controller, error) {
|
|
432
|
+
async #precondition(controller, error, ctx) {
|
|
433
|
+
this.#state = 'running';
|
|
310
434
|
if (OWNER_WATCHING.test(error.message)) {
|
|
311
|
-
|
|
312
|
-
// moving to another tab does. No pause and no count; the next action
|
|
313
|
-
// must observe first, so the model asks once instead of retrying.
|
|
435
|
+
this.#stop('owner-watching', ctx);
|
|
314
436
|
this.#message = OWNER_WATCHING_MESSAGE;
|
|
315
|
-
|
|
316
|
-
this.#needsObservation = true;
|
|
317
|
-
throw new BrowserPreconditionError(JSON.stringify({ error: OWNER_WATCHING_MESSAGE, dispatched: false,
|
|
318
|
-
recovery: 'Ask the owner now and wait for their answer. Do not retry by yourself.' }));
|
|
437
|
+
throw new BrowserPreconditionError(JSON.stringify({ error: OWNER_WATCHING_MESSAGE, dispatched: false }));
|
|
319
438
|
}
|
|
320
439
|
if (APP_BEHIND.test(error.message)) {
|
|
321
|
-
// The owner's own window came forward (typing in the dashboard does it).
|
|
322
|
-
// Not a targeting failure and nothing for the owner to do: the agent
|
|
323
|
-
// calls open for the same app. No count, no pause, and no recovery
|
|
324
|
-
// observation, which would only be refused the same way.
|
|
325
440
|
this.#message = error.message;
|
|
326
|
-
this.#state = 'running';
|
|
327
441
|
this.#observation = undefined;
|
|
328
442
|
this.#picture = undefined;
|
|
329
|
-
this.#needsObservation = true;
|
|
330
443
|
throw new BrowserPreconditionError(JSON.stringify({ error: error.message, dispatched: false,
|
|
331
|
-
recovery: 'Call browser.act open with the same app now; it needs no approval.
|
|
444
|
+
recovery: 'Call browser.act open with the same app now; it needs no approval. It returns the app as it is.' }));
|
|
332
445
|
}
|
|
446
|
+
const cause = /stale|latest observation/i.test(error.message) ? 'stale-observation'
|
|
447
|
+
: /changed since|moved|redirect|different page/i.test(error.message) ? 'redirect' : 'stale-ref';
|
|
448
|
+
this.#stop(cause, ctx);
|
|
333
449
|
this.#message = error.message;
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
this.#
|
|
337
|
-
// Recover evidence, never replay input. Keep this a failed tool result
|
|
338
|
-
// so the runtime skips any remaining sequential calls in this batch.
|
|
339
|
-
try {
|
|
340
|
-
const observation = await this.driver.observe();
|
|
341
|
-
const picture = await this.driver.screenshot();
|
|
342
|
-
controller.signal.throwIfAborted();
|
|
343
|
-
this.#observation = this.#stamp(observation);
|
|
344
|
-
this.#picture = picture;
|
|
345
|
-
this.#observationFailures = 0;
|
|
346
|
-
}
|
|
347
|
-
catch (observationError) {
|
|
348
|
-
controller.signal.throwIfAborted();
|
|
349
|
-
const cause = observationError instanceof Error ? observationError.message : String(observationError);
|
|
350
|
-
const targeting = this.#state === 'paused';
|
|
351
|
-
const paused = this.#observationFailed(cause) || targeting;
|
|
352
|
-
if (paused)
|
|
353
|
-
this.#state = 'paused';
|
|
354
|
-
this.#message += ` Recovery observation failed: ${cause.replace(/\.$/, '')}.${paused ? ' Inspect the selected app/window and this error, then resume and observe. Do not retry while paused.' : APP_BEHIND.test(cause) ? '' : ` ${browserWaitMessage()}`}`;
|
|
450
|
+
if (++this.#targetingFailures >= MAX_TARGETING_FAILURES) {
|
|
451
|
+
this.#stop('targeting-cap', ctx, 'card');
|
|
452
|
+
return this.#cardResult(this.park('budget'), false);
|
|
355
453
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
454
|
+
const seen = await this.#look(controller, ctx).catch(() => false);
|
|
455
|
+
throw new BrowserPreconditionError(JSON.stringify({ error: error.message, dispatched: false,
|
|
456
|
+
...(seen && this.#observation?.observedAt ? { message: `${observedLine(this.#observation.observedAt)} The page changed; here it is now.` } : {}),
|
|
457
|
+
recovery: seen ? 'Nothing was done. Re-evaluate from the page below and act on it; prefer target:{ref:"..."} from it.' : browserWaitMessage(),
|
|
458
|
+
...(seen ? { observation: this.#observation } : {}) }));
|
|
360
459
|
}
|
|
361
460
|
/**
|
|
362
|
-
* The authority shell the secret tools run under:
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
* budget — and its start sequence and precondition path. A secret fill is a
|
|
366
|
-
* browser action like any other; only the value's route differs.
|
|
461
|
+
* The authority shell the secret tools run under: the same page, budget and
|
|
462
|
+
* card rules as `execute`. A secret fill is a browser action like any other;
|
|
463
|
+
* only the value's route differs.
|
|
367
464
|
*/
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const request = ctx.ownerRequest;
|
|
371
|
-
if (!request || !request.id || !request.text.trim() || request.expiresAt <= this.#now() ||
|
|
372
|
-
!ctx.agentId || !ctx.conversationId || (ctx.delegationDepth ?? 0) > 0) {
|
|
373
|
-
throw new Error('A current authenticated owner request is required.');
|
|
374
|
-
}
|
|
375
|
-
if (!this.#enabled)
|
|
376
|
-
throw new Error('Browser driving is available through buddi serve (dashboard or Telegram), not a separate CLI process.');
|
|
377
|
-
if (this.#state === 'stopped')
|
|
378
|
-
throw new Error(browserStoppedMessage(ctx.surface));
|
|
379
|
-
if (this.#busy)
|
|
380
|
-
throw new Error('Browser is busy; overlapping actions are refused.');
|
|
381
|
-
if (this.#session && (this.#session.ownerId !== ctx.buddi.owner.id || this.#session.agentId !== ctx.agentId || this.#session.conversationId !== ctx.conversationId)) {
|
|
382
|
-
throw new Error('Another agent/conversation owns the browser. Ask the owner to release it from the dashboard.');
|
|
383
|
-
}
|
|
384
|
-
if (this.#spent.has(request.id))
|
|
385
|
-
throw new Error('This browser request has ended. A new owner message is required.');
|
|
386
|
-
if (this.#state === 'paused')
|
|
387
|
-
throw new Error('Browser is under human control or needs inspection. Wait for the owner to resume in the dashboard, then observe.');
|
|
388
|
-
if (this.#needsObservation)
|
|
389
|
-
throw new Error('A fresh observation is required: observe the current page before acting. Do not replay an earlier action.');
|
|
390
|
-
if (!this.#session)
|
|
391
|
-
throw new Error('Start with navigate, or open an allowed application, and observe before using a secret here.');
|
|
392
|
-
if (this.#session.requestId !== request.id)
|
|
393
|
-
this.#rekey(request, ctx.agentId, ctx.conversationId, ctx.buddi.owner.id);
|
|
394
|
-
const active = this.#session;
|
|
395
|
-
if (!active || Date.parse(active.expiresAt) <= this.#now() || active.steps >= active.maxSteps) {
|
|
396
|
-
await this.#release('expired');
|
|
397
|
-
throw new Error('Browser task reached its time or step limit. Ask the owner for a new request.');
|
|
398
|
-
}
|
|
399
|
-
++active.steps;
|
|
400
|
-
this.#busy = true;
|
|
401
|
-
this.#lastAction = action;
|
|
402
|
-
this.#message = undefined;
|
|
403
|
-
const controller = new AbortController();
|
|
404
|
-
this.#controller = controller;
|
|
405
|
-
const cancel = () => {
|
|
406
|
-
controller.abort(ctx.signal?.reason ?? new Error('Browser action stopped.'));
|
|
407
|
-
this.#spent.add(request.id);
|
|
408
|
-
void this.#release('stopped');
|
|
409
|
-
void this.#persistStop(true).catch(() => { });
|
|
410
|
-
};
|
|
411
|
-
ctx.signal?.addEventListener('abort', cancel, { once: true });
|
|
412
|
-
try {
|
|
413
|
-
this.#state = 'starting';
|
|
414
|
-
await this.driver.start();
|
|
415
|
-
controller.signal.throwIfAborted();
|
|
465
|
+
#under(ctx, action, run) {
|
|
466
|
+
return this.#serial(async () => {
|
|
416
467
|
ctx.signal?.throwIfAborted();
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
if (
|
|
422
|
-
|
|
468
|
+
if (!ctx.agentId || !ctx.conversationId)
|
|
469
|
+
throw new Error('A browser action belongs to an agent and a conversation.');
|
|
470
|
+
if (!this.#enabled)
|
|
471
|
+
throw new Error('Browser driving is available through buddi serve (dashboard or Telegram), not a separate CLI process.');
|
|
472
|
+
if (this.#state === 'stopped')
|
|
473
|
+
throw new Error(browserStoppedMessage(ctx.surface));
|
|
474
|
+
if (this.#session && (this.#session.ownerId !== ctx.buddi.owner.id || this.#session.agentId !== ctx.agentId || this.#session.conversationId !== ctx.conversationId)) {
|
|
475
|
+
throw new Error('Another conversation owns this page.');
|
|
423
476
|
}
|
|
424
|
-
if (
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
477
|
+
if (this.#state === 'paused')
|
|
478
|
+
throw new Error('The owner has this page in their hands. Wait for them to give it back.');
|
|
479
|
+
if (!this.#session)
|
|
480
|
+
throw new Error('Open the page with browser.act navigate before using a secret here.');
|
|
481
|
+
this.#open(ctx.ownerRequest, ctx);
|
|
482
|
+
if (this.#card)
|
|
483
|
+
return this.#cardResult(this.#card, false);
|
|
484
|
+
const active = this.#session;
|
|
485
|
+
if (active.steps >= active.maxSteps || Date.parse(active.expiresAt) <= this.#now()) {
|
|
486
|
+
this.#stop('budget', ctx);
|
|
487
|
+
return this.#cardResult(this.park('budget'), false);
|
|
430
488
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
489
|
+
++active.steps;
|
|
490
|
+
++active.actions;
|
|
491
|
+
this.#busy = true;
|
|
492
|
+
this.#lastAction = action;
|
|
493
|
+
this.#lastActivity = this.#now();
|
|
494
|
+
this.#message = undefined;
|
|
495
|
+
const controller = new AbortController();
|
|
496
|
+
this.#controller = controller;
|
|
497
|
+
const cancel = () => { controller.abort(ctx.signal?.reason ?? new Error('Browser action stopped.')); void this.#release('idle'); };
|
|
498
|
+
ctx.signal?.addEventListener('abort', cancel, { once: true });
|
|
499
|
+
try {
|
|
500
|
+
this.#state = 'starting';
|
|
501
|
+
await this.driver.start();
|
|
502
|
+
controller.signal.throwIfAborted();
|
|
503
|
+
this.#state = 'running';
|
|
504
|
+
return await run(controller);
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
507
|
+
if (controller.signal.aborted)
|
|
508
|
+
throw error;
|
|
509
|
+
if (error instanceof BrowserPreconditionError)
|
|
510
|
+
return await this.#precondition(controller, error, ctx);
|
|
511
|
+
// The value may be part-way into the field: the owner looks.
|
|
512
|
+
this.#state = 'running';
|
|
513
|
+
this.#stop('uncertain-input', ctx, 'card');
|
|
514
|
+
return this.#cardResult(this.park('uncertain'), true, `${error instanceof Error ? error.message.replace(/\.$/, '') : String(error)}. I'm not sure that went through.`);
|
|
515
|
+
}
|
|
516
|
+
finally {
|
|
517
|
+
ctx.signal?.removeEventListener('abort', cancel);
|
|
518
|
+
if (this.#controller === controller)
|
|
519
|
+
this.#controller = undefined;
|
|
520
|
+
this.#busy = false;
|
|
521
|
+
this.#settled();
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
/** After a fill or typing the page changed: answer with it, as every action does. */
|
|
526
|
+
async #after(controller, ctx, result) {
|
|
527
|
+
const seen = await this.#look(controller, ctx).catch(() => false);
|
|
528
|
+
return seen ? { ...result, observation: this.#observation, message: observedLine(this.#observation.observedAt) } : result;
|
|
439
529
|
}
|
|
440
530
|
/**
|
|
441
531
|
* One owner secret into one field of the page this conversation drives
|
|
442
|
-
* (docs/owner-secrets.md §3, §4).
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
* origin, its password mark and its accessible name from the live page — the
|
|
446
|
-
* backend reports, the agent never claims (§8) — then core finds the binding,
|
|
447
|
-
* the destination checks that target against it, the rule is applied and the
|
|
448
|
-
* vault read, and the destination's `deliver` parks the value against the use
|
|
449
|
-
* id. Only then does the driver fill, re-checking the origin once more
|
|
450
|
-
* against what the use was delivered for. The result is `{ filled: true }`
|
|
451
|
-
* or a pending card; a refusal is the refusal's own sentence, and a value
|
|
452
|
-
* appears in none of them.
|
|
532
|
+
* (docs/owner-secrets.md §3, §4). The driver reads the field's frame origin,
|
|
533
|
+
* its password mark and its name from the live page; core finds the binding
|
|
534
|
+
* and the destination checks it; the value crosses only into the fill.
|
|
453
535
|
*/
|
|
454
536
|
async secretFill(input, ctx) {
|
|
455
|
-
return this.#under(ctx, 'secret.fill', async () => {
|
|
537
|
+
return this.#under(ctx, 'secret.fill', async (controller) => {
|
|
456
538
|
if (typeof this.driver.secretFieldInfo !== 'function' || typeof this.driver.secretFillField !== 'function') {
|
|
457
|
-
throw new BrowserPreconditionError('secret.fill works
|
|
539
|
+
throw new BrowserPreconditionError('secret.fill works on web pages (buddi\'s own browser or your Chrome); an app window has no page fields to fill.');
|
|
458
540
|
}
|
|
459
|
-
const
|
|
541
|
+
const observation = input.observation ?? this.#observation?.id ?? '';
|
|
542
|
+
const facts = await this.driver.secretFieldInfo(observation, input.ref);
|
|
460
543
|
const secrets = ctx.buddi?.secrets;
|
|
461
544
|
if (secrets === undefined)
|
|
462
545
|
throw new Error('This plugin has no secrets area; the owner updates the browser plugin to one that declares it.');
|
|
@@ -464,12 +547,10 @@ export class BrowserService {
|
|
|
464
547
|
if (secret === undefined) {
|
|
465
548
|
throw new BrowserPreconditionError(`There is no secret named "${input.name}" bound to this browser's destinations. The owner keeps one in Settings, under Keys and secrets.`);
|
|
466
549
|
}
|
|
467
|
-
// A visible field on an origin the owner bound as browser.field takes
|
|
468
|
-
// that binding; the card then names the field (§3).
|
|
469
550
|
const visibleField = !secret.totp && !facts.password && fieldBoundTo(secret.bindings, facts.origin);
|
|
470
551
|
const kind = secretKindFor(secret.totp, facts.password, visibleField);
|
|
471
552
|
if (kind === FORM_KIND && facts.name.trim() === '') {
|
|
472
|
-
throw new BrowserPreconditionError('That field has no name the page gives it, so it cannot be a form-field destination.
|
|
553
|
+
throw new BrowserPreconditionError('That field has no name the page gives it, so it cannot be a form-field destination. Pick another ref, or ask the owner to bind the secret to the page instead.');
|
|
473
554
|
}
|
|
474
555
|
const named = { origin: facts.origin, field: facts.name };
|
|
475
556
|
const target = kind === FORM_KIND || (visibleField && facts.name.trim() !== '') ? named : facts.origin;
|
|
@@ -482,26 +563,15 @@ export class BrowserService {
|
|
|
482
563
|
const value = takeDelivered(outcome.use);
|
|
483
564
|
if (value === undefined)
|
|
484
565
|
throw new Error('The use delivered nothing to fill with. Ask for the secret again.');
|
|
485
|
-
await this.driver.secretFillField(
|
|
486
|
-
this.#
|
|
487
|
-
return { filled: true };
|
|
566
|
+
await this.driver.secretFillField(observation, input.ref, value, facts.origin);
|
|
567
|
+
return this.#after(controller, ctx, { filled: true });
|
|
488
568
|
});
|
|
489
569
|
}
|
|
490
|
-
/**
|
|
491
|
-
* One owner secret typed into the focused field of the focused app
|
|
492
|
-
* (owner-secrets.md §3, native typing).
|
|
493
|
-
*
|
|
494
|
-
* The bundle id is the backend's answer about whatever app is in front right
|
|
495
|
-
* now, and the helper re-checks it before the first keystroke, so an app
|
|
496
|
-
* switch between the owner's approval and the typing refuses with nothing
|
|
497
|
-
* typed. There is no observed target here — the field is whatever the owner
|
|
498
|
-
* left focused — which is why the destination's loosest rule is a card every
|
|
499
|
-
* time.
|
|
500
|
-
*/
|
|
570
|
+
/** One owner secret typed into the focused field of the focused app (owner-secrets.md §3, native typing). */
|
|
501
571
|
async secretType(input, ctx) {
|
|
502
|
-
return this.#under(ctx, 'secret.type', async () => {
|
|
572
|
+
return this.#under(ctx, 'secret.type', async (controller) => {
|
|
503
573
|
if (typeof this.driver.focusedBundleId !== 'function' || typeof this.driver.nativeType !== 'function') {
|
|
504
|
-
throw new BrowserPreconditionError('secret.type
|
|
574
|
+
throw new BrowserPreconditionError('secret.type types into an app on this machine; a web page takes secret.fill instead.');
|
|
505
575
|
}
|
|
506
576
|
const bundleId = await this.driver.focusedBundleId();
|
|
507
577
|
if (!bundleId)
|
|
@@ -519,32 +589,36 @@ export class BrowserService {
|
|
|
519
589
|
if (value === undefined)
|
|
520
590
|
throw new Error('The use delivered nothing to type. Ask for the secret again.');
|
|
521
591
|
await this.driver.nativeType(value);
|
|
522
|
-
this.#
|
|
523
|
-
return { typed: true };
|
|
592
|
+
return this.#after(controller, ctx, { typed: true });
|
|
524
593
|
});
|
|
525
594
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
};
|
|
536
|
-
const next = this.#diskTail.then(write, write);
|
|
537
|
-
this.#diskTail = next.catch(() => { });
|
|
538
|
-
await next;
|
|
595
|
+
#markHeldEnd() {
|
|
596
|
+
const id = this.#session?.id;
|
|
597
|
+
if (id)
|
|
598
|
+
this.#lastHeld = { id, until: this.#now() + LOGIN_GRACE_MS };
|
|
599
|
+
}
|
|
600
|
+
/** The action in flight went (its `finally` ran): whoever waited on it hears. */
|
|
601
|
+
#settled() {
|
|
602
|
+
for (const resolve of this.#settleWaiters.splice(0))
|
|
603
|
+
resolve();
|
|
539
604
|
}
|
|
540
605
|
/**
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
* `interrupt` — or one whose page really did go — has its screen closed
|
|
545
|
-
* instead, which is the old behaviour and still the honest answer when there
|
|
546
|
-
* is nothing left to paint.
|
|
606
|
+
* The interrupted action, stopped and gone: abort it again, interrupt the
|
|
607
|
+
* driver, and wait for its `finally` — at most a few seconds, because a give
|
|
608
|
+
* back must not hang on an action that will not finish.
|
|
547
609
|
*/
|
|
610
|
+
async #settle(limitMs = 10_000) {
|
|
611
|
+
this.#controller?.abort(new Error('Owner took control during an action. Inspect the site before retrying.'));
|
|
612
|
+
const gone = new Promise((resolve) => { this.#settleWaiters.push(resolve); });
|
|
613
|
+
if (this.driver.interrupt)
|
|
614
|
+
await this.#interrupt().catch(() => false);
|
|
615
|
+
if (!this.#busy)
|
|
616
|
+
return;
|
|
617
|
+
let timer;
|
|
618
|
+
await Promise.race([gone, new Promise((resolve) => { timer = setTimeout(resolve, limitMs); timer.unref?.(); })]);
|
|
619
|
+
clearTimeout(timer);
|
|
620
|
+
}
|
|
621
|
+
/** Stop the action, keep the screen if the driver can. True when there is still something to drive. */
|
|
548
622
|
async #interrupt() {
|
|
549
623
|
if (!this.driver.interrupt) {
|
|
550
624
|
await this.driver.close().catch(() => { });
|
|
@@ -560,11 +634,20 @@ export class BrowserService {
|
|
|
560
634
|
return this.driver.handReady?.() !== false;
|
|
561
635
|
}
|
|
562
636
|
async #release(state) {
|
|
563
|
-
|
|
637
|
+
const session = this.#session;
|
|
638
|
+
if (session && this.options.telemetry) {
|
|
639
|
+
this.options.telemetry.record({ type: 'browser.task', outcome: this.#card ? (this.#card.kind === 'budget' ? 'budget' : 'needs-owner') : state === 'stopped' ? 'stopped' : 'done',
|
|
640
|
+
actions: session.actions, seconds: Math.round((this.#now() - session.startedAt) / 1000), cards: session.cards, agent: session.agentId, route: this.#route, ...(session.requestId === 'unattended' ? { mission: true } : {}) });
|
|
641
|
+
}
|
|
642
|
+
if (this.#observation?.url)
|
|
643
|
+
this.#lastUrl = this.#observation.url;
|
|
564
644
|
this.#handless = false;
|
|
645
|
+
if (this.#held) {
|
|
646
|
+
this.#markHeldEnd();
|
|
647
|
+
this.#held = false;
|
|
648
|
+
this.driver.resume?.();
|
|
649
|
+
}
|
|
565
650
|
this.#state = state;
|
|
566
|
-
if (this.#session)
|
|
567
|
-
this.#spent.add(this.#session.requestId);
|
|
568
651
|
this.#controller?.abort(new Error(`Browser ${state}. An in-flight submission may have completed; inspect before retrying.`));
|
|
569
652
|
clearTimeout(this.#expiry);
|
|
570
653
|
this.#session = undefined;
|
|
@@ -572,69 +655,89 @@ export class BrowserService {
|
|
|
572
655
|
this.#picture = undefined;
|
|
573
656
|
this.#lastAction = undefined;
|
|
574
657
|
this.#message = undefined;
|
|
575
|
-
this.#
|
|
576
|
-
this.#
|
|
658
|
+
this.#card = undefined;
|
|
659
|
+
this.#targetingFailures = 0;
|
|
577
660
|
await this.driver.close();
|
|
578
661
|
}
|
|
662
|
+
/**
|
|
663
|
+
* Take over a page in the owner's own Chrome: no stream, the tab itself.
|
|
664
|
+
* An action in flight is abandoned first (the tab is kept), then the tab is
|
|
665
|
+
* brought to the front of their Chrome with its bar saying buddi waits.
|
|
666
|
+
* When Chrome cannot do that (closed, an extension too old to know how),
|
|
667
|
+
* the page stays paused and the message says where it is instead.
|
|
668
|
+
*/
|
|
669
|
+
async #holdInPlace() {
|
|
670
|
+
this.#held = false;
|
|
671
|
+
if (this.#busy) {
|
|
672
|
+
this.#controller?.abort(new Error('Owner took control during an action. Inspect the site before retrying.'));
|
|
673
|
+
this.#picture = undefined;
|
|
674
|
+
this.#observation = undefined;
|
|
675
|
+
await this.#interrupt();
|
|
676
|
+
}
|
|
677
|
+
try {
|
|
678
|
+
await this.driver.takeover?.();
|
|
679
|
+
this.#held = true;
|
|
680
|
+
this.#message = 'The page is in front of you in your Chrome. Give it back when you are done.';
|
|
681
|
+
}
|
|
682
|
+
catch (error) {
|
|
683
|
+
const why = error instanceof Error ? error.message.replace(/\.$/, '') : String(error);
|
|
684
|
+
this.#message = `Your Chrome couldn't bring the page forward (${why}). It is in the buddi tab group there; give it back when you are done.`;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
579
687
|
/** Only authenticated owner UI handlers call this; it is not an agent tool. */
|
|
580
688
|
control(action, expectedSessionId) {
|
|
581
689
|
const run = async () => {
|
|
582
690
|
if (!this.#enabled)
|
|
583
691
|
throw new Error('The host browser service is unavailable.');
|
|
584
692
|
if (expectedSessionId !== undefined && this.#session?.id !== expectedSessionId) {
|
|
585
|
-
throw new Error('The
|
|
693
|
+
throw new Error('The page changed. Refresh before controlling it.');
|
|
586
694
|
}
|
|
587
695
|
if (action === 'stop') {
|
|
588
|
-
|
|
589
|
-
const closing = this.#release('stopped');
|
|
590
|
-
await this.#persistStop(true);
|
|
591
|
-
await closing;
|
|
696
|
+
await this.#release('stopped');
|
|
592
697
|
}
|
|
593
698
|
else if (action === 'takeover') {
|
|
594
699
|
this.#state = 'paused';
|
|
595
700
|
this.#message = undefined;
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
//
|
|
602
|
-
//
|
|
603
|
-
// what stops the interrupted command from overwriting `paused`.
|
|
701
|
+
this.#card = undefined;
|
|
702
|
+
if (this.driver.holdsInPlace) {
|
|
703
|
+
await this.#holdInPlace();
|
|
704
|
+
}
|
|
705
|
+
else if (this.#busy) {
|
|
706
|
+
// Take over is pressed most often *while* the agent works on a login:
|
|
707
|
+
// the action is abandoned and the page kept, when the driver can.
|
|
604
708
|
this.#controller?.abort(new Error('Owner took control during an action. Inspect the site before retrying.'));
|
|
605
709
|
this.#picture = undefined;
|
|
606
710
|
this.#observation = undefined;
|
|
607
|
-
this.#needsObservation = !!this.#session;
|
|
608
711
|
const kept = await this.#interrupt();
|
|
609
712
|
this.#handless = !kept;
|
|
610
713
|
this.#message = kept
|
|
611
|
-
? 'The in
|
|
612
|
-
: this.driver.preservesWindows ? 'Computer input was interrupted. Your apps remain open.
|
|
714
|
+
? 'The action in flight was stopped; the page is yours. Give it back when you are done.'
|
|
715
|
+
: this.driver.preservesWindows ? 'Computer input was interrupted. Your apps remain open. Give it back when you are done.' : 'The action in flight was stopped and the window closed. Give it back and the agent opens the page again.';
|
|
613
716
|
}
|
|
614
717
|
else {
|
|
615
718
|
await this.driver.takeover?.();
|
|
616
|
-
this.#message = this.driver.preservesWindows ? '
|
|
719
|
+
this.#message = this.driver.preservesWindows ? 'The app is yours. Give it back when you are done.' : 'The page is yours. Give it back when you are done.';
|
|
617
720
|
}
|
|
618
721
|
}
|
|
619
722
|
else if (action === 'resume') {
|
|
723
|
+
// Given back while the interrupted action is still stopping: stop it for good and wait for it, then give back. Never a refusal:
|
|
724
|
+
// the owner's Chrome has already taken its bar down.
|
|
620
725
|
if (this.#busy)
|
|
621
|
-
|
|
622
|
-
|
|
726
|
+
await this.#settle();
|
|
727
|
+
if (this.#held)
|
|
728
|
+
this.#markHeldEnd();
|
|
623
729
|
this.driver.resume?.();
|
|
624
730
|
this.#handless = false;
|
|
625
|
-
this.#
|
|
626
|
-
this.#observationFailures = 0;
|
|
731
|
+
this.#held = false;
|
|
627
732
|
this.#observation = undefined;
|
|
628
733
|
this.#picture = undefined;
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
await this.#release('idle');
|
|
734
|
+
// The owner acted: a fresh budget, and the agent's next action returns the page as the owner left it.
|
|
735
|
+
this.renew();
|
|
632
736
|
this.#state = this.#session ? 'running' : 'idle';
|
|
633
|
-
this.#message = '
|
|
737
|
+
this.#message = 'Given back. The agent carries on from the page as you left it.';
|
|
634
738
|
}
|
|
635
739
|
else {
|
|
636
|
-
|
|
637
|
-
await this.#release(stopped ? 'stopped' : 'idle');
|
|
740
|
+
await this.#release(this.#state === 'stopped' ? 'stopped' : 'idle');
|
|
638
741
|
}
|
|
639
742
|
return this.status();
|
|
640
743
|
};
|