@withbuddi/buddi 0.1.0-pre.36 → 0.1.0-pre.38
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/examples/agents/concierge/agent.md +5 -0
- package/examples/skills/letterhead/SKILL.md +21 -0
- package/examples/skills/letterhead/assets/letterhead.md +16 -0
- package/examples/skills/letterhead/assets/logo.svg +6 -0
- package/extension/background.js +130 -12
- 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 +160 -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 +29 -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 +28 -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 +90 -30
- package/node_modules/@buddi/cli/dist/doctor-probes.js.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor.d.ts +61 -12
- package/node_modules/@buddi/cli/dist/doctor.d.ts.map +1 -1
- package/node_modules/@buddi/cli/dist/doctor.js +60 -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 +18 -1
- 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/actions/approvals.d.ts +7 -0
- package/node_modules/@buddi/core/dist/actions/approvals.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/actions/approvals.js +11 -1
- package/node_modules/@buddi/core/dist/actions/approvals.js.map +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 +3 -2
- 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/agents/skills.d.ts +60 -1
- package/node_modules/@buddi/core/dist/agents/skills.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/agents/skills.js +157 -17
- package/node_modules/@buddi/core/dist/agents/skills.js.map +1 -1
- package/node_modules/@buddi/core/dist/day-month.d.ts +52 -0
- package/node_modules/@buddi/core/dist/day-month.d.ts.map +1 -0
- package/node_modules/@buddi/core/dist/day-month.js +101 -0
- package/node_modules/@buddi/core/dist/day-month.js.map +1 -0
- package/node_modules/@buddi/core/dist/host/build.d.ts +11 -2
- package/node_modules/@buddi/core/dist/host/build.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/host/build.js +115 -4
- package/node_modules/@buddi/core/dist/host/build.js.map +1 -1
- package/node_modules/@buddi/core/dist/host/http.d.ts +35 -0
- package/node_modules/@buddi/core/dist/host/http.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/host/http.js +133 -29
- package/node_modules/@buddi/core/dist/host/http.js.map +1 -1
- package/node_modules/@buddi/core/dist/host/types.d.ts +72 -1
- package/node_modules/@buddi/core/dist/host/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/index.d.ts +3 -0
- package/node_modules/@buddi/core/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/index.js +3 -0
- package/node_modules/@buddi/core/dist/index.js.map +1 -1
- package/node_modules/@buddi/core/dist/onboarding/store.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/onboarding/store.js +28 -5
- package/node_modules/@buddi/core/dist/onboarding/store.js.map +1 -1
- package/node_modules/@buddi/core/dist/onboarding/types.d.ts +10 -0
- package/node_modules/@buddi/core/dist/onboarding/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/onboarding/types.js.map +1 -1
- package/node_modules/@buddi/core/dist/pages.d.ts +145 -11
- package/node_modules/@buddi/core/dist/pages.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/pages.js +113 -5
- package/node_modules/@buddi/core/dist/pages.js.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/index.d.ts +7 -0
- package/node_modules/@buddi/core/dist/plugin/index.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/index.js +5 -0
- package/node_modules/@buddi/core/dist/plugin/index.js.map +1 -1
- package/node_modules/@buddi/core/dist/plugin/sign-in.d.ts +78 -0
- package/node_modules/@buddi/core/dist/plugin/sign-in.d.ts.map +1 -0
- package/node_modules/@buddi/core/dist/plugin/sign-in.js +54 -0
- package/node_modules/@buddi/core/dist/plugin/sign-in.js.map +1 -0
- 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/provider-accounts.d.ts +7 -0
- package/node_modules/@buddi/core/dist/provider-accounts.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/provider-accounts.js +15 -0
- package/node_modules/@buddi/core/dist/provider-accounts.js.map +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 +9 -1
- package/node_modules/@buddi/core/dist/questions/types.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/questions/types.js +16 -1
- package/node_modules/@buddi/core/dist/questions/types.js.map +1 -1
- package/node_modules/@buddi/core/dist/queue/jobs.d.ts +65 -2
- package/node_modules/@buddi/core/dist/queue/jobs.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/queue/jobs.js +123 -3
- package/node_modules/@buddi/core/dist/queue/jobs.js.map +1 -1
- package/node_modules/@buddi/core/dist/queue/worker.d.ts +26 -2
- package/node_modules/@buddi/core/dist/queue/worker.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/queue/worker.js +68 -12
- package/node_modules/@buddi/core/dist/queue/worker.js.map +1 -1
- package/node_modules/@buddi/core/dist/registry.d.ts +15 -1
- package/node_modules/@buddi/core/dist/registry.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/registry.js +88 -13
- 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/secrets/scrub.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/secrets/scrub.js +15 -0
- package/node_modules/@buddi/core/dist/secrets/scrub.js.map +1 -1
- package/node_modules/@buddi/core/dist/tools.d.ts +88 -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/dist/views.d.ts +12 -12
- package/node_modules/@buddi/core/dist/widgets.d.ts +14 -1
- package/node_modules/@buddi/core/dist/widgets.d.ts.map +1 -1
- package/node_modules/@buddi/core/dist/widgets.js +30 -0
- package/node_modules/@buddi/core/dist/widgets.js.map +1 -1
- package/node_modules/@buddi/core/migrations/074_owner_identity.sql +14 -0
- 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/catalog.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/catalog.js +3 -3
- package/node_modules/@buddi/gateway/dist/agents/catalog.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/catalogue-package.d.ts +46 -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 +17 -4
- 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/owner-tools.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/owner-tools.js +36 -2
- package/node_modules/@buddi/gateway/dist/agents/owner-tools.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.d.ts +26 -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 +123 -6
- package/node_modules/@buddi/gateway/dist/agents/platform-catalogue.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform.d.ts +4 -4
- package/node_modules/@buddi/gateway/dist/agents/platform.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/agents/platform.js +11 -0
- package/node_modules/@buddi/gateway/dist/agents/platform.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/bootstrap.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/bootstrap.js +12 -1
- 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/evals/golden.d.ts +33 -1
- package/node_modules/@buddi/gateway/dist/evals/golden.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/evals/golden.js +168 -3
- package/node_modules/@buddi/gateway/dist/evals/golden.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.d.ts +3 -1
- package/node_modules/@buddi/gateway/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/index.js +3 -1
- package/node_modules/@buddi/gateway/dist/index.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/dates.d.ts +98 -0
- package/node_modules/@buddi/gateway/dist/missions/dates.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions/dates.js +252 -0
- package/node_modules/@buddi/gateway/dist/missions/dates.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions/execute.d.ts +42 -1
- package/node_modules/@buddi/gateway/dist/missions/execute.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/execute.js +107 -8
- package/node_modules/@buddi/gateway/dist/missions/execute.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/parked.d.ts +133 -0
- package/node_modules/@buddi/gateway/dist/missions/parked.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions/parked.js +249 -0
- package/node_modules/@buddi/gateway/dist/missions/parked.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/missions/report.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/missions/report.js +1 -0
- package/node_modules/@buddi/gateway/dist/missions/report.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/ollama-local.d.ts +90 -0
- package/node_modules/@buddi/gateway/dist/ollama-local.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/ollama-local.js +201 -0
- package/node_modules/@buddi/gateway/dist/ollama-local.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/plugins-cli.d.ts +8 -0
- package/node_modules/@buddi/gateway/dist/plugins-cli.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/plugins-cli.js +22 -1
- package/node_modules/@buddi/gateway/dist/plugins-cli.js.map +1 -1
- 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 +99 -14
- 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/surfaces/pending-question.js +2 -2
- package/node_modules/@buddi/gateway/dist/system-context.d.ts +21 -1
- package/node_modules/@buddi/gateway/dist/system-context.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/system-context.js +75 -2
- package/node_modules/@buddi/gateway/dist/system-context.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/approvals.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/approvals.js +4 -2
- package/node_modules/@buddi/gateway/dist/telegram/approvals.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 +23 -2
- package/node_modules/@buddi/gateway/dist/telegram/channel.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/html.d.ts +34 -0
- package/node_modules/@buddi/gateway/dist/telegram/html.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/telegram/html.js +263 -0
- package/node_modules/@buddi/gateway/dist/telegram/html.js.map +1 -0
- 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/notify.d.ts +6 -0
- package/node_modules/@buddi/gateway/dist/telegram/notify.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/telegram/notify.js +25 -3
- package/node_modules/@buddi/gateway/dist/telegram/notify.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 +10 -0
- package/node_modules/@buddi/gateway/dist/tips/facts.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/tips/facts.js +12 -3
- 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 +25 -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 +168 -26
- package/node_modules/@buddi/gateway/dist/web/api-routes.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/api-scan.d.ts +1 -1
- package/node_modules/@buddi/gateway/dist/web/api-scan.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/api-scan.js +1 -0
- package/node_modules/@buddi/gateway/dist/web/api-scan.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 +71 -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/composer.d.ts +45 -0
- package/node_modules/@buddi/gateway/dist/web/composer.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/composer.js +85 -0
- package/node_modules/@buddi/gateway/dist/web/composer.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/extension.d.ts +9 -1
- package/node_modules/@buddi/gateway/dist/web/extension.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/extension.js +61 -1
- 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/market.d.ts +20 -1
- package/node_modules/@buddi/gateway/dist/web/market.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/market.js +41 -1
- package/node_modules/@buddi/gateway/dist/web/market.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/people.d.ts +44 -0
- package/node_modules/@buddi/gateway/dist/web/people.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/people.js +114 -0
- package/node_modules/@buddi/gateway/dist/web/people.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/server.d.ts +42 -2
- package/node_modules/@buddi/gateway/dist/web/server.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/server.js +713 -156
- 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/skill-bundles.d.ts +101 -0
- package/node_modules/@buddi/gateway/dist/web/skill-bundles.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/skill-bundles.js +439 -0
- package/node_modules/@buddi/gateway/dist/web/skill-bundles.js.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/skills.d.ts +57 -1
- package/node_modules/@buddi/gateway/dist/web/skills.d.ts.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/skills.js +171 -9
- package/node_modules/@buddi/gateway/dist/web/skills.js.map +1 -1
- package/node_modules/@buddi/gateway/dist/web/zip-read.d.ts +31 -0
- package/node_modules/@buddi/gateway/dist/web/zip-read.d.ts.map +1 -0
- package/node_modules/@buddi/gateway/dist/web/zip-read.js +125 -0
- package/node_modules/@buddi/gateway/dist/web/zip-read.js.map +1 -0
- package/node_modules/@buddi/install/dist/.tsbuildinfo +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/index.d.ts +1 -0
- package/node_modules/@buddi/runtime/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/runtime/dist/index.js +1 -0
- package/node_modules/@buddi/runtime/dist/index.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 +29 -5
- package/node_modules/@buddi/runtime/dist/loop.js.map +1 -1
- package/node_modules/@buddi/runtime/dist/plugin-sign-in.d.ts +12 -0
- package/node_modules/@buddi/runtime/dist/plugin-sign-in.d.ts.map +1 -0
- package/node_modules/@buddi/runtime/dist/plugin-sign-in.js +397 -0
- package/node_modules/@buddi/runtime/dist/plugin-sign-in.js.map +1 -0
- package/node_modules/@buddi/tool-artifacts/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-artifacts/dist/tools/write.d.ts.map +1 -1
- package/node_modules/@buddi/tool-artifacts/dist/tools/write.js +1 -0
- package/node_modules/@buddi/tool-artifacts/dist/tools/write.js.map +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 +76 -58
- package/node_modules/@buddi/tool-browser/dist/controller.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/controller.js +751 -219
- package/node_modules/@buddi/tool-browser/dist/controller.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/extension.d.ts +12 -0
- package/node_modules/@buddi/tool-browser/dist/extension.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/extension.js +8 -0
- package/node_modules/@buddi/tool-browser/dist/extension.js.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/index.d.ts +13 -5
- package/node_modules/@buddi/tool-browser/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/index.js +29 -12
- package/node_modules/@buddi/tool-browser/dist/index.js.map +1 -1
- 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 +130 -0
- package/node_modules/@buddi/tool-browser/dist/routes.d.ts.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/routes.js +283 -0
- package/node_modules/@buddi/tool-browser/dist/routes.js.map +1 -0
- package/node_modules/@buddi/tool-browser/dist/service.d.ts +157 -114
- package/node_modules/@buddi/tool-browser/dist/service.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/service.js +379 -390
- 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 +14 -3
- package/node_modules/@buddi/tool-browser/dist/types.d.ts.map +1 -1
- package/node_modules/@buddi/tool-browser/dist/types.js +9 -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-email/dist/widgets.d.ts.map +1 -1
- package/node_modules/@buddi/tool-email/dist/widgets.js +2 -1
- package/node_modules/@buddi/tool-email/dist/widgets.js.map +1 -1
- package/node_modules/@buddi/tool-host/dist/.tsbuildinfo +1 -1
- package/node_modules/@buddi/tool-host/dist/index.d.ts +2 -1
- package/node_modules/@buddi/tool-host/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/tool-host/dist/index.js +3 -2
- package/node_modules/@buddi/tool-host/dist/index.js.map +1 -1
- package/node_modules/@buddi/tool-host/dist/process.d.ts +4 -0
- package/node_modules/@buddi/tool-host/dist/process.d.ts.map +1 -1
- package/node_modules/@buddi/tool-host/dist/process.js +4 -2
- package/node_modules/@buddi/tool-host/dist/process.js.map +1 -1
- package/node_modules/@buddi/tool-host/dist/service.d.ts +66 -17
- package/node_modules/@buddi/tool-host/dist/service.d.ts.map +1 -1
- package/node_modules/@buddi/tool-host/dist/service.js +172 -9
- package/node_modules/@buddi/tool-host/dist/service.js.map +1 -1
- package/node_modules/@buddi/tool-host/dist/skill-run.d.ts +55 -0
- package/node_modules/@buddi/tool-host/dist/skill-run.d.ts.map +1 -0
- package/node_modules/@buddi/tool-host/dist/skill-run.js +132 -0
- package/node_modules/@buddi/tool-host/dist/skill-run.js.map +1 -0
- 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-memory/dist/index.d.ts +1 -0
- package/node_modules/@buddi/tool-memory/dist/index.d.ts.map +1 -1
- package/node_modules/@buddi/tool-memory/dist/index.js +7 -2
- package/node_modules/@buddi/tool-memory/dist/index.js.map +1 -1
- package/node_modules/@buddi/tool-memory/dist/people.d.ts +218 -0
- package/node_modules/@buddi/tool-memory/dist/people.d.ts.map +1 -0
- package/node_modules/@buddi/tool-memory/dist/people.js +582 -0
- package/node_modules/@buddi/tool-memory/dist/people.js.map +1 -0
- package/node_modules/@buddi/tool-memory/dist/preamble.d.ts +4 -1
- package/node_modules/@buddi/tool-memory/dist/preamble.d.ts.map +1 -1
- package/node_modules/@buddi/tool-memory/dist/preamble.js +25 -7
- package/node_modules/@buddi/tool-memory/dist/preamble.js.map +1 -1
- package/node_modules/@buddi/tool-memory/migrations/002_people.sql +40 -0
- package/node_modules/@buddi/tool-web/dist/.tsbuildinfo +1 -1
- package/node_modules/imapflow/CHANGELOG.md +23 -0
- package/node_modules/imapflow/dist/cjs/commands/append.js +27 -3
- package/node_modules/imapflow/dist/cjs/commands/store.js +31 -6
- package/node_modules/imapflow/dist/cjs/imap-flow.d.ts +1 -1
- package/node_modules/imapflow/dist/cjs/imap-flow.js +1 -1
- 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/commands/append.js +27 -3
- package/node_modules/imapflow/dist/esm/commands/store.js +31 -6
- package/node_modules/imapflow/dist/esm/imap-flow.d.ts +1 -1
- package/node_modules/imapflow/dist/esm/imap-flow.js +1 -1
- 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 +3 -3
- 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 +160 -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 +29 -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 +28 -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 +90 -30
- package/packages/cli/dist/doctor-probes.js.map +1 -1
- package/packages/cli/dist/doctor.d.ts +61 -12
- package/packages/cli/dist/doctor.d.ts.map +1 -1
- package/packages/cli/dist/doctor.js +60 -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 +18 -1
- package/packages/cli/dist/main.js.map +1 -1
- package/packages/core/dist/.tsbuildinfo +1 -1
- package/packages/core/dist/actions/approvals.d.ts +7 -0
- package/packages/core/dist/actions/approvals.d.ts.map +1 -1
- package/packages/core/dist/actions/approvals.js +11 -1
- package/packages/core/dist/actions/approvals.js.map +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 +3 -2
- 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/agents/skills.d.ts +60 -1
- package/packages/core/dist/agents/skills.d.ts.map +1 -1
- package/packages/core/dist/agents/skills.js +157 -17
- package/packages/core/dist/agents/skills.js.map +1 -1
- package/packages/core/dist/day-month.d.ts +52 -0
- package/packages/core/dist/day-month.d.ts.map +1 -0
- package/packages/core/dist/day-month.js +101 -0
- package/packages/core/dist/day-month.js.map +1 -0
- package/packages/core/dist/host/build.d.ts +11 -2
- package/packages/core/dist/host/build.d.ts.map +1 -1
- package/packages/core/dist/host/build.js +115 -4
- package/packages/core/dist/host/build.js.map +1 -1
- package/packages/core/dist/host/http.d.ts +35 -0
- package/packages/core/dist/host/http.d.ts.map +1 -1
- package/packages/core/dist/host/http.js +133 -29
- package/packages/core/dist/host/http.js.map +1 -1
- package/packages/core/dist/host/types.d.ts +72 -1
- package/packages/core/dist/host/types.d.ts.map +1 -1
- package/packages/core/dist/index.d.ts +3 -0
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +3 -0
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/onboarding/store.d.ts.map +1 -1
- package/packages/core/dist/onboarding/store.js +28 -5
- package/packages/core/dist/onboarding/store.js.map +1 -1
- package/packages/core/dist/onboarding/types.d.ts +10 -0
- package/packages/core/dist/onboarding/types.d.ts.map +1 -1
- package/packages/core/dist/onboarding/types.js.map +1 -1
- package/packages/core/dist/pages.d.ts +145 -11
- package/packages/core/dist/pages.d.ts.map +1 -1
- package/packages/core/dist/pages.js +113 -5
- package/packages/core/dist/pages.js.map +1 -1
- package/packages/core/dist/plugin/index.d.ts +7 -0
- package/packages/core/dist/plugin/index.d.ts.map +1 -1
- package/packages/core/dist/plugin/index.js +5 -0
- package/packages/core/dist/plugin/index.js.map +1 -1
- package/packages/core/dist/plugin/sign-in.d.ts +78 -0
- package/packages/core/dist/plugin/sign-in.d.ts.map +1 -0
- package/packages/core/dist/plugin/sign-in.js +54 -0
- package/packages/core/dist/plugin/sign-in.js.map +1 -0
- package/packages/core/dist/plugin/version.d.ts +1 -1
- package/packages/core/dist/plugin/version.js +1 -1
- package/packages/core/dist/provider-accounts.d.ts +7 -0
- package/packages/core/dist/provider-accounts.d.ts.map +1 -1
- package/packages/core/dist/provider-accounts.js +15 -0
- package/packages/core/dist/provider-accounts.js.map +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 +9 -1
- package/packages/core/dist/questions/types.d.ts.map +1 -1
- package/packages/core/dist/questions/types.js +16 -1
- package/packages/core/dist/questions/types.js.map +1 -1
- package/packages/core/dist/queue/jobs.d.ts +65 -2
- package/packages/core/dist/queue/jobs.d.ts.map +1 -1
- package/packages/core/dist/queue/jobs.js +123 -3
- package/packages/core/dist/queue/jobs.js.map +1 -1
- package/packages/core/dist/queue/worker.d.ts +26 -2
- package/packages/core/dist/queue/worker.d.ts.map +1 -1
- package/packages/core/dist/queue/worker.js +68 -12
- package/packages/core/dist/queue/worker.js.map +1 -1
- package/packages/core/dist/registry.d.ts +15 -1
- package/packages/core/dist/registry.d.ts.map +1 -1
- package/packages/core/dist/registry.js +88 -13
- 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/secrets/scrub.d.ts.map +1 -1
- package/packages/core/dist/secrets/scrub.js +15 -0
- package/packages/core/dist/secrets/scrub.js.map +1 -1
- package/packages/core/dist/tools.d.ts +88 -2
- package/packages/core/dist/tools.d.ts.map +1 -1
- package/packages/core/dist/tools.js.map +1 -1
- package/packages/core/dist/views.d.ts +12 -12
- package/packages/core/dist/widgets.d.ts +14 -1
- package/packages/core/dist/widgets.d.ts.map +1 -1
- package/packages/core/dist/widgets.js +30 -0
- package/packages/core/dist/widgets.js.map +1 -1
- package/packages/core/migrations/074_owner_identity.sql +14 -0
- 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/catalog.d.ts.map +1 -1
- package/packages/gateway/dist/agents/catalog.js +3 -3
- package/packages/gateway/dist/agents/catalog.js.map +1 -1
- package/packages/gateway/dist/agents/catalogue-package.d.ts +46 -20
- package/packages/gateway/dist/agents/catalogue-package.d.ts.map +1 -1
- package/packages/gateway/dist/agents/catalogue-package.js +17 -4
- 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/owner-tools.d.ts.map +1 -1
- package/packages/gateway/dist/agents/owner-tools.js +36 -2
- package/packages/gateway/dist/agents/owner-tools.js.map +1 -1
- package/packages/gateway/dist/agents/platform-catalogue.d.ts +26 -1
- package/packages/gateway/dist/agents/platform-catalogue.d.ts.map +1 -1
- package/packages/gateway/dist/agents/platform-catalogue.js +123 -6
- package/packages/gateway/dist/agents/platform-catalogue.js.map +1 -1
- package/packages/gateway/dist/agents/platform.d.ts +4 -4
- package/packages/gateway/dist/agents/platform.d.ts.map +1 -1
- package/packages/gateway/dist/agents/platform.js +11 -0
- package/packages/gateway/dist/agents/platform.js.map +1 -1
- package/packages/gateway/dist/bootstrap.d.ts.map +1 -1
- package/packages/gateway/dist/bootstrap.js +12 -1
- 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/evals/golden.d.ts +33 -1
- package/packages/gateway/dist/evals/golden.d.ts.map +1 -1
- package/packages/gateway/dist/evals/golden.js +168 -3
- package/packages/gateway/dist/evals/golden.js.map +1 -1
- package/packages/gateway/dist/index.d.ts +3 -1
- package/packages/gateway/dist/index.d.ts.map +1 -1
- package/packages/gateway/dist/index.js +3 -1
- package/packages/gateway/dist/index.js.map +1 -1
- package/packages/gateway/dist/missions/dates.d.ts +98 -0
- package/packages/gateway/dist/missions/dates.d.ts.map +1 -0
- package/packages/gateway/dist/missions/dates.js +252 -0
- package/packages/gateway/dist/missions/dates.js.map +1 -0
- package/packages/gateway/dist/missions/execute.d.ts +42 -1
- package/packages/gateway/dist/missions/execute.d.ts.map +1 -1
- package/packages/gateway/dist/missions/execute.js +107 -8
- package/packages/gateway/dist/missions/execute.js.map +1 -1
- package/packages/gateway/dist/missions/parked.d.ts +133 -0
- package/packages/gateway/dist/missions/parked.d.ts.map +1 -0
- package/packages/gateway/dist/missions/parked.js +249 -0
- package/packages/gateway/dist/missions/parked.js.map +1 -0
- package/packages/gateway/dist/missions/report.d.ts.map +1 -1
- package/packages/gateway/dist/missions/report.js +1 -0
- package/packages/gateway/dist/missions/report.js.map +1 -1
- package/packages/gateway/dist/ollama-local.d.ts +90 -0
- package/packages/gateway/dist/ollama-local.d.ts.map +1 -0
- package/packages/gateway/dist/ollama-local.js +201 -0
- package/packages/gateway/dist/ollama-local.js.map +1 -0
- package/packages/gateway/dist/plugins-cli.d.ts +8 -0
- package/packages/gateway/dist/plugins-cli.d.ts.map +1 -1
- package/packages/gateway/dist/plugins-cli.js +22 -1
- package/packages/gateway/dist/plugins-cli.js.map +1 -1
- 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 +99 -14
- 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/surfaces/pending-question.js +2 -2
- package/packages/gateway/dist/system-context.d.ts +21 -1
- package/packages/gateway/dist/system-context.d.ts.map +1 -1
- package/packages/gateway/dist/system-context.js +75 -2
- package/packages/gateway/dist/system-context.js.map +1 -1
- package/packages/gateway/dist/telegram/approvals.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/approvals.js +4 -2
- package/packages/gateway/dist/telegram/approvals.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 +23 -2
- package/packages/gateway/dist/telegram/channel.js.map +1 -1
- package/packages/gateway/dist/telegram/html.d.ts +34 -0
- package/packages/gateway/dist/telegram/html.d.ts.map +1 -0
- package/packages/gateway/dist/telegram/html.js +263 -0
- package/packages/gateway/dist/telegram/html.js.map +1 -0
- 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/notify.d.ts +6 -0
- package/packages/gateway/dist/telegram/notify.d.ts.map +1 -1
- package/packages/gateway/dist/telegram/notify.js +25 -3
- package/packages/gateway/dist/telegram/notify.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 +10 -0
- package/packages/gateway/dist/tips/facts.d.ts.map +1 -1
- package/packages/gateway/dist/tips/facts.js +12 -3
- 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 +25 -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 +168 -26
- package/packages/gateway/dist/web/api-routes.js.map +1 -1
- package/packages/gateway/dist/web/api-scan.d.ts +1 -1
- package/packages/gateway/dist/web/api-scan.d.ts.map +1 -1
- package/packages/gateway/dist/web/api-scan.js +1 -0
- package/packages/gateway/dist/web/api-scan.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 +71 -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/composer.d.ts +45 -0
- package/packages/gateway/dist/web/composer.d.ts.map +1 -0
- package/packages/gateway/dist/web/composer.js +85 -0
- package/packages/gateway/dist/web/composer.js.map +1 -0
- package/packages/gateway/dist/web/extension.d.ts +9 -1
- package/packages/gateway/dist/web/extension.d.ts.map +1 -1
- package/packages/gateway/dist/web/extension.js +61 -1
- 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/market.d.ts +20 -1
- package/packages/gateway/dist/web/market.d.ts.map +1 -1
- package/packages/gateway/dist/web/market.js +41 -1
- package/packages/gateway/dist/web/market.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/people.d.ts +44 -0
- package/packages/gateway/dist/web/people.d.ts.map +1 -0
- package/packages/gateway/dist/web/people.js +114 -0
- package/packages/gateway/dist/web/people.js.map +1 -0
- package/packages/gateway/dist/web/server.d.ts +42 -2
- package/packages/gateway/dist/web/server.d.ts.map +1 -1
- package/packages/gateway/dist/web/server.js +713 -156
- 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/skill-bundles.d.ts +101 -0
- package/packages/gateway/dist/web/skill-bundles.d.ts.map +1 -0
- package/packages/gateway/dist/web/skill-bundles.js +439 -0
- package/packages/gateway/dist/web/skill-bundles.js.map +1 -0
- package/packages/gateway/dist/web/skills.d.ts +57 -1
- package/packages/gateway/dist/web/skills.d.ts.map +1 -1
- package/packages/gateway/dist/web/skills.js +171 -9
- package/packages/gateway/dist/web/skills.js.map +1 -1
- package/packages/gateway/dist/web/zip-read.d.ts +31 -0
- package/packages/gateway/dist/web/zip-read.d.ts.map +1 -0
- package/packages/gateway/dist/web/zip-read.js +125 -0
- package/packages/gateway/dist/web/zip-read.js.map +1 -0
- package/packages/install/dist/.tsbuildinfo +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/index.d.ts +1 -0
- package/packages/runtime/dist/index.d.ts.map +1 -1
- package/packages/runtime/dist/index.js +1 -0
- package/packages/runtime/dist/index.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 +29 -5
- package/packages/runtime/dist/loop.js.map +1 -1
- package/packages/runtime/dist/plugin-sign-in.d.ts +12 -0
- package/packages/runtime/dist/plugin-sign-in.d.ts.map +1 -0
- package/packages/runtime/dist/plugin-sign-in.js +397 -0
- package/packages/runtime/dist/plugin-sign-in.js.map +1 -0
- package/packages/tools/artifacts/dist/.tsbuildinfo +1 -1
- package/packages/tools/artifacts/dist/tools/write.d.ts.map +1 -1
- package/packages/tools/artifacts/dist/tools/write.js +1 -0
- package/packages/tools/artifacts/dist/tools/write.js.map +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 +76 -58
- package/packages/tools/browser/dist/controller.d.ts.map +1 -1
- package/packages/tools/browser/dist/controller.js +751 -219
- package/packages/tools/browser/dist/controller.js.map +1 -1
- package/packages/tools/browser/dist/extension.d.ts +12 -0
- package/packages/tools/browser/dist/extension.d.ts.map +1 -1
- package/packages/tools/browser/dist/extension.js +8 -0
- package/packages/tools/browser/dist/extension.js.map +1 -1
- package/packages/tools/browser/dist/index.d.ts +13 -5
- package/packages/tools/browser/dist/index.d.ts.map +1 -1
- package/packages/tools/browser/dist/index.js +29 -12
- package/packages/tools/browser/dist/index.js.map +1 -1
- 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 +130 -0
- package/packages/tools/browser/dist/routes.d.ts.map +1 -0
- package/packages/tools/browser/dist/routes.js +283 -0
- package/packages/tools/browser/dist/routes.js.map +1 -0
- package/packages/tools/browser/dist/service.d.ts +157 -114
- package/packages/tools/browser/dist/service.d.ts.map +1 -1
- package/packages/tools/browser/dist/service.js +379 -390
- 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 +14 -3
- package/packages/tools/browser/dist/types.d.ts.map +1 -1
- package/packages/tools/browser/dist/types.js +9 -9
- package/packages/tools/browser/dist/types.js.map +1 -1
- package/packages/tools/email/dist/.tsbuildinfo +1 -1
- package/packages/tools/email/dist/widgets.d.ts.map +1 -1
- package/packages/tools/email/dist/widgets.js +2 -1
- package/packages/tools/email/dist/widgets.js.map +1 -1
- package/packages/tools/host/dist/.tsbuildinfo +1 -1
- package/packages/tools/host/dist/index.d.ts +2 -1
- package/packages/tools/host/dist/index.d.ts.map +1 -1
- package/packages/tools/host/dist/index.js +3 -2
- package/packages/tools/host/dist/index.js.map +1 -1
- package/packages/tools/host/dist/process.d.ts +4 -0
- package/packages/tools/host/dist/process.d.ts.map +1 -1
- package/packages/tools/host/dist/process.js +4 -2
- package/packages/tools/host/dist/process.js.map +1 -1
- package/packages/tools/host/dist/service.d.ts +66 -17
- package/packages/tools/host/dist/service.d.ts.map +1 -1
- package/packages/tools/host/dist/service.js +172 -9
- package/packages/tools/host/dist/service.js.map +1 -1
- package/packages/tools/host/dist/skill-run.d.ts +55 -0
- package/packages/tools/host/dist/skill-run.d.ts.map +1 -0
- package/packages/tools/host/dist/skill-run.js +132 -0
- package/packages/tools/host/dist/skill-run.js.map +1 -0
- package/packages/tools/mcp/dist/.tsbuildinfo +1 -1
- package/packages/tools/memory/dist/.tsbuildinfo +1 -1
- package/packages/tools/memory/dist/index.d.ts +1 -0
- package/packages/tools/memory/dist/index.d.ts.map +1 -1
- package/packages/tools/memory/dist/index.js +7 -2
- package/packages/tools/memory/dist/index.js.map +1 -1
- package/packages/tools/memory/dist/people.d.ts +218 -0
- package/packages/tools/memory/dist/people.d.ts.map +1 -0
- package/packages/tools/memory/dist/people.js +582 -0
- package/packages/tools/memory/dist/people.js.map +1 -0
- package/packages/tools/memory/dist/preamble.d.ts +4 -1
- package/packages/tools/memory/dist/preamble.d.ts.map +1 -1
- package/packages/tools/memory/dist/preamble.js +25 -7
- package/packages/tools/memory/dist/preamble.js.map +1 -1
- package/packages/tools/memory/migrations/002_people.sql +40 -0
- package/packages/tools/web/dist/.tsbuildinfo +1 -1
- package/packages/web/dist/assets/index-Bac-CdD-.css +1 -0
- package/packages/web/dist/assets/index-DI8bp_D7.js +146 -0
- package/packages/web/dist/assets/{lottie_light-Dj5SSwxs.js → lottie_light-CuiSMqnl.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/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-B_P_ux2I.css +0 -1
- package/packages/web/dist/assets/index-CjOzIGL7.js +0 -134
|
@@ -46,7 +46,8 @@ import { agentMuteRoute, focusRoute, listNotificationsRoute, markSeenRoute, noti
|
|
|
46
46
|
import { catalogSkillLookup, discardProposalFromWeb, keepAllProposalsFromWeb, keepProposalFromWeb, readProposals, registryChangeLookup } from './proposals.js';
|
|
47
47
|
import { latestDigest, readDigestSchedule, setDigestSchedule } from '../agents/learning-digest.js';
|
|
48
48
|
import { readAgentSkills, removeLearnedSkillFromWeb } from '../agents/learned-skills.js';
|
|
49
|
-
import { createSkillRoute, deleteSkillRoute, editSkillRoute, grantSkillRoute, listSkillsRoute, skillDetailRoute, skillDownload, trustSkillRoute, } from './skills.js';
|
|
49
|
+
import { createSkillRoute, deleteSkillRoute, editSkillRoute, grantSkillRoute, listSkillsRoute, skillDetailRoute, skillDownload, skillFileRoute, skillImage, stagedFileRoute, stagedImage, acceptBundleRoute, trustSkillRoute, } from './skills.js';
|
|
50
|
+
import { discardStaged, incomingDirFor, receiveBundleUpload, stageBundle, uploadLabel } from './skill-bundles.js';
|
|
50
51
|
import { bindMcpRequests, requestThroughMcp } from '../mcp/requests.js';
|
|
51
52
|
import { randomUUID, createHmac, createHash } from 'node:crypto';
|
|
52
53
|
import { StringDecoder } from 'node:string_decoder';
|
|
@@ -55,18 +56,18 @@ import { carryOverDeps } from '../surfaces/carry-over.js';
|
|
|
55
56
|
import { deleteCarryOver } from '../surfaces/browser-handoff.js';
|
|
56
57
|
import { ProviderSettingsError } from '../providers.js';
|
|
57
58
|
import { ProviderAccountError } from '../provider-accounts.js';
|
|
58
|
-
import { listBrowserProfiles, listInstalledApps } from './apps.js';
|
|
59
59
|
import { agentSearchPath, EXAMPLES_AGENTS_DIR } from '../agents/catalog.js';
|
|
60
60
|
import { setDelegatesFromWeb } from './write.js';
|
|
61
61
|
import { mlxhBaseUrl, probeMlxh } from '../mlxh.js';
|
|
62
|
-
import {
|
|
62
|
+
import { PullRefusal, createOllamaPulls, ollamaMachine } from '../ollama-local.js';
|
|
63
|
+
import { OnboardingRefusal, WEB_ONBOARDING_STEPS, WEB_ONBOARDING_SURFACE, claimOpeningTurn, createFirstAgent, OLLAMA_BASE_URL, probeOllama, readOnboarding, rebindBrain, updateFirstAgent, withFirstRunFacts, readFirstAgentPersona } from './onboarding.js';
|
|
63
64
|
import { TakeOnRefusal, readTakeOn, startTakeOn } from './take-on.js';
|
|
64
65
|
import { TelegramWebError, saveTelegramToken, telegramBot, telegramDevices, telegramPairing, telegramStatus, unpairTelegramDevice, } from './telegram.js';
|
|
65
66
|
import { PAGE_ROUTE, sendPageFile, actOnPage, actRateLimited, listPageDescriptors, runPageQuery, } from './pages.js';
|
|
66
67
|
import { listSecrets, secretUses, secretsAct } from './secrets.js';
|
|
67
68
|
import { sayRoute, transcribeRoute } from './speech.js';
|
|
68
69
|
import { createServer } from 'node:http';
|
|
69
|
-
import { getAction, idleRolloverMs, inRecovery, listMissions, listPendingActions, isJobState, parseAgentFile, setSentinelEnabled, snoozeFinding, snoozeFindings, unmuteFindings } from '@buddi/core';
|
|
70
|
+
import { asksEachTime, getAction, idleRolloverMs, inRecovery, listMissions, listPendingActions, isJobState, parseAgentFile, setSentinelEnabled, snoozeFinding, snoozeFindings, unmuteFindings } from '@buddi/core';
|
|
70
71
|
import { actOnAlerts, askPrompt, findingsForAsk, muteAlert } from './alerts.js';
|
|
71
72
|
import { connectionsOf } from '@buddi/tool-mcp';
|
|
72
73
|
import { CONNECTIONS_CALLBACK_PATH, connectionsRoute } from './connections.js';
|
|
@@ -75,6 +76,7 @@ import { hostService } from '@buddi/tool-host';
|
|
|
75
76
|
import { listToolPermissions, revokeToolPermission, getArtifact, readArtifactBytes, artifactBytesExist, discardUnreferencedUpload, listLibrary, getLibraryEntry, decodeCursor, filterKey, textPreviewable, readArtifactPrefix, FILE_FAMILIES, LIBRARY_PAGE_MAX, getOwnerProfile, saveOwnerProfile, isKnownTimezone, listGroups, getGroup, createGroup, updateGroup, archiveGroup, deleteGroup, restoreGroup, clearGroupHistory, groupHistorySize, GROUP_UNDO_MS, GroupRefusal, createGroupConversation, listGroupConversations, latestGroupConversation, openGroupRequest, conversationGroup } from '@buddi/core';
|
|
76
77
|
import { EXPORT_MIME, MAX_EXPORT_SOURCE_BYTES, exportFormats, exportName } from '../export/document.js';
|
|
77
78
|
import { ExportRefused, runExport } from '../export/convert.js';
|
|
79
|
+
import { createVault } from '@buddi/core';
|
|
78
80
|
import { beginOnboarding, completeOnboarding, markStepDone, setOnboardingDetails, skipOnboarding, readWebSetting, writeWebSetting, isAssetKey, readPluginAsset } from '@buddi/core';
|
|
79
81
|
import { listMemory, setPreference, forgetPreference, updateNote, forgetNote } from '@buddi/tool-memory';
|
|
80
82
|
import { purgeGroups, stopGroupWork } from './group-lifecycle.js';
|
|
@@ -92,7 +94,14 @@ import { ATTACHMENTS_UNAVAILABLE, CHAT_CONVERSATIONS_LIMIT, CHAT_UNAVAILABLE, WE
|
|
|
92
94
|
import { readAgentAttention, streamAttention } from './attention.js';
|
|
93
95
|
import { PreviewApp, PreviewTickets, parsePreviewApiPath } from './preview.js';
|
|
94
96
|
import { allowedOrigins, isLoopback, webAssetsDir, webUrl } from './config.js';
|
|
95
|
-
import { TAILSCALE_SETTING_KEY, daemonWhois,
|
|
97
|
+
import { TAILSCALE_SETTING_KEY, daemonWhois, plausibleLogin, proxiedThroughTailscale, tailscaleProvider, tailscaleSelf, tailscaleServeCommand, } from './access/tailscale.js';
|
|
98
|
+
import { CLOUDFLARE_SETTING_KEY, cloudflareProvider, createJwks, normalizeTeamDomain, plausibleTeamDomain, validateCloudflareInput, } from './access/cloudflare.js';
|
|
99
|
+
import { arrivalOf } from './access/arrival.js';
|
|
100
|
+
import { CloudflareApiError, createCloudflareApi, CLOUDFLARE_PERMISSION_LINES, CLOUDFLARE_TOKEN_URL } from './access/cloudflare-api.js';
|
|
101
|
+
import { CLOUDFLARE_SETUP_KEY, checkSetupInput, claimSetupOperation, freshProgress, setupBusySentence, setupOperation, removeCloudflareSetup, runCloudflareSetup, } from './access/cloudflare-setup.js';
|
|
102
|
+
import { ownerSecretTokenStore } from './access/cloudflare-token.js';
|
|
103
|
+
import { createAccessRegistry } from './access/registry.js';
|
|
104
|
+
import { createIngress } from './access/ingress.js';
|
|
96
105
|
import { clientKey } from './client-key.js';
|
|
97
106
|
import { retryHref, sendSignedOut, wantsSignedOutPage } from './signed-out.js';
|
|
98
107
|
import { extensionEndpoint } from './extension.js';
|
|
@@ -112,7 +121,10 @@ import { tipsRoute } from '../tips/route.js';
|
|
|
112
121
|
import { createWidgets, widgetsRoute } from './widgets.js';
|
|
113
122
|
import { createRequirements } from '../plugins/requires.js';
|
|
114
123
|
import { placesList, placesRoute } from './places.js';
|
|
115
|
-
import {
|
|
124
|
+
import { peopleRoute } from './people.js';
|
|
125
|
+
import { syncDateMissions } from '../missions/dates.js';
|
|
126
|
+
import { resumeParkedForPage } from '../missions/parked.js';
|
|
127
|
+
import { OWNER_DATE_FORMATS, OWNER_TIME_FORMATS, validDayMonth } from '@buddi/core';
|
|
116
128
|
import { readFacts, webSettingsStore } from '../tips/facts.js';
|
|
117
129
|
import { dismissAgentOffer, isPendingAccept, raiseAgentOffers, readAgentOffers } from './agent-offers.js';
|
|
118
130
|
import { currentVersion, upgradeJobRoute, upgradeRoute, versionCheckRoute, versionRoute, } from './version.js';
|
|
@@ -125,6 +137,8 @@ import { ensureWebToken, verifyTicket } from './token.js';
|
|
|
125
137
|
import { MAX_UPLOAD_BYTES, readUpload } from './upload.js';
|
|
126
138
|
import { LOCKED_BODY, LockUnavailable, allowedWhileLocked, clientOf, createLock } from './lock.js';
|
|
127
139
|
import { matchApiRoute, TOKEN_REFUSALS } from './api-routes.js';
|
|
140
|
+
import { QUIET_UNAVAILABLE_TEXT, pluginCommands } from './composer.js';
|
|
141
|
+
import { createEngagementHooks } from '../missions/engagement.js';
|
|
128
142
|
import { apiTokensRoute, bearerOf, verifyApiToken } from './api-tokens.js';
|
|
129
143
|
import { LockImageRefusal, MAX_LOCK_IMAGE_BYTES, normaliseLockImage } from './lock-image.js';
|
|
130
144
|
import { cancelJobFromWeb, cancelReminderFromWeb, decideApprovalFromWeb, retryJobFromWeb, retryJobsFromWeb, dismissJobsFromWeb, undismissJobsFromWeb, setMissionEnabledFromWeb, keepMissionFromWeb, answerStillUsefulFromWeb, setPausedFromWeb, setScheduleFromWeb, dismissOfferFromWeb, dismissOffersFromWeb, takeOfferFromWeb, } from './write.js';
|
|
@@ -154,6 +168,21 @@ const PREVIEW_APPS = new WeakMap();
|
|
|
154
168
|
* reloads once the next process answers `/_buddi/ready` with a new `boot`.
|
|
155
169
|
*/
|
|
156
170
|
const CLOSING_SAYS = new WeakMap();
|
|
171
|
+
/** Each server's ingress listener (web/access/ingress.ts). */
|
|
172
|
+
const INGRESS_OF = new WeakMap();
|
|
173
|
+
/** Each server's request handler, for a listener without a socket of its own (the relay, provider 3). */
|
|
174
|
+
const DISPATCH_OF = new WeakMap();
|
|
175
|
+
/** The ingress listener belonging to a server built by `createWebApp`. */
|
|
176
|
+
export function ingressOf(server) {
|
|
177
|
+
return INGRESS_OF.get(server);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The request handler of a server built by `createWebApp`: what an in-process
|
|
181
|
+
* listener hands a request to after tagging its arrival (`markRequestArrival`).
|
|
182
|
+
*/
|
|
183
|
+
export function dispatchOf(server) {
|
|
184
|
+
return DISPATCH_OF.get(server);
|
|
185
|
+
}
|
|
157
186
|
/** How long a closing frame may take to reach the pages before the sockets go. */
|
|
158
187
|
const CLOSING_FLUSH_MS = 250;
|
|
159
188
|
/** The chat surface this server is running, if any. */
|
|
@@ -264,13 +293,13 @@ export function createWebApp(deps) {
|
|
|
264
293
|
// A locked dashboard drives nothing (docs/dashboard.md, "Lock screen").
|
|
265
294
|
if (await lock.locked(session))
|
|
266
295
|
return null;
|
|
267
|
-
if (session.via === '
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
296
|
+
if (session.via === 'provider') {
|
|
297
|
+
const confirmed = await access.confirm(session, req, now);
|
|
298
|
+
// "Could not ask", or a stray request without the provider's proof:
|
|
299
|
+
// no socket now, but the session stays.
|
|
300
|
+
if (confirmed.answer === 'unanswered' || confirmed.answer === 'refuse')
|
|
301
|
+
return null;
|
|
302
|
+
if (confirmed.answer === 'end') {
|
|
274
303
|
await sessions.destroy(session.id).catch(() => { });
|
|
275
304
|
return null;
|
|
276
305
|
}
|
|
@@ -312,6 +341,9 @@ export function createWebApp(deps) {
|
|
|
312
341
|
// Plugin readiness and requirements: serve's, or this server's own.
|
|
313
342
|
const requirements = deps.requirements ??
|
|
314
343
|
createRequirements({ registry: deps.registry, ctx: deps.ctx, env: deps.env ?? process.env, pool: deps.pool, now: deps.now, log });
|
|
344
|
+
// Ollama on this computer: the first run's pull of a small model, one at a time.
|
|
345
|
+
const ollamaPulls = deps.ollamaPulls ?? createOllamaPulls({ baseUrl: OLLAMA_BASE_URL });
|
|
346
|
+
const machine = deps.ollamaMachine ?? (() => ollamaMachine());
|
|
315
347
|
// Home's widgets: one cache per server (web/widgets.ts).
|
|
316
348
|
const widgets = createWidgets({ pool: deps.pool, registry: deps.registry, ctx: deps.ctx, now: deps.now });
|
|
317
349
|
/*
|
|
@@ -418,6 +450,7 @@ export function createWebApp(deps) {
|
|
|
418
450
|
now: deps.now,
|
|
419
451
|
get timezone() { return deps.timezone; },
|
|
420
452
|
log,
|
|
453
|
+
browser: deps.browser ?? browserHost(deps.env ?? process.env),
|
|
421
454
|
...deps.chat,
|
|
422
455
|
})
|
|
423
456
|
: undefined;
|
|
@@ -429,8 +462,21 @@ export function createWebApp(deps) {
|
|
|
429
462
|
* Failures are the recovery's own business and land in the log.
|
|
430
463
|
*/
|
|
431
464
|
void chat?.recoverPendingInput().catch((err) => log(`web chat: recovering queued input failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
465
|
+
/*
|
|
466
|
+
* Give it back: the run that waited on the page carries on. A mission parked
|
|
467
|
+
* on it wakes (missions/parked.ts); otherwise the conversation the take-over
|
|
468
|
+
* held gets its turn. Either way with no message from the owner.
|
|
469
|
+
*/
|
|
470
|
+
const offGiveBack = (deps.browser ?? browserHost(deps.env ?? process.env)).onGiveBack?.((info) => {
|
|
471
|
+
void (async () => {
|
|
472
|
+
if (await resumeParkedForPage(deps.pool, info.conversationId, deps.now()))
|
|
473
|
+
return;
|
|
474
|
+
await chat?.continueAfterGiveBack({ conversationId: info.conversationId, agentId: info.agentId });
|
|
475
|
+
})().catch((err) => log(`browser: carrying on after the page was given back failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
476
|
+
});
|
|
432
477
|
const streams = new StreamBudget();
|
|
433
|
-
|
|
478
|
+
// A bundle script's run asks every time: its card offers no standing permission (`asksEachTime`).
|
|
479
|
+
const permissionScopes = (tool, envelope) => deps.registry.lookup(tool)?.reusableApproval && !asksEachTime(envelope)
|
|
434
480
|
? { permissionScopes: ['conversation', 'always'] } : {};
|
|
435
481
|
writeDeps.resumeInteractive = (action, outcome) => chat?.resumeHost(action, outcome);
|
|
436
482
|
/*
|
|
@@ -473,55 +519,204 @@ export function createWebApp(deps) {
|
|
|
473
519
|
// ticket-and-session gate. The override is a test seam, nothing more.
|
|
474
520
|
const openAccess = deps.openAccess ?? (deps.env?.BUDDI_WEB_REQUIRE_AUTH !== '1' && isLoopback(deps.config.host));
|
|
475
521
|
/*
|
|
476
|
-
*
|
|
522
|
+
* Trusted access providers (web/access/): something in front of buddi
|
|
523
|
+
* proves who is knocking, buddi checks the proof itself, and its own
|
|
524
|
+
* `remote` session rules apply. Tailscale (provider 1) asks the local
|
|
525
|
+
* daemon; Cloudflare Access (provider 2) verifies the JWT Access signs.
|
|
477
526
|
*
|
|
478
527
|
* Which sessions were established that way is a field on the session itself
|
|
479
|
-
* (`via`), not a map beside it
|
|
480
|
-
*
|
|
481
|
-
* keeps a tailnet session from widening its own access (`PUT /api/tailscale`
|
|
528
|
+
* (`via: 'provider'` and `provider`), not a map beside it. It is what keeps
|
|
529
|
+
* a provider session from widening its own access (changing a provider
|
|
482
530
|
* wants a session from this machine) and what lets `/api/session` say how
|
|
483
531
|
* the browser got in.
|
|
484
532
|
*/
|
|
485
533
|
const whois = deps.tailscale?.whois ?? daemonWhois();
|
|
486
534
|
const tailscaleSelfOf = deps.tailscale?.self ?? (() => tailscaleSelf());
|
|
535
|
+
const jwks = deps.cloudflare?.jwks ?? createJwks({ log });
|
|
536
|
+
const boundPort = () => server.address()?.port ?? deps.config.port;
|
|
537
|
+
const accessCtx = {
|
|
538
|
+
dashboardPort: boundPort,
|
|
539
|
+
ingressPort: () => ingress.port(),
|
|
540
|
+
publicOrigin: () => deps.config.publicOrigin,
|
|
541
|
+
};
|
|
542
|
+
const tailscale = tailscaleProvider({ whois, self: tailscaleSelfOf, log });
|
|
543
|
+
const cloudflare = cloudflareProvider({ jwks, log, ingressProblem: () => ingress.problem() });
|
|
544
|
+
const access = createAccessRegistry({
|
|
545
|
+
providers: [tailscale, cloudflare],
|
|
546
|
+
readSetting: (key) => readWebSetting(deps.pool, key),
|
|
547
|
+
});
|
|
548
|
+
/** The command that publishes this dashboard on the tailnet, with this installation's own ports. */
|
|
549
|
+
const serveCommand = () => tailscaleServeCommand(boundPort(), deps.config.publicOrigin);
|
|
550
|
+
const readTailscaleSetting = async () => access.settingOf(tailscale);
|
|
551
|
+
/*
|
|
552
|
+
* The Cloudflare setting as last read, so the synchronous Origin check can
|
|
553
|
+
* honour the public address the panel stored. Refreshed on every read.
|
|
554
|
+
*/
|
|
555
|
+
let cloudflareSeen = null;
|
|
556
|
+
const readCloudflareSetting = async () => {
|
|
557
|
+
cloudflareSeen = await access.settingOf(cloudflare);
|
|
558
|
+
return cloudflareSeen;
|
|
559
|
+
};
|
|
560
|
+
/** Did this request come through a provider, or does it hold a session one minted? Then the block is read-only. */
|
|
561
|
+
const throughProvider = (req, session) => session.via === 'provider' || arrivalOf(req) !== 'main' || proxiedThroughTailscale(req);
|
|
562
|
+
/** The Tailscale panel's whole payload (unchanged by the move behind the provider interface). */
|
|
563
|
+
const tailscaleView = async (req, session) => {
|
|
564
|
+
const stored = await readTailscaleSetting();
|
|
565
|
+
const daemon = await tailscaleSelfOf();
|
|
566
|
+
return {
|
|
567
|
+
enabled: stored.enabled,
|
|
568
|
+
login: stored.login,
|
|
569
|
+
available: daemon.available,
|
|
570
|
+
self: daemon.self,
|
|
571
|
+
proxied: throughProvider(req, session),
|
|
572
|
+
// What the owner has to run on this machine, with this installation's own two ports in it.
|
|
573
|
+
serveCommand: serveCommand(),
|
|
574
|
+
};
|
|
575
|
+
};
|
|
576
|
+
/** The Cloudflare panel's payload: the stored fields, the status, the setup copy with the real ingress port. */
|
|
577
|
+
const cloudflareView = async (req, session) => {
|
|
578
|
+
const stored = await readCloudflareSetting();
|
|
579
|
+
const status = await cloudflare.status(stored, accessCtx);
|
|
580
|
+
const visit = cloudflare.lastVisit();
|
|
581
|
+
return {
|
|
582
|
+
enabled: stored.enabled,
|
|
583
|
+
teamDomain: stored.teamDomain,
|
|
584
|
+
aud: stored.aud,
|
|
585
|
+
email: stored.email,
|
|
586
|
+
publicOrigin: stored.publicOrigin,
|
|
587
|
+
status,
|
|
588
|
+
ingressPort: ingress.port() ?? accessCtx.dashboardPort() + 2,
|
|
589
|
+
listening: ingress.port() !== null,
|
|
590
|
+
lastVisit: visit ? { at: visit.at.toISOString(), email: visit.email } : null,
|
|
591
|
+
setup: cloudflare.setup(stored, accessCtx),
|
|
592
|
+
proxied: throughProvider(req, session),
|
|
593
|
+
};
|
|
594
|
+
};
|
|
487
595
|
/**
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
596
|
+
* Store a Cloudflare setting and do what a Save does: end the sessions it
|
|
597
|
+
* admitted unless the same person, team and application stay on, then bind
|
|
598
|
+
* or close the ingress listener. The panel's Save and "Set it up for me"
|
|
599
|
+
* both come through here.
|
|
491
600
|
*/
|
|
492
|
-
const
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
601
|
+
const applyCloudflareSetting = async (value) => {
|
|
602
|
+
const before = await readCloudflareSetting();
|
|
603
|
+
await writeWebSetting(deps.pool, CLOUDFLARE_SETTING_KEY, value);
|
|
604
|
+
await readCloudflareSetting();
|
|
605
|
+
const same = before.enabled && value.enabled && before.email.toLowerCase() === value.email.toLowerCase()
|
|
606
|
+
&& before.teamDomain === value.teamDomain && before.aud === value.aud;
|
|
607
|
+
if (!same) {
|
|
608
|
+
const forgotten = new Set();
|
|
609
|
+
await sessions.forget((s) => { const drop = s.via === 'provider' && s.provider === 'cloudflare-access'; if (drop && s.id)
|
|
610
|
+
forgotten.add(s.id); return drop; });
|
|
611
|
+
hand.revoke((lease) => forgotten.has(lease), 'Cloudflare access changed. Sign in again.');
|
|
499
612
|
}
|
|
500
|
-
|
|
613
|
+
await ingress.sync();
|
|
501
614
|
};
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
*
|
|
505
|
-
*
|
|
506
|
-
*
|
|
615
|
+
/*
|
|
616
|
+
* "Set it up for me" (access/cloudflare-setup.ts): one run at a time, in
|
|
617
|
+
* the background — the health wait lasts as long as the owner takes to run
|
|
618
|
+
* one command — and its progress kept here for the panel to poll. The token
|
|
619
|
+
* is an owner secret, read once per run.
|
|
507
620
|
*/
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
621
|
+
let cfTokens = deps.cloudflare?.tokens ?? null;
|
|
622
|
+
const tokenStore = () => (cfTokens ??= ownerSecretTokenStore(deps.pool, createVault({ env: deps.env ?? process.env })));
|
|
623
|
+
let setupRun = null;
|
|
624
|
+
const readSetupRecord = async () => {
|
|
625
|
+
const row = await readWebSetting(deps.pool, CLOUDFLARE_SETUP_KEY);
|
|
626
|
+
return row && typeof row === 'object' && typeof row.host === 'string' ? row : null;
|
|
627
|
+
};
|
|
628
|
+
const setupDepsFor = (token, lease, signal) => ({
|
|
629
|
+
api: createCloudflareApi({ token, transport: deps.cloudflare?.api?.transport, baseUrl: deps.cloudflare?.api?.baseUrl }),
|
|
630
|
+
ingressPort: ingress.port() ?? (askedIngressPort() || null) ?? accessCtx.dashboardPort() + 2,
|
|
631
|
+
platform: deps.cloudflare?.platform ?? process.platform,
|
|
632
|
+
readSetting: readCloudflareSetting,
|
|
633
|
+
saveSetting: applyCloudflareSetting,
|
|
634
|
+
readRecord: readSetupRecord,
|
|
635
|
+
saveRecord: (record) => writeWebSetting(deps.pool, CLOUDFLARE_SETUP_KEY, record),
|
|
636
|
+
test: (team) => jwks.refresh(team),
|
|
637
|
+
...(deps.cloudflare?.setup ?? {}),
|
|
638
|
+
signal,
|
|
639
|
+
lease,
|
|
640
|
+
});
|
|
641
|
+
const setupView = async () => {
|
|
642
|
+
const record = await readSetupRecord();
|
|
643
|
+
return {
|
|
644
|
+
progress: setupRun?.progress ?? freshProgress(record?.host ?? '', record?.email ?? ''),
|
|
645
|
+
tokenStored: await tokenStore().has().catch(() => false),
|
|
646
|
+
record: record ? { host: record.host, email: record.email, zone: record.zone.name, teamDomain: record.teamDomain } : null,
|
|
647
|
+
permissions: CLOUDFLARE_PERMISSION_LINES,
|
|
648
|
+
tokenUrl: CLOUDFLARE_TOKEN_URL,
|
|
649
|
+
ingressPort: ingress.port() ?? (askedIngressPort() || null) ?? accessCtx.dashboardPort() + 2,
|
|
650
|
+
};
|
|
651
|
+
};
|
|
652
|
+
/** Run in the background; the lease (claimed by the caller) goes when the run ends. */
|
|
653
|
+
const startSetup = (lease, job, first) => {
|
|
654
|
+
const abort = new AbortController();
|
|
655
|
+
const run = { progress: first, abort, done: Promise.resolve() };
|
|
656
|
+
setupRun = run;
|
|
657
|
+
run.done = job((p) => { run.progress = p; }, abort.signal)
|
|
658
|
+
.then((p) => { run.progress = p; })
|
|
659
|
+
.catch(() => { run.progress = { ...run.progress, state: 'failed', error: 'The setup stopped unexpectedly. Try again.' }; })
|
|
660
|
+
.finally(() => lease.release());
|
|
661
|
+
};
|
|
662
|
+
/*
|
|
663
|
+
* A setting written elsewhere (`buddi access cloudflare setup` writes the
|
|
664
|
+
* database directly) reaches the ingress listener here: bound or closed
|
|
665
|
+
* within a quarter of a minute.
|
|
666
|
+
*/
|
|
667
|
+
const ingressResync = setInterval(() => {
|
|
668
|
+
void readCloudflareSetting().then((setting) => {
|
|
669
|
+
if (setting.enabled !== (ingress.port() !== null))
|
|
670
|
+
return ingress.sync();
|
|
671
|
+
return undefined;
|
|
672
|
+
}).catch(() => undefined);
|
|
673
|
+
}, 15_000);
|
|
674
|
+
ingressResync.unref?.();
|
|
675
|
+
/** Every provider's row, for "Sign in from elsewhere". */
|
|
676
|
+
const accessView = async (req, session) => ({
|
|
677
|
+
proxied: throughProvider(req, session),
|
|
678
|
+
providers: await Promise.all(access.providers.map(async (p) => {
|
|
679
|
+
const setting = await access.settingOf(p);
|
|
680
|
+
return { id: p.id, title: p.title, identity: p.identity, proxy: p.proxy, enabled: p.enabled(setting), status: await p.status(setting, accessCtx) };
|
|
681
|
+
})),
|
|
682
|
+
});
|
|
683
|
+
/*
|
|
684
|
+
* The ingress listener (specs/trusted-access.md §3.3): a second loopback
|
|
685
|
+
* listener, the dashboard's port + 2 (or `BUDDI_INGRESS_PORT`), bound only
|
|
686
|
+
* while a this-machine provider other than Tailscale is on. Every request
|
|
687
|
+
* on it is remote, whatever its headers or Host say, and it never passes a
|
|
688
|
+
* loopback-only check. cloudflared points here, never at the dashboard's
|
|
689
|
+
* own port, so a tunnel arrival can never be mistaken for this machine.
|
|
690
|
+
*/
|
|
691
|
+
/** `BUDDI_INGRESS_PORT`, when it names a port. */
|
|
692
|
+
function askedIngressPort() {
|
|
693
|
+
const raw = (deps.env ?? process.env).BUDDI_INGRESS_PORT?.trim();
|
|
694
|
+
const asked = raw ? Number(raw) : NaN;
|
|
695
|
+
return Number.isInteger(asked) && asked >= 0 && asked <= 65535 ? asked : null;
|
|
696
|
+
}
|
|
697
|
+
const ingress = createIngress({
|
|
698
|
+
onRequest: (req, res) => onRequest(req, res),
|
|
699
|
+
onUpgrade: (req, socket, head) => { server.emit('upgrade', req, socket, head); },
|
|
700
|
+
port: () => askedIngressPort() ?? (deps.config.port === 0 ? 0 : boundPort() + 2),
|
|
701
|
+
wanted: async () => (await readCloudflareSetting()).enabled,
|
|
511
702
|
log,
|
|
512
|
-
now: () => now,
|
|
513
|
-
onRefusal,
|
|
514
703
|
});
|
|
515
704
|
/**
|
|
516
705
|
* The pair a browser holds: the HttpOnly session and the readable CSRF value
|
|
517
706
|
* the page has to echo back in a header. Both carry the same `Max-Age`, which
|
|
518
707
|
* is the lifetime this session's scope earned it.
|
|
519
708
|
*/
|
|
709
|
+
/*
|
|
710
|
+
* Secure cookies for a remote session behind an HTTPS proxy: the configured
|
|
711
|
+
* public origin, or anything on the ingress listener (Cloudflare's edge
|
|
712
|
+
* always speaks HTTPS to the browser).
|
|
713
|
+
*/
|
|
714
|
+
const secureCookies = (req, scope) => scope === 'remote' && (!!deps.config.publicOrigin || arrivalOf(req) === 'ingress');
|
|
520
715
|
const sessionCookies = (req, session) => {
|
|
521
716
|
const maxAgeSeconds = SessionStore.maxAgeSeconds(session);
|
|
522
717
|
return [
|
|
523
|
-
cookieHeader(sessionCookieName(cookiePort(req)), session.id, { httpOnly: true, maxAgeSeconds, secure: session.scope
|
|
524
|
-
cookieHeader(csrfCookieName(cookiePort(req)), session.csrf, { httpOnly: false, maxAgeSeconds, secure: session.scope
|
|
718
|
+
cookieHeader(sessionCookieName(cookiePort(req)), session.id, { httpOnly: true, maxAgeSeconds, secure: secureCookies(req, session.scope) }),
|
|
719
|
+
cookieHeader(csrfCookieName(cookiePort(req)), session.csrf, { httpOnly: false, maxAgeSeconds, secure: secureCookies(req, session.scope) }),
|
|
525
720
|
];
|
|
526
721
|
};
|
|
527
722
|
/**
|
|
@@ -530,7 +725,7 @@ export function createWebApp(deps) {
|
|
|
530
725
|
* polling page then sends no credential at all, which counts as nothing.
|
|
531
726
|
*/
|
|
532
727
|
const expiredCookies = (req) => {
|
|
533
|
-
const secure = requestScope(req)
|
|
728
|
+
const secure = secureCookies(req, requestScope(req));
|
|
534
729
|
return [
|
|
535
730
|
cookieHeader(sessionCookieName(cookiePort(req)), '', { httpOnly: true, maxAgeSeconds: 0, secure }),
|
|
536
731
|
cookieHeader(csrfCookieName(cookiePort(req)), '', { httpOnly: false, maxAgeSeconds: 0, secure }),
|
|
@@ -538,9 +733,23 @@ export function createWebApp(deps) {
|
|
|
538
733
|
};
|
|
539
734
|
/**
|
|
540
735
|
* What the signed-out page should offer this request: how it arrived,
|
|
541
|
-
*
|
|
736
|
+
* which provider can sign it in, why it could not, and whether a lockout is
|
|
737
|
+
* running.
|
|
542
738
|
*/
|
|
543
|
-
const signedOutFor = async (req, pathname, search, now,
|
|
739
|
+
const signedOutFor = async (req, pathname, search, now, refused, key) => {
|
|
740
|
+
const lockedForMs = limiter.retryAfterMs(key, now);
|
|
741
|
+
const locked = lockedForMs > 0 ? { lockedForMs } : {};
|
|
742
|
+
if (arrivalOf(req) === 'ingress') {
|
|
743
|
+
return {
|
|
744
|
+
retry: retryHref(pathname, search),
|
|
745
|
+
arrived: 'remote',
|
|
746
|
+
provider: {
|
|
747
|
+
title: cloudflare.title,
|
|
748
|
+
...(refused?.provider === 'cloudflare-access' ? { refusal: refused.refusal.refusal, kind: refused.refusal.kind } : { refusal: 'no-assertion', kind: 'other' }),
|
|
749
|
+
},
|
|
750
|
+
...locked,
|
|
751
|
+
};
|
|
752
|
+
}
|
|
544
753
|
const proxied = proxiedThroughTailscale(req);
|
|
545
754
|
let publicHost;
|
|
546
755
|
try {
|
|
@@ -559,14 +768,14 @@ export function createWebApp(deps) {
|
|
|
559
768
|
const scope = requestScope(req);
|
|
560
769
|
const arrived = proxied || (publicHost !== undefined && host === publicHost) ? 'tailnet' : scope === 'local' ? 'local' : 'remote';
|
|
561
770
|
const setting = arrived === 'tailnet' ? await readTailscaleSetting() : null;
|
|
562
|
-
const
|
|
771
|
+
const tailscaleRefusal = refused?.provider === 'tailscale' ? refused.refusal : undefined;
|
|
563
772
|
return {
|
|
564
773
|
retry: retryHref(pathname, search),
|
|
565
774
|
arrived,
|
|
566
|
-
tailscaleSignIn: !!setting?.enabled &&
|
|
567
|
-
...(
|
|
568
|
-
...(
|
|
569
|
-
...
|
|
775
|
+
tailscaleSignIn: !!setting?.enabled && tailscaleRefusal?.kind !== 'login',
|
|
776
|
+
...(tailscaleRefusal?.kind === 'login' ? { tailscaleRefusal: tailscaleRefusal.sentence } : {}),
|
|
777
|
+
...(tailscaleRefusal?.kind === 'unanswered' ? { tailscaleUnanswered: true } : {}),
|
|
778
|
+
...locked,
|
|
570
779
|
};
|
|
571
780
|
};
|
|
572
781
|
/**
|
|
@@ -575,7 +784,16 @@ export function createWebApp(deps) {
|
|
|
575
784
|
* loopback page and the tailnet page each keep their own pair. Set, read and
|
|
576
785
|
* checked through this one function.
|
|
577
786
|
*/
|
|
578
|
-
const cookiePort = (req) =>
|
|
787
|
+
const cookiePort = (req) => {
|
|
788
|
+
// Cloudflare's edge serves the page on HTTPS's own port, whatever
|
|
789
|
+
// cloudflared says on the way in; the page names its cookie by it.
|
|
790
|
+
if (arrivalOf(req) === 'ingress') {
|
|
791
|
+
const host = req.headers.host ?? '';
|
|
792
|
+
if (!/:\d+$/.test(host.replace(/^\[[^\]]*\]/, '')))
|
|
793
|
+
return 443;
|
|
794
|
+
}
|
|
795
|
+
return requestPort(req, server.address()?.port ?? deps.config.port, deps.config.publicOrigin);
|
|
796
|
+
};
|
|
579
797
|
/**
|
|
580
798
|
* The origins a write may claim, resolved against the port actually bound.
|
|
581
799
|
*
|
|
@@ -586,8 +804,13 @@ export function createWebApp(deps) {
|
|
|
586
804
|
let originCache;
|
|
587
805
|
const allowed = () => {
|
|
588
806
|
const bound = server.address()?.port ?? deps.config.port;
|
|
589
|
-
|
|
590
|
-
|
|
807
|
+
// The public address the Cloudflare panel stored, while that provider is on.
|
|
808
|
+
const extra = cloudflareSeen?.enabled ? cloudflareSeen.publicOrigin : '';
|
|
809
|
+
if (originCache?.port !== bound || originCache.extra !== extra) {
|
|
810
|
+
const set = new Set(allowedOrigins({ ...deps.config, port: bound }));
|
|
811
|
+
if (extra)
|
|
812
|
+
set.add(extra);
|
|
813
|
+
originCache = { port: bound, extra, set };
|
|
591
814
|
}
|
|
592
815
|
return originCache.set;
|
|
593
816
|
};
|
|
@@ -595,7 +818,7 @@ export function createWebApp(deps) {
|
|
|
595
818
|
// caller that needs to drain it on shutdown (or in a test) can, without
|
|
596
819
|
// `createWebApp` growing a second return value every existing caller would
|
|
597
820
|
// have to unpack.
|
|
598
|
-
|
|
821
|
+
function onRequest(req, res) {
|
|
599
822
|
handle(req, res).catch((err) => {
|
|
600
823
|
// The lock could not say whether this request may pass: refused, never let in (web/lock.ts).
|
|
601
824
|
if (err instanceof LockUnavailable) {
|
|
@@ -612,9 +835,14 @@ export function createWebApp(deps) {
|
|
|
612
835
|
else
|
|
613
836
|
res.end();
|
|
614
837
|
});
|
|
615
|
-
}
|
|
838
|
+
}
|
|
839
|
+
const server = createServer(onRequest);
|
|
616
840
|
if (chat)
|
|
617
841
|
WEB_CHATS.set(server, chat);
|
|
842
|
+
INGRESS_OF.set(server, ingress);
|
|
843
|
+
// The seam the relay (provider 3) hands its in-process requests to,
|
|
844
|
+
// tagged `markRequestArrival(req, 'relay')` first. Never replayed as HTTP to 127.0.0.1.
|
|
845
|
+
DISPATCH_OF.set(server, onRequest);
|
|
618
846
|
PREVIEW_APPS.set(server, previews);
|
|
619
847
|
CLOSING_SAYS.set(server, async () => {
|
|
620
848
|
const said = frame('closing', goingAway === undefined ? {} : { for: goingAway });
|
|
@@ -645,13 +873,25 @@ export function createWebApp(deps) {
|
|
|
645
873
|
// rather than in `startWebServer` so every caller, tests included, has it.
|
|
646
874
|
extension.attach(server);
|
|
647
875
|
extension.attachPath(REMOTE_HAND_SOCKET_PATH, (req, socket, head) => hand.upgrade(req, socket, head));
|
|
648
|
-
server.once('close', () => { extension.shutdown(); hand.shutdown(); clearInterval(idleSweep); });
|
|
876
|
+
server.once('close', () => { extension.shutdown(); hand.shutdown(); clearInterval(idleSweep); clearInterval(ingressResync); setupRun?.abort.abort(); void ingress.close(); });
|
|
877
|
+
server.once('close', () => offGiveBack?.());
|
|
649
878
|
return server;
|
|
650
879
|
async function handle(req, res) {
|
|
651
880
|
const now = deps.now();
|
|
652
881
|
const method = (req.method ?? 'GET').toUpperCase();
|
|
653
882
|
const url = parseUrl(req);
|
|
654
|
-
|
|
883
|
+
/*
|
|
884
|
+
* The bucket failed sign-ins count against (client-key.ts, §7.5): by the
|
|
885
|
+
* arrival path, so a stranger behind a tunnel can never lock out this
|
|
886
|
+
* machine or the tailnet. A request on the ingress listener is asked of
|
|
887
|
+
* its provider at once — a JWT check against cached keys — because its
|
|
888
|
+
* bucket depends on it: `cf:unverified` until it verifies, then the
|
|
889
|
+
* client's own address.
|
|
890
|
+
*/
|
|
891
|
+
let key = access.bucketOf(req) ?? clientKey(req);
|
|
892
|
+
const early = arrivalOf(req) === 'main' ? null : await access.identify(req, now);
|
|
893
|
+
if (early?.result.ok && early.result.identity.bucket)
|
|
894
|
+
key = early.result.identity.bucket;
|
|
655
895
|
// No CORS, and therefore no preflight.
|
|
656
896
|
if (method === 'OPTIONS')
|
|
657
897
|
return sendEmpty(res, 405);
|
|
@@ -753,12 +993,12 @@ export function createWebApp(deps) {
|
|
|
753
993
|
const presentedSession = cookies[sessionCookieName(cookiePort(req))];
|
|
754
994
|
let session = await sessions.resolve(presentedSession, scope, now);
|
|
755
995
|
/*
|
|
756
|
-
* Why
|
|
757
|
-
* "this
|
|
758
|
-
* says; every other reason is the ordinary "you're
|
|
996
|
+
* Why a provider gave this request no identity, when it was asked. Only
|
|
997
|
+
* "this person is not the one allowed" and "could not ask" change what
|
|
998
|
+
* the signed-out page says; every other reason is the ordinary "you're
|
|
999
|
+
* signed out".
|
|
759
1000
|
*/
|
|
760
|
-
let refusal;
|
|
761
|
-
const noteRefusal = (reason) => { refusal = reason; };
|
|
1001
|
+
let refused = early && !early.result.ok ? { provider: early.provider.id, refusal: early.result } : undefined;
|
|
762
1002
|
/*
|
|
763
1003
|
* Set when the browser presented a session that is gone: the refusal then
|
|
764
1004
|
* expires its cookies, so it stops presenting them (and stops counting).
|
|
@@ -767,7 +1007,7 @@ export function createWebApp(deps) {
|
|
|
767
1007
|
/*
|
|
768
1008
|
* The answer to a refused request: the signed-out page for a person
|
|
769
1009
|
* opening a page, the empty status for everything else (docs/web.md).
|
|
770
|
-
* 401 is "signed out", 429 "too many tries from here", 503 "
|
|
1010
|
+
* 401 is "signed out", 429 "too many tries from here", 503 "the provider
|
|
771
1011
|
* could not be asked; the session is still good, try again".
|
|
772
1012
|
*/
|
|
773
1013
|
const refuse = async (status = 401) => {
|
|
@@ -778,33 +1018,40 @@ export function createWebApp(deps) {
|
|
|
778
1018
|
headers['Retry-After'] = '5';
|
|
779
1019
|
if (!wantsSignedOutPage(req, method, url.pathname))
|
|
780
1020
|
return sendEmpty(res, status, headers);
|
|
781
|
-
return sendSignedOut(res, await signedOutFor(req, url.pathname, url.search, now,
|
|
1021
|
+
return sendSignedOut(res, await signedOutFor(req, url.pathname, url.search, now, refused, key), headers, status);
|
|
782
1022
|
};
|
|
783
|
-
/* A
|
|
1023
|
+
/* A provider session this request ended: not a guess, so never a failed sign-in. */
|
|
784
1024
|
let revoked = false;
|
|
785
1025
|
/*
|
|
786
|
-
* A
|
|
1026
|
+
* A provider session is re-confirmed on every single request.
|
|
787
1027
|
*
|
|
788
|
-
* A cookie on its own would be a bearer token the
|
|
789
|
-
* loosely related to: it would outlive the setting being turned off,
|
|
790
|
-
* allowed login being changed, and the device being handed to somebody
|
|
791
|
-
* else. So the
|
|
792
|
-
* reused for a minute
|
|
793
|
-
*
|
|
794
|
-
*
|
|
795
|
-
* can only do if it is still the person the owner allowed.
|
|
1028
|
+
* A cookie on its own would be a bearer token the provider's identity is
|
|
1029
|
+
* only loosely related to: it would outlive the setting being turned off,
|
|
1030
|
+
* the allowed login being changed, and the device being handed to somebody
|
|
1031
|
+
* else. So the provider is asked again — Tailscale's daemon (a whois
|
|
1032
|
+
* answer is reused for a minute), Cloudflare's JWT on this very request —
|
|
1033
|
+
* and the person it names now must be the one this session was minted
|
|
1034
|
+
* for. Anything else and the session is gone, not merely ignored.
|
|
796
1035
|
*/
|
|
797
|
-
if (session?.via === '
|
|
798
|
-
const confirmed = await
|
|
799
|
-
if (
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
1036
|
+
if (session?.via === 'provider') {
|
|
1037
|
+
const confirmed = await access.confirm(session, req, now);
|
|
1038
|
+
if (confirmed.refusal)
|
|
1039
|
+
refused = { provider: session.provider, refusal: confirmed.refusal };
|
|
1040
|
+
/*
|
|
1041
|
+
* The provider could not be asked (a daemon busy or starting, keys that
|
|
1042
|
+
* could not be fetched). That is not an answer about anyone, so the
|
|
1043
|
+
* session is not ended for it and nothing is counted. This request waits.
|
|
1044
|
+
*/
|
|
1045
|
+
if (confirmed.answer === 'unanswered')
|
|
1046
|
+
return refuse(503);
|
|
1047
|
+
/*
|
|
1048
|
+
* This request lacks the provider's proof (Cloudflare's header), but
|
|
1049
|
+
* the session is not ended for it: a stray request without the header
|
|
1050
|
+
* must not sign the owner out. Nothing is counted either.
|
|
1051
|
+
*/
|
|
1052
|
+
if (confirmed.answer === 'refuse')
|
|
1053
|
+
return refuse(401);
|
|
1054
|
+
if (confirmed.answer === 'end') {
|
|
808
1055
|
const ended = session.id;
|
|
809
1056
|
// A hand this session was holding does not outlive the session.
|
|
810
1057
|
hand.revoke((lease) => lease === ended);
|
|
@@ -813,7 +1060,7 @@ export function createWebApp(deps) {
|
|
|
813
1060
|
revoked = true;
|
|
814
1061
|
forgetCookies = true;
|
|
815
1062
|
// The identity on this very request may still earn a new session below.
|
|
816
|
-
|
|
1063
|
+
refused = undefined;
|
|
817
1064
|
}
|
|
818
1065
|
}
|
|
819
1066
|
/*
|
|
@@ -838,26 +1085,32 @@ export function createWebApp(deps) {
|
|
|
838
1085
|
res.setHeader('Set-Cookie', sessionCookies(req, session));
|
|
839
1086
|
}
|
|
840
1087
|
/*
|
|
841
|
-
* Signed in through
|
|
1088
|
+
* Signed in through a trusted access provider.
|
|
842
1089
|
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
*
|
|
847
|
-
*
|
|
848
|
-
*
|
|
849
|
-
*
|
|
1090
|
+
* Tailscale: the proxy runs on this machine and the daemon confirms who
|
|
1091
|
+
* is behind the forwarded address. Cloudflare Access: the JWT Access
|
|
1092
|
+
* signed verifies against the team's keys, for this application, naming
|
|
1093
|
+
* the allowed email, and it arrived on the ingress listener. When that
|
|
1094
|
+
* agrees with the person the owner allowed, the request gets a `remote`
|
|
1095
|
+
* session exactly as the ticket exchange would have minted one — same
|
|
1096
|
+
* cookies, same 12 hours, same CSRF on every write. Anything less falls
|
|
1097
|
+
* through to the 401 below. A provider identity signs in during a lockout.
|
|
850
1098
|
*/
|
|
851
1099
|
if (!session) {
|
|
852
|
-
const
|
|
853
|
-
if (
|
|
1100
|
+
const asked = early ?? await access.identify(req, now);
|
|
1101
|
+
if (asked && !asked.result.ok)
|
|
1102
|
+
refused = { provider: asked.provider.id, refusal: asked.result };
|
|
1103
|
+
if (asked?.result.ok) {
|
|
1104
|
+
const identity = asked.result.identity;
|
|
854
1105
|
limiter.reset(key);
|
|
855
1106
|
const locked = await lock.startLocked('browser');
|
|
1107
|
+
const capMs = Math.min(asked.provider.absoluteCapMs, identity.expiresAt ? Math.max(0, identity.expiresAt.getTime() - now.getTime()) : asked.provider.absoluteCapMs);
|
|
856
1108
|
session = sessions.create('remote', now, {
|
|
857
|
-
via: '
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
1109
|
+
via: 'provider',
|
|
1110
|
+
provider: identity.provider,
|
|
1111
|
+
providerSubject: identity.subject,
|
|
1112
|
+
...(identity.detail ? { providerDetail: identity.detail } : {}),
|
|
1113
|
+
absoluteCapMs: capMs,
|
|
861
1114
|
}, locked ? { locked } : {});
|
|
862
1115
|
res.setHeader('Set-Cookie', sessionCookies(req, session));
|
|
863
1116
|
}
|
|
@@ -872,14 +1125,26 @@ export function createWebApp(deps) {
|
|
|
872
1125
|
// the same stale cookie counts once however often it is sent: all tailnet
|
|
873
1126
|
// and tunnel traffic shares 127.0.0.1, so a forgotten tab must not be
|
|
874
1127
|
// able to lock the owner out of every way in.
|
|
875
|
-
|
|
1128
|
+
//
|
|
1129
|
+
// A provider's credential that failed (a Cloudflare assertion that does
|
|
1130
|
+
// not verify) is an attempt too, cookie or not, in the bucket the
|
|
1131
|
+
// provider names (per Cf-Connecting-Ip). No assertion at all, or keys
|
|
1132
|
+
// that could not be fetched, carry no attempt.
|
|
1133
|
+
const tried = refused?.refusal.attempt;
|
|
1134
|
+
if (!presentedSession && !tried)
|
|
876
1135
|
return refuse();
|
|
877
|
-
|
|
1136
|
+
if (tried)
|
|
1137
|
+
key = tried.bucket;
|
|
1138
|
+
if (presentedSession)
|
|
1139
|
+
forgetCookies = true;
|
|
878
1140
|
if (revoked)
|
|
879
1141
|
return refuse();
|
|
880
1142
|
if (limiter.blocked(key, now))
|
|
881
1143
|
return refuse(429);
|
|
882
|
-
|
|
1144
|
+
if (tried)
|
|
1145
|
+
limiter.failCredential(key, tried.credential, now);
|
|
1146
|
+
if (presentedSession)
|
|
1147
|
+
limiter.failCredential(key, presentedSession, now);
|
|
883
1148
|
return refuse();
|
|
884
1149
|
}
|
|
885
1150
|
/*
|
|
@@ -1078,6 +1343,10 @@ export function createWebApp(deps) {
|
|
|
1078
1343
|
now: deps.now,
|
|
1079
1344
|
agents: () => deps.catalog.list(),
|
|
1080
1345
|
plugins: () => deps.registry.manifests().map((m) => m.name),
|
|
1346
|
+
appsWithoutPlugin: () => {
|
|
1347
|
+
const apps = browser.status().routes?.find((route) => route.kind === 'apps');
|
|
1348
|
+
return apps !== undefined && apps.installed === false && apps.mode !== undefined && apps.mode !== 'off';
|
|
1349
|
+
},
|
|
1081
1350
|
needsSetup: async () => {
|
|
1082
1351
|
const out = [];
|
|
1083
1352
|
for (const manifest of deps.registry.manifests()) {
|
|
@@ -1158,6 +1427,20 @@ export function createWebApp(deps) {
|
|
|
1158
1427
|
return sendEmpty(res, 204);
|
|
1159
1428
|
return sendJson(res, answer.status, answer.body);
|
|
1160
1429
|
}
|
|
1430
|
+
// `/quiet` typed into the composer: the verb Telegram and the terminal answer, in their words (missions/engagement.ts).
|
|
1431
|
+
if (path === '/api/quiet' && method === 'POST') {
|
|
1432
|
+
let body;
|
|
1433
|
+
try {
|
|
1434
|
+
body = await readJsonBody(req);
|
|
1435
|
+
}
|
|
1436
|
+
catch {
|
|
1437
|
+
return sendJson(res, 400, { error: 'request body must be JSON' });
|
|
1438
|
+
}
|
|
1439
|
+
const raw = body?.arg;
|
|
1440
|
+
const arg = typeof raw === 'string' ? raw.trim().slice(0, 40) : '';
|
|
1441
|
+
const text = await createEngagementHooks({ pool: deps.pool, now: deps.now, timezone: deps.timezone, unavailableText: QUIET_UNAVAILABLE_TEXT }).quiet(arg);
|
|
1442
|
+
return sendJson(res, 200, { text });
|
|
1443
|
+
}
|
|
1161
1444
|
// Home's widgets: the gallery, the owner's layout, each placed one's body (web/widgets.ts).
|
|
1162
1445
|
if (path === '/api/widgets' || path.startsWith('/api/widgets/')) {
|
|
1163
1446
|
let body = {};
|
|
@@ -1363,15 +1646,16 @@ export function createWebApp(deps) {
|
|
|
1363
1646
|
const permissions = (await listToolPermissions(deps.pool, deps.ctx.ownerId)).filter(p => p.tool === 'host.exec' && (!agentId || p.agentId === agentId) && (!conversationId || !p.conversationId || p.conversationId === conversationId));
|
|
1364
1647
|
return sendJson(res, 200, { permissions, runs: host.runs(deps.ctx.ownerId, agentId, conversationId) });
|
|
1365
1648
|
}
|
|
1366
|
-
case '/api/host/apps':
|
|
1367
|
-
return sendJson(res, 200, { apps: await listInstalledApps() });
|
|
1368
|
-
case '/api/host/browser-profiles':
|
|
1369
|
-
return sendJson(res, 200, { profiles: await listBrowserProfiles(q.get('app') ?? '') });
|
|
1370
1649
|
case '/api/extension':
|
|
1371
1650
|
return sendJson(res, 200, await extension.view());
|
|
1372
1651
|
case '/api/browser':
|
|
1373
1652
|
return sendJson(res, 200, q.has('conversationId') && q.has('agentId')
|
|
1374
1653
|
? browser.status({ agentId: q.get('agentId'), conversationId: q.get('conversationId') }) : browser.status());
|
|
1654
|
+
case '/api/browser/telemetry': {
|
|
1655
|
+
// Stops by cause, cards and routes over the last week: how flakiness is seen to fall.
|
|
1656
|
+
const summary = browser.telemetrySummary?.(Number(q.get('days') ?? '7') || 7);
|
|
1657
|
+
return sendJson(res, 200, summary ?? { days: 7, tasks: 0, stops: 0, cards: 0, byCause: [], routes: {}, stopsPerTask: 0 });
|
|
1658
|
+
}
|
|
1375
1659
|
case '/api/browser/screenshot': {
|
|
1376
1660
|
const expectedSession = url.searchParams.get('sessionId');
|
|
1377
1661
|
const current = browser.status(expectedSession !== null ? { sessionId: expectedSession } : undefined);
|
|
@@ -1410,10 +1694,14 @@ export function createWebApp(deps) {
|
|
|
1410
1694
|
// from the page rather than implied by a number in a source file.
|
|
1411
1695
|
scope: session.scope,
|
|
1412
1696
|
// How this browser got in. `local` is the open loopback mint,
|
|
1413
|
-
// `ticket` the five-minute ticket exchange,
|
|
1414
|
-
//
|
|
1415
|
-
|
|
1416
|
-
|
|
1697
|
+
// `ticket` the five-minute ticket exchange, or the provider that
|
|
1698
|
+
// verified it (`tailscale`, `cloudflare-access`) — and then the
|
|
1699
|
+
// name to greet.
|
|
1700
|
+
signedInThrough: session.via === 'provider' ? session.provider : session.via,
|
|
1701
|
+
...(session.via === 'provider' ? { provider: session.provider, providerSubject: session.providerSubject } : {}),
|
|
1702
|
+
...(session.via === 'provider' && session.provider === 'tailscale'
|
|
1703
|
+
? { tailscaleName: session.providerDetail?.name ?? session.providerSubject, tailscaleLogin: session.providerSubject }
|
|
1704
|
+
: {}),
|
|
1417
1705
|
expiresAt: session.expiresAt.toISOString(),
|
|
1418
1706
|
// What this gateway is running. The page keeps it across an
|
|
1419
1707
|
// upgrade so that "it came back" can be told from "it is still
|
|
@@ -1428,20 +1716,24 @@ export function createWebApp(deps) {
|
|
|
1428
1716
|
* memory), and whether this very request came through the proxy —
|
|
1429
1717
|
* which is what disables the switch on a tailnet browser.
|
|
1430
1718
|
*/
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
return sendJson(res, 200,
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1719
|
+
// `/api/tailscale` stays one release as an alias (docs/api.md).
|
|
1720
|
+
case '/api/tailscale':
|
|
1721
|
+
case '/api/access/tailscale':
|
|
1722
|
+
return sendJson(res, 200, await tailscaleView(req, session));
|
|
1723
|
+
/*
|
|
1724
|
+
* "Sign in from elsewhere": every provider's row — its status in one
|
|
1725
|
+
* line — and whether this very request came through one, which makes
|
|
1726
|
+
* the whole block read-only.
|
|
1727
|
+
*/
|
|
1728
|
+
case '/api/access':
|
|
1729
|
+
return sendJson(res, 200, await accessView(req, session));
|
|
1730
|
+
case '/api/access/cloudflare-access':
|
|
1731
|
+
return sendJson(res, 200, await cloudflareView(req, session));
|
|
1732
|
+
case '/api/access/cloudflare-access/setup':
|
|
1733
|
+
// The install line holds the tunnel's connector token: this machine only.
|
|
1734
|
+
if (session.via !== 'local')
|
|
1735
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
1736
|
+
return sendJson(res, 200, await setupView());
|
|
1445
1737
|
case '/api/overview':
|
|
1446
1738
|
return sendJson(res, 200, {
|
|
1447
1739
|
...(await readOverview({
|
|
@@ -1493,8 +1785,8 @@ export function createWebApp(deps) {
|
|
|
1493
1785
|
}
|
|
1494
1786
|
case '/api/approvals': {
|
|
1495
1787
|
const approvals = await readApprovals(deps.pool, now, boundedLimit(q.get('limit'), 50));
|
|
1496
|
-
return sendJson(res, 200, { pending: approvals.pending.map(a => ({ ...a, ...permissionScopes(a.tool) })),
|
|
1497
|
-
recent: approvals.recent.map(a => ({ ...a, ...permissionScopes(a.tool) })) });
|
|
1788
|
+
return sendJson(res, 200, { pending: approvals.pending.map(a => ({ ...a, ...permissionScopes(a.tool, a.envelope) })),
|
|
1789
|
+
recent: approvals.recent.map(a => ({ ...a, ...permissionScopes(a.tool, a.envelope) })) });
|
|
1498
1790
|
}
|
|
1499
1791
|
case '/api/offers':
|
|
1500
1792
|
// The roster goes in so the read can lapse an offer whose agent is
|
|
@@ -1524,7 +1816,8 @@ export function createWebApp(deps) {
|
|
|
1524
1816
|
case '/api/sentinels':
|
|
1525
1817
|
return sendJson(res, 200, await readSentinels(deps.pool, deps.registry, deps.now()));
|
|
1526
1818
|
case '/api/chat/agents':
|
|
1527
|
-
|
|
1819
|
+
// With the commands the plugins add to the composer's `/` menu (web/composer.ts).
|
|
1820
|
+
return sendJson(res, 200, { ...readChatAgents(deps.catalog, await avatarVersions(deps.pool)), commands: pluginCommands(deps.registry) });
|
|
1528
1821
|
// Which agents are waiting on the owner. One small query, and the only
|
|
1529
1822
|
// definition of "waiting" in the installation — see attention.ts.
|
|
1530
1823
|
case '/api/chat/attention':
|
|
@@ -1681,8 +1974,12 @@ export function createWebApp(deps) {
|
|
|
1681
1974
|
const persona = readFirstAgentPersona(onboardingDeps());
|
|
1682
1975
|
return persona ? sendJson(res, 200, persona) : sendJson(res, 404, { error: 'There is no assistant of your own yet.' });
|
|
1683
1976
|
}
|
|
1977
|
+
// With what the machine says: installed or not, how to install it, the
|
|
1978
|
+
// model the first run would fetch here, and a fetch already going.
|
|
1684
1979
|
case '/api/onboarding/ollama':
|
|
1685
|
-
return sendJson(res, 200, await probeOllama());
|
|
1980
|
+
return sendJson(res, 200, { ...(await probeOllama()), machine: machine(), pull: ollamaPulls.read() });
|
|
1981
|
+
case '/api/onboarding/ollama/pull':
|
|
1982
|
+
return sendJson(res, 200, { pull: ollamaPulls.read() });
|
|
1686
1983
|
// Is mlxh running here? The same question, asked the same way, of port 1060.
|
|
1687
1984
|
case '/api/onboarding/mlxh':
|
|
1688
1985
|
return sendJson(res, 200, await probeMlxh({ baseUrl: mlxhBaseUrl(deps.env ?? process.env) }));
|
|
@@ -1700,6 +1997,12 @@ export function createWebApp(deps) {
|
|
|
1700
1997
|
const profile = await getOwnerProfile(deps.pool);
|
|
1701
1998
|
return sendJson(res, 200, { ...profile, places: await placesList(deps.pool), detectedTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone, zones: knownTimezones() });
|
|
1702
1999
|
}
|
|
2000
|
+
// Settings → Memory → People, and Home's birthday card (web/people.ts).
|
|
2001
|
+
case '/api/memory/people':
|
|
2002
|
+
case '/api/owner/birthday': {
|
|
2003
|
+
const answered = await peopleRoute({ pool: deps.pool, catalog: deps.catalog, now: deps.now, log }, 'GET', path, {});
|
|
2004
|
+
return sendJson(res, answered.status, answered.body);
|
|
2005
|
+
}
|
|
1703
2006
|
case '/api/memory': {
|
|
1704
2007
|
try {
|
|
1705
2008
|
// `?agent=` narrows it to what that agent sees: the agent sheet's tab.
|
|
@@ -1859,6 +2162,30 @@ export function createWebApp(deps) {
|
|
|
1859
2162
|
// The Skills page: every skill, grouped, who holds each; one whole; one as its file.
|
|
1860
2163
|
if (path === '/api/skills')
|
|
1861
2164
|
return reply(res, listSkillsRoute(skillsDeps()));
|
|
2165
|
+
/*
|
|
2166
|
+
* A bundle's files, for the viewer: one file's text (or its size when
|
|
2167
|
+
* it is not text), and a picture's bytes for an <img>. The same for an
|
|
2168
|
+
* upload still waiting in the preview. A picture is served with a CSP
|
|
2169
|
+
* that runs nothing, so an SVG opened on its own cannot script the page.
|
|
2170
|
+
*/
|
|
2171
|
+
const bundleRead = /^\/api\/skills\/(bundles\/)?([^/]+)\/(file|image)$/.exec(path);
|
|
2172
|
+
if (bundleRead) {
|
|
2173
|
+
const id = decodeURIComponent(bundleRead[2]);
|
|
2174
|
+
const rel = url.searchParams.get('path') ?? '';
|
|
2175
|
+
if (bundleRead[3] === 'file') {
|
|
2176
|
+
return reply(res, bundleRead[1] ? stagedFileRoute(skillsDeps(), id, rel) : skillFileRoute(skillsDeps(), id, rel));
|
|
2177
|
+
}
|
|
2178
|
+
const picture = bundleRead[1] ? stagedImage(skillsDeps(), id, rel) : skillImage(skillsDeps(), id, rel);
|
|
2179
|
+
if (!picture)
|
|
2180
|
+
return sendJson(res, 404, { error: `There is no picture "${rel}" in this bundle.` });
|
|
2181
|
+
res.statusCode = 200;
|
|
2182
|
+
res.setHeader('Content-Type', picture.type);
|
|
2183
|
+
res.setHeader('Content-Security-Policy', "default-src 'none'; style-src 'unsafe-inline'; sandbox");
|
|
2184
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
2185
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
2186
|
+
res.end(method === 'HEAD' ? undefined : picture.bytes);
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
1862
2189
|
const skillRead = /^\/api\/skills\/([^/]+)(\/download)?$/.exec(path);
|
|
1863
2190
|
if (skillRead) {
|
|
1864
2191
|
const id = decodeURIComponent(skillRead[1]);
|
|
@@ -1867,6 +2194,14 @@ export function createWebApp(deps) {
|
|
|
1867
2194
|
const file = skillDownload(skillsDeps(), id);
|
|
1868
2195
|
if (!file)
|
|
1869
2196
|
return sendJson(res, 404, { error: `There is no skill "${id}".` });
|
|
2197
|
+
if ('zip' in file) {
|
|
2198
|
+
res.statusCode = 200;
|
|
2199
|
+
res.setHeader('Content-Type', 'application/zip');
|
|
2200
|
+
res.setHeader('Content-Disposition', `attachment; filename="${file.filename}"`);
|
|
2201
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
2202
|
+
res.end(method === 'HEAD' ? undefined : Buffer.from(file.zip));
|
|
2203
|
+
return;
|
|
2204
|
+
}
|
|
1870
2205
|
res.statusCode = 200;
|
|
1871
2206
|
res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
|
|
1872
2207
|
res.setHeader('Content-Disposition', `attachment; filename="${file.filename}"`);
|
|
@@ -1914,7 +2249,7 @@ export function createWebApp(deps) {
|
|
|
1914
2249
|
const action = await getAction(deps.pool, decodeURIComponent(approval[1]));
|
|
1915
2250
|
if (!action)
|
|
1916
2251
|
return sendJson(res, 404, { error: 'no such action' });
|
|
1917
|
-
return sendJson(res, 200, { action: { ...toApprovalView(action), ...permissionScopes(action.tool) } });
|
|
2252
|
+
return sendJson(res, 200, { action: { ...toApprovalView(action), ...permissionScopes(action.tool, action.envelope) } });
|
|
1918
2253
|
}
|
|
1919
2254
|
/* ---------------- chat ---------------- */
|
|
1920
2255
|
const groupConversations = /^\/api\/groups\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\/conversations$/i.exec(path);
|
|
@@ -2078,6 +2413,9 @@ export function createWebApp(deps) {
|
|
|
2078
2413
|
return sendJson(res, forgotten.status, forgotten.body);
|
|
2079
2414
|
}
|
|
2080
2415
|
// Delete a skill: the agents that asked for it stop, the file goes to the trash.
|
|
2416
|
+
const stagedGone = /^\/api\/skills\/bundles\/([^/]+)$/.exec(path);
|
|
2417
|
+
if (stagedGone)
|
|
2418
|
+
return reply(res, discardStaged(incomingDirFor(skillsDeps().skillsDir), decodeURIComponent(stagedGone[1])));
|
|
2081
2419
|
const skillGone = /^\/api\/skills\/([^/]+)$/.exec(path);
|
|
2082
2420
|
if (skillGone)
|
|
2083
2421
|
return reply(res, await deleteSkillRoute(skillsDeps(), decodeURIComponent(skillGone[1])));
|
|
@@ -2155,7 +2493,7 @@ export function createWebApp(deps) {
|
|
|
2155
2493
|
* everything else.
|
|
2156
2494
|
*/
|
|
2157
2495
|
if (method === 'PUT') {
|
|
2158
|
-
const puttable = ['/api/backups/schedule', '/api/backups/passphrase', '/api/version/check', '/api/tailscale', '/api/notifications/settings', '/api/notifications/focus'];
|
|
2496
|
+
const puttable = ['/api/backups/schedule', '/api/backups/passphrase', '/api/version/check', '/api/tailscale', '/api/access/tailscale', '/api/access/cloudflare-access', '/api/notifications/settings', '/api/notifications/focus'];
|
|
2159
2497
|
if (!puttable.includes(path))
|
|
2160
2498
|
return sendEmpty(res, 405);
|
|
2161
2499
|
let put;
|
|
@@ -2165,7 +2503,20 @@ export function createWebApp(deps) {
|
|
|
2165
2503
|
catch {
|
|
2166
2504
|
return sendJson(res, 400, { error: 'request body must be JSON' });
|
|
2167
2505
|
}
|
|
2168
|
-
if (path === '/api/
|
|
2506
|
+
if (path === '/api/access/cloudflare-access') {
|
|
2507
|
+
// Who may widen access: only a browser on this machine, as for Tailscale below.
|
|
2508
|
+
if (session.via !== 'local') {
|
|
2509
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
2510
|
+
}
|
|
2511
|
+
const checked = validateCloudflareInput(put);
|
|
2512
|
+
if (!checked.ok)
|
|
2513
|
+
return sendJson(res, 400, { error: checked.error });
|
|
2514
|
+
await applyCloudflareSetting(checked.value);
|
|
2515
|
+
// On Save buddi fetches the team's keys once and says whether it worked.
|
|
2516
|
+
const test = checked.value.enabled ? await jwks.refresh(checked.value.teamDomain) : null;
|
|
2517
|
+
return sendJson(res, 200, { ...(await cloudflareView(req, session)), ...(test ? { test } : {}) });
|
|
2518
|
+
}
|
|
2519
|
+
if (path === '/api/tailscale' || path === '/api/access/tailscale') {
|
|
2169
2520
|
/*
|
|
2170
2521
|
* Who may widen access: only a browser that is already on this
|
|
2171
2522
|
* machine.
|
|
@@ -2202,20 +2553,11 @@ export function createWebApp(deps) {
|
|
|
2202
2553
|
* in a browser on the far side of the tailnet.
|
|
2203
2554
|
*/
|
|
2204
2555
|
const forgotten = new Set();
|
|
2205
|
-
await sessions.forget((s) => { const drop = s.via === 'tailscale'; if (drop && s.id)
|
|
2556
|
+
await sessions.forget((s) => { const drop = s.via === 'provider' && s.provider === 'tailscale'; if (drop && s.id)
|
|
2206
2557
|
forgotten.add(s.id); return drop; });
|
|
2207
2558
|
// Including whichever of them had a hand on the owner's browser.
|
|
2208
2559
|
hand.revoke((lease) => forgotten.has(lease), 'Tailscale access changed. Sign in again.');
|
|
2209
|
-
|
|
2210
|
-
const stored = toTailscaleSetting({ enabled, login });
|
|
2211
|
-
return sendJson(res, 200, {
|
|
2212
|
-
enabled: stored.enabled,
|
|
2213
|
-
login: stored.login,
|
|
2214
|
-
available: daemon.available,
|
|
2215
|
-
self: daemon.self,
|
|
2216
|
-
proxied: false,
|
|
2217
|
-
serveCommand: serveCommand(),
|
|
2218
|
-
});
|
|
2560
|
+
return sendJson(res, 200, await tailscaleView(req, session));
|
|
2219
2561
|
}
|
|
2220
2562
|
if (path === '/api/version/check')
|
|
2221
2563
|
return reply(res, await versionCheckRoute(versionDeps(), 'PUT', put));
|
|
@@ -2229,6 +2571,135 @@ export function createWebApp(deps) {
|
|
|
2229
2571
|
}
|
|
2230
2572
|
if (method !== 'POST')
|
|
2231
2573
|
return sendEmpty(res, 405);
|
|
2574
|
+
/*
|
|
2575
|
+
* "Test my setup": fetch the team's signing keys for the domain in the
|
|
2576
|
+
* form (saved or not) and say what came back. Nothing is stored. From
|
|
2577
|
+
* this machine only, like the setting itself: it makes this computer
|
|
2578
|
+
* fetch a URL the caller names part of.
|
|
2579
|
+
*/
|
|
2580
|
+
/*
|
|
2581
|
+
* "Set it up for me": start a run (202, then poll GET …/setup), stop the
|
|
2582
|
+
* health wait, or remove what buddi made. From this machine only, like the
|
|
2583
|
+
* setting it fills in.
|
|
2584
|
+
*/
|
|
2585
|
+
if (path === '/api/access/cloudflare-access/setup' || path === '/api/access/cloudflare-access/setup/stop' || path === '/api/access/cloudflare-access/setup/remove') {
|
|
2586
|
+
if (session.via !== 'local')
|
|
2587
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
2588
|
+
/*
|
|
2589
|
+
* One operation at a time (cloudflare-setup's lock, claimed before the
|
|
2590
|
+
* first await and held to the end): a second setup or a removal while
|
|
2591
|
+
* one runs is a 409, and so is Stop while a removal runs.
|
|
2592
|
+
*/
|
|
2593
|
+
if (path.endsWith('/stop')) {
|
|
2594
|
+
const going = setupOperation();
|
|
2595
|
+
if (going === 'remove')
|
|
2596
|
+
return sendJson(res, 409, { error: setupBusySentence(going) });
|
|
2597
|
+
const lease = going === null ? claimSetupOperation('setup') : null;
|
|
2598
|
+
try {
|
|
2599
|
+
setupRun?.abort.abort();
|
|
2600
|
+
await setupRun?.done;
|
|
2601
|
+
return sendJson(res, 200, await setupView());
|
|
2602
|
+
}
|
|
2603
|
+
finally {
|
|
2604
|
+
lease?.release();
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
const lease = claimSetupOperation(path.endsWith('/remove') ? 'remove' : 'setup');
|
|
2608
|
+
if (!lease)
|
|
2609
|
+
return sendJson(res, 409, { error: setupBusySentence(setupOperation()) });
|
|
2610
|
+
let handedOff = false;
|
|
2611
|
+
try {
|
|
2612
|
+
const body = await readJsonBody(req).catch(() => ({}));
|
|
2613
|
+
const str = (v) => (typeof v === 'string' ? v.trim() : '');
|
|
2614
|
+
const tokens = tokenStore();
|
|
2615
|
+
const pasted = str(body.token);
|
|
2616
|
+
if (path.endsWith('/remove')) {
|
|
2617
|
+
const token = pasted || await tokens.use().catch(() => null);
|
|
2618
|
+
if (!token)
|
|
2619
|
+
return sendJson(res, 400, { error: 'Paste the Cloudflare API token again: buddi needs it to remove what it made.' });
|
|
2620
|
+
const run = {
|
|
2621
|
+
progress: { ...freshProgress(), state: 'removing', steps: [] }, abort: new AbortController(), done: Promise.resolve(),
|
|
2622
|
+
};
|
|
2623
|
+
setupRun = run;
|
|
2624
|
+
const progress = await removeCloudflareSetup({ ...setupDepsFor(token, lease), host: str(body.host) || undefined }, (p) => { run.progress = p; });
|
|
2625
|
+
run.progress = progress;
|
|
2626
|
+
if (!progress.error)
|
|
2627
|
+
await tokens.remove().catch(() => undefined);
|
|
2628
|
+
return sendJson(res, 200, await setupView());
|
|
2629
|
+
}
|
|
2630
|
+
const input = { host: str(body.host), email: str(body.email), zone: str(body.zone) || undefined, adopt: body.adopt === true };
|
|
2631
|
+
const invalid = checkSetupInput(input);
|
|
2632
|
+
if (invalid)
|
|
2633
|
+
return sendJson(res, 400, { error: invalid });
|
|
2634
|
+
if (pasted) {
|
|
2635
|
+
if (/\s/.test(pasted) || pasted.length < 20 || pasted.length > 400)
|
|
2636
|
+
return sendJson(res, 400, { error: 'That doesn’t look like a Cloudflare API token.' });
|
|
2637
|
+
try {
|
|
2638
|
+
await tokens.put(pasted);
|
|
2639
|
+
}
|
|
2640
|
+
catch {
|
|
2641
|
+
return sendJson(res, 409, { error: 'The token could not be kept in the vault. Check that the vault is unlocked, then try again.' });
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
const token = pasted || await tokens.use().catch(() => null);
|
|
2645
|
+
if (!token)
|
|
2646
|
+
return sendJson(res, 400, { error: 'Paste a Cloudflare API token.' });
|
|
2647
|
+
const first = { ...freshProgress(input.host, input.email), state: 'running' };
|
|
2648
|
+
startSetup(lease, (onProgress, signal) => runCloudflareSetup(input, setupDepsFor(token, lease, signal), onProgress), first);
|
|
2649
|
+
handedOff = true;
|
|
2650
|
+
return sendJson(res, 202, await setupView());
|
|
2651
|
+
}
|
|
2652
|
+
finally {
|
|
2653
|
+
if (!handedOff)
|
|
2654
|
+
lease.release();
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
/*
|
|
2658
|
+
* The setup form's domain choice: check the token and list the zones it
|
|
2659
|
+
* can see. The pasted token is only used for these two calls — keeping it
|
|
2660
|
+
* stays with setup — and never goes back out, not even in an error.
|
|
2661
|
+
*/
|
|
2662
|
+
if (path === '/api/access/cloudflare-access/zones') {
|
|
2663
|
+
if (session.via !== 'local')
|
|
2664
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
2665
|
+
const body = await readJsonBody(req).catch(() => ({}));
|
|
2666
|
+
const pasted = typeof body?.token === 'string' ? body.token.trim() : '';
|
|
2667
|
+
if (pasted && (/\s/.test(pasted) || pasted.length < 20 || pasted.length > 400))
|
|
2668
|
+
return sendJson(res, 400, { error: 'That doesn’t look like a Cloudflare API token.' });
|
|
2669
|
+
const token = pasted || await tokenStore().use().catch(() => null);
|
|
2670
|
+
if (!token)
|
|
2671
|
+
return sendJson(res, 400, { error: 'Paste a Cloudflare API token.' });
|
|
2672
|
+
const api = createCloudflareApi({ token, transport: deps.cloudflare?.api?.transport, baseUrl: deps.cloudflare?.api?.baseUrl });
|
|
2673
|
+
try {
|
|
2674
|
+
if (await api.verifyToken() === 'inactive')
|
|
2675
|
+
return sendJson(res, 400, { error: 'Cloudflare says this API token is not active. Check that it has not expired or been turned off.' });
|
|
2676
|
+
const zones = await api.zones();
|
|
2677
|
+
return sendJson(res, 200, { zones: zones.map((z) => ({ id: z.id, name: z.name })) });
|
|
2678
|
+
}
|
|
2679
|
+
catch (error) {
|
|
2680
|
+
if (!(error instanceof CloudflareApiError))
|
|
2681
|
+
throw error;
|
|
2682
|
+
const refused = error.status === 401 || error.permission !== undefined || (error.status >= 400 && error.status < 500 && error.status !== 429);
|
|
2683
|
+
return sendJson(res, refused ? 400 : 502, { error: error.message });
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
if (path === '/api/access/cloudflare-access/test') {
|
|
2687
|
+
if (session.via !== 'local')
|
|
2688
|
+
return sendJson(res, 403, { error: 'Change this from the computer buddi runs on.' });
|
|
2689
|
+
const body = await readJsonBody(req).catch(() => ({}));
|
|
2690
|
+
const team = normalizeTeamDomain(typeof body.teamDomain === 'string' ? body.teamDomain : (await readCloudflareSetting()).teamDomain);
|
|
2691
|
+
if (!plausibleTeamDomain(team)) {
|
|
2692
|
+
return sendJson(res, 400, { error: 'That is not a Cloudflare team domain. It looks like yourteam.cloudflareaccess.com, under Zero Trust → Settings.' });
|
|
2693
|
+
}
|
|
2694
|
+
const result = await jwks.refresh(team);
|
|
2695
|
+
return sendJson(res, 200, {
|
|
2696
|
+
...result,
|
|
2697
|
+
teamDomain: team,
|
|
2698
|
+
sentence: result.ok ? `${team} answered with ${result.keys} signing key${result.keys === 1 ? '' : 's'}.` : result.error,
|
|
2699
|
+
listening: ingress.port() !== null,
|
|
2700
|
+
ingressPort: ingress.port(),
|
|
2701
|
+
});
|
|
2702
|
+
}
|
|
2232
2703
|
if (path === '/api/extension/pair') {
|
|
2233
2704
|
// A six-digit code is worth guessing at scale, so a wrong one costs a
|
|
2234
2705
|
// budget — this session's pairing budget, not the shared sign-in one.
|
|
@@ -2275,24 +2746,47 @@ export function createWebApp(deps) {
|
|
|
2275
2746
|
return sendJson(res, 200, { ok: false, message: error instanceof Error ? error.message : String(error) });
|
|
2276
2747
|
}
|
|
2277
2748
|
}
|
|
2278
|
-
if (path === '/api/browser/settings'
|
|
2749
|
+
if (path === '/api/browser/settings') {
|
|
2279
2750
|
const body = await readJsonBody(req);
|
|
2280
2751
|
try {
|
|
2281
|
-
if (
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
return sendJson(res, 200, await browser.configure(body));
|
|
2285
|
-
}
|
|
2286
|
-
if (!body || typeof body !== 'object' || Array.isArray(body) || Object.keys(body).some((key) => key !== 'prompt') || ('prompt' in body && typeof body.prompt !== 'boolean'))
|
|
2287
|
-
return sendJson(res, 400, { error: 'Expected {prompt: boolean}' });
|
|
2288
|
-
if (!browser.checkPermissions)
|
|
2289
|
-
return sendJson(res, 409, { error: 'This host does not support native permission checks.' });
|
|
2290
|
-
return sendJson(res, 200, await browser.checkPermissions(body.prompt === true));
|
|
2752
|
+
if (!browser.configure)
|
|
2753
|
+
return sendJson(res, 409, { error: 'This host does not support changing control modes.' });
|
|
2754
|
+
return sendJson(res, 200, await browser.configure(body));
|
|
2291
2755
|
}
|
|
2292
2756
|
catch (error) {
|
|
2293
2757
|
return sendJson(res, 409, { error: error instanceof Error ? error.message : String(error) });
|
|
2294
2758
|
}
|
|
2295
2759
|
}
|
|
2760
|
+
/*
|
|
2761
|
+
* Pin one conversation to a route (the chip under the composer,
|
|
2762
|
+
* `/use browser:chrome`), or clear it with `auto`. A pin narrows; it never
|
|
2763
|
+
* allows a route the owner's switches forbid.
|
|
2764
|
+
*/
|
|
2765
|
+
if (path === '/api/browser/pin') {
|
|
2766
|
+
const body = await readJsonBody(req);
|
|
2767
|
+
if (typeof body?.conversationId !== 'string' || typeof body.route !== 'string')
|
|
2768
|
+
return sendJson(res, 400, { error: 'Expected {conversationId: string, route: auto|own|chrome|apps}' });
|
|
2769
|
+
if (!browser.pin)
|
|
2770
|
+
return sendJson(res, 409, { error: 'This host cannot pin a route.' });
|
|
2771
|
+
try {
|
|
2772
|
+
return sendJson(res, 200, await browser.pin(body.conversationId, body.route));
|
|
2773
|
+
}
|
|
2774
|
+
catch (error) {
|
|
2775
|
+
return sendJson(res, 400, { error: error instanceof Error ? error.message : String(error) });
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
/*
|
|
2779
|
+
* A tap on a browser card (Look, Keep going, Take over, Use my Chrome,
|
|
2780
|
+
* Resume) from a page that draws its own buttons: the same as the owner
|
|
2781
|
+
* sending the label in the chat, without a message.
|
|
2782
|
+
*/
|
|
2783
|
+
if (path === '/api/browser/card') {
|
|
2784
|
+
const body = await readJsonBody(req);
|
|
2785
|
+
if (typeof body?.conversationId !== 'string' || typeof body.answer !== 'string' || body.answer.length > 80)
|
|
2786
|
+
return sendJson(res, 400, { error: 'Expected {conversationId: string, answer: string}' });
|
|
2787
|
+
const answered = await browser.touch?.({ conversationId: body.conversationId, text: body.answer });
|
|
2788
|
+
return sendJson(res, 200, { ...(answered && 'answered' in answered ? answered : {}), status: browser.status({ conversationId: body.conversationId }) });
|
|
2789
|
+
}
|
|
2296
2790
|
const control = /^\/api\/browser\/(stop|takeover|resume|release)$/.exec(path);
|
|
2297
2791
|
if (control) {
|
|
2298
2792
|
const body = await readJsonBody(req);
|
|
@@ -2307,7 +2801,8 @@ export function createWebApp(deps) {
|
|
|
2307
2801
|
// frozen picture.
|
|
2308
2802
|
if (action !== 'takeover')
|
|
2309
2803
|
await hand.close(action === 'stop' ? undefined : sessionId, action === 'resume' ? 'You gave the screen back.' : 'That session was released.');
|
|
2310
|
-
|
|
2804
|
+
// Stop agents' browsing expires (an hour by default); `forever` is "until I say".
|
|
2805
|
+
const status = await browser.control(action, sessionId, action === 'stop' && body?.forever === true ? { forever: true } : undefined);
|
|
2311
2806
|
// Whether this screen can be driven from here at all. The dashboard
|
|
2312
2807
|
// shows the mode's own sentence when it cannot.
|
|
2313
2808
|
const taken = sessionId ?? status.session?.id;
|
|
@@ -2318,7 +2813,7 @@ export function createWebApp(deps) {
|
|
|
2318
2813
|
* as that, with a reason the dashboard offers its ways out on, rather
|
|
2319
2814
|
* than the mode's "use this conversation's host tab".
|
|
2320
2815
|
*/
|
|
2321
|
-
if (offer && offer.supported && !offer.hand && status.mode === 'extension' && !extension.connected()) {
|
|
2816
|
+
if (offer && offer.supported && !offer.hand && (status.route === 'chrome' || status.mode === 'extension') && !extension.connected()) {
|
|
2322
2817
|
return sendJson(res, 200, { ...status, hand: false, handReason: 'browser-offline', handMessage: 'Your browser isn’t connected.' });
|
|
2323
2818
|
}
|
|
2324
2819
|
return sendJson(res, 200, offer
|
|
@@ -2369,6 +2864,20 @@ export function createWebApp(deps) {
|
|
|
2369
2864
|
* staged exactly like a `.tgz` path they could have typed, and the upload
|
|
2370
2865
|
* is deleted once staging has copied it.
|
|
2371
2866
|
*/
|
|
2867
|
+
/*
|
|
2868
|
+
* A skill bundle (.zip), handed over raw like a plugin tarball: streamed
|
|
2869
|
+
* to a temporary file under a cap, checked, unpacked into staging, and
|
|
2870
|
+
* answered with what is inside. Nothing in it runs, and nothing is kept
|
|
2871
|
+
* until the owner accepts it (`POST /api/skills/bundles/:staged`).
|
|
2872
|
+
*/
|
|
2873
|
+
if (path === '/api/skills/bundles') {
|
|
2874
|
+
const incoming = incomingDirFor(skillsDeps().skillsDir);
|
|
2875
|
+
const filename = uploadLabel(first(req.headers['x-filename']));
|
|
2876
|
+
const received = await receiveBundleUpload(incoming, req, filename);
|
|
2877
|
+
if ('status' in received)
|
|
2878
|
+
return reply(res, received);
|
|
2879
|
+
return reply(res, stageBundle(incoming, received.path, filename, deps.now()));
|
|
2880
|
+
}
|
|
2372
2881
|
if (path === '/api/plugins/upload') {
|
|
2373
2882
|
const received = await receivePluginUpload(pluginDeps(), req, first(req.headers['x-filename']));
|
|
2374
2883
|
if ('status' in received)
|
|
@@ -3014,6 +3523,20 @@ export function createWebApp(deps) {
|
|
|
3014
3523
|
* Chapter 3: what buddi takes on. Records the tiles and starts the By-buddi
|
|
3015
3524
|
* installs in the background; answers at once with a job per plugin.
|
|
3016
3525
|
*/
|
|
3526
|
+
/*
|
|
3527
|
+
* Fetch a model into the local Ollama, for the first run's "on this
|
|
3528
|
+
* computer". Answers at once; GET the same path for the progress.
|
|
3529
|
+
*/
|
|
3530
|
+
if (path === '/api/onboarding/ollama/pull') {
|
|
3531
|
+
try {
|
|
3532
|
+
return sendJson(res, 202, { pull: ollamaPulls.start(typeof body.model === 'string' ? body.model : '') });
|
|
3533
|
+
}
|
|
3534
|
+
catch (error) {
|
|
3535
|
+
if (error instanceof PullRefusal)
|
|
3536
|
+
return sendJson(res, error.status, { error: error.message });
|
|
3537
|
+
throw error;
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3017
3540
|
if (path === '/api/onboarding/take-on') {
|
|
3018
3541
|
try {
|
|
3019
3542
|
return sendJson(res, 202, await startTakeOn(takeOnDeps(), body.tiles));
|
|
@@ -3193,7 +3716,7 @@ export function createWebApp(deps) {
|
|
|
3193
3716
|
*/
|
|
3194
3717
|
if (path === '/api/owner') {
|
|
3195
3718
|
const patch = {};
|
|
3196
|
-
for (const key of ['preferredName', 'timezone', 'language', 'about']) {
|
|
3719
|
+
for (const key of ['preferredName', 'timezone', 'language', 'about', 'fullName', 'pronouns']) {
|
|
3197
3720
|
const given = body[key];
|
|
3198
3721
|
if (given === undefined)
|
|
3199
3722
|
continue;
|
|
@@ -3218,8 +3741,27 @@ export function createWebApp(deps) {
|
|
|
3218
3741
|
return sendJson(res, 400, { error: 'The name is too long (80 characters at most).' });
|
|
3219
3742
|
if (patch.about && patch.about.length > 1000)
|
|
3220
3743
|
return sendJson(res, 400, { error: 'Keep the line about you under 1,000 characters.' });
|
|
3744
|
+
if (patch.fullName && patch.fullName.length > 120)
|
|
3745
|
+
return sendJson(res, 400, { error: 'The full name is too long (120 characters at most).' });
|
|
3746
|
+
if (patch.pronouns && patch.pronouns.length > 40)
|
|
3747
|
+
return sendJson(res, 400, { error: 'Keep the pronouns under 40 characters.' });
|
|
3748
|
+
// The birthday: day and month (the year optional), or null to clear it.
|
|
3749
|
+
if (body.birthday !== undefined) {
|
|
3750
|
+
if (body.birthday === null)
|
|
3751
|
+
patch.birthday = null;
|
|
3752
|
+
else {
|
|
3753
|
+
const birthday = validDayMonth(body.birthday);
|
|
3754
|
+
if (!birthday)
|
|
3755
|
+
return sendJson(res, 400, { error: 'The birthday needs a real day and month; the year is optional.' });
|
|
3756
|
+
patch.birthday = birthday;
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3221
3759
|
// The zone applies at once; schedules kept in the old one move with it.
|
|
3222
3760
|
const { profile, zoneChange } = await saveOwnerProfile(deps.pool, patch, deps.env ?? process.env);
|
|
3761
|
+
// The birthday greeting follows the new day at once (missions/dates.ts).
|
|
3762
|
+
if (patch.birthday !== undefined) {
|
|
3763
|
+
await syncDateMissions({ pool: deps.pool, catalog: deps.catalog, now: deps.now, log }).catch((err) => log(`dates: ${err instanceof Error ? err.message : String(err)}`));
|
|
3764
|
+
}
|
|
3223
3765
|
if (zoneChange)
|
|
3224
3766
|
log(`owner: timezone ${zoneChange.from} → ${zoneChange.to}${zoneChange.missions.length > 0 ? `; moved ${zoneChange.missions.join(', ')}` : ''}`);
|
|
3225
3767
|
return sendJson(res, 200, { ...profile, places: await placesList(deps.pool), detectedTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone, zones: knownTimezones() });
|
|
@@ -3233,6 +3775,12 @@ export function createWebApp(deps) {
|
|
|
3233
3775
|
return sendJson(res, answered.status, answered.body);
|
|
3234
3776
|
}
|
|
3235
3777
|
}
|
|
3778
|
+
/* People, the owner's side: add, change, forget, bring back (web/people.ts). */
|
|
3779
|
+
if (path.startsWith('/api/memory/people')) {
|
|
3780
|
+
const answered = await peopleRoute({ pool: deps.pool, catalog: deps.catalog, now: deps.now, log }, 'POST', path, body);
|
|
3781
|
+
if (answered)
|
|
3782
|
+
return sendJson(res, answered.status, answered.body);
|
|
3783
|
+
}
|
|
3236
3784
|
/* Memory, the owner's side: correct a preference, retire one, edit or forget a note. */
|
|
3237
3785
|
if (path === '/api/memory/preferences') {
|
|
3238
3786
|
const key = typeof body.key === 'string' ? body.key.trim() : '';
|
|
@@ -3424,6 +3972,9 @@ export function createWebApp(deps) {
|
|
|
3424
3972
|
/* The Skills page's writes (skills.ts): each checked by reloading the catalog. */
|
|
3425
3973
|
if (path === '/api/skills')
|
|
3426
3974
|
return reply(res, createSkillRoute(skillsDeps(), body));
|
|
3975
|
+
const bundleAccept = /^\/api\/skills\/bundles\/([^/]+)$/.exec(path);
|
|
3976
|
+
if (bundleAccept)
|
|
3977
|
+
return reply(res, acceptBundleRoute(skillsDeps(), decodeURIComponent(bundleAccept[1]), body));
|
|
3427
3978
|
const skillWrite = /^\/api\/skills\/([^/]+)\/(text|grants|trust)$/.exec(path);
|
|
3428
3979
|
if (skillWrite) {
|
|
3429
3980
|
const id = decodeURIComponent(skillWrite[1]);
|
|
@@ -3598,6 +4149,10 @@ export async function startWebServer(deps) {
|
|
|
3598
4149
|
*/
|
|
3599
4150
|
if (previewPort !== null)
|
|
3600
4151
|
publishPreviewPort(deps.env ?? process.env, previewPort);
|
|
4152
|
+
// The ingress listener, after the previews have taken their port: bound
|
|
4153
|
+
// now when Cloudflare Access is on, and from then on as the setting changes.
|
|
4154
|
+
const ingress = ingressOf(server);
|
|
4155
|
+
await ingress.sync();
|
|
3601
4156
|
/*
|
|
3602
4157
|
* An approval nobody decides expires, and a delegation waiting on one is
|
|
3603
4158
|
* handed the expiry as its failure: the approval's own lifetime is the
|
|
@@ -3615,6 +4170,7 @@ export async function startWebServer(deps) {
|
|
|
3615
4170
|
server,
|
|
3616
4171
|
port,
|
|
3617
4172
|
previewPort,
|
|
4173
|
+
ingress,
|
|
3618
4174
|
url: webUrl({ host: deps.config.host, port }),
|
|
3619
4175
|
chat: webChatOf(server),
|
|
3620
4176
|
close: async () => {
|
|
@@ -3626,6 +4182,7 @@ export async function startWebServer(deps) {
|
|
|
3626
4182
|
// still held, and the next thing to want it — the next test, the
|
|
3627
4183
|
// gateway coming back up — finds it taken.
|
|
3628
4184
|
await Promise.all([
|
|
4185
|
+
ingress.close(),
|
|
3629
4186
|
new Promise((resolve) => {
|
|
3630
4187
|
if (!previews || previewPort === null)
|
|
3631
4188
|
return resolve();
|