@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,3 +1,4 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'node:fs';
|
|
1
2
|
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { randomUUID } from 'node:crypto';
|
|
@@ -5,88 +6,241 @@ import { ToolRefusal } from '@buddi/core/plugin';
|
|
|
5
6
|
import { BrowserManager } from './manager.js';
|
|
6
7
|
import { PlaywrightHost } from './host.js';
|
|
7
8
|
import { PlaywrightDriver } from './driver.js';
|
|
8
|
-
import { COMPUTER_HELPER_MISSING, ComputerDriver, computerHelperPresent, NativeComputerBridge, resolveApp, settingsSchema, spotlightApps } from './computer.js';
|
|
9
9
|
import { ExtensionDriver, NOT_CONNECTED } from './extension.js';
|
|
10
|
+
import { browserStoppedMessage } from './service.js';
|
|
10
11
|
import { BrowserPreconditionError } from './types.js';
|
|
11
12
|
import { detectBrowser, HEADLESS_NOTE, installBrowser, InstallProgressReader, missingLibrariesMessage, needsHeadless, noSandboxMessage, NO_BROWSER_STATUS, probeLaunch } from './availability.js';
|
|
13
|
+
import { applySettingsChange, migrateSettings, PIN_VALUES, settingsSchema } from './settings.js';
|
|
14
|
+
import { agoText, cardAnswer, ownerClock, chooseRoute, detectSignedOut, detectWall, ownerCard, RouteProviderDriver, routeNote, siteListed, siteOf } from './routes.js';
|
|
15
|
+
import { BrowserTelemetry, missionMark, readTelemetry, summarize } from './telemetry.js';
|
|
16
|
+
import { canonicalOrigin, fieldBoundTo } from './secrets.js';
|
|
17
|
+
import { LoginKeeper } from './logins.js';
|
|
18
|
+
import { LOGIN_GONE, LOGIN_NOT_KEPT } from './types.js';
|
|
12
19
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
13
20
|
/** The one control an app card carries: how long the yes lasts. */
|
|
14
21
|
const REMEMBER = { key: 'remember', label: 'Allow', options: ['Once', 'Always'], default: 'Once' };
|
|
15
22
|
function isAppEnvelope(value) {
|
|
16
23
|
return typeof value === 'object' && value !== null && typeof value.allowApp === 'string';
|
|
17
24
|
}
|
|
18
|
-
/**
|
|
25
|
+
/** What the agent is told when an app job has no route: the one fix, never a mode. */
|
|
26
|
+
/** What a mission is told when it asks for the owner's Chrome (docs/browser.md, "Missions"). */
|
|
27
|
+
export const UNATTENDED_CHROME = "A mission looks only in buddi's own browser, never the owner's Chrome: nobody is there to watch it. Use the own browser, or report what needs the owner's sign-in.";
|
|
28
|
+
/** What a mission is told when it asks for an app. */
|
|
29
|
+
export const UNATTENDED_APPS = "A mission looks only in buddi's own browser; the owner's apps need the owner. Report what you could not do instead.";
|
|
30
|
+
export const APPS_UNAVAILABLE = 'Your apps are not available to agents right now. The owner can turn them on, or repair them, in Settings → Where agents may look.';
|
|
31
|
+
/** What the agent is told when no plugin provides the apps route. */
|
|
32
|
+
export const APPS_NOT_INSTALLED = 'Agents cannot work in apps here: that needs the Computer plugin (macOS), which the owner installs from Settings → Plugins.';
|
|
33
|
+
const asApp = (target) => ({ bundleId: target.id, name: target.name });
|
|
34
|
+
const ROUTES = ['own', 'chrome', 'apps'];
|
|
35
|
+
/**
|
|
36
|
+
* Where agents may look, and the runtime that picks for them
|
|
37
|
+
* (docs/browser.md).
|
|
38
|
+
*
|
|
39
|
+
* Three routes, one manager each: buddi's own browser (headless, shown in the
|
|
40
|
+
* Canvas), the owner's Chrome (background tabs through the extension) and the
|
|
41
|
+
* owner's apps (a route a plugin provides: the Computer plugin). The
|
|
42
|
+
* settings are permissions; per task the runtime chooses, falls back
|
|
43
|
+
* silently when a route cannot serve, and says one line when the route was
|
|
44
|
+
* not its own browser. The owner is asked on four occasions only, by card.
|
|
45
|
+
*/
|
|
19
46
|
export class HostController {
|
|
20
47
|
dir;
|
|
21
48
|
options;
|
|
22
|
-
#manager;
|
|
23
49
|
#settings = settingsSchema.parse({});
|
|
24
|
-
#permissions;
|
|
25
50
|
#enabled = false;
|
|
26
|
-
#changing = false;
|
|
27
|
-
#requests = new Map();
|
|
28
51
|
#extension;
|
|
52
|
+
#providers;
|
|
29
53
|
#problem;
|
|
30
54
|
#install;
|
|
31
|
-
/** Apps the owner allowed Once, by conversation. Memory only: the ledger answers again after a restart. */
|
|
32
55
|
#once = new Map();
|
|
33
|
-
/** The conversation
|
|
34
|
-
#
|
|
56
|
+
/** The apps each conversation was let into (listed or allowed by card), for the Telegram picture check. */
|
|
57
|
+
#opened = new Map();
|
|
58
|
+
#names = new Map();
|
|
59
|
+
#managers;
|
|
60
|
+
#ownOptions;
|
|
61
|
+
#host;
|
|
62
|
+
#stop;
|
|
63
|
+
#pins = new Map();
|
|
64
|
+
#learned = new Set();
|
|
65
|
+
/** The route each conversation's page is on: `[owner, agent, conversation]`. */
|
|
66
|
+
#current = new Map();
|
|
67
|
+
/** Notes already said, so the chat line comes once per site and route. */
|
|
68
|
+
#noted = new Set();
|
|
69
|
+
/** The last thing the owner's Chrome failed with, by conversation key, so the same failure is not retried a third time. */
|
|
70
|
+
#chromeFailed = new Map();
|
|
71
|
+
/** Stop cards shown, by conversation, so a Resume tap is understood. */
|
|
72
|
+
#stopCards = new Map();
|
|
73
|
+
/** Cards already handed to a surface, so one moment is one card. */
|
|
74
|
+
#asked = new WeakSet();
|
|
75
|
+
/** Who hears that the owner gave a page back (the gateway continues the run that waited on it). */
|
|
76
|
+
#giveBack = new Set();
|
|
77
|
+
telemetry;
|
|
78
|
+
/** Sign-ins the owner made on a page they held: asked about, kept or refused here, never by a model. */
|
|
79
|
+
logins;
|
|
35
80
|
constructor(dir, options = {}) {
|
|
36
81
|
this.dir = dir;
|
|
37
82
|
this.options = options;
|
|
38
83
|
this.#extension = options.extensionBridge;
|
|
39
|
-
this
|
|
84
|
+
this.logins = new LoginKeeper(path.join(dir, 'logins.json'), options.service?.now ? { now: options.service.now } : {});
|
|
85
|
+
this.telemetry = new BrowserTelemetry(path.join(dir, 'telemetry.jsonl'), options.service?.now);
|
|
86
|
+
const self = this;
|
|
87
|
+
const hostOptions = {
|
|
88
|
+
profileDir: path.join(this.dir, 'profile'), channel: this.options.channel, allowedHosts: this.options.allowedHosts,
|
|
89
|
+
...(this.options.lookup ? { lookup: this.options.lookup } : {}),
|
|
90
|
+
detect: () => this.#detect(), report: (problem) => { this.#problem = problem; },
|
|
91
|
+
};
|
|
92
|
+
// Read at launch, so Show the window applies to the next launch without a restart.
|
|
93
|
+
Object.defineProperty(hostOptions, 'headless', { enumerable: true, get: () => self.#headless });
|
|
94
|
+
this.#host = new PlaywrightHost(hostOptions);
|
|
95
|
+
const base = { ...options.service, telemetry: this.telemetry, requestTakeover: (sessionId) => { void this.control('takeover', sessionId).catch(() => undefined); },
|
|
96
|
+
requestResume: (sessionId) => { void this.control('resume', sessionId).catch(() => undefined); },
|
|
97
|
+
loginSeen: (sessionId, login) => this.#loginSeen(sessionId, login) };
|
|
98
|
+
this.#ownOptions = { ...base, route: 'own', maxSessions: options.limits?.own ?? this.#settings.maxOwnPages, closeHost: () => this.#host.close(),
|
|
99
|
+
...(options.idleEvictMs !== undefined ? { idleEvictMs: options.idleEvictMs } : {}), ...(options.queueTimeoutMs !== undefined ? { queueTimeoutMs: options.queueTimeoutMs } : {}) };
|
|
100
|
+
this.#managers = {
|
|
101
|
+
own: new BrowserManager(() => this.options.drivers?.own?.() ?? new PlaywrightDriver(this.#host.options, this.#host), this.#ownOptions),
|
|
102
|
+
chrome: new BrowserManager(() => this.options.drivers?.chrome?.() ?? new ExtensionDriver(this.#bridge(), this.options.allowedHosts, { logins: () => this.#loginFacts() }), { ...base, route: 'chrome', siteLocks: true, maxSessions: options.limits?.chrome ?? 8,
|
|
103
|
+
...(options.idleEvictMs !== undefined ? { idleEvictMs: options.idleEvictMs } : {}), ...(options.queueTimeoutMs !== undefined ? { queueTimeoutMs: options.queueTimeoutMs } : {}) }),
|
|
104
|
+
apps: new BrowserManager(() => this.#appsDriver(), { ...base, route: 'apps', allowOpen: true, maxSessions: options.limits?.apps ?? 1,
|
|
105
|
+
...(options.idleEvictMs !== undefined ? { idleEvictMs: options.idleEvictMs } : {}), ...(options.queueTimeoutMs !== undefined ? { queueTimeoutMs: options.queueTimeoutMs } : {}) }),
|
|
106
|
+
};
|
|
40
107
|
}
|
|
41
108
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* before the gateway has a server to attach a socket to. Only the composition
|
|
47
|
-
* root calls this, and only before `enable`.
|
|
109
|
+
* A sign-in on a page the owner holds. Answered in the owner's Chrome
|
|
110
|
+
* already (Save or Never in the tab), or asked about in the Page tab. The
|
|
111
|
+
* password stops at the keeper; whatever goes wrong is dropped without a
|
|
112
|
+
* word, because a word here could carry it.
|
|
48
113
|
*/
|
|
114
|
+
#loginSeen(sessionId, login) {
|
|
115
|
+
if (!login.decision) {
|
|
116
|
+
void this.logins.seen(sessionId, login).catch(() => undefined);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// The owner's Chrome asks first whether this sign-in is worth a question: the keeper compares the password's mark, and keeps nothing.
|
|
120
|
+
if (login.decision === 'check')
|
|
121
|
+
return this.logins.check(login).then((ask) => ({ ask }), () => ({ ask: 'save' }));
|
|
122
|
+
// The owner's Chrome waits to hear what became of a Save: kept, or one plain sentence why not (never the store's words).
|
|
123
|
+
return this.logins.decided(login, login.decision).then((answer) => answer.outcome === 'saved' || answer.outcome === 'never' ? { saved: true } : { saved: false, reason: LOGIN_GONE }, () => ({ saved: false, reason: LOGIN_NOT_KEPT }));
|
|
124
|
+
}
|
|
125
|
+
/** What the owner's Chrome needs to know before it asks: the sites never to ask about, and the logins already kept. */
|
|
126
|
+
#loginFacts() {
|
|
127
|
+
return { never: this.logins.never(), saved: this.logins.saved().map(({ site, username }) => ({ site, username })) };
|
|
128
|
+
}
|
|
129
|
+
/** The gateway hands its WebSocket endpoint over once it exists. */
|
|
49
130
|
useExtension(bridge) { this.#extension = bridge; }
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return new BrowserManager(() => new PlaywrightDriver(host.options, host), { controlFile: path.join(this.dir, 'control.json'), closeHost: () => host.close() });
|
|
66
|
-
}
|
|
67
|
-
get #headless() { return needsHeadless(this.options.platform ?? process.platform, this.options.env ?? process.env); }
|
|
131
|
+
/** The routes plugins provide (core's registry), read on every choice. */
|
|
132
|
+
useRouteProviders(providers) { this.#providers = providers; }
|
|
133
|
+
/** The agents' pins from their `agent.md`. */
|
|
134
|
+
useAgentPins(pin) { this.options.agentPin = pin; }
|
|
135
|
+
#bridge() {
|
|
136
|
+
const offline = { connected: () => false, send: () => Promise.reject(new Error(NOT_CONNECTED)), close: () => { } };
|
|
137
|
+
return this.#extension?.() ?? offline;
|
|
138
|
+
}
|
|
139
|
+
get #env() { return this.options.env ?? process.env; }
|
|
140
|
+
/** Headless unless the owner asked to see the window (or BUDDI_BROWSER_HEADED=1); always headless with no display. */
|
|
141
|
+
get #headless() {
|
|
142
|
+
if (needsHeadless(this.options.platform ?? process.platform, this.#env))
|
|
143
|
+
return true;
|
|
144
|
+
return !(this.#settings.showWindow || this.#env.BUDDI_BROWSER_HEADED === '1');
|
|
145
|
+
}
|
|
68
146
|
#detect() { return (this.options.detect ?? detectBrowser)(); }
|
|
69
|
-
/** The agents' own browser, said for the owner and the model alike. */
|
|
70
147
|
#engine() {
|
|
71
148
|
const found = this.#detect();
|
|
72
149
|
const headless = this.#headless;
|
|
73
150
|
const problem = found.engine === 'none' ? undefined : this.#problem;
|
|
151
|
+
const forced = needsHeadless(this.options.platform ?? process.platform, this.#env);
|
|
74
152
|
const message = found.engine === 'none' ? NO_BROWSER_STATUS
|
|
75
153
|
: problem === 'missing-libraries' ? missingLibrariesMessage()
|
|
76
154
|
: problem === 'no-sandbox' ? noSandboxMessage()
|
|
77
|
-
:
|
|
155
|
+
: forced ? HEADLESS_NOTE : undefined;
|
|
78
156
|
return { engine: found.engine, headless, ...(problem ? { problem } : {}), ...(message ? { message } : {}), ...(this.#install ? { install: { ...this.#install } } : {}) };
|
|
79
157
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
158
|
+
/* ---------------- the apps route ---------------- */
|
|
159
|
+
/** The plugin that provides the apps route on this platform, when one is installed. */
|
|
160
|
+
#pluginApps() {
|
|
161
|
+
const platform = this.options.platform ?? process.platform;
|
|
162
|
+
return this.#providers?.().find((provider) => provider.kind === 'apps' && (!provider.platforms || provider.platforms.includes(platform)));
|
|
163
|
+
}
|
|
164
|
+
#appsDriver() {
|
|
165
|
+
const test = this.options.drivers?.apps;
|
|
166
|
+
if (test)
|
|
167
|
+
return test();
|
|
168
|
+
const plugin = this.#pluginApps();
|
|
169
|
+
if (!plugin)
|
|
170
|
+
throw new BrowserPreconditionError(APPS_NOT_INSTALLED);
|
|
171
|
+
return new RouteProviderDriver(plugin, randomUUID());
|
|
172
|
+
}
|
|
173
|
+
/* ---------------- routes and their health ---------------- */
|
|
174
|
+
#chromeConnected() { try {
|
|
175
|
+
return this.#bridge().connected();
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return false;
|
|
179
|
+
} }
|
|
180
|
+
#chromePaired() { try {
|
|
181
|
+
return this.#bridge().paired?.() ?? this.#chromeConnected();
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return false;
|
|
185
|
+
} }
|
|
186
|
+
/** The owner's Chrome as Settings and the composer's pin see it: not paired with this buddi, paired but closed, or connected. */
|
|
187
|
+
chromeLink() {
|
|
188
|
+
return this.#chromeConnected() ? 'connected' : this.#chromePaired() ? 'closed' : 'unpaired';
|
|
189
|
+
}
|
|
190
|
+
/** Why the owner's Chrome cannot serve right now, for the one line a fallback says. */
|
|
191
|
+
#chromeMiss() {
|
|
192
|
+
if (!this.#settings.yourChrome)
|
|
193
|
+
return 'off';
|
|
194
|
+
const link = this.chromeLink();
|
|
195
|
+
return link === 'connected' ? undefined : link;
|
|
196
|
+
}
|
|
197
|
+
routes() {
|
|
198
|
+
const engine = this.#engine();
|
|
199
|
+
const ownOk = engine.engine !== 'none' && !engine.problem;
|
|
200
|
+
const own = { kind: 'own', allowed: true, available: ownOk || this.options.drivers?.own !== undefined, provider: 'core',
|
|
201
|
+
...(engine.message ? { message: engine.message } : {}),
|
|
202
|
+
...(engine.engine === 'none' ? { repair: 'install' } : engine.problem === 'no-sandbox' ? { repair: 'sandbox' } : engine.problem ? { repair: 'install' } : {}) };
|
|
203
|
+
const connected = this.#chromeConnected();
|
|
204
|
+
const paired = this.#chromePaired();
|
|
205
|
+
const chrome = { kind: 'chrome', allowed: this.#settings.yourChrome, available: this.#settings.yourChrome && connected, provider: 'core', paired, connected,
|
|
206
|
+
link: connected ? 'connected' : paired ? 'closed' : 'unpaired',
|
|
207
|
+
...(!paired ? { message: 'Add buddi to Chrome and pair it to let agents use your Chrome.', repair: 'pair' }
|
|
208
|
+
: !connected ? { message: 'Your Chrome is paired but not connected right now: open Chrome.' } : {}) };
|
|
209
|
+
const plugin = this.#pluginApps();
|
|
210
|
+
let health;
|
|
211
|
+
if (this.options.drivers?.apps)
|
|
212
|
+
health = { ok: true };
|
|
213
|
+
else if (plugin) {
|
|
214
|
+
try {
|
|
215
|
+
const answered = plugin.health();
|
|
216
|
+
health = answered instanceof Promise ? this.#lastPluginHealth : answered;
|
|
217
|
+
if (answered instanceof Promise)
|
|
218
|
+
void answered.then((value) => { this.#lastPluginHealth = value; }, () => undefined);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
health = { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else
|
|
225
|
+
health = { ok: false, message: APPS_NOT_INSTALLED, repair: 'install' };
|
|
226
|
+
const installed = plugin !== undefined || this.options.drivers?.apps !== undefined;
|
|
227
|
+
const apps = { kind: 'apps', allowed: installed && this.#settings.yourApps !== 'off', available: installed && this.#settings.yourApps !== 'off' && health.ok,
|
|
228
|
+
provider: plugin?.plugin ?? (this.options.drivers?.apps ? 'test' : ''), installed, mode: this.#settings.yourApps,
|
|
229
|
+
...(plugin ? { label: plugin.label } : {}),
|
|
230
|
+
...(health.message ? { message: health.message } : {}), ...(health.repair ? { repair: health.repair } : {}) };
|
|
231
|
+
return [own, chrome, apps];
|
|
232
|
+
}
|
|
233
|
+
#lastPluginHealth = { ok: true };
|
|
234
|
+
#usable() {
|
|
235
|
+
const list = this.routes();
|
|
236
|
+
const allowed = Object.fromEntries(list.map((route) => [route.kind, route.allowed]));
|
|
237
|
+
const available = Object.fromEntries(list.map((route) => [route.kind, route.available]));
|
|
238
|
+
return { allowed, available };
|
|
239
|
+
}
|
|
240
|
+
/* ---------------- install and launch ---------------- */
|
|
85
241
|
installBrowser() {
|
|
86
242
|
if (this.#install?.state === 'running')
|
|
87
243
|
return this.status();
|
|
88
|
-
// The installer's lines are read into numbers here and go no further: the
|
|
89
|
-
// page draws a bar and says it in buddi's words, never the installer's.
|
|
90
244
|
const reader = new InstallProgressReader();
|
|
91
245
|
const install = { state: 'running', progress: reader.progress };
|
|
92
246
|
this.#install = install;
|
|
@@ -106,16 +260,8 @@ export class HostController {
|
|
|
106
260
|
});
|
|
107
261
|
return this.status();
|
|
108
262
|
}
|
|
109
|
-
/**
|
|
110
|
-
* Launch the agents' browser once and close it, headed or headless as this
|
|
111
|
-
* machine dictates. Only the agents' own browser has a binary to start; the
|
|
112
|
-
* other modes answer ok, since there is nothing of buddi's to launch.
|
|
113
|
-
* A missing-libraries or no-sandbox failure is remembered as the status's problem, as a
|
|
114
|
-
* failed launch from a real session would be.
|
|
115
|
-
*/
|
|
263
|
+
/** Launch the agents' own browser once and close it: does it start on this machine? */
|
|
116
264
|
async checkLaunch() {
|
|
117
|
-
if (this.#settings.mode !== 'playwright')
|
|
118
|
-
return { ok: true };
|
|
119
265
|
const check = await probeLaunch({
|
|
120
266
|
headless: this.#headless,
|
|
121
267
|
detect: () => this.#detect(),
|
|
@@ -128,67 +274,163 @@ export class HostController {
|
|
|
128
274
|
this.#problem = check.problem;
|
|
129
275
|
return check;
|
|
130
276
|
}
|
|
131
|
-
|
|
277
|
+
/* ---------------- lifecycle and persistence ---------------- */
|
|
278
|
+
async #readJson(name) {
|
|
279
|
+
try {
|
|
280
|
+
return JSON.parse(await readFile(path.join(this.dir, name), 'utf8'));
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
if (error.code === 'ENOENT')
|
|
284
|
+
return undefined;
|
|
285
|
+
throw error;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
async #writeJson(name, value) {
|
|
289
|
+
await mkdir(this.dir, { recursive: true, mode: 0o700 });
|
|
290
|
+
const file = path.join(this.dir, name);
|
|
291
|
+
const temp = `${file}.${randomUUID()}.tmp`;
|
|
292
|
+
await writeFile(temp, JSON.stringify(value), { mode: 0o600 });
|
|
293
|
+
await rename(temp, file);
|
|
294
|
+
}
|
|
132
295
|
async enable() {
|
|
133
296
|
if (this.#enabled)
|
|
134
297
|
return;
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
this.#settings =
|
|
298
|
+
void this.logins.load();
|
|
299
|
+
const raw = await this.#readJson('settings.json');
|
|
300
|
+
if (raw !== undefined) {
|
|
301
|
+
const { settings, migrated } = migrateSettings(raw, { paired: this.#chromePaired() });
|
|
302
|
+
this.#settings = settings;
|
|
303
|
+
if (migrated) {
|
|
304
|
+
// The first shape is kept once; a v2 file only loses the apps list the Computer plugin keeps now.
|
|
305
|
+
const v2 = raw?.version === 2;
|
|
306
|
+
await this.#writeJson(v2 ? 'settings.apps.json' : 'settings.v1.json', raw).catch(() => undefined);
|
|
307
|
+
await this.#writeJson('settings.json', settings);
|
|
308
|
+
}
|
|
140
309
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
310
|
+
this.#ownOptions.maxSessions = this.options.limits?.own ?? this.#settings.maxOwnPages;
|
|
311
|
+
const control = await this.#readJson('control.json');
|
|
312
|
+
if (control?.stopped) {
|
|
313
|
+
// A Stop from before expiries: it held from when it was written, for the default hour.
|
|
314
|
+
let at = typeof control.at === 'number' ? control.at : undefined;
|
|
315
|
+
if (at === undefined) {
|
|
316
|
+
try {
|
|
317
|
+
at = statSync(path.join(this.dir, 'control.json')).mtimeMs;
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
at = this.#now();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const until = control.until === null ? undefined : typeof control.until === 'number' ? control.until : at + 60 * 60_000;
|
|
324
|
+
this.#stop = { at, ...(until !== undefined ? { until } : {}) };
|
|
144
325
|
}
|
|
145
|
-
|
|
146
|
-
|
|
326
|
+
const pins = await this.#readJson('pins.json');
|
|
327
|
+
for (const [conversation, pin] of Object.entries(pins ?? {}))
|
|
328
|
+
if (PIN_VALUES.includes(pin))
|
|
329
|
+
this.#pins.set(conversation, pin);
|
|
330
|
+
const learned = await this.#readJson('sign-in-sites.json');
|
|
331
|
+
for (const site of Array.isArray(learned) ? learned.slice(-500) : [])
|
|
332
|
+
if (typeof site === 'string')
|
|
333
|
+
this.#learned.add(site);
|
|
334
|
+
await Promise.all(ROUTES.map((route) => this.#managers[route].enable()));
|
|
147
335
|
this.#enabled = true;
|
|
148
336
|
}
|
|
337
|
+
#now() { return this.options.service?.now?.() ?? Date.now(); }
|
|
338
|
+
/** The global Stop, if it still holds; an expired one is cleared here. */
|
|
339
|
+
#activeStop() {
|
|
340
|
+
if (this.#stop?.until !== undefined && this.#now() >= this.#stop.until) {
|
|
341
|
+
this.#stop = undefined;
|
|
342
|
+
this.#later(this.#writeJson('control.json', { stopped: false }));
|
|
343
|
+
}
|
|
344
|
+
return this.#stop;
|
|
345
|
+
}
|
|
346
|
+
/* ---------------- status ---------------- */
|
|
347
|
+
#key(ownerId, agentId, conversationId) { return JSON.stringify([ownerId, agentId, conversationId]); }
|
|
348
|
+
#pageOf(scope) {
|
|
349
|
+
for (const route of ROUTES) {
|
|
350
|
+
const manager = this.#managers[route];
|
|
351
|
+
if (manager.child(scope))
|
|
352
|
+
return { route, manager };
|
|
353
|
+
}
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
149
356
|
status(scope) {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
357
|
+
const found = scope ? this.#pageOf(scope) : undefined;
|
|
358
|
+
let status;
|
|
359
|
+
if (scope)
|
|
360
|
+
status = found ? found.manager.status(scope) : { state: this.#enabled ? 'idle' : 'unavailable', enabled: this.#enabled, busy: false, hasScreenshot: false };
|
|
361
|
+
else {
|
|
362
|
+
const sessions = ROUTES.flatMap((route) => this.#managers[route].status().sessions ?? []);
|
|
363
|
+
const latest = sessions.at(-1) ?? { state: this.#enabled ? 'idle' : 'unavailable', enabled: this.#enabled, busy: false, hasScreenshot: false };
|
|
364
|
+
status = { ...latest, busy: sessions.some((session) => session.busy), sessions };
|
|
365
|
+
}
|
|
366
|
+
const stop = this.#activeStop();
|
|
367
|
+
if (stop && !status.session)
|
|
368
|
+
status = { ...status, state: 'stopped' };
|
|
369
|
+
const metadata = {
|
|
370
|
+
settings: { ...this.#settings, signInSites: [...this.#settings.signInSites] },
|
|
371
|
+
// The sites buddi added itself when it met their sign-in page: one list with the owner's in Settings.
|
|
372
|
+
learnedSignInSites: [...this.#learned].filter((site) => !this.#settings.signInSites.includes(site)).sort(),
|
|
373
|
+
browser: this.#engine(), routes: this.routes(), chrome: this.chromeLink(),
|
|
374
|
+
...(stop ? { stop: { at: new Date(stop.at).toISOString(), ...(stop.until !== undefined ? { until: new Date(stop.until).toISOString() } : {}) } } : {}),
|
|
375
|
+
...(scope?.conversationId && this.#pins.has(scope.conversationId) ? { pin: this.#pins.get(scope.conversationId) } : {}),
|
|
376
|
+
};
|
|
155
377
|
const once = (entry) => {
|
|
156
378
|
const allowed = entry.session ? this.#once.get(entry.session.conversationId) : undefined;
|
|
157
|
-
|
|
379
|
+
const opened = entry.session ? this.#opened.get(entry.session.conversationId) : undefined;
|
|
380
|
+
const withMode = { ...entry, mode: entry.mode ?? 'playwright' };
|
|
381
|
+
if (!withMode.session || (!allowed?.size && !opened?.size))
|
|
382
|
+
return withMode;
|
|
383
|
+
return { ...withMode, session: { ...withMode.session, ...(allowed?.size ? { allowedOnce: [...allowed] } : {}), ...(opened?.size ? { allowedApps: [...opened] } : {}) } };
|
|
158
384
|
};
|
|
159
385
|
return once({ ...status, ...metadata, ...(status.sessions ? { sessions: status.sessions.map((session) => once({ ...session, ...metadata })) } : {}) });
|
|
160
386
|
}
|
|
161
|
-
/**
|
|
162
|
-
|
|
163
|
-
|
|
387
|
+
/** `buddi doctor browser`: the last week of stops, cards and routes. */
|
|
388
|
+
telemetrySummary(days = 7) {
|
|
389
|
+
const file = this.telemetry.file;
|
|
390
|
+
const events = file && existsSync(file) ? readTelemetry(file) : this.telemetry.events;
|
|
391
|
+
return summarize(events, this.#now(), days);
|
|
164
392
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
async #
|
|
171
|
-
const
|
|
172
|
-
if (
|
|
173
|
-
return
|
|
393
|
+
/* ---------------- apps: names, cards, Once / Always ---------------- */
|
|
394
|
+
/**
|
|
395
|
+
* May this conversation open the app without a card? `ask` asks every
|
|
396
|
+
* time; `on` opens what the plugin lists. A Once yes counts either way.
|
|
397
|
+
*/
|
|
398
|
+
async #allowed(appId, conversationId) {
|
|
399
|
+
const once = conversationId !== undefined && this.#once.get(conversationId)?.has(appId) === true;
|
|
400
|
+
if (once)
|
|
401
|
+
return true;
|
|
402
|
+
if (this.#settings.yourApps !== 'on')
|
|
403
|
+
return false;
|
|
404
|
+
const reach = this.#pluginApps()?.reach;
|
|
405
|
+
if (!reach)
|
|
406
|
+
return this.options.drivers?.apps !== undefined || this.#pluginApps() !== undefined;
|
|
174
407
|
try {
|
|
175
|
-
return
|
|
408
|
+
return (await reach.listed(appId)) === true;
|
|
176
409
|
}
|
|
177
410
|
catch {
|
|
178
|
-
return
|
|
411
|
+
return false;
|
|
179
412
|
}
|
|
180
413
|
}
|
|
181
|
-
|
|
414
|
+
#remember(app) { if (app.name !== app.bundleId)
|
|
415
|
+
this.#names.set(app.bundleId, app.name); return app; }
|
|
182
416
|
async #resolve(command, conversationId) {
|
|
183
|
-
const
|
|
184
|
-
if (command.app
|
|
185
|
-
return
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
417
|
+
const reach = this.#pluginApps()?.reach;
|
|
418
|
+
if (command.app === undefined && await this.#allowed(command.appId, conversationId))
|
|
419
|
+
return { bundleId: command.appId, name: this.#names.get(command.appId) ?? command.appId };
|
|
420
|
+
if (!reach) {
|
|
421
|
+
if (command.app !== undefined)
|
|
422
|
+
throw new BrowserPreconditionError(`The apps route cannot look up ${command.app} by name. Ask with its id.`);
|
|
423
|
+
return { bundleId: command.appId, name: command.appId };
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
return this.#remember(asApp(await reach.resolve(command.app !== undefined ? { name: command.app } : { id: command.appId })));
|
|
427
|
+
}
|
|
428
|
+
catch (error) {
|
|
429
|
+
if (error.precondition === true && !(error instanceof BrowserPreconditionError))
|
|
430
|
+
throw new BrowserPreconditionError(error.message);
|
|
431
|
+
throw error;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
192
434
|
async #resolveOrRefuse(command, conversationId) {
|
|
193
435
|
try {
|
|
194
436
|
return await this.#resolve(command, conversationId);
|
|
@@ -197,20 +439,33 @@ export class HostController {
|
|
|
197
439
|
throw error instanceof BrowserPreconditionError ? new ToolRefusal(error.message) : error;
|
|
198
440
|
}
|
|
199
441
|
}
|
|
200
|
-
/**
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
442
|
+
/** What the plugin does with an app not on its list: a card, or a refusal. */
|
|
443
|
+
async #unlisted() {
|
|
444
|
+
const reach = this.#pluginApps()?.reach;
|
|
445
|
+
if (!reach || this.#settings.yourApps === 'ask')
|
|
446
|
+
return 'ask';
|
|
447
|
+
try {
|
|
448
|
+
return (await reach.unlisted()) === 'refuse' ? 'refuse' : 'ask';
|
|
449
|
+
}
|
|
450
|
+
catch {
|
|
451
|
+
return 'ask';
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/** Session for everything but an `open` of an app the owner has not allowed: that one asks with a card. */
|
|
208
455
|
async tierFor(command, ctx) {
|
|
209
|
-
if (command.action !== 'open' || this.#settings.
|
|
456
|
+
if (command.action !== 'open' || this.#settings.yourApps === 'off')
|
|
457
|
+
return { tier: 'session' };
|
|
458
|
+
// No app card for a mission: nobody is there to answer it, and apps are never its route.
|
|
459
|
+
if (!ctx.ownerRequest)
|
|
460
|
+
throw new ToolRefusal(UNATTENDED_APPS);
|
|
461
|
+
// No plugin provides apps: no card either; the call itself says what to install.
|
|
462
|
+
if (!this.#pluginApps() && !this.options.drivers?.apps)
|
|
210
463
|
return { tier: 'session' };
|
|
211
464
|
const app = await this.#resolveOrRefuse(command, ctx.conversationId);
|
|
212
|
-
if (this.#allowed(app.bundleId, ctx.conversationId))
|
|
465
|
+
if (await this.#allowed(app.bundleId, ctx.conversationId))
|
|
213
466
|
return { tier: 'session' };
|
|
467
|
+
if (await this.#unlisted() === 'refuse')
|
|
468
|
+
throw new ToolRefusal(`${app.name} is not on the owner's list of apps, and the owner said not to open others. They can add it in Settings → Computer.`);
|
|
214
469
|
const conversationId = ctx.conversationId;
|
|
215
470
|
if (conversationId && UUID.test(conversationId) && ctx.buddi?.approvals.decisionsInConversation) {
|
|
216
471
|
const cards = (await ctx.buddi.approvals.decisionsInConversation('browser.act', conversationId))
|
|
@@ -228,15 +483,14 @@ export class HostController {
|
|
|
228
483
|
return { tier: 'gated' };
|
|
229
484
|
}
|
|
230
485
|
async describe(command, ctx) {
|
|
231
|
-
// Always looked up, never read from an allowance: the executor describes
|
|
232
|
-
// again before it runs, and the card must say the same both times.
|
|
233
486
|
const app = await this.#resolveOrRefuse(command, undefined);
|
|
234
487
|
const agent = ctx.agentId ?? 'An agent';
|
|
235
488
|
const envelope = { tool: 'browser.act', allowApp: app.bundleId, name: app.name };
|
|
489
|
+
const always = this.#settings.yourApps === 'on' && this.#pluginApps()?.reach?.remember !== undefined;
|
|
236
490
|
return {
|
|
237
491
|
envelope,
|
|
238
492
|
preview: `Use ${app.name} on your computer?\n${agent} wants to open ${app.name} (${app.bundleId}). While it works, buddi sees that window's screen and sends it to the model, as with the apps you allowed already.`,
|
|
239
|
-
choices: [{ ...REMEMBER, options: [...REMEMBER.options] }],
|
|
493
|
+
choices: [{ ...REMEMBER, options: always ? [...REMEMBER.options] : ['Once'] }],
|
|
240
494
|
};
|
|
241
495
|
}
|
|
242
496
|
#allowOnce(conversationId, appId) {
|
|
@@ -244,31 +498,31 @@ export class HostController {
|
|
|
244
498
|
apps.add(appId);
|
|
245
499
|
this.#once.set(conversationId, apps);
|
|
246
500
|
}
|
|
247
|
-
/**
|
|
248
|
-
* The owner said yes on the card. Once: this conversation. Always: the
|
|
249
|
-
* owner's list, written the way Settings writes it — without restarting
|
|
250
|
-
* the driver, since the agent's session is usually live. A full list falls
|
|
251
|
-
* back to Once and says so.
|
|
252
|
-
*/
|
|
253
501
|
async #grant(command, ctx) {
|
|
254
|
-
if (this.#settings.
|
|
255
|
-
throw new BrowserPreconditionError('
|
|
502
|
+
if (this.#settings.yourApps === 'off' || !this.#pluginApps())
|
|
503
|
+
throw new BrowserPreconditionError('Your apps are off, so there is no app to allow. Ask the owner.');
|
|
256
504
|
if (!ctx.conversationId)
|
|
257
505
|
throw new Error('An app is allowed for a conversation, and this call has none.');
|
|
258
506
|
const app = await this.#resolve(command, undefined);
|
|
259
507
|
let remember = ctx.choices?.remember === 'Always' ? 'Always' : 'Once';
|
|
260
508
|
let note = '';
|
|
261
|
-
|
|
262
|
-
|
|
509
|
+
const reach = this.#pluginApps()?.reach;
|
|
510
|
+
if (remember === 'Always') {
|
|
511
|
+
let kept = false;
|
|
512
|
+
try {
|
|
513
|
+
kept = reach?.remember ? await reach.remember({ id: app.bundleId, name: app.name }) : false;
|
|
514
|
+
}
|
|
515
|
+
catch {
|
|
516
|
+
kept = false;
|
|
517
|
+
}
|
|
518
|
+
if (!kept) {
|
|
263
519
|
remember = 'Once';
|
|
264
|
-
note = ' The list of apps
|
|
520
|
+
note = ' The list of apps could not take it (it may be full), so it is allowed for this conversation only.';
|
|
265
521
|
}
|
|
266
|
-
else
|
|
267
|
-
await this.#writeSettings({ ...this.#settings, allowedApps: [...this.#settings.allowedApps, app.bundleId] });
|
|
268
522
|
}
|
|
269
523
|
if (remember === 'Once')
|
|
270
524
|
this.#allowOnce(ctx.conversationId, app.bundleId);
|
|
271
|
-
const how = remember === 'Always' ? 'Always: it is now on the list in Settings' : 'Once: for this conversation';
|
|
525
|
+
const how = remember === 'Always' ? 'Always: it is now on the list in Settings → Computer' : 'Once: for this conversation';
|
|
272
526
|
return {
|
|
273
527
|
allowed: { appId: app.bundleId, name: app.name, remember },
|
|
274
528
|
message: `Allowed ${app.name} (${how}).${note}`,
|
|
@@ -277,143 +531,495 @@ export class HostController {
|
|
|
277
531
|
}
|
|
278
532
|
async #writeSettings(next) {
|
|
279
533
|
const parsed = settingsSchema.parse(next);
|
|
280
|
-
await
|
|
281
|
-
const file = path.join(this.dir, 'settings.json');
|
|
282
|
-
const temp = `${file}.${randomUUID()}.tmp`;
|
|
283
|
-
await writeFile(temp, JSON.stringify(parsed), { mode: 0o600 });
|
|
284
|
-
await rename(temp, file);
|
|
534
|
+
await this.#writeJson('settings.json', parsed);
|
|
285
535
|
this.#settings = parsed;
|
|
536
|
+
this.#ownOptions.maxSessions = this.options.limits?.own ?? parsed.maxOwnPages;
|
|
537
|
+
}
|
|
538
|
+
/* ---------------- pages ---------------- */
|
|
539
|
+
screenshot(sessionId) {
|
|
540
|
+
if (sessionId)
|
|
541
|
+
return this.#pageOf({ sessionId })?.manager.screenshot(sessionId);
|
|
542
|
+
const latest = this.status().session?.id;
|
|
543
|
+
return latest ? this.#pageOf({ sessionId: latest })?.manager.screenshot(latest) : undefined;
|
|
286
544
|
}
|
|
287
|
-
screenshot(sessionId) { return this.#manager.screenshot(sessionId); }
|
|
288
545
|
hand(scope) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
546
|
+
const found = scope ? this.#pageOf(scope) : undefined;
|
|
547
|
+
if (!found)
|
|
548
|
+
return { supported: true, message: 'That page changed. Refresh before driving it.' };
|
|
549
|
+
return found.manager.hand(scope);
|
|
292
550
|
}
|
|
293
551
|
rollover(input) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
552
|
+
let moved = false;
|
|
553
|
+
for (const route of ROUTES)
|
|
554
|
+
moved = this.#managers[route].rollover(input) || moved;
|
|
555
|
+
const oldKey = this.#key(input.ownerId, input.agentId, input.previousConversationId);
|
|
556
|
+
const current = this.#current.get(oldKey);
|
|
557
|
+
if (moved && current) {
|
|
558
|
+
this.#current.delete(oldKey);
|
|
559
|
+
this.#current.set(this.#key(input.ownerId, input.agentId, input.conversationId), current);
|
|
560
|
+
}
|
|
297
561
|
const once = this.#once.get(input.previousConversationId);
|
|
298
562
|
if (moved && once) {
|
|
299
563
|
this.#once.delete(input.previousConversationId);
|
|
300
564
|
this.#once.set(input.conversationId, once);
|
|
301
565
|
}
|
|
566
|
+
const opened = this.#opened.get(input.previousConversationId);
|
|
567
|
+
if (moved && opened) {
|
|
568
|
+
this.#opened.delete(input.previousConversationId);
|
|
569
|
+
this.#opened.set(input.conversationId, opened);
|
|
570
|
+
}
|
|
571
|
+
const pin = this.#pins.get(input.previousConversationId);
|
|
572
|
+
if (pin) {
|
|
573
|
+
this.#pins.set(input.conversationId, pin);
|
|
574
|
+
this.#later(this.#savePins());
|
|
575
|
+
}
|
|
302
576
|
return moved;
|
|
303
577
|
}
|
|
578
|
+
/** The owner's own sign-in list, plus the sites buddi met a login wall on. */
|
|
579
|
+
#signInSite(site) {
|
|
580
|
+
return siteListed(site, this.#settings.signInSites) || siteListed(site, this.#learned);
|
|
581
|
+
}
|
|
582
|
+
#learn(site) {
|
|
583
|
+
if (!site || this.#learned.has(site))
|
|
584
|
+
return;
|
|
585
|
+
this.#learned.add(site);
|
|
586
|
+
this.#later(this.#saveLearned());
|
|
587
|
+
}
|
|
588
|
+
#learnedWrite = Promise.resolve();
|
|
589
|
+
/** One write at a time, each of the list as it is then: a late write never brings back a forgotten site. */
|
|
590
|
+
#saveLearned() {
|
|
591
|
+
const next = this.#learnedWrite.catch(() => undefined).then(() => this.#writeJson('sign-in-sites.json', [...this.#learned].slice(-500)));
|
|
592
|
+
this.#learnedWrite = next;
|
|
593
|
+
return next;
|
|
594
|
+
}
|
|
595
|
+
async #storedLogin(ctx, url) {
|
|
596
|
+
const origin = canonicalOrigin(url);
|
|
597
|
+
if (!origin || !ctx.buddi?.secrets)
|
|
598
|
+
return false;
|
|
599
|
+
try {
|
|
600
|
+
return (await ctx.buddi.secrets.list()).some((secret) => fieldBoundTo(secret.bindings, origin));
|
|
601
|
+
}
|
|
602
|
+
catch {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
#pinFor(ctx) {
|
|
607
|
+
return {
|
|
608
|
+
conversation: ctx.conversationId ? this.#pins.get(ctx.conversationId) : undefined,
|
|
609
|
+
agent: ctx.agentId ? this.options.agentPin?.(ctx.agentId) : undefined,
|
|
610
|
+
global: this.#settings.defaultRoute,
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
/** Hand a card to the surface once, as a question with choices. */
|
|
614
|
+
#ask(ctx, card) {
|
|
615
|
+
if (this.#asked.has(card))
|
|
616
|
+
return;
|
|
617
|
+
this.#asked.add(card);
|
|
618
|
+
try {
|
|
619
|
+
ctx.ask?.({ question: card.question, options: card.options.map((option) => ({ label: option.label, ...(option.hint ? { hint: option.hint } : {}), ...(option.recommended ? { recommended: true } : {}) })), allowOther: false });
|
|
620
|
+
}
|
|
621
|
+
catch { /* a surface's drawing never decides a run */ }
|
|
622
|
+
}
|
|
623
|
+
/** How long a mission run waits on a card for the owner, in milliseconds (settings `missionWaitMinutes`). */
|
|
624
|
+
missionWaitMs() {
|
|
625
|
+
return this.#settings.missionWaitMinutes * 60_000;
|
|
626
|
+
}
|
|
304
627
|
async execute(command, ctx) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
628
|
+
ctx.signal?.throwIfAborted();
|
|
629
|
+
if (!this.#enabled)
|
|
630
|
+
throw new Error('Browser driving is available through buddi serve.');
|
|
631
|
+
if (!ctx.agentId || !ctx.conversationId || !ctx.buddi)
|
|
632
|
+
throw new Error('A browser action belongs to an agent and a conversation.');
|
|
633
|
+
const unattended = !ctx.ownerRequest;
|
|
634
|
+
// The owner's Stop: one card with Resume, never a Settings trip.
|
|
635
|
+
const stop = this.#activeStop();
|
|
636
|
+
if (stop && command.action !== 'close') {
|
|
637
|
+
this.telemetry.stop('owner-stop', { route: 'own', agent: ctx.agentId, ...missionMark(ctx), ...(ctx.surface?.id ? { surface: ctx.surface.id } : {}) });
|
|
638
|
+
// The core context carries the owner's zone; the plugin type does not name it.
|
|
639
|
+
const clock = (at) => ownerClock(at, ctx.timezone);
|
|
640
|
+
const wanted = command.action === 'navigate' ? siteOf(command.url) : undefined;
|
|
641
|
+
const card = ownerCard('stopped', { since: clock(stop.at), stoppedAgo: agoText(this.#now() - stop.at), ...(stop.until !== undefined ? { until: clock(stop.until) } : {}), ...(wanted ? { site: wanted } : {}) });
|
|
642
|
+
this.#stopCards.set(ctx.conversationId, card);
|
|
643
|
+
// The owner's own Stop is not a moment to park a mission on: it says so and ends.
|
|
644
|
+
if (!unattended)
|
|
645
|
+
this.#ask(ctx, card);
|
|
646
|
+
return { completed: false, dispatched: false, needsOwner: card, message: `${browserStoppedMessage(ctx.surface)} Say that in one sentence and stop.` };
|
|
647
|
+
}
|
|
317
648
|
// The owner's yes on an app card, run by core's executor: record it; the agent opens next.
|
|
318
649
|
if (ctx.actionId !== undefined && command.action === 'open')
|
|
319
650
|
return this.#grant(command, ctx);
|
|
651
|
+
if (unattended && command.action === 'open') {
|
|
652
|
+
this.telemetry.stop('apps-unavailable', { route: 'apps', agent: ctx.agentId, ...missionMark(ctx) });
|
|
653
|
+
throw new ToolRefusal(UNATTENDED_APPS);
|
|
654
|
+
}
|
|
655
|
+
const key = this.#key(ctx.buddi.owner.id, ctx.agentId, ctx.conversationId);
|
|
656
|
+
if (command.action === 'close') {
|
|
657
|
+
for (const route of ROUTES)
|
|
658
|
+
await this.#managers[route].execute(command, ctx);
|
|
659
|
+
this.#current.delete(key);
|
|
660
|
+
return { closed: true };
|
|
661
|
+
}
|
|
662
|
+
if (command.target?.x !== undefined && this.#current.get(key) !== 'apps') {
|
|
663
|
+
throw new BrowserPreconditionError('Coordinates are for an app window. On a web page, use a ref from the page.');
|
|
664
|
+
}
|
|
320
665
|
let run = command;
|
|
666
|
+
let appName;
|
|
321
667
|
if (command.action === 'open') {
|
|
668
|
+
if (!this.#pluginApps() && !this.options.drivers?.apps) {
|
|
669
|
+
this.telemetry.stop('apps-unavailable', { route: 'apps', agent: ctx.agentId });
|
|
670
|
+
throw new Error(APPS_NOT_INSTALLED);
|
|
671
|
+
}
|
|
672
|
+
if (this.#settings.yourApps === 'off') {
|
|
673
|
+
this.telemetry.stop('apps-unavailable', { route: 'apps', agent: ctx.agentId, ...missionMark(ctx) });
|
|
674
|
+
throw new Error(APPS_UNAVAILABLE);
|
|
675
|
+
}
|
|
322
676
|
const app = await this.#resolve(command, ctx.conversationId);
|
|
323
|
-
if (!this.#allowed(app.bundleId, ctx.conversationId))
|
|
677
|
+
if (!await this.#allowed(app.bundleId, ctx.conversationId))
|
|
324
678
|
throw new BrowserPreconditionError(`${app.name} is not allowed yet. Ask to open it again so the owner gets a card.`);
|
|
325
679
|
run = { ...command, appId: app.bundleId, app: undefined };
|
|
680
|
+
appName = app.name;
|
|
681
|
+
const opened = this.#opened.get(ctx.conversationId) ?? new Set();
|
|
682
|
+
opened.add(app.bundleId);
|
|
683
|
+
this.#opened.set(ctx.conversationId, opened);
|
|
326
684
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
685
|
+
// A mission browses in buddi's own browser only: asked for the owner's Chrome, it is told so plainly (no pin changes that).
|
|
686
|
+
if (unattended && command.prefer === 'yours') {
|
|
687
|
+
this.telemetry.stop('route-unavailable', { route: 'chrome', agent: ctx.agentId, ...missionMark(ctx) });
|
|
688
|
+
throw new ToolRefusal(UNATTENDED_CHROME);
|
|
689
|
+
}
|
|
690
|
+
let route = this.#current.get(key);
|
|
691
|
+
let choice = { route, reason: 'continuing' };
|
|
692
|
+
const site = siteOf(command.url);
|
|
693
|
+
if (!route || command.action === 'navigate' || command.action === 'open') {
|
|
694
|
+
const { allowed, available } = this.#usable();
|
|
695
|
+
choice = chooseRoute({ command: run, prefer: command.prefer, pins: this.#pinFor(ctx), allowed, available, signInSite: this.#signInSite(site), unattended });
|
|
696
|
+
// A task already in the owner's Chrome stays there for its next page (a checkout on
|
|
697
|
+
// another domain keeps his sign-in), unless something asked for another route.
|
|
698
|
+
if (route === 'chrome' && command.action === 'navigate' && choice.route === 'own' && choice.reason === 'default' && allowed.chrome && available.chrome) {
|
|
699
|
+
choice = { route: 'chrome', reason: 'continuing' };
|
|
700
|
+
}
|
|
701
|
+
if (!choice.route) {
|
|
702
|
+
this.telemetry.stop('apps-unavailable', { route: 'apps', agent: ctx.agentId, ...missionMark(ctx) });
|
|
703
|
+
throw new Error(unattended ? UNATTENDED_APPS : APPS_UNAVAILABLE);
|
|
704
|
+
}
|
|
705
|
+
if (choice.fallbackFrom)
|
|
706
|
+
this.telemetry.stop('route-unavailable', { route: choice.route, agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
|
|
707
|
+
if (route && route !== choice.route)
|
|
708
|
+
await this.#managers[route].release(ctx.conversationId, ctx.agentId);
|
|
709
|
+
if (route !== choice.route)
|
|
710
|
+
this.telemetry.record({ type: 'browser.route', chosen: choice.route, reason: choice.reason, ...(choice.fallbackFrom ? { fallbackFrom: choice.fallbackFrom } : {}), agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
|
|
711
|
+
route = choice.route;
|
|
712
|
+
this.#current.set(key, route);
|
|
713
|
+
}
|
|
714
|
+
let result;
|
|
715
|
+
{
|
|
716
|
+
try {
|
|
717
|
+
result = await this.#managers[route].execute(run, ctx);
|
|
718
|
+
if (route === 'chrome')
|
|
719
|
+
this.#chromeFailed.delete(key);
|
|
720
|
+
}
|
|
721
|
+
catch (error) {
|
|
722
|
+
// The same failure from the owner's Chrome twice running: one plain line, not a third identical try.
|
|
723
|
+
const repeated = route === 'chrome' ? this.#chromeRepeat(key, error, ctx) : undefined;
|
|
724
|
+
if (repeated)
|
|
725
|
+
return repeated;
|
|
726
|
+
// The owner's Chrome went away: the same page in buddi's own browser, silently.
|
|
727
|
+
if (route !== 'chrome' || !(error instanceof Error) || !error.message.includes(NOT_CONNECTED.slice(0, 30)))
|
|
728
|
+
throw error;
|
|
729
|
+
this.telemetry.stop('not-connected', { route: 'chrome', agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
|
|
730
|
+
const last = this.#managers.chrome.child({ agentId: ctx.agentId, conversationId: ctx.conversationId })?.lastUrl;
|
|
731
|
+
await this.#managers.chrome.release(ctx.conversationId, ctx.agentId);
|
|
732
|
+
route = 'own';
|
|
733
|
+
this.#current.set(key, route);
|
|
734
|
+
choice = { route, reason: 'chrome-unavailable', fallbackFrom: 'chrome' };
|
|
735
|
+
const url = run.action === 'navigate' ? run.url : last;
|
|
736
|
+
if (!url)
|
|
737
|
+
throw error;
|
|
738
|
+
result = await this.#managers.own.execute({ action: 'navigate', url }, ctx);
|
|
739
|
+
}
|
|
740
|
+
({ result, route, choice } = await this.#walls(result, route, choice, ctx, unattended));
|
|
330
741
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
742
|
+
return this.#annotate(result, route, choice, ctx, appName);
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* The owner's Chrome failed: remember how. The second identical failure in
|
|
746
|
+
* a row is answered with one plain line and a stop, rather than letting
|
|
747
|
+
* the agent try the same step a third time and then tell the owner the
|
|
748
|
+
* page never opened. A refusal (stale page, owner looking), a stop and a
|
|
749
|
+
* lost connection are not failures of this kind and are left as they are.
|
|
750
|
+
*/
|
|
751
|
+
#chromeRepeat(key, error, ctx) {
|
|
752
|
+
if (!(error instanceof Error) || error instanceof BrowserPreconditionError || error instanceof ToolRefusal || ctx.signal?.aborted)
|
|
753
|
+
return undefined;
|
|
754
|
+
if (error.message.includes(NOT_CONNECTED.slice(0, 30)))
|
|
755
|
+
return undefined;
|
|
756
|
+
const said = error.message.trim();
|
|
757
|
+
if (this.#chromeFailed.get(key) !== said) {
|
|
758
|
+
this.#chromeFailed.set(key, said);
|
|
759
|
+
return undefined;
|
|
334
760
|
}
|
|
761
|
+
this.#chromeFailed.delete(key);
|
|
762
|
+
return { completed: false, dispatched: false,
|
|
763
|
+
message: `Your Chrome failed the same way twice: ${said.replace(/\.$/, '')}. Don't try it again; tell the owner that in one sentence.` };
|
|
335
764
|
}
|
|
336
765
|
/**
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
766
|
+
* A login wall or a human check on the page just returned. In buddi's own
|
|
767
|
+
* browser a sign-in moves to the owner's Chrome when it is allowed and
|
|
768
|
+
* connected (the site is remembered as one that needs his sign-in); a
|
|
769
|
+
* stored login is pointed at; otherwise one Sign in card. A captcha is a
|
|
770
|
+
* Human check card wherever it appears.
|
|
340
771
|
*/
|
|
341
|
-
#
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}
|
|
352
|
-
|
|
772
|
+
async #walls(result, route, choice, ctx, unattended) {
|
|
773
|
+
const observation = result;
|
|
774
|
+
if (!observation?.observation || observation.needsOwner)
|
|
775
|
+
return { result, route, choice };
|
|
776
|
+
const seenSite = siteOf(observation.observation.url);
|
|
777
|
+
// A full login page, or a page that renders signed out where the task needs the owner's account.
|
|
778
|
+
const wall = detectWall(observation.observation)
|
|
779
|
+
?? (detectSignedOut(observation.observation, { task: ctx.ownerRequest?.text, signInSite: this.#signInSite(seenSite) }) ? 'sign-in' : undefined);
|
|
780
|
+
if (!wall)
|
|
781
|
+
return { result, route, choice };
|
|
782
|
+
const scope = { agentId: ctx.agentId, conversationId: ctx.conversationId };
|
|
783
|
+
const child = this.#managers[route].child(scope);
|
|
784
|
+
if (!child)
|
|
785
|
+
return { result, route, choice };
|
|
786
|
+
const url = observation.observation.url;
|
|
787
|
+
const site = siteOf(url);
|
|
788
|
+
if (wall === 'human') {
|
|
789
|
+
this.telemetry.stop('human-check', { route, agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
|
|
790
|
+
const card = child.park('human');
|
|
791
|
+
return { result: { ...observation, completed: false, needsOwner: card, message: `${site ?? 'This page'} asks for a human. Say so in one sentence and stop; the card asks the owner to take over.` }, route, choice };
|
|
792
|
+
}
|
|
793
|
+
this.#learn(site);
|
|
794
|
+
const { allowed, available } = this.#usable();
|
|
795
|
+
const chromeUsable = allowed.chrome && available.chrome && !unattended;
|
|
796
|
+
// A pin to another route (the conversation's, the agent's, the default) holds here too:
|
|
797
|
+
// the move to the owner's Chrome is then his choice on the card, never automatic.
|
|
798
|
+
const pins = this.#pinFor(ctx);
|
|
799
|
+
const pin = [pins.conversation, pins.agent, pins.global].find((value) => value !== undefined && value !== 'auto');
|
|
800
|
+
if (route === 'own' && chromeUsable && (pin === undefined || pin === 'chrome')) {
|
|
801
|
+
// The owner is signed in there: the same address, in a background tab of his Chrome.
|
|
802
|
+
await this.#managers.own.release(ctx.conversationId, ctx.agentId);
|
|
803
|
+
const key = this.#key(ctx.buddi.owner.id, ctx.agentId, ctx.conversationId);
|
|
804
|
+
this.#current.set(key, 'chrome');
|
|
805
|
+
this.telemetry.record({ type: 'browser.route', chosen: 'chrome', reason: 'sign-in-fallback', fallbackFrom: 'own', agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
|
|
806
|
+
const moved = await this.#managers.chrome.execute({ action: 'navigate', url }, ctx);
|
|
807
|
+
return this.#walls(moved, 'chrome', { route: 'chrome', reason: 'sign-in-fallback', fallbackFrom: 'own' }, ctx, unattended);
|
|
808
|
+
}
|
|
809
|
+
if (await this.#storedLogin(ctx, url)) {
|
|
810
|
+
return { result: { ...observation, message: `${observation.message ?? ''} This is a sign-in page and the owner keeps a login for it: secret.list, then secret.fill (a TOTP secret answers a code).`.trim() }, route, choice };
|
|
811
|
+
}
|
|
812
|
+
// A mission's sign-in is one of the four moments too: the card parks the run until the owner answers (Take over, or a saved login).
|
|
813
|
+
this.telemetry.stop('sign-in', { route, agent: ctx.agentId, ...missionMark(ctx), ...(site ? { host: site } : {}) });
|
|
814
|
+
const card = child.park(wall === 'code' ? 'code' : 'sign-in', { chrome: route === 'chrome' ? 'none' : chromeUsable ? 'usable' : allowed.chrome && !available.chrome ? 'offline' : 'none', storedLogin: false });
|
|
815
|
+
return { result: { ...observation, completed: false, needsOwner: card, message: `${card.title}. Say that in one sentence and stop; the card has Take over. You continue when the owner gives the page back.` }, route, choice };
|
|
816
|
+
}
|
|
817
|
+
#annotate(result, route, choice, ctx, appName) {
|
|
818
|
+
if (!result || typeof result !== 'object')
|
|
819
|
+
return result;
|
|
820
|
+
const value = result;
|
|
821
|
+
const site = siteOf(value.observation?.url) ?? undefined;
|
|
822
|
+
let note;
|
|
823
|
+
const reason = choice.reason;
|
|
824
|
+
if (route !== 'own' || choice.fallbackFrom) {
|
|
825
|
+
const candidate = routeNote(route, reason, site, appName, choice.fallbackFrom === 'chrome' ? this.#chromeMiss() : undefined);
|
|
826
|
+
const said = `${ctx.conversationId}|${route}|${site ?? appName ?? ''}`;
|
|
827
|
+
if (candidate && !this.#noted.has(said) && reason !== 'continuing') {
|
|
828
|
+
this.#noted.add(said);
|
|
829
|
+
note = candidate;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
if (value.needsOwner)
|
|
833
|
+
this.#ask(ctx, value.needsOwner);
|
|
834
|
+
return { ...value, route, ...(note ? { routeNote: note } : {}) };
|
|
835
|
+
}
|
|
836
|
+
/** The secret tools act on the page the conversation is already on, whichever route it is. */
|
|
837
|
+
async #secretRoute(ctx) {
|
|
838
|
+
if (!this.#enabled)
|
|
839
|
+
throw new Error('Browser driving is available through buddi serve.');
|
|
840
|
+
if (this.#activeStop())
|
|
841
|
+
throw new Error(browserStoppedMessage(ctx.surface));
|
|
842
|
+
const found = ctx.agentId && ctx.conversationId ? this.#pageOf({ agentId: ctx.agentId, conversationId: ctx.conversationId }) : undefined;
|
|
843
|
+
return found?.manager ?? this.#managers.own;
|
|
353
844
|
}
|
|
354
845
|
async secretFill(input, ctx) {
|
|
355
|
-
|
|
846
|
+
const manager = await this.#secretRoute(ctx);
|
|
847
|
+
const result = await manager.secretFill(input, ctx);
|
|
848
|
+
const card = result?.needsOwner;
|
|
849
|
+
if (card)
|
|
850
|
+
this.#ask(ctx, card);
|
|
851
|
+
return result;
|
|
356
852
|
}
|
|
357
853
|
async secretType(input, ctx) {
|
|
358
|
-
|
|
854
|
+
const manager = await this.#secretRoute(ctx);
|
|
855
|
+
const result = await manager.secretType(input, ctx);
|
|
856
|
+
const card = result?.needsOwner;
|
|
857
|
+
if (card)
|
|
858
|
+
this.#ask(ctx, card);
|
|
859
|
+
return result;
|
|
359
860
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
861
|
+
/**
|
|
862
|
+
* The owner spoke or tapped in a conversation. Every page there gets a
|
|
863
|
+
* fresh budget and its card is answered: Look / Take over hands the page
|
|
864
|
+
* over, Use my Chrome pins the conversation to it, Resume lifts the Stop.
|
|
865
|
+
*/
|
|
866
|
+
async touch(input) {
|
|
867
|
+
const text = input.text ?? '';
|
|
868
|
+
let answered;
|
|
869
|
+
const stopCard = this.#stopCards.get(input.conversationId);
|
|
870
|
+
if (stopCard) {
|
|
871
|
+
const answer = cardAnswer(stopCard, text);
|
|
872
|
+
if (answer)
|
|
873
|
+
this.#stopCards.delete(input.conversationId);
|
|
874
|
+
if (answer === 'resume') {
|
|
875
|
+
await this.control('resume');
|
|
876
|
+
answered = 'resume';
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
for (const route of ROUTES) {
|
|
880
|
+
for (const { child, card } of this.#managers[route].renew(input.conversationId, input.agentId)) {
|
|
881
|
+
if (!card)
|
|
882
|
+
continue;
|
|
883
|
+
const answer = cardAnswer(card, text);
|
|
884
|
+
if (answer === 'takeover') {
|
|
885
|
+
const id = child.status().session?.id;
|
|
886
|
+
if (id) {
|
|
887
|
+
await this.control('takeover', id).catch(() => undefined);
|
|
888
|
+
answered = 'takeover';
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
else if (answer === 'chrome') {
|
|
892
|
+
this.#pins.set(input.conversationId, 'chrome');
|
|
893
|
+
this.#later(this.#savePins());
|
|
894
|
+
const session = child.status().session;
|
|
895
|
+
const last = child.lastUrl;
|
|
896
|
+
if (session && route !== 'chrome') {
|
|
897
|
+
await this.#managers[route].release(input.conversationId, session.agentId);
|
|
898
|
+
for (const [key] of this.#current)
|
|
899
|
+
if (key.endsWith(JSON.stringify(input.conversationId) + ']'))
|
|
900
|
+
this.#current.delete(key);
|
|
901
|
+
if (last)
|
|
902
|
+
this.#managers.chrome.remember(session.agentId, input.conversationId, last);
|
|
903
|
+
}
|
|
904
|
+
answered = 'chrome';
|
|
905
|
+
}
|
|
906
|
+
else if (answer)
|
|
907
|
+
answered = answer;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
return answered ? { answered } : {};
|
|
365
911
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
912
|
+
/** Writes nobody waits for, finished before shutdown so a closing process loses none. */
|
|
913
|
+
#pending = new Set();
|
|
914
|
+
#later(work) {
|
|
915
|
+
const tracked = work.catch(() => undefined).finally(() => { this.#pending.delete(tracked); });
|
|
916
|
+
this.#pending.add(tracked);
|
|
917
|
+
}
|
|
918
|
+
async #savePins() { await this.#writeJson('pins.json', Object.fromEntries(this.#pins)).catch(() => undefined); }
|
|
919
|
+
/** Pin a conversation to a route (`/use browser:chrome`), or clear it with `auto`. */
|
|
920
|
+
async pin(conversationId, pin) {
|
|
921
|
+
if (!PIN_VALUES.includes(pin))
|
|
922
|
+
throw new Error(`A pin is one of ${PIN_VALUES.join(', ')}.`);
|
|
923
|
+
if (pin === 'auto')
|
|
924
|
+
this.#pins.delete(conversationId);
|
|
925
|
+
else
|
|
926
|
+
this.#pins.set(conversationId, pin);
|
|
927
|
+
await this.#savePins();
|
|
928
|
+
return this.status({ conversationId });
|
|
929
|
+
}
|
|
930
|
+
async control(action, sessionId, options = {}) {
|
|
370
931
|
if (!this.#enabled)
|
|
371
|
-
throw new Error('
|
|
372
|
-
if (
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const file = path.join(this.dir, 'settings.json');
|
|
381
|
-
const temp = `${file}.${randomUUID()}.tmp`;
|
|
382
|
-
await writeFile(temp, JSON.stringify(next), { mode: 0o600 });
|
|
383
|
-
await rename(temp, file);
|
|
384
|
-
for (const record of this.#requests.values())
|
|
385
|
-
record.revoked = true;
|
|
386
|
-
await this.#manager.shutdown();
|
|
387
|
-
this.#settings = next;
|
|
388
|
-
this.#manager = this.#create();
|
|
389
|
-
await this.#manager.enable();
|
|
932
|
+
throw new Error('The host browser service is unavailable.');
|
|
933
|
+
if (!sessionId && action === 'stop') {
|
|
934
|
+
// Stop agents' browsing: every page closes, and it expires (an hour by default) unless "until I say".
|
|
935
|
+
const minutes = options.forever ? 0 : this.#settings.stopExpiryMinutes;
|
|
936
|
+
const at = this.#now();
|
|
937
|
+
this.#stop = { at, ...(minutes > 0 ? { until: at + minutes * 60_000 } : {}) };
|
|
938
|
+
await this.#writeJson('control.json', { stopped: true, at, until: this.#stop.until ?? null });
|
|
939
|
+
await Promise.all(ROUTES.map((route) => this.#managers[route].control('stop')));
|
|
940
|
+
this.#current.clear();
|
|
390
941
|
return this.status();
|
|
391
942
|
}
|
|
392
|
-
|
|
393
|
-
this.#
|
|
943
|
+
if (!sessionId && action === 'resume') {
|
|
944
|
+
this.#stop = undefined;
|
|
945
|
+
this.#stopCards.clear();
|
|
946
|
+
await this.#writeJson('control.json', { stopped: false });
|
|
947
|
+
return this.status();
|
|
394
948
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
949
|
+
if (!sessionId) {
|
|
950
|
+
const pages = ROUTES.flatMap((route) => this.#managers[route].pages());
|
|
951
|
+
if (pages.length === 0 && action === 'release')
|
|
952
|
+
return this.status();
|
|
953
|
+
throw new Error('Select a page before using this control.');
|
|
954
|
+
}
|
|
955
|
+
const found = this.#pageOf({ sessionId });
|
|
956
|
+
if (!found)
|
|
957
|
+
throw new Error('That page changed. Refresh before controlling it.');
|
|
958
|
+
if (action === 'takeover') {
|
|
959
|
+
// One page in the owner's hands at a time.
|
|
960
|
+
const held = ROUTES.flatMap((route) => this.#managers[route].pages()).find((page) => page.status().state === 'paused' && page.status().session?.id !== sessionId);
|
|
961
|
+
if (held)
|
|
962
|
+
throw new Error('You already have a page in your hands. Give it back first.');
|
|
963
|
+
}
|
|
964
|
+
const before = found.manager.status({ sessionId });
|
|
965
|
+
await found.manager.control(action, sessionId);
|
|
966
|
+
// Given back: the run that waited on the owner carries on (a parked mission, a held conversation).
|
|
967
|
+
if (action === 'resume' && before.state === 'paused' && before.session) {
|
|
968
|
+
const info = { sessionId, agentId: before.session.agentId, conversationId: before.session.conversationId };
|
|
969
|
+
for (const listener of this.#giveBack) {
|
|
970
|
+
try {
|
|
971
|
+
listener(info);
|
|
972
|
+
}
|
|
973
|
+
catch { /* a listener never fails the give-back */ }
|
|
410
974
|
}
|
|
411
|
-
return this.status();
|
|
412
975
|
}
|
|
413
|
-
|
|
414
|
-
|
|
976
|
+
// The page asked about, not whichever page changed last.
|
|
977
|
+
return this.status({ sessionId });
|
|
978
|
+
}
|
|
979
|
+
/** Hear every give-back of a page the owner held. Returns the unsubscribe. */
|
|
980
|
+
onGiveBack(listener) {
|
|
981
|
+
this.#giveBack.add(listener);
|
|
982
|
+
return () => { this.#giveBack.delete(listener); };
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Change what agents may use. No lock: a page already open keeps working,
|
|
986
|
+
* and turning a route off closes its pages.
|
|
987
|
+
*/
|
|
988
|
+
async configure(input) {
|
|
989
|
+
if (!this.#enabled)
|
|
990
|
+
throw new Error('Host control is unavailable. Start buddi serve.');
|
|
991
|
+
// Removing a sign-in site removes it wherever it is kept: the owner's list and the sites buddi learned.
|
|
992
|
+
let change = input;
|
|
993
|
+
if (change && typeof change === 'object' && !Array.isArray(change) && 'forgetSignInSite' in change) {
|
|
994
|
+
const { forgetSignInSite, ...rest } = change;
|
|
995
|
+
if (typeof forgetSignInSite !== 'string' || forgetSignInSite.trim() === '')
|
|
996
|
+
throw new Error('forgetSignInSite is a site, like amazon.com.');
|
|
997
|
+
const site = forgetSignInSite.trim().toLowerCase();
|
|
998
|
+
if (this.#learned.delete(site))
|
|
999
|
+
await this.#saveLearned();
|
|
1000
|
+
const listed = Array.isArray(rest.signInSites) ? rest.signInSites : this.#settings.signInSites;
|
|
1001
|
+
change = { ...rest, signInSites: listed.filter((entry) => entry !== site) };
|
|
415
1002
|
}
|
|
1003
|
+
const next = applySettingsChange(this.#settings, change);
|
|
1004
|
+
if (next.yourApps !== 'off' && this.#settings.yourApps === 'off' && !this.#pluginApps() && !this.options.drivers?.apps)
|
|
1005
|
+
throw new Error('Your apps need the Computer plugin. Install it from Settings → Plugins first.');
|
|
1006
|
+
const chromeOff = this.#settings.yourChrome && !next.yourChrome;
|
|
1007
|
+
const appsOff = this.#settings.yourApps !== 'off' && next.yourApps === 'off';
|
|
1008
|
+
await this.#writeSettings(next);
|
|
1009
|
+
if (chromeOff)
|
|
1010
|
+
await this.#managers.chrome.control('stop');
|
|
1011
|
+
if (appsOff)
|
|
1012
|
+
await this.#managers.apps.control('stop');
|
|
1013
|
+
for (const [key, route] of this.#current)
|
|
1014
|
+
if ((chromeOff && route === 'chrome') || (appsOff && route === 'apps'))
|
|
1015
|
+
this.#current.delete(key);
|
|
1016
|
+
return this.status();
|
|
1017
|
+
}
|
|
1018
|
+
async shutdown() {
|
|
1019
|
+
this.#enabled = false;
|
|
1020
|
+
this.logins.clear();
|
|
1021
|
+
await Promise.all(ROUTES.map((route) => this.#managers[route].shutdown()));
|
|
1022
|
+
await Promise.all([...this.#pending]);
|
|
416
1023
|
}
|
|
417
|
-
async shutdown() { this.#enabled = false; await this.#manager.shutdown(); }
|
|
418
1024
|
}
|
|
419
1025
|
//# sourceMappingURL=controller.js.map
|