@aitne/daemon 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/adapters/composite-dashboard-stream.d.ts +42 -0
- package/dist/adapters/composite-dashboard-stream.d.ts.map +1 -0
- package/dist/adapters/composite-dashboard-stream.js +49 -0
- package/dist/adapters/composite-dashboard-stream.js.map +1 -0
- package/dist/adapters/dashboard-adapter.d.ts +104 -0
- package/dist/adapters/dashboard-adapter.d.ts.map +1 -0
- package/dist/adapters/dashboard-adapter.js +216 -0
- package/dist/adapters/dashboard-adapter.js.map +1 -0
- package/dist/adapters/discord.d.ts +77 -0
- package/dist/adapters/discord.d.ts.map +1 -0
- package/dist/adapters/discord.js +339 -0
- package/dist/adapters/discord.js.map +1 -0
- package/dist/adapters/docs-qa-adapter.d.ts +123 -0
- package/dist/adapters/docs-qa-adapter.d.ts.map +1 -0
- package/dist/adapters/docs-qa-adapter.js +218 -0
- package/dist/adapters/docs-qa-adapter.js.map +1 -0
- package/dist/adapters/message-hub.d.ts +70 -0
- package/dist/adapters/message-hub.d.ts.map +1 -0
- package/dist/adapters/message-hub.js +359 -0
- package/dist/adapters/message-hub.js.map +1 -0
- package/dist/adapters/notification-manager.d.ts +99 -0
- package/dist/adapters/notification-manager.d.ts.map +1 -0
- package/dist/adapters/notification-manager.js +498 -0
- package/dist/adapters/notification-manager.js.map +1 -0
- package/dist/adapters/outbound-text.d.ts +28 -0
- package/dist/adapters/outbound-text.d.ts.map +1 -0
- package/dist/adapters/outbound-text.js +58 -0
- package/dist/adapters/outbound-text.js.map +1 -0
- package/dist/adapters/slack-adapter.d.ts +82 -0
- package/dist/adapters/slack-adapter.d.ts.map +1 -0
- package/dist/adapters/slack-adapter.js +359 -0
- package/dist/adapters/slack-adapter.js.map +1 -0
- package/dist/adapters/telegram-adapter.d.ts +107 -0
- package/dist/adapters/telegram-adapter.d.ts.map +1 -0
- package/dist/adapters/telegram-adapter.js +477 -0
- package/dist/adapters/telegram-adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +92 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/whatsapp-adapter.d.ts +213 -0
- package/dist/adapters/whatsapp-adapter.d.ts.map +1 -0
- package/dist/adapters/whatsapp-adapter.js +1216 -0
- package/dist/adapters/whatsapp-adapter.js.map +1 -0
- package/dist/api/chat-binding-query.d.ts +36 -0
- package/dist/api/chat-binding-query.d.ts.map +1 -0
- package/dist/api/chat-binding-query.js +63 -0
- package/dist/api/chat-binding-query.js.map +1 -0
- package/dist/api/chat-session-resume.d.ts +12 -0
- package/dist/api/chat-session-resume.d.ts.map +1 -0
- package/dist/api/chat-session-resume.js +21 -0
- package/dist/api/chat-session-resume.js.map +1 -0
- package/dist/api/delegated-proxy-helper.d.ts +33 -0
- package/dist/api/delegated-proxy-helper.d.ts.map +1 -0
- package/dist/api/delegated-proxy-helper.js +54 -0
- package/dist/api/delegated-proxy-helper.js.map +1 -0
- package/dist/api/directory-picker.d.ts +38 -0
- package/dist/api/directory-picker.d.ts.map +1 -0
- package/dist/api/directory-picker.js +278 -0
- package/dist/api/directory-picker.js.map +1 -0
- package/dist/api/env-writer.d.ts +25 -0
- package/dist/api/env-writer.d.ts.map +1 -0
- package/dist/api/env-writer.js +421 -0
- package/dist/api/env-writer.js.map +1 -0
- package/dist/api/integration-route-gate.d.ts +60 -0
- package/dist/api/integration-route-gate.d.ts.map +1 -0
- package/dist/api/integration-route-gate.js +83 -0
- package/dist/api/integration-route-gate.js.map +1 -0
- package/dist/api/json-body.d.ts +29 -0
- package/dist/api/json-body.d.ts.map +1 -0
- package/dist/api/json-body.js +87 -0
- package/dist/api/json-body.js.map +1 -0
- package/dist/api/routes/activity-sources.d.ts +20 -0
- package/dist/api/routes/activity-sources.d.ts.map +1 -0
- package/dist/api/routes/activity-sources.js +18 -0
- package/dist/api/routes/activity-sources.js.map +1 -0
- package/dist/api/routes/agent.d.ts +4 -0
- package/dist/api/routes/agent.d.ts.map +1 -0
- package/dist/api/routes/agent.js +619 -0
- package/dist/api/routes/agent.js.map +1 -0
- package/dist/api/routes/apple-calendar.d.ts +31 -0
- package/dist/api/routes/apple-calendar.d.ts.map +1 -0
- package/dist/api/routes/apple-calendar.js +310 -0
- package/dist/api/routes/apple-calendar.js.map +1 -0
- package/dist/api/routes/attachments.d.ts +36 -0
- package/dist/api/routes/attachments.d.ts.map +1 -0
- package/dist/api/routes/attachments.js +305 -0
- package/dist/api/routes/attachments.js.map +1 -0
- package/dist/api/routes/backends.d.ts +4 -0
- package/dist/api/routes/backends.d.ts.map +1 -0
- package/dist/api/routes/backends.js +1132 -0
- package/dist/api/routes/backends.js.map +1 -0
- package/dist/api/routes/books.d.ts +63 -0
- package/dist/api/routes/books.d.ts.map +1 -0
- package/dist/api/routes/books.js +467 -0
- package/dist/api/routes/books.js.map +1 -0
- package/dist/api/routes/calendar.d.ts +36 -0
- package/dist/api/routes/calendar.d.ts.map +1 -0
- package/dist/api/routes/calendar.js +351 -0
- package/dist/api/routes/calendar.js.map +1 -0
- package/dist/api/routes/commands.d.ts +4 -0
- package/dist/api/routes/commands.d.ts.map +1 -0
- package/dist/api/routes/commands.js +251 -0
- package/dist/api/routes/commands.js.map +1 -0
- package/dist/api/routes/context.d.ts +57 -0
- package/dist/api/routes/context.d.ts.map +1 -0
- package/dist/api/routes/context.js +1765 -0
- package/dist/api/routes/context.js.map +1 -0
- package/dist/api/routes/dashboard.d.ts +29 -0
- package/dist/api/routes/dashboard.d.ts.map +1 -0
- package/dist/api/routes/dashboard.js +2062 -0
- package/dist/api/routes/dashboard.js.map +1 -0
- package/dist/api/routes/delegated-sync.d.ts +4 -0
- package/dist/api/routes/delegated-sync.d.ts.map +1 -0
- package/dist/api/routes/delegated-sync.js +192 -0
- package/dist/api/routes/delegated-sync.js.map +1 -0
- package/dist/api/routes/delegated.d.ts +42 -0
- package/dist/api/routes/delegated.d.ts.map +1 -0
- package/dist/api/routes/delegated.js +250 -0
- package/dist/api/routes/delegated.js.map +1 -0
- package/dist/api/routes/docs.d.ts +34 -0
- package/dist/api/routes/docs.d.ts.map +1 -0
- package/dist/api/routes/docs.js +580 -0
- package/dist/api/routes/docs.js.map +1 -0
- package/dist/api/routes/entities.d.ts +9 -0
- package/dist/api/routes/entities.d.ts.map +1 -0
- package/dist/api/routes/entities.js +176 -0
- package/dist/api/routes/entities.js.map +1 -0
- package/dist/api/routes/git-accounts.d.ts +23 -0
- package/dist/api/routes/git-accounts.d.ts.map +1 -0
- package/dist/api/routes/git-accounts.js +227 -0
- package/dist/api/routes/git-accounts.js.map +1 -0
- package/dist/api/routes/git-templates.d.ts +50 -0
- package/dist/api/routes/git-templates.d.ts.map +1 -0
- package/dist/api/routes/git-templates.js +276 -0
- package/dist/api/routes/git-templates.js.map +1 -0
- package/dist/api/routes/git.d.ts +34 -0
- package/dist/api/routes/git.d.ts.map +1 -0
- package/dist/api/routes/git.js +126 -0
- package/dist/api/routes/git.js.map +1 -0
- package/dist/api/routes/github.d.ts +34 -0
- package/dist/api/routes/github.d.ts.map +1 -0
- package/dist/api/routes/github.js +465 -0
- package/dist/api/routes/github.js.map +1 -0
- package/dist/api/routes/health.d.ts +4 -0
- package/dist/api/routes/health.d.ts.map +1 -0
- package/dist/api/routes/health.js +257 -0
- package/dist/api/routes/health.js.map +1 -0
- package/dist/api/routes/integrations-reconcile.d.ts +33 -0
- package/dist/api/routes/integrations-reconcile.d.ts.map +1 -0
- package/dist/api/routes/integrations-reconcile.js +463 -0
- package/dist/api/routes/integrations-reconcile.js.map +1 -0
- package/dist/api/routes/integrations.d.ts +19 -0
- package/dist/api/routes/integrations.d.ts.map +1 -0
- package/dist/api/routes/integrations.js +1384 -0
- package/dist/api/routes/integrations.js.map +1 -0
- package/dist/api/routes/knowledge.d.ts +4 -0
- package/dist/api/routes/knowledge.d.ts.map +1 -0
- package/dist/api/routes/knowledge.js +224 -0
- package/dist/api/routes/knowledge.js.map +1 -0
- package/dist/api/routes/mail.d.ts +39 -0
- package/dist/api/routes/mail.d.ts.map +1 -0
- package/dist/api/routes/mail.js +1406 -0
- package/dist/api/routes/mail.js.map +1 -0
- package/dist/api/routes/managed-tasks.d.ts +48 -0
- package/dist/api/routes/managed-tasks.d.ts.map +1 -0
- package/dist/api/routes/managed-tasks.js +844 -0
- package/dist/api/routes/managed-tasks.js.map +1 -0
- package/dist/api/routes/mcp.d.ts +50 -0
- package/dist/api/routes/mcp.d.ts.map +1 -0
- package/dist/api/routes/mcp.js +470 -0
- package/dist/api/routes/mcp.js.map +1 -0
- package/dist/api/routes/metrics.d.ts +13 -0
- package/dist/api/routes/metrics.d.ts.map +1 -0
- package/dist/api/routes/metrics.js +117 -0
- package/dist/api/routes/metrics.js.map +1 -0
- package/dist/api/routes/notion.d.ts +35 -0
- package/dist/api/routes/notion.d.ts.map +1 -0
- package/dist/api/routes/notion.js +442 -0
- package/dist/api/routes/notion.js.map +1 -0
- package/dist/api/routes/observations.d.ts +4 -0
- package/dist/api/routes/observations.d.ts.map +1 -0
- package/dist/api/routes/observations.js +177 -0
- package/dist/api/routes/observations.js.map +1 -0
- package/dist/api/routes/obsidian.d.ts +16 -0
- package/dist/api/routes/obsidian.d.ts.map +1 -0
- package/dist/api/routes/obsidian.js +321 -0
- package/dist/api/routes/obsidian.js.map +1 -0
- package/dist/api/routes/profile-questions.d.ts +17 -0
- package/dist/api/routes/profile-questions.d.ts.map +1 -0
- package/dist/api/routes/profile-questions.js +115 -0
- package/dist/api/routes/profile-questions.js.map +1 -0
- package/dist/api/routes/receipts.d.ts +4 -0
- package/dist/api/routes/receipts.d.ts.map +1 -0
- package/dist/api/routes/receipts.js +155 -0
- package/dist/api/routes/receipts.js.map +1 -0
- package/dist/api/routes/recurring-schedules.d.ts +4 -0
- package/dist/api/routes/recurring-schedules.d.ts.map +1 -0
- package/dist/api/routes/recurring-schedules.js +137 -0
- package/dist/api/routes/recurring-schedules.js.map +1 -0
- package/dist/api/routes/repositories.d.ts +40 -0
- package/dist/api/routes/repositories.d.ts.map +1 -0
- package/dist/api/routes/repositories.js +857 -0
- package/dist/api/routes/repositories.js.map +1 -0
- package/dist/api/routes/setup-migrate.d.ts +74 -0
- package/dist/api/routes/setup-migrate.d.ts.map +1 -0
- package/dist/api/routes/setup-migrate.js +944 -0
- package/dist/api/routes/setup-migrate.js.map +1 -0
- package/dist/api/routes/setup.d.ts +4 -0
- package/dist/api/routes/setup.d.ts.map +1 -0
- package/dist/api/routes/setup.js +443 -0
- package/dist/api/routes/setup.js.map +1 -0
- package/dist/api/routes/skill-curation.d.ts +5 -0
- package/dist/api/routes/skill-curation.d.ts.map +1 -0
- package/dist/api/routes/skill-curation.js +728 -0
- package/dist/api/routes/skill-curation.js.map +1 -0
- package/dist/api/routes/skills.d.ts +52 -0
- package/dist/api/routes/skills.d.ts.map +1 -0
- package/dist/api/routes/skills.js +429 -0
- package/dist/api/routes/skills.js.map +1 -0
- package/dist/api/routes/sot-bindings.d.ts +20 -0
- package/dist/api/routes/sot-bindings.d.ts.map +1 -0
- package/dist/api/routes/sot-bindings.js +163 -0
- package/dist/api/routes/sot-bindings.js.map +1 -0
- package/dist/api/routes/sse.d.ts +86 -0
- package/dist/api/routes/sse.d.ts.map +1 -0
- package/dist/api/routes/sse.js +378 -0
- package/dist/api/routes/sse.js.map +1 -0
- package/dist/api/routes/system.d.ts +4 -0
- package/dist/api/routes/system.d.ts.map +1 -0
- package/dist/api/routes/system.js +207 -0
- package/dist/api/routes/system.js.map +1 -0
- package/dist/api/routes/task-flows.d.ts +30 -0
- package/dist/api/routes/task-flows.d.ts.map +1 -0
- package/dist/api/routes/task-flows.js +155 -0
- package/dist/api/routes/task-flows.js.map +1 -0
- package/dist/api/routes/travel-bookings.d.ts +4 -0
- package/dist/api/routes/travel-bookings.d.ts.map +1 -0
- package/dist/api/routes/travel-bookings.js +142 -0
- package/dist/api/routes/travel-bookings.js.map +1 -0
- package/dist/api/routes/travel-time.d.ts +8 -0
- package/dist/api/routes/travel-time.d.ts.map +1 -0
- package/dist/api/routes/travel-time.js +87 -0
- package/dist/api/routes/travel-time.js.map +1 -0
- package/dist/api/routes/triggers.d.ts +4 -0
- package/dist/api/routes/triggers.d.ts.map +1 -0
- package/dist/api/routes/triggers.js +101 -0
- package/dist/api/routes/triggers.js.map +1 -0
- package/dist/api/routes/voice.d.ts +48 -0
- package/dist/api/routes/voice.d.ts.map +1 -0
- package/dist/api/routes/voice.js +232 -0
- package/dist/api/routes/voice.js.map +1 -0
- package/dist/api/server.d.ts +428 -0
- package/dist/api/server.d.ts.map +1 -0
- package/dist/api/server.js +558 -0
- package/dist/api/server.js.map +1 -0
- package/dist/config.d.ts +136 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +699 -0
- package/dist/config.js.map +1 -0
- package/dist/core/agent-core.d.ts +517 -0
- package/dist/core/agent-core.d.ts.map +1 -0
- package/dist/core/agent-core.js +102 -0
- package/dist/core/agent-core.js.map +1 -0
- package/dist/core/alerts.d.ts +86 -0
- package/dist/core/alerts.d.ts.map +1 -0
- package/dist/core/alerts.js +304 -0
- package/dist/core/alerts.js.map +1 -0
- package/dist/core/atomic-write.d.ts +51 -0
- package/dist/core/atomic-write.d.ts.map +1 -0
- package/dist/core/atomic-write.js +135 -0
- package/dist/core/atomic-write.js.map +1 -0
- package/dist/core/backends/api-key-probe.d.ts +40 -0
- package/dist/core/backends/api-key-probe.d.ts.map +1 -0
- package/dist/core/backends/api-key-probe.js +116 -0
- package/dist/core/backends/api-key-probe.js.map +1 -0
- package/dist/core/backends/auth-health-monitor.d.ts +373 -0
- package/dist/core/backends/auth-health-monitor.d.ts.map +1 -0
- package/dist/core/backends/auth-health-monitor.js +950 -0
- package/dist/core/backends/auth-health-monitor.js.map +1 -0
- package/dist/core/backends/auth-recovery.d.ts +263 -0
- package/dist/core/backends/auth-recovery.d.ts.map +1 -0
- package/dist/core/backends/auth-recovery.js +1086 -0
- package/dist/core/backends/auth-recovery.js.map +1 -0
- package/dist/core/backends/auth-telemetry.d.ts +81 -0
- package/dist/core/backends/auth-telemetry.d.ts.map +1 -0
- package/dist/core/backends/auth-telemetry.js +108 -0
- package/dist/core/backends/auth-telemetry.js.map +1 -0
- package/dist/core/backends/backend-router.d.ts +272 -0
- package/dist/core/backends/backend-router.d.ts.map +1 -0
- package/dist/core/backends/backend-router.js +759 -0
- package/dist/core/backends/backend-router.js.map +1 -0
- package/dist/core/backends/claude-code-core.d.ts +299 -0
- package/dist/core/backends/claude-code-core.d.ts.map +1 -0
- package/dist/core/backends/claude-code-core.js +2541 -0
- package/dist/core/backends/claude-code-core.js.map +1 -0
- package/dist/core/backends/claude-credentials-store.d.ts +83 -0
- package/dist/core/backends/claude-credentials-store.d.ts.map +1 -0
- package/dist/core/backends/claude-credentials-store.js +243 -0
- package/dist/core/backends/claude-credentials-store.js.map +1 -0
- package/dist/core/backends/cli-utils.d.ts +95 -0
- package/dist/core/backends/cli-utils.d.ts.map +1 -0
- package/dist/core/backends/cli-utils.js +464 -0
- package/dist/core/backends/cli-utils.js.map +1 -0
- package/dist/core/backends/codex-core.d.ts +127 -0
- package/dist/core/backends/codex-core.d.ts.map +1 -0
- package/dist/core/backends/codex-core.js +1693 -0
- package/dist/core/backends/codex-core.js.map +1 -0
- package/dist/core/backends/gemini-cli-core.d.ts +367 -0
- package/dist/core/backends/gemini-cli-core.d.ts.map +1 -0
- package/dist/core/backends/gemini-cli-core.js +2331 -0
- package/dist/core/backends/gemini-cli-core.js.map +1 -0
- package/dist/core/backends/idle-watchdog.d.ts +77 -0
- package/dist/core/backends/idle-watchdog.d.ts.map +1 -0
- package/dist/core/backends/idle-watchdog.js +94 -0
- package/dist/core/backends/idle-watchdog.js.map +1 -0
- package/dist/core/backends/install-methods.d.ts +93 -0
- package/dist/core/backends/install-methods.d.ts.map +1 -0
- package/dist/core/backends/install-methods.js +267 -0
- package/dist/core/backends/install-methods.js.map +1 -0
- package/dist/core/backends/model-registry.d.ts +58 -0
- package/dist/core/backends/model-registry.d.ts.map +1 -0
- package/dist/core/backends/model-registry.js +539 -0
- package/dist/core/backends/model-registry.js.map +1 -0
- package/dist/core/backends/plan-presets.d.ts +123 -0
- package/dist/core/backends/plan-presets.d.ts.map +1 -0
- package/dist/core/backends/plan-presets.js +235 -0
- package/dist/core/backends/plan-presets.js.map +1 -0
- package/dist/core/backends/price-fetcher.d.ts +48 -0
- package/dist/core/backends/price-fetcher.d.ts.map +1 -0
- package/dist/core/backends/price-fetcher.js +248 -0
- package/dist/core/backends/price-fetcher.js.map +1 -0
- package/dist/core/backends/process-config-cascade.d.ts +68 -0
- package/dist/core/backends/process-config-cascade.d.ts.map +1 -0
- package/dist/core/backends/process-config-cascade.js +173 -0
- package/dist/core/backends/process-config-cascade.js.map +1 -0
- package/dist/core/backends/prompt-utils.d.ts +6 -0
- package/dist/core/backends/prompt-utils.d.ts.map +1 -0
- package/dist/core/backends/prompt-utils.js +80 -0
- package/dist/core/backends/prompt-utils.js.map +1 -0
- package/dist/core/backends/proxy-model-registry.d.ts +110 -0
- package/dist/core/backends/proxy-model-registry.d.ts.map +1 -0
- package/dist/core/backends/proxy-model-registry.js +195 -0
- package/dist/core/backends/proxy-model-registry.js.map +1 -0
- package/dist/core/backends/silent-api-error-detector.d.ts +31 -0
- package/dist/core/backends/silent-api-error-detector.d.ts.map +1 -0
- package/dist/core/backends/silent-api-error-detector.js +44 -0
- package/dist/core/backends/silent-api-error-detector.js.map +1 -0
- package/dist/core/bang-commands/commands-cost.d.ts +13 -0
- package/dist/core/bang-commands/commands-cost.d.ts.map +1 -0
- package/dist/core/bang-commands/commands-cost.js +91 -0
- package/dist/core/bang-commands/commands-cost.js.map +1 -0
- package/dist/core/bang-commands/commands-report.d.ts +18 -0
- package/dist/core/bang-commands/commands-report.d.ts.map +1 -0
- package/dist/core/bang-commands/commands-report.js +105 -0
- package/dist/core/bang-commands/commands-report.js.map +1 -0
- package/dist/core/bang-commands/commands-stop-start.d.ts +4 -0
- package/dist/core/bang-commands/commands-stop-start.d.ts.map +1 -0
- package/dist/core/bang-commands/commands-stop-start.js +88 -0
- package/dist/core/bang-commands/commands-stop-start.js.map +1 -0
- package/dist/core/bang-commands/format-utils.d.ts +34 -0
- package/dist/core/bang-commands/format-utils.d.ts.map +1 -0
- package/dist/core/bang-commands/format-utils.js +118 -0
- package/dist/core/bang-commands/format-utils.js.map +1 -0
- package/dist/core/bang-commands/index.d.ts +20 -0
- package/dist/core/bang-commands/index.d.ts.map +1 -0
- package/dist/core/bang-commands/index.js +31 -0
- package/dist/core/bang-commands/index.js.map +1 -0
- package/dist/core/bang-commands/registry.d.ts +72 -0
- package/dist/core/bang-commands/registry.d.ts.map +1 -0
- package/dist/core/bang-commands/registry.js +174 -0
- package/dist/core/bang-commands/registry.js.map +1 -0
- package/dist/core/bang-commands/user-commands.d.ts +86 -0
- package/dist/core/bang-commands/user-commands.d.ts.map +1 -0
- package/dist/core/bang-commands/user-commands.js +212 -0
- package/dist/core/bang-commands/user-commands.js.map +1 -0
- package/dist/core/channel-timeline.d.ts +28 -0
- package/dist/core/channel-timeline.d.ts.map +1 -0
- package/dist/core/channel-timeline.js +117 -0
- package/dist/core/channel-timeline.js.map +1 -0
- package/dist/core/character-block.d.ts +37 -0
- package/dist/core/character-block.d.ts.map +1 -0
- package/dist/core/character-block.js +162 -0
- package/dist/core/character-block.js.map +1 -0
- package/dist/core/context/activity-sources.d.ts +37 -0
- package/dist/core/context/activity-sources.d.ts.map +1 -0
- package/dist/core/context/activity-sources.js +69 -0
- package/dist/core/context/activity-sources.js.map +1 -0
- package/dist/core/context/activity-view-reconciler.d.ts +110 -0
- package/dist/core/context/activity-view-reconciler.d.ts.map +1 -0
- package/dist/core/context/activity-view-reconciler.js +252 -0
- package/dist/core/context/activity-view-reconciler.js.map +1 -0
- package/dist/core/context/activity-view-runner.d.ts +38 -0
- package/dist/core/context/activity-view-runner.d.ts.map +1 -0
- package/dist/core/context/activity-view-runner.js +402 -0
- package/dist/core/context/activity-view-runner.js.map +1 -0
- package/dist/core/context/default-schedules-reconciler.d.ts +85 -0
- package/dist/core/context/default-schedules-reconciler.d.ts.map +1 -0
- package/dist/core/context/default-schedules-reconciler.js +153 -0
- package/dist/core/context/default-schedules-reconciler.js.map +1 -0
- package/dist/core/context/default-schedules-runner.d.ts +40 -0
- package/dist/core/context/default-schedules-runner.d.ts.map +1 -0
- package/dist/core/context/default-schedules-runner.js +233 -0
- package/dist/core/context/default-schedules-runner.js.map +1 -0
- package/dist/core/context/domain-index-reconciler.d.ts +81 -0
- package/dist/core/context/domain-index-reconciler.d.ts.map +1 -0
- package/dist/core/context/domain-index-reconciler.js +199 -0
- package/dist/core/context/domain-index-reconciler.js.map +1 -0
- package/dist/core/context/domain-index-runner.d.ts +35 -0
- package/dist/core/context/domain-index-runner.d.ts.map +1 -0
- package/dist/core/context/domain-index-runner.js +223 -0
- package/dist/core/context/domain-index-runner.js.map +1 -0
- package/dist/core/context/entity-mirror.d.ts +227 -0
- package/dist/core/context/entity-mirror.d.ts.map +1 -0
- package/dist/core/context/entity-mirror.js +629 -0
- package/dist/core/context/entity-mirror.js.map +1 -0
- package/dist/core/context/entity-source-rename.d.ts +61 -0
- package/dist/core/context/entity-source-rename.d.ts.map +1 -0
- package/dist/core/context/entity-source-rename.js +237 -0
- package/dist/core/context/entity-source-rename.js.map +1 -0
- package/dist/core/context/index-reconciler.d.ts +61 -0
- package/dist/core/context/index-reconciler.d.ts.map +1 -0
- package/dist/core/context/index-reconciler.js +329 -0
- package/dist/core/context/index-reconciler.js.map +1 -0
- package/dist/core/context/policy-index-reconciler.d.ts +102 -0
- package/dist/core/context/policy-index-reconciler.d.ts.map +1 -0
- package/dist/core/context/policy-index-reconciler.js +202 -0
- package/dist/core/context/policy-index-reconciler.js.map +1 -0
- package/dist/core/context/policy-index-runner.d.ts +66 -0
- package/dist/core/context/policy-index-runner.d.ts.map +1 -0
- package/dist/core/context/policy-index-runner.js +406 -0
- package/dist/core/context/policy-index-runner.js.map +1 -0
- package/dist/core/context/reconciler-runner.d.ts +44 -0
- package/dist/core/context/reconciler-runner.d.ts.map +1 -0
- package/dist/core/context/reconciler-runner.js +273 -0
- package/dist/core/context/reconciler-runner.js.map +1 -0
- package/dist/core/context-builder.d.ts +115 -0
- package/dist/core/context-builder.d.ts.map +1 -0
- package/dist/core/context-builder.js +1148 -0
- package/dist/core/context-builder.js.map +1 -0
- package/dist/core/context-frontmatter-backfill.d.ts +33 -0
- package/dist/core/context-frontmatter-backfill.d.ts.map +1 -0
- package/dist/core/context-frontmatter-backfill.js +111 -0
- package/dist/core/context-frontmatter-backfill.js.map +1 -0
- package/dist/core/context-frontmatter.d.ts +13 -0
- package/dist/core/context-frontmatter.d.ts.map +1 -0
- package/dist/core/context-frontmatter.js +325 -0
- package/dist/core/context-frontmatter.js.map +1 -0
- package/dist/core/context-health.d.ts +51 -0
- package/dist/core/context-health.d.ts.map +1 -0
- package/dist/core/context-health.js +304 -0
- package/dist/core/context-health.js.map +1 -0
- package/dist/core/context-paths.d.ts +183 -0
- package/dist/core/context-paths.d.ts.map +1 -0
- package/dist/core/context-paths.js +241 -0
- package/dist/core/context-paths.js.map +1 -0
- package/dist/core/context-staleness.d.ts +45 -0
- package/dist/core/context-staleness.d.ts.map +1 -0
- package/dist/core/context-staleness.js +88 -0
- package/dist/core/context-staleness.js.map +1 -0
- package/dist/core/custom-routine-scheduler.d.ts +151 -0
- package/dist/core/custom-routine-scheduler.d.ts.map +1 -0
- package/dist/core/custom-routine-scheduler.js +335 -0
- package/dist/core/custom-routine-scheduler.js.map +1 -0
- package/dist/core/daemon-api-cli.d.ts +33 -0
- package/dist/core/daemon-api-cli.d.ts.map +1 -0
- package/dist/core/daemon-api-cli.js +614 -0
- package/dist/core/daemon-api-cli.js.map +1 -0
- package/dist/core/dashboard-session-cleanup.d.ts +39 -0
- package/dist/core/dashboard-session-cleanup.d.ts.map +1 -0
- package/dist/core/dashboard-session-cleanup.js +108 -0
- package/dist/core/dashboard-session-cleanup.js.map +1 -0
- package/dist/core/dashboard-session-controls.d.ts +41 -0
- package/dist/core/dashboard-session-controls.d.ts.map +1 -0
- package/dist/core/dashboard-session-controls.js +154 -0
- package/dist/core/dashboard-session-controls.js.map +1 -0
- package/dist/core/delegated-connector-health.d.ts +63 -0
- package/dist/core/delegated-connector-health.d.ts.map +1 -0
- package/dist/core/delegated-connector-health.js +157 -0
- package/dist/core/delegated-connector-health.js.map +1 -0
- package/dist/core/dispatcher.d.ts +999 -0
- package/dist/core/dispatcher.d.ts.map +1 -0
- package/dist/core/dispatcher.js +4378 -0
- package/dist/core/dispatcher.js.map +1 -0
- package/dist/core/dm-freshness-metrics.d.ts +73 -0
- package/dist/core/dm-freshness-metrics.d.ts.map +1 -0
- package/dist/core/dm-freshness-metrics.js +138 -0
- package/dist/core/dm-freshness-metrics.js.map +1 -0
- package/dist/core/docs/citation-validator.d.ts +73 -0
- package/dist/core/docs/citation-validator.d.ts.map +1 -0
- package/dist/core/docs/citation-validator.js +195 -0
- package/dist/core/docs/citation-validator.js.map +1 -0
- package/dist/core/docs/extract-terms.d.ts +78 -0
- package/dist/core/docs/extract-terms.d.ts.map +1 -0
- package/dist/core/docs/extract-terms.js +147 -0
- package/dist/core/docs/extract-terms.js.map +1 -0
- package/dist/core/docs/indexer.d.ts +104 -0
- package/dist/core/docs/indexer.d.ts.map +1 -0
- package/dist/core/docs/indexer.js +340 -0
- package/dist/core/docs/indexer.js.map +1 -0
- package/dist/core/drift-effects.d.ts +30 -0
- package/dist/core/drift-effects.d.ts.map +1 -0
- package/dist/core/drift-effects.js +384 -0
- package/dist/core/drift-effects.js.map +1 -0
- package/dist/core/event-bus.d.ts +56 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +135 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/git-project-docs.d.ts +77 -0
- package/dist/core/git-project-docs.d.ts.map +1 -0
- package/dist/core/git-project-docs.js +439 -0
- package/dist/core/git-project-docs.js.map +1 -0
- package/dist/core/health-monitor.d.ts +57 -0
- package/dist/core/health-monitor.d.ts.map +1 -0
- package/dist/core/health-monitor.js +137 -0
- package/dist/core/health-monitor.js.map +1 -0
- package/dist/core/heartbeat.d.ts +26 -0
- package/dist/core/heartbeat.d.ts.map +1 -0
- package/dist/core/heartbeat.js +48 -0
- package/dist/core/heartbeat.js.map +1 -0
- package/dist/core/integration-health.d.ts +49 -0
- package/dist/core/integration-health.d.ts.map +1 -0
- package/dist/core/integration-health.js +89 -0
- package/dist/core/integration-health.js.map +1 -0
- package/dist/core/integration-lifecycle.d.ts +79 -0
- package/dist/core/integration-lifecycle.d.ts.map +1 -0
- package/dist/core/integration-lifecycle.js +153 -0
- package/dist/core/integration-lifecycle.js.map +1 -0
- package/dist/core/integration-main-backend.d.ts +36 -0
- package/dist/core/integration-main-backend.d.ts.map +1 -0
- package/dist/core/integration-main-backend.js +59 -0
- package/dist/core/integration-main-backend.js.map +1 -0
- package/dist/core/integration-probe.d.ts +98 -0
- package/dist/core/integration-probe.d.ts.map +1 -0
- package/dist/core/integration-probe.js +152 -0
- package/dist/core/integration-probe.js.map +1 -0
- package/dist/core/management-md-write-lock.d.ts +68 -0
- package/dist/core/management-md-write-lock.d.ts.map +1 -0
- package/dist/core/management-md-write-lock.js +93 -0
- package/dist/core/management-md-write-lock.js.map +1 -0
- package/dist/core/management-md.d.ts +186 -0
- package/dist/core/management-md.d.ts.map +1 -0
- package/dist/core/management-md.js +652 -0
- package/dist/core/management-md.js.map +1 -0
- package/dist/core/management-registry.d.ts +245 -0
- package/dist/core/management-registry.d.ts.map +1 -0
- package/dist/core/management-registry.js +906 -0
- package/dist/core/management-registry.js.map +1 -0
- package/dist/core/management-telemetry.d.ts +100 -0
- package/dist/core/management-telemetry.d.ts.map +1 -0
- package/dist/core/management-telemetry.js +156 -0
- package/dist/core/management-telemetry.js.map +1 -0
- package/dist/core/message-recorder.d.ts +38 -0
- package/dist/core/message-recorder.d.ts.map +1 -0
- package/dist/core/message-recorder.js +88 -0
- package/dist/core/message-recorder.js.map +1 -0
- package/dist/core/metrics.d.ts +338 -0
- package/dist/core/metrics.d.ts.map +1 -0
- package/dist/core/metrics.js +747 -0
- package/dist/core/metrics.js.map +1 -0
- package/dist/core/migration-backup.d.ts +218 -0
- package/dist/core/migration-backup.d.ts.map +1 -0
- package/dist/core/migration-backup.js +934 -0
- package/dist/core/migration-backup.js.map +1 -0
- package/dist/core/overview-write-lock.d.ts +48 -0
- package/dist/core/overview-write-lock.d.ts.map +1 -0
- package/dist/core/overview-write-lock.js +56 -0
- package/dist/core/overview-write-lock.js.map +1 -0
- package/dist/core/path-compat.d.ts +22 -0
- package/dist/core/path-compat.d.ts.map +1 -0
- package/dist/core/path-compat.js +67 -0
- package/dist/core/path-compat.js.map +1 -0
- package/dist/core/path-rewrite.d.ts +58 -0
- package/dist/core/path-rewrite.d.ts.map +1 -0
- package/dist/core/path-rewrite.js +141 -0
- package/dist/core/path-rewrite.js.map +1 -0
- package/dist/core/policy-files.d.ts +108 -0
- package/dist/core/policy-files.d.ts.map +1 -0
- package/dist/core/policy-files.js +198 -0
- package/dist/core/policy-files.js.map +1 -0
- package/dist/core/profile-questions/seed.d.ts +44 -0
- package/dist/core/profile-questions/seed.d.ts.map +1 -0
- package/dist/core/profile-questions/seed.js +173 -0
- package/dist/core/profile-questions/seed.js.map +1 -0
- package/dist/core/profile-questions/slot-filled.d.ts +51 -0
- package/dist/core/profile-questions/slot-filled.d.ts.map +1 -0
- package/dist/core/profile-questions/slot-filled.js +118 -0
- package/dist/core/profile-questions/slot-filled.js.map +1 -0
- package/dist/core/prompts.d.ts +111 -0
- package/dist/core/prompts.d.ts.map +1 -0
- package/dist/core/prompts.js +267 -0
- package/dist/core/prompts.js.map +1 -0
- package/dist/core/quiet-hours-sync.d.ts +15 -0
- package/dist/core/quiet-hours-sync.d.ts.map +1 -0
- package/dist/core/quiet-hours-sync.js +51 -0
- package/dist/core/quiet-hours-sync.js.map +1 -0
- package/dist/core/read-sensitive-token-manager.d.ts +19 -0
- package/dist/core/read-sensitive-token-manager.d.ts.map +1 -0
- package/dist/core/read-sensitive-token-manager.js +29 -0
- package/dist/core/read-sensitive-token-manager.js.map +1 -0
- package/dist/core/recurrence.d.ts +24 -0
- package/dist/core/recurrence.d.ts.map +1 -0
- package/dist/core/recurrence.js +162 -0
- package/dist/core/recurrence.js.map +1 -0
- package/dist/core/reinstall.d.ts +107 -0
- package/dist/core/reinstall.d.ts.map +1 -0
- package/dist/core/reinstall.js +163 -0
- package/dist/core/reinstall.js.map +1 -0
- package/dist/core/release-assets.d.ts +106 -0
- package/dist/core/release-assets.d.ts.map +1 -0
- package/dist/core/release-assets.js +434 -0
- package/dist/core/release-assets.js.map +1 -0
- package/dist/core/repository-management-docs.d.ts +216 -0
- package/dist/core/repository-management-docs.d.ts.map +1 -0
- package/dist/core/repository-management-docs.js +855 -0
- package/dist/core/repository-management-docs.js.map +1 -0
- package/dist/core/retention.d.ts +164 -0
- package/dist/core/retention.d.ts.map +1 -0
- package/dist/core/retention.js +1008 -0
- package/dist/core/retention.js.map +1 -0
- package/dist/core/review-context.d.ts +48 -0
- package/dist/core/review-context.d.ts.map +1 -0
- package/dist/core/review-context.js +282 -0
- package/dist/core/review-context.js.map +1 -0
- package/dist/core/roadmap-horizon.d.ts +48 -0
- package/dist/core/roadmap-horizon.d.ts.map +1 -0
- package/dist/core/roadmap-horizon.js +213 -0
- package/dist/core/roadmap-horizon.js.map +1 -0
- package/dist/core/roadmap-ids.d.ts +57 -0
- package/dist/core/roadmap-ids.d.ts.map +1 -0
- package/dist/core/roadmap-ids.js +118 -0
- package/dist/core/roadmap-ids.js.map +1 -0
- package/dist/core/roadmap-merge.d.ts +7 -0
- package/dist/core/roadmap-merge.d.ts.map +1 -0
- package/dist/core/roadmap-merge.js +187 -0
- package/dist/core/roadmap-merge.js.map +1 -0
- package/dist/core/roadmap-refresh-triggers.d.ts +32 -0
- package/dist/core/roadmap-refresh-triggers.d.ts.map +1 -0
- package/dist/core/roadmap-refresh-triggers.js +51 -0
- package/dist/core/roadmap-refresh-triggers.js.map +1 -0
- package/dist/core/roadmap-truncate.d.ts +49 -0
- package/dist/core/roadmap-truncate.d.ts.map +1 -0
- package/dist/core/roadmap-truncate.js +152 -0
- package/dist/core/roadmap-truncate.js.map +1 -0
- package/dist/core/roadmap-validate.d.ts +31 -0
- package/dist/core/roadmap-validate.d.ts.map +1 -0
- package/dist/core/roadmap-validate.js +403 -0
- package/dist/core/roadmap-validate.js.map +1 -0
- package/dist/core/roadmap-write-lock.d.ts +53 -0
- package/dist/core/roadmap-write-lock.d.ts.map +1 -0
- package/dist/core/roadmap-write-lock.js +59 -0
- package/dist/core/roadmap-write-lock.js.map +1 -0
- package/dist/core/schedule-insert-helper.d.ts +46 -0
- package/dist/core/schedule-insert-helper.d.ts.map +1 -0
- package/dist/core/schedule-insert-helper.js +52 -0
- package/dist/core/schedule-insert-helper.js.map +1 -0
- package/dist/core/schedule-maintenance.d.ts +22 -0
- package/dist/core/schedule-maintenance.d.ts.map +1 -0
- package/dist/core/schedule-maintenance.js +57 -0
- package/dist/core/schedule-maintenance.js.map +1 -0
- package/dist/core/scheduler.d.ts +208 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +896 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/semaphore.d.ts +13 -0
- package/dist/core/semaphore.d.ts.map +1 -0
- package/dist/core/semaphore.js +31 -0
- package/dist/core/semaphore.js.map +1 -0
- package/dist/core/session-gate.d.ts +37 -0
- package/dist/core/session-gate.d.ts.map +1 -0
- package/dist/core/session-gate.js +69 -0
- package/dist/core/session-gate.js.map +1 -0
- package/dist/core/session-manager.d.ts +252 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +716 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/signal-detector.d.ts +97 -0
- package/dist/core/signal-detector.d.ts.map +1 -0
- package/dist/core/signal-detector.js +215 -0
- package/dist/core/signal-detector.js.map +1 -0
- package/dist/core/skeleton.d.ts +83 -0
- package/dist/core/skeleton.d.ts.map +1 -0
- package/dist/core/skeleton.js +255 -0
- package/dist/core/skeleton.js.map +1 -0
- package/dist/core/skill-curation/apply-proposal.d.ts +71 -0
- package/dist/core/skill-curation/apply-proposal.d.ts.map +1 -0
- package/dist/core/skill-curation/apply-proposal.js +175 -0
- package/dist/core/skill-curation/apply-proposal.js.map +1 -0
- package/dist/core/skill-curation/auto-revert.d.ts +43 -0
- package/dist/core/skill-curation/auto-revert.d.ts.map +1 -0
- package/dist/core/skill-curation/auto-revert.js +155 -0
- package/dist/core/skill-curation/auto-revert.js.map +1 -0
- package/dist/core/skill-curation/classify-diff.d.ts +27 -0
- package/dist/core/skill-curation/classify-diff.d.ts.map +1 -0
- package/dist/core/skill-curation/classify-diff.js +0 -0
- package/dist/core/skill-curation/classify-diff.js.map +1 -0
- package/dist/core/skill-curation/declarations.d.ts +32 -0
- package/dist/core/skill-curation/declarations.d.ts.map +1 -0
- package/dist/core/skill-curation/declarations.js +171 -0
- package/dist/core/skill-curation/declarations.js.map +1 -0
- package/dist/core/skill-curation/knowledge-map.d.ts +26 -0
- package/dist/core/skill-curation/knowledge-map.d.ts.map +1 -0
- package/dist/core/skill-curation/knowledge-map.js +154 -0
- package/dist/core/skill-curation/knowledge-map.js.map +1 -0
- package/dist/core/skill-curation/orphan-overlay.d.ts +35 -0
- package/dist/core/skill-curation/orphan-overlay.d.ts.map +1 -0
- package/dist/core/skill-curation/orphan-overlay.js +167 -0
- package/dist/core/skill-curation/orphan-overlay.js.map +1 -0
- package/dist/core/skill-curation/overlay-store.d.ts +41 -0
- package/dist/core/skill-curation/overlay-store.d.ts.map +1 -0
- package/dist/core/skill-curation/overlay-store.js +143 -0
- package/dist/core/skill-curation/overlay-store.js.map +1 -0
- package/dist/core/skill-curation/render/convention-notes.d.ts +4 -0
- package/dist/core/skill-curation/render/convention-notes.d.ts.map +1 -0
- package/dist/core/skill-curation/render/convention-notes.js +13 -0
- package/dist/core/skill-curation/render/convention-notes.js.map +1 -0
- package/dist/core/skill-curation/render/cross-references.d.ts +4 -0
- package/dist/core/skill-curation/render/cross-references.d.ts.map +1 -0
- package/dist/core/skill-curation/render/cross-references.js +10 -0
- package/dist/core/skill-curation/render/cross-references.js.map +1 -0
- package/dist/core/skill-curation/render/frontmatter-schema.d.ts +4 -0
- package/dist/core/skill-curation/render/frontmatter-schema.d.ts.map +1 -0
- package/dist/core/skill-curation/render/frontmatter-schema.js +25 -0
- package/dist/core/skill-curation/render/frontmatter-schema.js.map +1 -0
- package/dist/core/skill-curation/render/index.d.ts +5 -0
- package/dist/core/skill-curation/render/index.d.ts.map +1 -0
- package/dist/core/skill-curation/render/index.js +42 -0
- package/dist/core/skill-curation/render/index.js.map +1 -0
- package/dist/core/skill-curation/render/knowledge-layout.d.ts +4 -0
- package/dist/core/skill-curation/render/knowledge-layout.d.ts.map +1 -0
- package/dist/core/skill-curation/render/knowledge-layout.js +36 -0
- package/dist/core/skill-curation/render/knowledge-layout.js.map +1 -0
- package/dist/core/skill-curation/render/routing-table.d.ts +4 -0
- package/dist/core/skill-curation/render/routing-table.d.ts.map +1 -0
- package/dist/core/skill-curation/render/routing-table.js +37 -0
- package/dist/core/skill-curation/render/routing-table.js.map +1 -0
- package/dist/core/skill-curation/render/search-recipes.d.ts +4 -0
- package/dist/core/skill-curation/render/search-recipes.d.ts.map +1 -0
- package/dist/core/skill-curation/render/search-recipes.js +39 -0
- package/dist/core/skill-curation/render/search-recipes.js.map +1 -0
- package/dist/core/skill-curation/run-token.d.ts +27 -0
- package/dist/core/skill-curation/run-token.d.ts.map +1 -0
- package/dist/core/skill-curation/run-token.js +81 -0
- package/dist/core/skill-curation/run-token.js.map +1 -0
- package/dist/core/skill-curation/signals.d.ts +49 -0
- package/dist/core/skill-curation/signals.d.ts.map +1 -0
- package/dist/core/skill-curation/signals.js +149 -0
- package/dist/core/skill-curation/signals.js.map +1 -0
- package/dist/core/skill-curation/smoke-test.d.ts +39 -0
- package/dist/core/skill-curation/smoke-test.d.ts.map +1 -0
- package/dist/core/skill-curation/smoke-test.js +313 -0
- package/dist/core/skill-curation/smoke-test.js.map +1 -0
- package/dist/core/skill-curation/splicer.d.ts +16 -0
- package/dist/core/skill-curation/splicer.d.ts.map +1 -0
- package/dist/core/skill-curation/splicer.js +78 -0
- package/dist/core/skill-curation/splicer.js.map +1 -0
- package/dist/core/skill-curation/workdir.d.ts +40 -0
- package/dist/core/skill-curation/workdir.d.ts.map +1 -0
- package/dist/core/skill-curation/workdir.js +242 -0
- package/dist/core/skill-curation/workdir.js.map +1 -0
- package/dist/core/skills-compiler.d.ts +391 -0
- package/dist/core/skills-compiler.d.ts.map +1 -0
- package/dist/core/skills-compiler.js +1271 -0
- package/dist/core/skills-compiler.js.map +1 -0
- package/dist/core/skills-manifest.d.ts +8 -0
- package/dist/core/skills-manifest.d.ts.map +1 -0
- package/dist/core/skills-manifest.js +408 -0
- package/dist/core/skills-manifest.js.map +1 -0
- package/dist/core/system-reset.d.ts +268 -0
- package/dist/core/system-reset.d.ts.map +1 -0
- package/dist/core/system-reset.js +816 -0
- package/dist/core/system-reset.js.map +1 -0
- package/dist/core/template-store.d.ts +170 -0
- package/dist/core/template-store.d.ts.map +1 -0
- package/dist/core/template-store.js +388 -0
- package/dist/core/template-store.js.map +1 -0
- package/dist/core/template-versions.d.ts +95 -0
- package/dist/core/template-versions.d.ts.map +1 -0
- package/dist/core/template-versions.js +175 -0
- package/dist/core/template-versions.js.map +1 -0
- package/dist/core/today-agent-plan.d.ts +33 -0
- package/dist/core/today-agent-plan.d.ts.map +1 -0
- package/dist/core/today-agent-plan.js +120 -0
- package/dist/core/today-agent-plan.js.map +1 -0
- package/dist/core/today-direct-writer.d.ts +62 -0
- package/dist/core/today-direct-writer.d.ts.map +1 -0
- package/dist/core/today-direct-writer.js +132 -0
- package/dist/core/today-direct-writer.js.map +1 -0
- package/dist/core/today-write-lock.d.ts +89 -0
- package/dist/core/today-write-lock.d.ts.map +1 -0
- package/dist/core/today-write-lock.js +154 -0
- package/dist/core/today-write-lock.js.map +1 -0
- package/dist/core/trigger-dispatch.d.ts +31 -0
- package/dist/core/trigger-dispatch.d.ts.map +1 -0
- package/dist/core/trigger-dispatch.js +100 -0
- package/dist/core/trigger-dispatch.js.map +1 -0
- package/dist/core/trigger-evaluator.d.ts +59 -0
- package/dist/core/trigger-evaluator.d.ts.map +1 -0
- package/dist/core/trigger-evaluator.js +243 -0
- package/dist/core/trigger-evaluator.js.map +1 -0
- package/dist/core/workdir.d.ts +241 -0
- package/dist/core/workdir.d.ts.map +1 -0
- package/dist/core/workdir.js +565 -0
- package/dist/core/workdir.js.map +1 -0
- package/dist/db/automation-triggers.d.ts +90 -0
- package/dist/db/automation-triggers.d.ts.map +1 -0
- package/dist/db/automation-triggers.js +199 -0
- package/dist/db/automation-triggers.js.map +1 -0
- package/dist/db/client.d.ts +6 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +47 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/entities-store.d.ts +92 -0
- package/dist/db/entities-store.d.ts.map +1 -0
- package/dist/db/entities-store.js +180 -0
- package/dist/db/entities-store.js.map +1 -0
- package/dist/db/hourly-check-signals.d.ts +78 -0
- package/dist/db/hourly-check-signals.d.ts.map +1 -0
- package/dist/db/hourly-check-signals.js +289 -0
- package/dist/db/hourly-check-signals.js.map +1 -0
- package/dist/db/integration-probe-store.d.ts +27 -0
- package/dist/db/integration-probe-store.d.ts.map +1 -0
- package/dist/db/integration-probe-store.js +75 -0
- package/dist/db/integration-probe-store.js.map +1 -0
- package/dist/db/integrations-store.d.ts +19 -0
- package/dist/db/integrations-store.d.ts.map +1 -0
- package/dist/db/integrations-store.js +85 -0
- package/dist/db/integrations-store.js.map +1 -0
- package/dist/db/managed-tasks-store.d.ts +130 -0
- package/dist/db/managed-tasks-store.d.ts.map +1 -0
- package/dist/db/managed-tasks-store.js +238 -0
- package/dist/db/managed-tasks-store.js.map +1 -0
- package/dist/db/management-parse-failures-store.d.ts +45 -0
- package/dist/db/management-parse-failures-store.d.ts.map +1 -0
- package/dist/db/management-parse-failures-store.js +36 -0
- package/dist/db/management-parse-failures-store.js.map +1 -0
- package/dist/db/observations.d.ts +145 -0
- package/dist/db/observations.d.ts.map +1 -0
- package/dist/db/observations.js +287 -0
- package/dist/db/observations.js.map +1 -0
- package/dist/db/recurring-schedules.d.ts +70 -0
- package/dist/db/recurring-schedules.d.ts.map +1 -0
- package/dist/db/recurring-schedules.js +213 -0
- package/dist/db/recurring-schedules.js.map +1 -0
- package/dist/db/repositories-store.d.ts +296 -0
- package/dist/db/repositories-store.d.ts.map +1 -0
- package/dist/db/repositories-store.js +754 -0
- package/dist/db/repositories-store.js.map +1 -0
- package/dist/db/runtime-state.d.ts +61 -0
- package/dist/db/runtime-state.d.ts.map +1 -0
- package/dist/db/runtime-state.js +104 -0
- package/dist/db/runtime-state.js.map +1 -0
- package/dist/db/schema.d.ts +4 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +1338 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/sot-bindings-store.d.ts +41 -0
- package/dist/db/sot-bindings-store.d.ts.map +1 -0
- package/dist/db/sot-bindings-store.js +64 -0
- package/dist/db/sot-bindings-store.js.map +1 -0
- package/dist/db/test-schemas.d.ts +23 -0
- package/dist/db/test-schemas.d.ts.map +1 -0
- package/dist/db/test-schemas.js +111 -0
- package/dist/db/test-schemas.js.map +1 -0
- package/dist/db/voice-transcripts-store.d.ts +28 -0
- package/dist/db/voice-transcripts-store.d.ts.map +1 -0
- package/dist/db/voice-transcripts-store.js +43 -0
- package/dist/db/voice-transcripts-store.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2913 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +7 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +32 -0
- package/dist/init.js.map +1 -0
- package/dist/log-buffer.d.ts +71 -0
- package/dist/log-buffer.d.ts.map +1 -0
- package/dist/log-buffer.js +201 -0
- package/dist/log-buffer.js.map +1 -0
- package/dist/logging.d.ts +5 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +130 -0
- package/dist/logging.js.map +1 -0
- package/dist/management-rules.d.ts +2 -0
- package/dist/management-rules.d.ts.map +1 -0
- package/dist/management-rules.js +62 -0
- package/dist/management-rules.js.map +1 -0
- package/dist/messaging/constants.d.ts +33 -0
- package/dist/messaging/constants.d.ts.map +1 -0
- package/dist/messaging/constants.js +52 -0
- package/dist/messaging/constants.js.map +1 -0
- package/dist/messaging/magic-phrase.d.ts +16 -0
- package/dist/messaging/magic-phrase.d.ts.map +1 -0
- package/dist/messaging/magic-phrase.js +103 -0
- package/dist/messaging/magic-phrase.js.map +1 -0
- package/dist/messaging/owner-channels.d.ts +20 -0
- package/dist/messaging/owner-channels.d.ts.map +1 -0
- package/dist/messaging/owner-channels.js +41 -0
- package/dist/messaging/owner-channels.js.map +1 -0
- package/dist/observers/calendar-poller.d.ts +51 -0
- package/dist/observers/calendar-poller.d.ts.map +1 -0
- package/dist/observers/calendar-poller.js +128 -0
- package/dist/observers/calendar-poller.js.map +1 -0
- package/dist/observers/context-index-reconciler-observer.d.ts +72 -0
- package/dist/observers/context-index-reconciler-observer.d.ts.map +1 -0
- package/dist/observers/context-index-reconciler-observer.js +253 -0
- package/dist/observers/context-index-reconciler-observer.js.map +1 -0
- package/dist/observers/delegated-probe-observer.d.ts +83 -0
- package/dist/observers/delegated-probe-observer.d.ts.map +1 -0
- package/dist/observers/delegated-probe-observer.js +237 -0
- package/dist/observers/delegated-probe-observer.js.map +1 -0
- package/dist/observers/delegated-sync-worker.d.ts +375 -0
- package/dist/observers/delegated-sync-worker.d.ts.map +1 -0
- package/dist/observers/delegated-sync-worker.js +1087 -0
- package/dist/observers/delegated-sync-worker.js.map +1 -0
- package/dist/observers/entity-mirror-observer.d.ts +55 -0
- package/dist/observers/entity-mirror-observer.d.ts.map +1 -0
- package/dist/observers/entity-mirror-observer.js +73 -0
- package/dist/observers/entity-mirror-observer.js.map +1 -0
- package/dist/observers/git-delegated-cron.d.ts +41 -0
- package/dist/observers/git-delegated-cron.d.ts.map +1 -0
- package/dist/observers/git-delegated-cron.js +159 -0
- package/dist/observers/git-delegated-cron.js.map +1 -0
- package/dist/observers/git-event-classifier.d.ts +52 -0
- package/dist/observers/git-event-classifier.d.ts.map +1 -0
- package/dist/observers/git-event-classifier.js +70 -0
- package/dist/observers/git-event-classifier.js.map +1 -0
- package/dist/observers/git-watcher.d.ts +162 -0
- package/dist/observers/git-watcher.d.ts.map +1 -0
- package/dist/observers/git-watcher.js +768 -0
- package/dist/observers/git-watcher.js.map +1 -0
- package/dist/observers/github-poller-classifier.d.ts +101 -0
- package/dist/observers/github-poller-classifier.d.ts.map +1 -0
- package/dist/observers/github-poller-classifier.js +199 -0
- package/dist/observers/github-poller-classifier.js.map +1 -0
- package/dist/observers/github-poller.d.ts +291 -0
- package/dist/observers/github-poller.d.ts.map +1 -0
- package/dist/observers/github-poller.js +609 -0
- package/dist/observers/github-poller.js.map +1 -0
- package/dist/observers/imminent-event-scheduler.d.ts +34 -0
- package/dist/observers/imminent-event-scheduler.d.ts.map +1 -0
- package/dist/observers/imminent-event-scheduler.js +125 -0
- package/dist/observers/imminent-event-scheduler.js.map +1 -0
- package/dist/observers/mail-poller.d.ts +133 -0
- package/dist/observers/mail-poller.d.ts.map +1 -0
- package/dist/observers/mail-poller.js +563 -0
- package/dist/observers/mail-poller.js.map +1 -0
- package/dist/observers/mail-reconciliation.d.ts +87 -0
- package/dist/observers/mail-reconciliation.d.ts.map +1 -0
- package/dist/observers/mail-reconciliation.js +241 -0
- package/dist/observers/mail-reconciliation.js.map +1 -0
- package/dist/observers/manager.d.ts +67 -0
- package/dist/observers/manager.d.ts.map +1 -0
- package/dist/observers/manager.js +136 -0
- package/dist/observers/manager.js.map +1 -0
- package/dist/observers/notion-poller.d.ts +43 -0
- package/dist/observers/notion-poller.d.ts.map +1 -0
- package/dist/observers/notion-poller.js +184 -0
- package/dist/observers/notion-poller.js.map +1 -0
- package/dist/observers/observation-summarizer/index.d.ts +13 -0
- package/dist/observers/observation-summarizer/index.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/index.js +13 -0
- package/dist/observers/observation-summarizer/index.js.map +1 -0
- package/dist/observers/observation-summarizer/pre-filter.d.ts +62 -0
- package/dist/observers/observation-summarizer/pre-filter.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/pre-filter.js +189 -0
- package/dist/observers/observation-summarizer/pre-filter.js.map +1 -0
- package/dist/observers/observation-summarizer/response-parser.d.ts +30 -0
- package/dist/observers/observation-summarizer/response-parser.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/response-parser.js +106 -0
- package/dist/observers/observation-summarizer/response-parser.js.map +1 -0
- package/dist/observers/observation-summarizer/summarizer-client.d.ts +83 -0
- package/dist/observers/observation-summarizer/summarizer-client.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/summarizer-client.js +185 -0
- package/dist/observers/observation-summarizer/summarizer-client.js.map +1 -0
- package/dist/observers/observation-summarizer/summarizer-prompts.d.ts +51 -0
- package/dist/observers/observation-summarizer/summarizer-prompts.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/summarizer-prompts.js +286 -0
- package/dist/observers/observation-summarizer/summarizer-prompts.js.map +1 -0
- package/dist/observers/observation-summarizer/worker.d.ts +106 -0
- package/dist/observers/observation-summarizer/worker.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/worker.js +311 -0
- package/dist/observers/observation-summarizer/worker.js.map +1 -0
- package/dist/observers/obsidian-watcher.d.ts +90 -0
- package/dist/observers/obsidian-watcher.d.ts.map +1 -0
- package/dist/observers/obsidian-watcher.js +166 -0
- package/dist/observers/obsidian-watcher.js.map +1 -0
- package/dist/observers/primary-vault-watcher.d.ts +73 -0
- package/dist/observers/primary-vault-watcher.d.ts.map +1 -0
- package/dist/observers/primary-vault-watcher.js +115 -0
- package/dist/observers/primary-vault-watcher.js.map +1 -0
- package/dist/observers/repository-management-cron.d.ts +70 -0
- package/dist/observers/repository-management-cron.d.ts.map +1 -0
- package/dist/observers/repository-management-cron.js +166 -0
- package/dist/observers/repository-management-cron.js.map +1 -0
- package/dist/observers/skill-curation-walker.d.ts +33 -0
- package/dist/observers/skill-curation-walker.d.ts.map +1 -0
- package/dist/observers/skill-curation-walker.js +216 -0
- package/dist/observers/skill-curation-walker.js.map +1 -0
- package/dist/safety/absolute-block-audit.d.ts +22 -0
- package/dist/safety/absolute-block-audit.d.ts.map +1 -0
- package/dist/safety/absolute-block-audit.js +32 -0
- package/dist/safety/absolute-block-audit.js.map +1 -0
- package/dist/safety/agent-write-tracker.d.ts +42 -0
- package/dist/safety/agent-write-tracker.d.ts.map +1 -0
- package/dist/safety/agent-write-tracker.js +82 -0
- package/dist/safety/agent-write-tracker.js.map +1 -0
- package/dist/safety/always-disallowed.d.ts +66 -0
- package/dist/safety/always-disallowed.d.ts.map +1 -0
- package/dist/safety/always-disallowed.js +347 -0
- package/dist/safety/always-disallowed.js.map +1 -0
- package/dist/safety/audit.d.ts +118 -0
- package/dist/safety/audit.d.ts.map +1 -0
- package/dist/safety/audit.js +324 -0
- package/dist/safety/audit.js.map +1 -0
- package/dist/safety/integration-write-tracker.d.ts +58 -0
- package/dist/safety/integration-write-tracker.d.ts.map +1 -0
- package/dist/safety/integration-write-tracker.js +41 -0
- package/dist/safety/integration-write-tracker.js.map +1 -0
- package/dist/safety/risk-classifier.d.ts +65 -0
- package/dist/safety/risk-classifier.d.ts.map +1 -0
- package/dist/safety/risk-classifier.js +763 -0
- package/dist/safety/risk-classifier.js.map +1 -0
- package/dist/scheduler/hourly-check-gate.d.ts +73 -0
- package/dist/scheduler/hourly-check-gate.d.ts.map +1 -0
- package/dist/scheduler/hourly-check-gate.js +128 -0
- package/dist/scheduler/hourly-check-gate.js.map +1 -0
- package/dist/secrets/backend-api-key-env.d.ts +104 -0
- package/dist/secrets/backend-api-key-env.d.ts.map +1 -0
- package/dist/secrets/backend-api-key-env.js +197 -0
- package/dist/secrets/backend-api-key-env.js.map +1 -0
- package/dist/secrets/codex-home-materializer.d.ts +35 -0
- package/dist/secrets/codex-home-materializer.d.ts.map +1 -0
- package/dist/secrets/codex-home-materializer.js +76 -0
- package/dist/secrets/codex-home-materializer.js.map +1 -0
- package/dist/secrets/encrypted-blob-store.d.ts +20 -0
- package/dist/secrets/encrypted-blob-store.d.ts.map +1 -0
- package/dist/secrets/encrypted-blob-store.js +80 -0
- package/dist/secrets/encrypted-blob-store.js.map +1 -0
- package/dist/secrets/platform-secret-store.d.ts +17 -0
- package/dist/secrets/platform-secret-store.d.ts.map +1 -0
- package/dist/secrets/platform-secret-store.js +37 -0
- package/dist/secrets/platform-secret-store.js.map +1 -0
- package/dist/secrets/redaction.d.ts +2 -0
- package/dist/secrets/redaction.d.ts.map +1 -0
- package/dist/secrets/redaction.js +2 -0
- package/dist/secrets/redaction.js.map +1 -0
- package/dist/secrets/secret-broker.d.ts +61 -0
- package/dist/secrets/secret-broker.d.ts.map +1 -0
- package/dist/secrets/secret-broker.js +160 -0
- package/dist/secrets/secret-broker.js.map +1 -0
- package/dist/secrets/secret-names.d.ts +34 -0
- package/dist/secrets/secret-names.d.ts.map +1 -0
- package/dist/secrets/secret-names.js +39 -0
- package/dist/secrets/secret-names.js.map +1 -0
- package/dist/secrets/secret-store.d.ts +8 -0
- package/dist/secrets/secret-store.d.ts.map +1 -0
- package/dist/secrets/secret-store.js +2 -0
- package/dist/secrets/secret-store.js.map +1 -0
- package/dist/secrets/types.d.ts +7 -0
- package/dist/secrets/types.d.ts.map +1 -0
- package/dist/secrets/types.js +2 -0
- package/dist/secrets/types.js.map +1 -0
- package/dist/services/apple-calendar/caldav-client.d.ts +48 -0
- package/dist/services/apple-calendar/caldav-client.d.ts.map +1 -0
- package/dist/services/apple-calendar/caldav-client.js +86 -0
- package/dist/services/apple-calendar/caldav-client.js.map +1 -0
- package/dist/services/apple-calendar/caldav-codec.d.ts +67 -0
- package/dist/services/apple-calendar/caldav-codec.d.ts.map +1 -0
- package/dist/services/apple-calendar/caldav-codec.js +341 -0
- package/dist/services/apple-calendar/caldav-codec.js.map +1 -0
- package/dist/services/apple-calendar/index.d.ts +3 -0
- package/dist/services/apple-calendar/index.d.ts.map +1 -0
- package/dist/services/apple-calendar/index.js +2 -0
- package/dist/services/apple-calendar/index.js.map +1 -0
- package/dist/services/apple-calendar/service.d.ts +75 -0
- package/dist/services/apple-calendar/service.d.ts.map +1 -0
- package/dist/services/apple-calendar/service.js +374 -0
- package/dist/services/apple-calendar/service.js.map +1 -0
- package/dist/services/apple-calendar/types.d.ts +78 -0
- package/dist/services/apple-calendar/types.d.ts.map +1 -0
- package/dist/services/apple-calendar/types.js +17 -0
- package/dist/services/apple-calendar/types.js.map +1 -0
- package/dist/services/attachments/hardlink.d.ts +11 -0
- package/dist/services/attachments/hardlink.d.ts.map +1 -0
- package/dist/services/attachments/hardlink.js +56 -0
- package/dist/services/attachments/hardlink.js.map +1 -0
- package/dist/services/attachments/sanitize.d.ts +21 -0
- package/dist/services/attachments/sanitize.d.ts.map +1 -0
- package/dist/services/attachments/sanitize.js +128 -0
- package/dist/services/attachments/sanitize.js.map +1 -0
- package/dist/services/attachments/store.d.ts +146 -0
- package/dist/services/attachments/store.d.ts.map +1 -0
- package/dist/services/attachments/store.js +477 -0
- package/dist/services/attachments/store.js.map +1 -0
- package/dist/services/calendar/outlook/graph-calendar-client.d.ts +114 -0
- package/dist/services/calendar/outlook/graph-calendar-client.d.ts.map +1 -0
- package/dist/services/calendar/outlook/graph-calendar-client.js +146 -0
- package/dist/services/calendar/outlook/graph-calendar-client.js.map +1 -0
- package/dist/services/calendar.d.ts +115 -0
- package/dist/services/calendar.d.ts.map +1 -0
- package/dist/services/calendar.js +281 -0
- package/dist/services/calendar.js.map +1 -0
- package/dist/services/delegated-backend-invoker.d.ts +414 -0
- package/dist/services/delegated-backend-invoker.d.ts.map +1 -0
- package/dist/services/delegated-backend-invoker.js +2372 -0
- package/dist/services/delegated-backend-invoker.js.map +1 -0
- package/dist/services/delegated-proxy-config.d.ts +93 -0
- package/dist/services/delegated-proxy-config.d.ts.map +1 -0
- package/dist/services/delegated-proxy-config.js +98 -0
- package/dist/services/delegated-proxy-config.js.map +1 -0
- package/dist/services/delegated-task-result-cache.d.ts +176 -0
- package/dist/services/delegated-task-result-cache.d.ts.map +1 -0
- package/dist/services/delegated-task-result-cache.js +0 -0
- package/dist/services/delegated-task-result-cache.js.map +1 -0
- package/dist/services/delegated-task-runtime.d.ts +346 -0
- package/dist/services/delegated-task-runtime.d.ts.map +1 -0
- package/dist/services/delegated-task-runtime.js +589 -0
- package/dist/services/delegated-task-runtime.js.map +1 -0
- package/dist/services/delegated-task-session-pool.d.ts +182 -0
- package/dist/services/delegated-task-session-pool.d.ts.map +1 -0
- package/dist/services/delegated-task-session-pool.js +292 -0
- package/dist/services/delegated-task-session-pool.js.map +1 -0
- package/dist/services/delegated-tool-runtime.d.ts +50 -0
- package/dist/services/delegated-tool-runtime.d.ts.map +1 -0
- package/dist/services/delegated-tool-runtime.js +120 -0
- package/dist/services/delegated-tool-runtime.js.map +1 -0
- package/dist/services/fts5.d.ts +40 -0
- package/dist/services/fts5.d.ts.map +1 -0
- package/dist/services/fts5.js +54 -0
- package/dist/services/fts5.js.map +1 -0
- package/dist/services/git-account-registry.d.ts +164 -0
- package/dist/services/git-account-registry.d.ts.map +1 -0
- package/dist/services/git-account-registry.js +297 -0
- package/dist/services/git-account-registry.js.map +1 -0
- package/dist/services/github.d.ts +49 -0
- package/dist/services/github.d.ts.map +1 -0
- package/dist/services/github.js +123 -0
- package/dist/services/github.js.map +1 -0
- package/dist/services/gmail-classifier.d.ts +62 -0
- package/dist/services/gmail-classifier.d.ts.map +1 -0
- package/dist/services/gmail-classifier.js +221 -0
- package/dist/services/gmail-classifier.js.map +1 -0
- package/dist/services/gmail.d.ts +192 -0
- package/dist/services/gmail.d.ts.map +1 -0
- package/dist/services/gmail.js +678 -0
- package/dist/services/gmail.js.map +1 -0
- package/dist/services/google-auth.d.ts +16 -0
- package/dist/services/google-auth.d.ts.map +1 -0
- package/dist/services/google-auth.js +37 -0
- package/dist/services/google-auth.js.map +1 -0
- package/dist/services/google-maps.d.ts +35 -0
- package/dist/services/google-maps.d.ts.map +1 -0
- package/dist/services/google-maps.js +82 -0
- package/dist/services/google-maps.js.map +1 -0
- package/dist/services/integrations/extract-write-item-id.d.ts +64 -0
- package/dist/services/integrations/extract-write-item-id.d.ts.map +1 -0
- package/dist/services/integrations/extract-write-item-id.js +188 -0
- package/dist/services/integrations/extract-write-item-id.js.map +1 -0
- package/dist/services/integrations/reconcile.d.ts +136 -0
- package/dist/services/integrations/reconcile.d.ts.map +1 -0
- package/dist/services/integrations/reconcile.js +218 -0
- package/dist/services/integrations/reconcile.js.map +1 -0
- package/dist/services/integrations/snapshot-partitions.d.ts +40 -0
- package/dist/services/integrations/snapshot-partitions.d.ts.map +1 -0
- package/dist/services/integrations/snapshot-partitions.js +113 -0
- package/dist/services/integrations/snapshot-partitions.js.map +1 -0
- package/dist/services/journal/render.d.ts +15 -0
- package/dist/services/journal/render.d.ts.map +1 -0
- package/dist/services/journal/render.js +17 -0
- package/dist/services/journal/render.js.map +1 -0
- package/dist/services/journal/writer.d.ts +26 -0
- package/dist/services/journal/writer.d.ts.map +1 -0
- package/dist/services/journal/writer.js +50 -0
- package/dist/services/journal/writer.js.map +1 -0
- package/dist/services/mail/account-registry.d.ts +208 -0
- package/dist/services/mail/account-registry.d.ts.map +1 -0
- package/dist/services/mail/account-registry.js +554 -0
- package/dist/services/mail/account-registry.js.map +1 -0
- package/dist/services/mail/gmail/auth-failure-classifier.d.ts +24 -0
- package/dist/services/mail/gmail/auth-failure-classifier.d.ts.map +1 -0
- package/dist/services/mail/gmail/auth-failure-classifier.js +67 -0
- package/dist/services/mail/gmail/auth-failure-classifier.js.map +1 -0
- package/dist/services/mail/gmail/gmail-provider.d.ts +58 -0
- package/dist/services/mail/gmail/gmail-provider.d.ts.map +1 -0
- package/dist/services/mail/gmail/gmail-provider.js +434 -0
- package/dist/services/mail/gmail/gmail-provider.js.map +1 -0
- package/dist/services/mail/gmail/legacy-row.d.ts +24 -0
- package/dist/services/mail/gmail/legacy-row.d.ts.map +1 -0
- package/dist/services/mail/gmail/legacy-row.js +71 -0
- package/dist/services/mail/gmail/legacy-row.js.map +1 -0
- package/dist/services/mail/gmail/poll-cursor.d.ts +12 -0
- package/dist/services/mail/gmail/poll-cursor.d.ts.map +1 -0
- package/dist/services/mail/gmail/poll-cursor.js +32 -0
- package/dist/services/mail/gmail/poll-cursor.js.map +1 -0
- package/dist/services/mail/html-to-plaintext.d.ts +27 -0
- package/dist/services/mail/html-to-plaintext.d.ts.map +1 -0
- package/dist/services/mail/html-to-plaintext.js +163 -0
- package/dist/services/mail/html-to-plaintext.js.map +1 -0
- package/dist/services/mail/imap/app-password.d.ts +27 -0
- package/dist/services/mail/imap/app-password.d.ts.map +1 -0
- package/dist/services/mail/imap/app-password.js +86 -0
- package/dist/services/mail/imap/app-password.js.map +1 -0
- package/dist/services/mail/imap/auth-failure-classifier.d.ts +21 -0
- package/dist/services/mail/imap/auth-failure-classifier.d.ts.map +1 -0
- package/dist/services/mail/imap/auth-failure-classifier.js +54 -0
- package/dist/services/mail/imap/auth-failure-classifier.js.map +1 -0
- package/dist/services/mail/imap/capabilities.d.ts +30 -0
- package/dist/services/mail/imap/capabilities.d.ts.map +1 -0
- package/dist/services/mail/imap/capabilities.js +70 -0
- package/dist/services/mail/imap/capabilities.js.map +1 -0
- package/dist/services/mail/imap/client.d.ts +15 -0
- package/dist/services/mail/imap/client.d.ts.map +1 -0
- package/dist/services/mail/imap/client.js +60 -0
- package/dist/services/mail/imap/client.js.map +1 -0
- package/dist/services/mail/imap/cursor.d.ts +19 -0
- package/dist/services/mail/imap/cursor.d.ts.map +1 -0
- package/dist/services/mail/imap/cursor.js +47 -0
- package/dist/services/mail/imap/cursor.js.map +1 -0
- package/dist/services/mail/imap/folder-resolver.d.ts +24 -0
- package/dist/services/mail/imap/folder-resolver.d.ts.map +1 -0
- package/dist/services/mail/imap/folder-resolver.js +58 -0
- package/dist/services/mail/imap/folder-resolver.js.map +1 -0
- package/dist/services/mail/imap/icloud-provider.d.ts +5 -0
- package/dist/services/mail/imap/icloud-provider.d.ts.map +1 -0
- package/dist/services/mail/imap/icloud-provider.js +5 -0
- package/dist/services/mail/imap/icloud-provider.js.map +1 -0
- package/dist/services/mail/imap/imap-provider-base.d.ts +173 -0
- package/dist/services/mail/imap/imap-provider-base.d.ts.map +1 -0
- package/dist/services/mail/imap/imap-provider-base.js +1004 -0
- package/dist/services/mail/imap/imap-provider-base.js.map +1 -0
- package/dist/services/mail/imap/query-translator.d.ts +13 -0
- package/dist/services/mail/imap/query-translator.d.ts.map +1 -0
- package/dist/services/mail/imap/query-translator.js +114 -0
- package/dist/services/mail/imap/query-translator.js.map +1 -0
- package/dist/services/mail/imap/reconcile-planner.d.ts +56 -0
- package/dist/services/mail/imap/reconcile-planner.d.ts.map +1 -0
- package/dist/services/mail/imap/reconcile-planner.js +52 -0
- package/dist/services/mail/imap/reconcile-planner.js.map +1 -0
- package/dist/services/mail/imap/reply-mime.d.ts +24 -0
- package/dist/services/mail/imap/reply-mime.d.ts.map +1 -0
- package/dist/services/mail/imap/reply-mime.js +77 -0
- package/dist/services/mail/imap/reply-mime.js.map +1 -0
- package/dist/services/mail/imap/yahoo-provider.d.ts +5 -0
- package/dist/services/mail/imap/yahoo-provider.d.ts.map +1 -0
- package/dist/services/mail/imap/yahoo-provider.js +5 -0
- package/dist/services/mail/imap/yahoo-provider.js.map +1 -0
- package/dist/services/mail/mail-search.d.ts +35 -0
- package/dist/services/mail/mail-search.d.ts.map +1 -0
- package/dist/services/mail/mail-search.js +59 -0
- package/dist/services/mail/mail-search.js.map +1 -0
- package/dist/services/mail/outlook/auth-failure-classifier.d.ts +38 -0
- package/dist/services/mail/outlook/auth-failure-classifier.d.ts.map +1 -0
- package/dist/services/mail/outlook/auth-failure-classifier.js +91 -0
- package/dist/services/mail/outlook/auth-failure-classifier.js.map +1 -0
- package/dist/services/mail/outlook/client-config.d.ts +34 -0
- package/dist/services/mail/outlook/client-config.d.ts.map +1 -0
- package/dist/services/mail/outlook/client-config.js +58 -0
- package/dist/services/mail/outlook/client-config.js.map +1 -0
- package/dist/services/mail/outlook/delta-cursor.d.ts +66 -0
- package/dist/services/mail/outlook/delta-cursor.d.ts.map +1 -0
- package/dist/services/mail/outlook/delta-cursor.js +85 -0
- package/dist/services/mail/outlook/delta-cursor.js.map +1 -0
- package/dist/services/mail/outlook/graph-client.d.ts +98 -0
- package/dist/services/mail/outlook/graph-client.d.ts.map +1 -0
- package/dist/services/mail/outlook/graph-client.js +198 -0
- package/dist/services/mail/outlook/graph-client.js.map +1 -0
- package/dist/services/mail/outlook/msal-app-factory.d.ts +20 -0
- package/dist/services/mail/outlook/msal-app-factory.d.ts.map +1 -0
- package/dist/services/mail/outlook/msal-app-factory.js +62 -0
- package/dist/services/mail/outlook/msal-app-factory.js.map +1 -0
- package/dist/services/mail/outlook/msal-cache-plugin.d.ts +19 -0
- package/dist/services/mail/outlook/msal-cache-plugin.d.ts.map +1 -0
- package/dist/services/mail/outlook/msal-cache-plugin.js +30 -0
- package/dist/services/mail/outlook/msal-cache-plugin.js.map +1 -0
- package/dist/services/mail/outlook/oauth-device-code.d.ts +26 -0
- package/dist/services/mail/outlook/oauth-device-code.d.ts.map +1 -0
- package/dist/services/mail/outlook/oauth-device-code.js +32 -0
- package/dist/services/mail/outlook/oauth-device-code.js.map +1 -0
- package/dist/services/mail/outlook/oauth-loopback.d.ts +41 -0
- package/dist/services/mail/outlook/oauth-loopback.d.ts.map +1 -0
- package/dist/services/mail/outlook/oauth-loopback.js +223 -0
- package/dist/services/mail/outlook/oauth-loopback.js.map +1 -0
- package/dist/services/mail/outlook/outlook-provider.d.ts +100 -0
- package/dist/services/mail/outlook/outlook-provider.d.ts.map +1 -0
- package/dist/services/mail/outlook/outlook-provider.js +619 -0
- package/dist/services/mail/outlook/outlook-provider.js.map +1 -0
- package/dist/services/mail/outlook/query-translator.d.ts +10 -0
- package/dist/services/mail/outlook/query-translator.d.ts.map +1 -0
- package/dist/services/mail/outlook/query-translator.js +103 -0
- package/dist/services/mail/outlook/query-translator.js.map +1 -0
- package/dist/services/mail/provider.d.ts +267 -0
- package/dist/services/mail/provider.d.ts.map +1 -0
- package/dist/services/mail/provider.js +34 -0
- package/dist/services/mail/provider.js.map +1 -0
- package/dist/services/mail/query-utils.d.ts +13 -0
- package/dist/services/mail/query-utils.d.ts.map +1 -0
- package/dist/services/mail/query-utils.js +18 -0
- package/dist/services/mail/query-utils.js.map +1 -0
- package/dist/services/mail-classifier.d.ts +25 -0
- package/dist/services/mail-classifier.d.ts.map +1 -0
- package/dist/services/mail-classifier.js +52 -0
- package/dist/services/mail-classifier.js.map +1 -0
- package/dist/services/mail-ingestion.d.ts +139 -0
- package/dist/services/mail-ingestion.d.ts.map +1 -0
- package/dist/services/mail-ingestion.js +223 -0
- package/dist/services/mail-ingestion.js.map +1 -0
- package/dist/services/mcp/auto-probe.d.ts +76 -0
- package/dist/services/mcp/auto-probe.d.ts.map +1 -0
- package/dist/services/mcp/auto-probe.js +147 -0
- package/dist/services/mcp/auto-probe.js.map +1 -0
- package/dist/services/mcp/generators/claude.d.ts +18 -0
- package/dist/services/mcp/generators/claude.d.ts.map +1 -0
- package/dist/services/mcp/generators/claude.js +90 -0
- package/dist/services/mcp/generators/claude.js.map +1 -0
- package/dist/services/mcp/generators/codex.d.ts +22 -0
- package/dist/services/mcp/generators/codex.d.ts.map +1 -0
- package/dist/services/mcp/generators/codex.js +102 -0
- package/dist/services/mcp/generators/codex.js.map +1 -0
- package/dist/services/mcp/generators/gemini.d.ts +20 -0
- package/dist/services/mcp/generators/gemini.d.ts.map +1 -0
- package/dist/services/mcp/generators/gemini.js +97 -0
- package/dist/services/mcp/generators/gemini.js.map +1 -0
- package/dist/services/mcp/generators/index.d.ts +20 -0
- package/dist/services/mcp/generators/index.d.ts.map +1 -0
- package/dist/services/mcp/generators/index.js +29 -0
- package/dist/services/mcp/generators/index.js.map +1 -0
- package/dist/services/mcp/generators/types.d.ts +47 -0
- package/dist/services/mcp/generators/types.d.ts.map +1 -0
- package/dist/services/mcp/generators/types.js +40 -0
- package/dist/services/mcp/generators/types.js.map +1 -0
- package/dist/services/mcp/probe.d.ts +31 -0
- package/dist/services/mcp/probe.d.ts.map +1 -0
- package/dist/services/mcp/probe.js +437 -0
- package/dist/services/mcp/probe.js.map +1 -0
- package/dist/services/mcp/registry.d.ts +84 -0
- package/dist/services/mcp/registry.d.ts.map +1 -0
- package/dist/services/mcp/registry.js +387 -0
- package/dist/services/mcp/registry.js.map +1 -0
- package/dist/services/mcp/risk.d.ts +82 -0
- package/dist/services/mcp/risk.d.ts.map +1 -0
- package/dist/services/mcp/risk.js +126 -0
- package/dist/services/mcp/risk.js.map +1 -0
- package/dist/services/mcp/session-materializer.d.ts +123 -0
- package/dist/services/mcp/session-materializer.d.ts.map +1 -0
- package/dist/services/mcp/session-materializer.js +361 -0
- package/dist/services/mcp/session-materializer.js.map +1 -0
- package/dist/services/mcp/tool-audit.d.ts +53 -0
- package/dist/services/mcp/tool-audit.d.ts.map +1 -0
- package/dist/services/mcp/tool-audit.js +74 -0
- package/dist/services/mcp/tool-audit.js.map +1 -0
- package/dist/services/mcp/types.d.ts +88 -0
- package/dist/services/mcp/types.d.ts.map +1 -0
- package/dist/services/mcp/types.js +94 -0
- package/dist/services/mcp/types.js.map +1 -0
- package/dist/services/notion.d.ts +134 -0
- package/dist/services/notion.d.ts.map +1 -0
- package/dist/services/notion.js +350 -0
- package/dist/services/notion.js.map +1 -0
- package/dist/services/obsidian.d.ts +116 -0
- package/dist/services/obsidian.d.ts.map +1 -0
- package/dist/services/obsidian.js +305 -0
- package/dist/services/obsidian.js.map +1 -0
- package/dist/services/service-registry.d.ts +31 -0
- package/dist/services/service-registry.d.ts.map +1 -0
- package/dist/services/service-registry.js +15 -0
- package/dist/services/service-registry.js.map +1 -0
- package/dist/services/voice/transcriber-impl.d.ts +15 -0
- package/dist/services/voice/transcriber-impl.d.ts.map +1 -0
- package/dist/services/voice/transcriber-impl.js +129 -0
- package/dist/services/voice/transcriber-impl.js.map +1 -0
- package/dist/services/voice/transcriber.d.ts +117 -0
- package/dist/services/voice/transcriber.d.ts.map +1 -0
- package/dist/services/voice/transcriber.js +201 -0
- package/dist/services/voice/transcriber.js.map +1 -0
- package/dist/settings/runtime-settings.d.ts +232 -0
- package/dist/settings/runtime-settings.d.ts.map +1 -0
- package/dist/settings/runtime-settings.js +769 -0
- package/dist/settings/runtime-settings.js.map +1 -0
- package/dist/settings/settings-store.d.ts +13 -0
- package/dist/settings/settings-store.d.ts.map +1 -0
- package/dist/settings/settings-store.js +87 -0
- package/dist/settings/settings-store.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,2062 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { APP_NAME, EDITABLE_RUNTIME_KEY_TUPLE, getAgentDayBoundsUtc, normalizeAgentDisplayName, } from "@aitne/shared";
|
|
6
|
+
import { applyConfigUpdates } from "../env-writer.js";
|
|
7
|
+
import { runDefaultSchedulesReconciler } from "../../core/context/default-schedules-runner.js";
|
|
8
|
+
import { syncDmSessionTimesToQuietHours } from "../../core/quiet-hours-sync.js";
|
|
9
|
+
import { detectGoogleCredentialType, getGoogleOAuthClientConfig, parseGoogleCredentialsJson, } from "../../services/google-auth.js";
|
|
10
|
+
import { getContextDir } from "../../config.js";
|
|
11
|
+
import { CONTEXT_RELATIVE_PATHS } from "../../core/context-paths.js";
|
|
12
|
+
import { createLogger, toSafeErrorMessage } from "../../logging.js";
|
|
13
|
+
import { upsertManagementRulesAgentIdentity } from "../../management-rules.js";
|
|
14
|
+
import { DEFAULT_DISALLOWED_TOOLS, runtimeSettingsSchema } from "../../settings/runtime-settings.js";
|
|
15
|
+
import { createSettingsStore } from "../../settings/settings-store.js";
|
|
16
|
+
import { getSessionWorkdirPath } from "../../core/workdir.js";
|
|
17
|
+
import { rewriteCharacterBlock } from "../../core/skills-compiler.js";
|
|
18
|
+
import { DASHBOARD_CHAT_SCOPE, DOCS_QA_SCOPE } from "../../messaging/constants.js";
|
|
19
|
+
import { deleteAllChatSidebarSessions, deleteChatSession, } from "../../core/dashboard-session-cleanup.js";
|
|
20
|
+
import { readJsonBody } from "../json-body.js";
|
|
21
|
+
import { computeDmFreshnessAggregate } from "../../core/dm-freshness-metrics.js";
|
|
22
|
+
const MAX_UPLOAD_SIZE = 100 * 1024; // 100 KB — credential files are small
|
|
23
|
+
const MAX_OAUTH_STATE_AGE_MS = 10 * 60 * 1000;
|
|
24
|
+
const PUBLIC_CONFIG_RUNTIME_KEYS = [
|
|
25
|
+
"maxConcurrentSessions",
|
|
26
|
+
"maxReactiveSessions",
|
|
27
|
+
"delegatedProxyMaxConcurrent",
|
|
28
|
+
"delegatedTaskModeEnabled",
|
|
29
|
+
"delegatedTaskMaxPerDay",
|
|
30
|
+
"delegatedTaskDefaultMaxToolCalls",
|
|
31
|
+
"delegatedTaskDefaultMaxBudgetUsd",
|
|
32
|
+
"delegatedTaskDefaultTimeoutMs",
|
|
33
|
+
"delegatedTaskHeavyEnabled",
|
|
34
|
+
"executeTimeoutMinutes",
|
|
35
|
+
"agentDisplayName",
|
|
36
|
+
"sessionTimeoutDmMinutes",
|
|
37
|
+
"sessionTimeoutChannelMinutes",
|
|
38
|
+
"sessionTimeoutDashboardMinutes",
|
|
39
|
+
"timezone",
|
|
40
|
+
"dayBoundaryHour",
|
|
41
|
+
"hourlyCheckEnabled",
|
|
42
|
+
"hourlyCheckIntervalMinutes",
|
|
43
|
+
"hourlyCheckActiveStartHour",
|
|
44
|
+
"hourlyCheckActiveEndHour",
|
|
45
|
+
"hourlyCheckMinObservations",
|
|
46
|
+
"authProbeDisabled",
|
|
47
|
+
"authPreflightFreshnessMs",
|
|
48
|
+
"maxNotificationsPerHour",
|
|
49
|
+
"maxNotificationsPerDay",
|
|
50
|
+
"quietHoursStart",
|
|
51
|
+
"quietHoursEnd",
|
|
52
|
+
"batchIntervalMinutes",
|
|
53
|
+
"primaryPlatform",
|
|
54
|
+
"defaultNotificationPlatforms",
|
|
55
|
+
"whatsappEnabled",
|
|
56
|
+
"whatsappAuthDir",
|
|
57
|
+
"disallowedTools",
|
|
58
|
+
"claudeExecutionPermissionMode",
|
|
59
|
+
"codexExecutionPermissionMode",
|
|
60
|
+
"geminiExecutionPermissionMode",
|
|
61
|
+
"externalObsidianVaultPath",
|
|
62
|
+
"externalObsidianVaultName",
|
|
63
|
+
// SETUP-FLOW-REDESIGN-PLAN §6.3 — kill switch for the external-vault
|
|
64
|
+
// file watcher. Surfaced so the Note step's "Watch for changes"
|
|
65
|
+
// checkbox round-trips through the dashboard.
|
|
66
|
+
"externalObsidianWatch",
|
|
67
|
+
"primaryVaultPath",
|
|
68
|
+
"primaryVaultName",
|
|
69
|
+
// gitRepos / gitWatchedRepos / githubRepos removed at the unified-
|
|
70
|
+
// repositories cutover (docs/design/appendices/unified-repositories.md);
|
|
71
|
+
// dashboard reads the rows from /api/repositories instead.
|
|
72
|
+
"googleCalendarId",
|
|
73
|
+
"notionDatabaseIds",
|
|
74
|
+
"character",
|
|
75
|
+
"historyInjectionMaxMessages",
|
|
76
|
+
"historyInjectionMaxTokens",
|
|
77
|
+
"dmStalenessStrict",
|
|
78
|
+
"obsidianDebounceSeconds",
|
|
79
|
+
"schedulePollIntervalSeconds",
|
|
80
|
+
"gitPollIntervalSeconds",
|
|
81
|
+
"gitPushOverdueMinutes",
|
|
82
|
+
"gitProjectUpdateDebounceMinutes",
|
|
83
|
+
"notionPollIntervalSeconds",
|
|
84
|
+
"calendarPollIntervalSeconds",
|
|
85
|
+
"gmailPollIntervalSeconds",
|
|
86
|
+
"mcpAutoProbeIntervalMinutes",
|
|
87
|
+
"delegatedProbeIntervalMinutes",
|
|
88
|
+
"autonomousDailyCostCapUsd",
|
|
89
|
+
"autonomousMonthlyCostCapUsd",
|
|
90
|
+
"primaryLanguage",
|
|
91
|
+
"vaultMode",
|
|
92
|
+
];
|
|
93
|
+
const PUBLIC_CONFIG_NULLABLE_STRING_KEYS = new Set([
|
|
94
|
+
"whatsappAuthDir",
|
|
95
|
+
"externalObsidianVaultPath",
|
|
96
|
+
"externalObsidianVaultName",
|
|
97
|
+
"primaryVaultPath",
|
|
98
|
+
"primaryVaultName",
|
|
99
|
+
]);
|
|
100
|
+
/**
|
|
101
|
+
* Pre-defined static cost queries — no string interpolation of user input.
|
|
102
|
+
* `byModel` is computed in JS via `aggregateByBilledModel` because the SDK
|
|
103
|
+
* can route a request for one model to a sibling (e.g. opus-4-7 →
|
|
104
|
+
* opus-4-6[1m]); SQL `GROUP BY model_used` would lump cost under the
|
|
105
|
+
* requested model and produce a chart that disagrees with the per-row
|
|
106
|
+
* billed-model badge on the same page.
|
|
107
|
+
*/
|
|
108
|
+
const COST_QUERIES = {
|
|
109
|
+
daily: {
|
|
110
|
+
byPeriod: `SELECT date(started_at) as period,
|
|
111
|
+
SUM(cost_usd) as total_cost, COUNT(*) as session_count,
|
|
112
|
+
SUM(tokens_input) as total_input_tokens, SUM(tokens_output) as total_output_tokens
|
|
113
|
+
FROM agent_actions WHERE started_at > datetime('now', '-30 days') AND cost_usd IS NOT NULL
|
|
114
|
+
GROUP BY date(started_at) ORDER BY period DESC`,
|
|
115
|
+
byModelRows: `SELECT model_used, model_usage_json, cost_usd
|
|
116
|
+
FROM agent_actions
|
|
117
|
+
WHERE started_at > datetime('now', '-30 days')
|
|
118
|
+
AND cost_usd IS NOT NULL
|
|
119
|
+
AND (model_used IS NOT NULL OR model_usage_json IS NOT NULL)`,
|
|
120
|
+
byEventType: `SELECT action_type as event_type, SUM(cost_usd) as total_cost, COUNT(*) as session_count
|
|
121
|
+
FROM agent_actions WHERE started_at > datetime('now', '-30 days') AND cost_usd IS NOT NULL
|
|
122
|
+
GROUP BY action_type ORDER BY total_cost DESC`,
|
|
123
|
+
},
|
|
124
|
+
weekly: {
|
|
125
|
+
byPeriod: `SELECT strftime('%Y-W%W', started_at) as period,
|
|
126
|
+
SUM(cost_usd) as total_cost, COUNT(*) as session_count,
|
|
127
|
+
SUM(tokens_input) as total_input_tokens, SUM(tokens_output) as total_output_tokens
|
|
128
|
+
FROM agent_actions WHERE started_at > datetime('now', '-90 days') AND cost_usd IS NOT NULL
|
|
129
|
+
GROUP BY strftime('%Y-W%W', started_at) ORDER BY period DESC`,
|
|
130
|
+
byModelRows: `SELECT model_used, model_usage_json, cost_usd
|
|
131
|
+
FROM agent_actions
|
|
132
|
+
WHERE started_at > datetime('now', '-90 days')
|
|
133
|
+
AND cost_usd IS NOT NULL
|
|
134
|
+
AND (model_used IS NOT NULL OR model_usage_json IS NOT NULL)`,
|
|
135
|
+
byEventType: `SELECT action_type as event_type, SUM(cost_usd) as total_cost, COUNT(*) as session_count
|
|
136
|
+
FROM agent_actions WHERE started_at > datetime('now', '-90 days') AND cost_usd IS NOT NULL
|
|
137
|
+
GROUP BY action_type ORDER BY total_cost DESC`,
|
|
138
|
+
},
|
|
139
|
+
monthly: {
|
|
140
|
+
byPeriod: `SELECT strftime('%Y-%m', started_at) as period,
|
|
141
|
+
SUM(cost_usd) as total_cost, COUNT(*) as session_count,
|
|
142
|
+
SUM(tokens_input) as total_input_tokens, SUM(tokens_output) as total_output_tokens
|
|
143
|
+
FROM agent_actions WHERE started_at > datetime('now', '-365 days') AND cost_usd IS NOT NULL
|
|
144
|
+
GROUP BY strftime('%Y-%m', started_at) ORDER BY period DESC`,
|
|
145
|
+
byModelRows: `SELECT model_used, model_usage_json, cost_usd
|
|
146
|
+
FROM agent_actions
|
|
147
|
+
WHERE started_at > datetime('now', '-365 days')
|
|
148
|
+
AND cost_usd IS NOT NULL
|
|
149
|
+
AND (model_used IS NOT NULL OR model_usage_json IS NOT NULL)`,
|
|
150
|
+
byEventType: `SELECT action_type as event_type, SUM(cost_usd) as total_cost, COUNT(*) as session_count
|
|
151
|
+
FROM agent_actions WHERE started_at > datetime('now', '-365 days') AND cost_usd IS NOT NULL
|
|
152
|
+
GROUP BY action_type ORDER BY total_cost DESC`,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Aggregate raw `byModelRows` into the `{ model, total_cost, session_count }`
|
|
157
|
+
* shape the dashboard expects, attributing cost to the actually-billed model
|
|
158
|
+
* from `model_usage_json` rather than the requested `model_used`. When a row
|
|
159
|
+
* has no usage breakdown we fall back to `model_used`. A row that touches
|
|
160
|
+
* multiple billed models contributes its split cost to each bucket and is
|
|
161
|
+
* counted once toward each model's `session_count`.
|
|
162
|
+
*
|
|
163
|
+
* Cost reconciliation: the SDK's `r.modelUsage[*].costUSD` covers LLM
|
|
164
|
+
* inference only — server-side tools (web_search, code_execution) appear in
|
|
165
|
+
* `r.total_cost_usd` (= row.cost_usd) but not in any per-model entry. If
|
|
166
|
+
* `Σ per-model cost < row.cost_usd`, the residual is credited to
|
|
167
|
+
* `model_used` (the requested model) so per-model totals add up to the
|
|
168
|
+
* dashboard's overall cost. Without this, a chart row's "billed total"
|
|
169
|
+
* silently drops tool-use spend.
|
|
170
|
+
*/
|
|
171
|
+
export function aggregateByBilledModel(rows) {
|
|
172
|
+
const map = new Map();
|
|
173
|
+
// Per-row scratch; a single row counts toward `session_count` exactly once
|
|
174
|
+
// per model it touched, even when residual handling credits the same model
|
|
175
|
+
// twice (once from per-model breakdown, once from tool-use residual).
|
|
176
|
+
const addCost = (model, cost) => {
|
|
177
|
+
const bucket = map.get(model) ?? { total_cost: 0, session_count: 0 };
|
|
178
|
+
bucket.total_cost += cost;
|
|
179
|
+
map.set(model, bucket);
|
|
180
|
+
};
|
|
181
|
+
const incSession = (rowSeen, model) => {
|
|
182
|
+
if (rowSeen.has(model))
|
|
183
|
+
return;
|
|
184
|
+
rowSeen.add(model);
|
|
185
|
+
const bucket = map.get(model) ?? { total_cost: 0, session_count: 0 };
|
|
186
|
+
bucket.session_count += 1;
|
|
187
|
+
map.set(model, bucket);
|
|
188
|
+
};
|
|
189
|
+
// 0.0001¢ — below this, treat the residual as float-arithmetic noise and
|
|
190
|
+
// skip the bookkeeping. Real tool-use costs are always orders of magnitude
|
|
191
|
+
// above this.
|
|
192
|
+
const RESIDUAL_EPSILON_USD = 0.000001;
|
|
193
|
+
for (const row of rows) {
|
|
194
|
+
const seenForRow = new Set();
|
|
195
|
+
let parsed = null;
|
|
196
|
+
if (row.model_usage_json) {
|
|
197
|
+
try {
|
|
198
|
+
parsed = JSON.parse(row.model_usage_json);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
parsed = null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
let perModelTotal = 0;
|
|
205
|
+
let touchedAny = false;
|
|
206
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
207
|
+
for (const [modelId, entry] of Object.entries(parsed)) {
|
|
208
|
+
if (!entry || typeof entry !== "object")
|
|
209
|
+
continue;
|
|
210
|
+
const v = entry;
|
|
211
|
+
const cost = typeof v.costUsd === "number" ? v.costUsd : 0;
|
|
212
|
+
addCost(modelId, cost);
|
|
213
|
+
incSession(seenForRow, modelId);
|
|
214
|
+
perModelTotal += cost;
|
|
215
|
+
touchedAny = true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (!touchedAny) {
|
|
219
|
+
if (row.model_used) {
|
|
220
|
+
addCost(row.model_used, row.cost_usd);
|
|
221
|
+
incSession(seenForRow, row.model_used);
|
|
222
|
+
}
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
// Residual handles server-side tool cost (web_search, code execution)
|
|
226
|
+
// that the SDK adds to total_cost_usd but not to any per-model bucket.
|
|
227
|
+
const residual = row.cost_usd - perModelTotal;
|
|
228
|
+
if (residual > RESIDUAL_EPSILON_USD && row.model_used) {
|
|
229
|
+
addCost(row.model_used, residual);
|
|
230
|
+
incSession(seenForRow, row.model_used);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return [...map.entries()]
|
|
234
|
+
.map(([model, v]) => ({ model, ...v }))
|
|
235
|
+
.sort((a, b) => b.total_cost - a.total_cost);
|
|
236
|
+
}
|
|
237
|
+
const COST_PERIOD_SPECS = {
|
|
238
|
+
daily: {
|
|
239
|
+
bucketExpr: "date(started_at)",
|
|
240
|
+
sinceExpr: "-30 days",
|
|
241
|
+
},
|
|
242
|
+
weekly: {
|
|
243
|
+
bucketExpr: "strftime('%Y-W%W', started_at)",
|
|
244
|
+
sinceExpr: "-90 days",
|
|
245
|
+
},
|
|
246
|
+
monthly: {
|
|
247
|
+
bucketExpr: "strftime('%Y-%m', started_at)",
|
|
248
|
+
sinceExpr: "-365 days",
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
/** Escape HTML special characters to prevent XSS */
|
|
252
|
+
function escapeHtml(s) {
|
|
253
|
+
return s
|
|
254
|
+
.replace(/&/g, "&")
|
|
255
|
+
.replace(/</g, "<")
|
|
256
|
+
.replace(/>/g, ">")
|
|
257
|
+
.replace(/"/g, """)
|
|
258
|
+
.replace(/'/g, "'");
|
|
259
|
+
}
|
|
260
|
+
function getLocalHourMinute(date, timeZone) {
|
|
261
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
262
|
+
hour: "2-digit",
|
|
263
|
+
minute: "2-digit",
|
|
264
|
+
hour12: false,
|
|
265
|
+
timeZone,
|
|
266
|
+
});
|
|
267
|
+
const parts = formatter.formatToParts(date);
|
|
268
|
+
const hour = Number(parts.find((part) => part.type === "hour")?.value ?? "0");
|
|
269
|
+
const minute = Number(parts.find((part) => part.type === "minute")?.value ?? "0");
|
|
270
|
+
return { hour, minute };
|
|
271
|
+
}
|
|
272
|
+
function isHourlyCheckSlot(date, config) {
|
|
273
|
+
if (!config.hourlyCheckEnabled)
|
|
274
|
+
return false;
|
|
275
|
+
const { hour, minute } = getLocalHourMinute(date, config.timezone || undefined);
|
|
276
|
+
if (hour === config.dayBoundaryHour)
|
|
277
|
+
return false;
|
|
278
|
+
if (hour < config.hourlyCheckActiveStartHour || hour >= config.hourlyCheckActiveEndHour) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
return minute % config.hourlyCheckIntervalMinutes === 0;
|
|
282
|
+
}
|
|
283
|
+
function getNextHourlyCheck(config) {
|
|
284
|
+
if (!config.hourlyCheckEnabled) {
|
|
285
|
+
return { active: false, nextRunAt: null };
|
|
286
|
+
}
|
|
287
|
+
const now = new Date();
|
|
288
|
+
const active = isHourlyCheckSlot(now, config);
|
|
289
|
+
const start = new Date(now.getTime() + 60_000);
|
|
290
|
+
start.setSeconds(0, 0);
|
|
291
|
+
for (let offset = 0; offset < 48 * 60; offset++) {
|
|
292
|
+
const candidate = new Date(start.getTime() + offset * 60_000);
|
|
293
|
+
if (isHourlyCheckSlot(candidate, config)) {
|
|
294
|
+
return { active, nextRunAt: candidate.toISOString() };
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return { active, nextRunAt: null };
|
|
298
|
+
}
|
|
299
|
+
function isStringRecord(value) {
|
|
300
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
return Object.entries(value).every(([key, entryValue]) => typeof key === "string" && typeof entryValue === "string");
|
|
304
|
+
}
|
|
305
|
+
function sameStringRecord(a, b) {
|
|
306
|
+
const aEntries = Object.entries(a);
|
|
307
|
+
const bEntries = Object.entries(b);
|
|
308
|
+
if (aEntries.length !== bEntries.length) {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
return aEntries.every(([key, value]) => b[key] === value);
|
|
312
|
+
}
|
|
313
|
+
function buildSafeConfig(config, secretSummary) {
|
|
314
|
+
const safeConfig = {};
|
|
315
|
+
for (const key of PUBLIC_CONFIG_RUNTIME_KEYS) {
|
|
316
|
+
const value = config[key];
|
|
317
|
+
safeConfig[key] = PUBLIC_CONFIG_NULLABLE_STRING_KEYS.has(key)
|
|
318
|
+
? value ?? ""
|
|
319
|
+
: value;
|
|
320
|
+
}
|
|
321
|
+
safeConfig.apiPort = config.apiPort;
|
|
322
|
+
safeConfig.allowedTools = config.allowedToolsOverride ?? [];
|
|
323
|
+
// Derived — the actual directory `getContextDir(config)` resolves to.
|
|
324
|
+
// Surfaces the mode/path → disk outcome to the dashboard so the
|
|
325
|
+
// Management Mode section can show the effective location without
|
|
326
|
+
// reimplementing the resolution logic. Always an absolute path.
|
|
327
|
+
safeConfig.contextDir = getContextDir(config);
|
|
328
|
+
safeConfig.slackConfigured = secretSummary.slackConfigured;
|
|
329
|
+
safeConfig.slackOwnerUserConfigured = !!config.slackOwnerUserId;
|
|
330
|
+
safeConfig.telegramConfigured = secretSummary.telegramConfigured;
|
|
331
|
+
safeConfig.telegramOwnerChatConfigured = !!config.telegramOwnerChatId;
|
|
332
|
+
safeConfig.discordConfigured = secretSummary.discordConfigured;
|
|
333
|
+
safeConfig.discordOwnerUserConfigured = !!config.discordOwnerUserId;
|
|
334
|
+
safeConfig.notionConfigured = secretSummary.notionConfigured;
|
|
335
|
+
safeConfig.githubConfigured = secretSummary.githubConfigured;
|
|
336
|
+
safeConfig.githubWebhookSecretConfigured = secretSummary.githubWebhookSecretConfigured;
|
|
337
|
+
safeConfig.apiTokenConfigured = secretSummary.apiTokenConfigured;
|
|
338
|
+
safeConfig.whatsappOwnerPhoneConfigured = !!config.whatsappOwnerPhone;
|
|
339
|
+
safeConfig.googleCalendarCredentialsConfigured = secretSummary.googleCalendarCredentialsConfigured;
|
|
340
|
+
safeConfig.googleCalendarTokenConfigured = secretSummary.googleCalendarTokenConfigured;
|
|
341
|
+
// SETUP-FLOW-REDESIGN-PLAN §6.1 — surface Outlook BYOA presence so
|
|
342
|
+
// dashboards can decide when direct-mode Outlook integrations are
|
|
343
|
+
// resumable.
|
|
344
|
+
safeConfig.outlookClientConfigConfigured = secretSummary.outlookClientConfigConfigured;
|
|
345
|
+
safeConfig.googleCredentialType = secretSummary.googleCredentialType;
|
|
346
|
+
return safeConfig;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Dashboard API routes — REST endpoints for the Dashboard UI.
|
|
350
|
+
*
|
|
351
|
+
* Provides:
|
|
352
|
+
* - Config management (GET/PATCH /api/config)
|
|
353
|
+
* - Event/action logs (GET /api/events)
|
|
354
|
+
* - Conversation history (GET /api/conversations)
|
|
355
|
+
* - Cost analytics (GET /api/cost)
|
|
356
|
+
* - Approval queue (GET/POST /api/approvals)
|
|
357
|
+
*/
|
|
358
|
+
const logger = createLogger("dashboard-api");
|
|
359
|
+
export function createDashboardRoutes(deps) {
|
|
360
|
+
const app = new Hono();
|
|
361
|
+
const { db, config, services, secretBroker } = deps;
|
|
362
|
+
const settingsStore = createSettingsStore(db);
|
|
363
|
+
const oauthStates = new Map();
|
|
364
|
+
const agentActionColumns = new Set(db.pragma("table_info(agent_actions)").map((column) => column.name));
|
|
365
|
+
const backendExpr = agentActionColumns.has("backend")
|
|
366
|
+
? "COALESCE(backend, 'claude')"
|
|
367
|
+
: "'claude'";
|
|
368
|
+
function pruneOauthStates(now = Date.now()) {
|
|
369
|
+
for (const [state, data] of oauthStates.entries()) {
|
|
370
|
+
if (now - data.createdAt > MAX_OAUTH_STATE_AGE_MS) {
|
|
371
|
+
oauthStates.delete(state);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
async function getSecretConfigSummary() {
|
|
376
|
+
const [slackBotToken, slackAppToken, telegramBotToken, discordBotToken, notionApiKey, githubToken, githubWebhookSecret, apiToken, googleCredentialsJson, googleTokenJson,] = await Promise.all([
|
|
377
|
+
secretBroker.getSlackBotToken(),
|
|
378
|
+
secretBroker.getSlackAppToken(),
|
|
379
|
+
secretBroker.getTelegramBotToken(),
|
|
380
|
+
secretBroker.getDiscordBotToken(),
|
|
381
|
+
secretBroker.getNotionApiKey(),
|
|
382
|
+
secretBroker.getGitHubToken(),
|
|
383
|
+
secretBroker.getGitHubWebhookSecret(),
|
|
384
|
+
secretBroker.getApiToken(),
|
|
385
|
+
secretBroker.getGoogleCredentialsJson(),
|
|
386
|
+
secretBroker.getGoogleTokenJson(),
|
|
387
|
+
]);
|
|
388
|
+
// SETUP-FLOW-REDESIGN-PLAN §6.1 — surface BYOA Outlook client config
|
|
389
|
+
// presence so the connections page knows when direct-mode Outlook
|
|
390
|
+
// integrations are resumable. Best-effort: if no blob store is
|
|
391
|
+
// wired (test harness), report `false` rather than crashing.
|
|
392
|
+
let outlookClientConfigConfigured = false;
|
|
393
|
+
try {
|
|
394
|
+
outlookClientConfigConfigured = deps.blobStore
|
|
395
|
+
? await deps.blobStore.exists("mail:outlook:client-config")
|
|
396
|
+
: false;
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
outlookClientConfigConfigured = false;
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
slackConfigured: !!(slackBotToken && slackAppToken),
|
|
403
|
+
telegramConfigured: !!telegramBotToken,
|
|
404
|
+
discordConfigured: !!discordBotToken,
|
|
405
|
+
notionConfigured: !!notionApiKey,
|
|
406
|
+
githubConfigured: !!githubToken,
|
|
407
|
+
githubWebhookSecretConfigured: !!githubWebhookSecret,
|
|
408
|
+
apiTokenConfigured: !!apiToken,
|
|
409
|
+
googleCalendarCredentialsConfigured: !!googleCredentialsJson,
|
|
410
|
+
googleCalendarTokenConfigured: !!googleTokenJson,
|
|
411
|
+
outlookClientConfigConfigured,
|
|
412
|
+
googleCredentialType: detectGoogleCredentialType(googleCredentialsJson),
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
async function notifySecretChange(scope) {
|
|
416
|
+
await deps.onSecretChanged?.(scope);
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* design/15-character.md §15.6.1 live-overwrite: when character changes,
|
|
420
|
+
* rewrite the `## Character` block inside every active session's
|
|
421
|
+
* instruction files (CLAUDE.md / AGENTS.md / GEMINI.md) so the next turn
|
|
422
|
+
* in the session picks up the new value without waiting for a session
|
|
423
|
+
* spawn. Per-workdir errors are counted and logged but never thrown —
|
|
424
|
+
* the DB write is already durable at the caller.
|
|
425
|
+
*
|
|
426
|
+
* Shared by PATCH /config (dashboard path, Approve tier) and
|
|
427
|
+
* PATCH /config/character (agent path, Notify tier).
|
|
428
|
+
*/
|
|
429
|
+
function fanOutCharacterToActiveSessions() {
|
|
430
|
+
const sessions = db
|
|
431
|
+
.prepare(`SELECT id FROM conversation_sessions WHERE status = 'active'`)
|
|
432
|
+
.all();
|
|
433
|
+
const totals = { rewritten: 0, skipped: 0, failed: 0, missing: 0 };
|
|
434
|
+
for (const row of sessions) {
|
|
435
|
+
const sessionId = typeof row.id === "bigint" ? Number(row.id) : row.id;
|
|
436
|
+
const workdir = getSessionWorkdirPath(config.dataDir, sessionId);
|
|
437
|
+
if (!existsSync(workdir)) {
|
|
438
|
+
totals.missing++;
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
try {
|
|
442
|
+
const summary = rewriteCharacterBlock(workdir, config.character);
|
|
443
|
+
totals.rewritten += summary.rewritten;
|
|
444
|
+
totals.skipped += summary.skipped;
|
|
445
|
+
totals.failed += summary.failed;
|
|
446
|
+
}
|
|
447
|
+
catch (err) {
|
|
448
|
+
totals.failed++;
|
|
449
|
+
logger.warn({ err, sessionId, workdir }, "rewriteCharacterBlock threw on character live-overwrite");
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
logger.info({ ...totals, activeSessions: sessions.length }, "Character block fanned out to active session workdirs");
|
|
453
|
+
}
|
|
454
|
+
// ── Config API ──
|
|
455
|
+
/** GET /config — return current configuration */
|
|
456
|
+
app.get("/config", async (c) => {
|
|
457
|
+
const secretSummary = await getSecretConfigSummary();
|
|
458
|
+
const safeConfig = buildSafeConfig({ ...config, agentDisplayName: normalizeAgentDisplayName(config.agentDisplayName) }, secretSummary);
|
|
459
|
+
return c.json(safeConfig);
|
|
460
|
+
});
|
|
461
|
+
/** GET /config/defaults — return Zod schema defaults for all editable keys */
|
|
462
|
+
app.get("/config/defaults", (c) => {
|
|
463
|
+
const zodDefaults = runtimeSettingsSchema.parse({});
|
|
464
|
+
const defaults = {};
|
|
465
|
+
for (const key of EDITABLE_RUNTIME_KEY_TUPLE) {
|
|
466
|
+
const val = zodDefaults[key];
|
|
467
|
+
// Mirror GET /config shape: allowedToolsOverride null → empty array
|
|
468
|
+
if (key === "allowedToolsOverride") {
|
|
469
|
+
defaults.allowedTools = val ?? [];
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
defaults[key] = val;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
// Bootstrap keys not in runtimeSettingsSchema
|
|
476
|
+
defaults.apiPort = 8321;
|
|
477
|
+
return c.json(defaults);
|
|
478
|
+
});
|
|
479
|
+
/** PATCH /config — update one or more config fields */
|
|
480
|
+
app.patch("/config", async (c) => {
|
|
481
|
+
const parsedBody = await readJsonBody(c);
|
|
482
|
+
if (!parsedBody.ok)
|
|
483
|
+
return parsedBody.response;
|
|
484
|
+
const body = parsedBody.body;
|
|
485
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
486
|
+
return c.json({ error: "Body must be a JSON object" }, 400);
|
|
487
|
+
}
|
|
488
|
+
const bodyRecord = { ...body };
|
|
489
|
+
if (Object.hasOwn(bodyRecord, "notionDatabaseIdsBase")) {
|
|
490
|
+
if (!Object.hasOwn(bodyRecord, "notionDatabaseIds")) {
|
|
491
|
+
return c.json({
|
|
492
|
+
error: "validation_failed",
|
|
493
|
+
details: {
|
|
494
|
+
notionDatabaseIdsBase: "notionDatabaseIdsBase requires notionDatabaseIds in the same request",
|
|
495
|
+
},
|
|
496
|
+
}, 400);
|
|
497
|
+
}
|
|
498
|
+
if (!isStringRecord(bodyRecord.notionDatabaseIdsBase)) {
|
|
499
|
+
return c.json({
|
|
500
|
+
error: "validation_failed",
|
|
501
|
+
details: {
|
|
502
|
+
notionDatabaseIdsBase: "notionDatabaseIdsBase must be an object mapping labels to database IDs",
|
|
503
|
+
},
|
|
504
|
+
}, 400);
|
|
505
|
+
}
|
|
506
|
+
if (!sameStringRecord(config.notionDatabaseIds, bodyRecord.notionDatabaseIdsBase)) {
|
|
507
|
+
return c.json({
|
|
508
|
+
error: "conflict",
|
|
509
|
+
message: "Notion database mappings changed on another tab. Reload and try again.",
|
|
510
|
+
}, 409);
|
|
511
|
+
}
|
|
512
|
+
delete bodyRecord.notionDatabaseIdsBase;
|
|
513
|
+
}
|
|
514
|
+
// Snapshot WhatsApp state BEFORE applying so we can detect a transition
|
|
515
|
+
// and trigger live enable/disable of the adapter (no daemon restart).
|
|
516
|
+
const prevWhatsappEnabled = config.whatsappEnabled;
|
|
517
|
+
const prevWhatsappOwnerPhone = config.whatsappOwnerPhone;
|
|
518
|
+
const prevWhatsappAuthDir = config.whatsappAuthDir;
|
|
519
|
+
// EXECUTION-MODE-DESIGN.md §5.2 / §6.3 — snapshot pre-apply execution mode
|
|
520
|
+
// so audit rows below can capture before → after per backend. The
|
|
521
|
+
// dedicated `POST /api/setup/mode` is the usual path (it emits its own
|
|
522
|
+
// audit row); this PATCH covers the power-user / env-style API caller
|
|
523
|
+
// who edits the key directly without going through the settings UI.
|
|
524
|
+
const prevExecMode = {
|
|
525
|
+
claude: config.claudeExecutionPermissionMode,
|
|
526
|
+
codex: config.codexExecutionPermissionMode,
|
|
527
|
+
gemini: config.geminiExecutionPermissionMode,
|
|
528
|
+
};
|
|
529
|
+
// design/15-character.md §15.6.1 — snapshot character pre-apply so the
|
|
530
|
+
// live-overwrite pass below has a stable "after" value to fan out to
|
|
531
|
+
// every active session workdir.
|
|
532
|
+
const prevCharacter = config.character;
|
|
533
|
+
// gitRepos / gitWatchedRepos no longer live in config — repository
|
|
534
|
+
// changes go through /api/repositories and trigger
|
|
535
|
+
// `onGitReposChanged` directly from that route.
|
|
536
|
+
// §6.2 Note Sources regeneration is centralized inside
|
|
537
|
+
// applyConfigUpdates (via the db option) — no inline hook in this
|
|
538
|
+
// handler. Any future caller of applyConfigUpdates that carries
|
|
539
|
+
// externalObsidianVaultPath / externalObsidianWatch automatically
|
|
540
|
+
// gets the same regeneration without copy-paste.
|
|
541
|
+
const result = await applyConfigUpdates(config, settingsStore, bodyRecord, {
|
|
542
|
+
db: deps.db,
|
|
543
|
+
});
|
|
544
|
+
if (Object.keys(result.errors).length > 0 && result.updated.length === 0) {
|
|
545
|
+
return c.json({ error: "validation_failed", details: result.errors }, 400);
|
|
546
|
+
}
|
|
547
|
+
// Hot-reload cron schedules when schedule-related config changes
|
|
548
|
+
const SCHEDULE_KEYS = [
|
|
549
|
+
"dayBoundaryHour",
|
|
550
|
+
"timezone",
|
|
551
|
+
"hourlyCheckEnabled",
|
|
552
|
+
"hourlyCheckIntervalMinutes",
|
|
553
|
+
"hourlyCheckActiveStartHour",
|
|
554
|
+
"hourlyCheckActiveEndHour",
|
|
555
|
+
];
|
|
556
|
+
if (result.updated.some((k) => SCHEDULE_KEYS.includes(k))) {
|
|
557
|
+
deps.onScheduleConfigChanged?.();
|
|
558
|
+
}
|
|
559
|
+
// git repository changes route through POST/PATCH /api/repositories
|
|
560
|
+
// (unified-repositories cutover); they trigger onGitReposChanged
|
|
561
|
+
// from there, not from the dashboard config PATCH path.
|
|
562
|
+
// SCHEDULED-DM-IMPLEMENTATION-PLAN §6.7 — when quietHoursEnd
|
|
563
|
+
// changes, retime every enabled `dm_session` recurring row whose
|
|
564
|
+
// `task_context.pin_to_quiet_hours_end === true` so the briefing
|
|
565
|
+
// tracks the user's quiet-hours edge by default. Rows with the
|
|
566
|
+
// pin flag false (user-pinned a custom time) are left alone.
|
|
567
|
+
if (result.updated.includes("quietHoursEnd")
|
|
568
|
+
&& typeof config.quietHoursEnd === "string"
|
|
569
|
+
&& /^\d{2}:\d{2}$/.test(config.quietHoursEnd)) {
|
|
570
|
+
try {
|
|
571
|
+
syncDmSessionTimesToQuietHours(db, config.quietHoursEnd);
|
|
572
|
+
runDefaultSchedulesReconciler({
|
|
573
|
+
db,
|
|
574
|
+
contextDir: getContextDir(config, db),
|
|
575
|
+
writeTracker: deps.writeTracker,
|
|
576
|
+
onPromptContextChanged: deps.onPromptContextChanged,
|
|
577
|
+
trigger: "manual",
|
|
578
|
+
}).catch((err) => {
|
|
579
|
+
logger.warn({ err }, "Default-schedules reconciler failed after quietHoursEnd change");
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
catch (err) {
|
|
583
|
+
logger.warn({ err }, "syncDmSessionTimesToQuietHours threw after dashboard config PATCH");
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
// Hot-refresh DM session skill dirs when enabledMailProviders changes
|
|
587
|
+
// through the generic config PATCH. The per-endpoint `PATCH /mail/providers`
|
|
588
|
+
// handler already drives this through MailAccountRegistry.onScopeChanged,
|
|
589
|
+
// but the dashboard's catch-all config PATCH bypasses that route, so
|
|
590
|
+
// without this dispatch the scope toggle wouldn't reach active workdirs.
|
|
591
|
+
if (result.updated.includes("enabledMailProviders")) {
|
|
592
|
+
try {
|
|
593
|
+
deps.services.mail?.onProviderSelectionChanged(config.enabledMailProviders);
|
|
594
|
+
}
|
|
595
|
+
catch (err) {
|
|
596
|
+
logger.warn({ err }, "onProviderSelectionChanged threw after dashboard config PATCH");
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
// Hot-reload WhatsApp adapter when whatsappEnabled / phone / auth dir change.
|
|
600
|
+
// This eliminates the daemon-restart requirement that previously made
|
|
601
|
+
// pairing impossible from the dashboard.
|
|
602
|
+
const whatsappKeysTouched = result.updated.some((k) => ["whatsappEnabled", "whatsappOwnerPhone", "whatsappAuthDir"].includes(k));
|
|
603
|
+
if (whatsappKeysTouched && deps.whatsappControls) {
|
|
604
|
+
const phoneChanged = config.whatsappOwnerPhone !== prevWhatsappOwnerPhone;
|
|
605
|
+
const authDirChanged = config.whatsappAuthDir !== prevWhatsappAuthDir;
|
|
606
|
+
try {
|
|
607
|
+
if (!config.whatsappEnabled && prevWhatsappEnabled) {
|
|
608
|
+
// disabled — tear down
|
|
609
|
+
await deps.whatsappControls.disable();
|
|
610
|
+
}
|
|
611
|
+
else if (config.whatsappEnabled) {
|
|
612
|
+
if (!prevWhatsappEnabled) {
|
|
613
|
+
// newly enabled — build and start
|
|
614
|
+
await deps.whatsappControls.enable();
|
|
615
|
+
}
|
|
616
|
+
else if (phoneChanged || authDirChanged) {
|
|
617
|
+
// settings changed while enabled — bounce
|
|
618
|
+
await deps.whatsappControls.disable();
|
|
619
|
+
await deps.whatsappControls.enable();
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
// Drop "whatsappEnabled" / phone / auth dir from requiresRestart since
|
|
623
|
+
// we just hot-reloaded them. Other restart-required keys (like Slack
|
|
624
|
+
// tokens) still report restart.
|
|
625
|
+
result.requiresRestart = result.requiresRestart.filter((k) => !["whatsappEnabled", "whatsappOwnerPhone", "whatsappAuthDir"].includes(k));
|
|
626
|
+
}
|
|
627
|
+
catch (err) {
|
|
628
|
+
const message = toSafeErrorMessage(err, "unknown WhatsApp error");
|
|
629
|
+
result.errors.whatsapp = `WhatsApp hot-reload failed: ${message}`;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
// EXECUTION-MODE-DESIGN.md §6.3 — emit one `execution_mode_changed`
|
|
633
|
+
// audit row per backend whose mode moved through this PATCH, matching
|
|
634
|
+
// the row shape that `POST /api/setup/mode` writes. Without this the
|
|
635
|
+
// PATCH path would silently bypass audit coverage for a power-user
|
|
636
|
+
// API caller.
|
|
637
|
+
for (const [backend, key] of [
|
|
638
|
+
["claude", "claudeExecutionPermissionMode"],
|
|
639
|
+
["codex", "codexExecutionPermissionMode"],
|
|
640
|
+
["gemini", "geminiExecutionPermissionMode"],
|
|
641
|
+
]) {
|
|
642
|
+
if (!result.updated.includes(key))
|
|
643
|
+
continue;
|
|
644
|
+
const before = prevExecMode[backend];
|
|
645
|
+
const after = config[key];
|
|
646
|
+
if (before === after)
|
|
647
|
+
continue;
|
|
648
|
+
try {
|
|
649
|
+
db.prepare(`INSERT INTO agent_actions (action_type, trigger, result, detail, backend)
|
|
650
|
+
VALUES (?, ?, ?, ?, ?)`).run("execution_mode_changed", "dashboard_config_patch", "success", JSON.stringify({ before, after }), backend);
|
|
651
|
+
}
|
|
652
|
+
catch (err) {
|
|
653
|
+
logger.warn({ err, backend }, "failed to record execution_mode_changed audit row (PATCH path)");
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (result.updated.includes("agentDisplayName")) {
|
|
657
|
+
try {
|
|
658
|
+
const rulesRelPath = CONTEXT_RELATIVE_PATHS.rules.management;
|
|
659
|
+
const rulesSnapshotKey = rulesRelPath.replace(/\.md$/, "");
|
|
660
|
+
const rulesPath = join(getContextDir(config, db), rulesRelPath);
|
|
661
|
+
if (existsSync(rulesPath)) {
|
|
662
|
+
const currentRules = readFileSync(rulesPath, "utf-8");
|
|
663
|
+
const nextRules = upsertManagementRulesAgentIdentity(currentRules, normalizeAgentDisplayName(config.agentDisplayName));
|
|
664
|
+
if (nextRules !== currentRules) {
|
|
665
|
+
db.prepare("INSERT INTO md_file_snapshots (file_path, content, trigger) VALUES (?, ?, ?)").run(rulesSnapshotKey, currentRules, "agent_name_update");
|
|
666
|
+
writeFileSync(rulesPath, nextRules, "utf-8");
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
catch (err) {
|
|
671
|
+
const message = toSafeErrorMessage(err, `unknown ${CONTEXT_RELATIVE_PATHS.rules.management} error`);
|
|
672
|
+
result.errors.agentDisplayName = `Saved config, but failed to sync ${CONTEXT_RELATIVE_PATHS.rules.management}: ${message}`;
|
|
673
|
+
}
|
|
674
|
+
deps.onPromptContextChanged?.("agentDisplayName", "config_update:agentDisplayName", "loud", { tierReason: "config_agent_display_name" });
|
|
675
|
+
}
|
|
676
|
+
// design/15-character.md §15.6.1 — character changed; fan the new value
|
|
677
|
+
// out to every active session's instruction files.
|
|
678
|
+
if (result.updated.includes("character") && config.character !== prevCharacter) {
|
|
679
|
+
fanOutCharacterToActiveSessions();
|
|
680
|
+
}
|
|
681
|
+
return c.json({
|
|
682
|
+
status: "updated",
|
|
683
|
+
updated: result.updated,
|
|
684
|
+
requiresRestart: result.requiresRestart,
|
|
685
|
+
errors: result.errors,
|
|
686
|
+
});
|
|
687
|
+
});
|
|
688
|
+
/**
|
|
689
|
+
* GET /config/character — agent-callable read of the persona string.
|
|
690
|
+
*
|
|
691
|
+
* design/15-character.md §15.6 — the general /api/config surface is
|
|
692
|
+
* Approve-tier (contains secret summaries, OAuth state, schedule keys),
|
|
693
|
+
* so bearer-less callers (the agent's curl from a session workdir) need
|
|
694
|
+
* a narrowly scoped read. Returns the single field shape `{character}`
|
|
695
|
+
* so `jq .character` in skills keeps working.
|
|
696
|
+
*/
|
|
697
|
+
app.get("/config/character", (c) => {
|
|
698
|
+
return c.json({ character: config.character });
|
|
699
|
+
});
|
|
700
|
+
/**
|
|
701
|
+
* PATCH /config/character — agent-callable write of the persona string.
|
|
702
|
+
*
|
|
703
|
+
* Notify tier: audit-logged by the auth middleware, no Bearer required.
|
|
704
|
+
* Accepts only `{character: string}` — extra keys are rejected so this
|
|
705
|
+
* route cannot be used as a side channel into other config fields.
|
|
706
|
+
* Zod validation (max 1000 chars, no marker substring, non-blank-or-empty)
|
|
707
|
+
* runs inside `applyConfigUpdates` as usual.
|
|
708
|
+
*/
|
|
709
|
+
app.patch("/config/character", async (c) => {
|
|
710
|
+
const parsedBody = await readJsonBody(c);
|
|
711
|
+
if (!parsedBody.ok)
|
|
712
|
+
return parsedBody.response;
|
|
713
|
+
const body = parsedBody.body;
|
|
714
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
715
|
+
return c.json({ error: "Body must be a JSON object" }, 400);
|
|
716
|
+
}
|
|
717
|
+
const bodyRecord = body;
|
|
718
|
+
const extraKeys = Object.keys(bodyRecord).filter((k) => k !== "character");
|
|
719
|
+
if (extraKeys.length > 0) {
|
|
720
|
+
return c.json({
|
|
721
|
+
error: "validation_failed",
|
|
722
|
+
details: {
|
|
723
|
+
_extraKeys: `Only "character" is accepted on this endpoint; got: ${extraKeys.join(", ")}`,
|
|
724
|
+
},
|
|
725
|
+
}, 400);
|
|
726
|
+
}
|
|
727
|
+
if (!Object.hasOwn(bodyRecord, "character")) {
|
|
728
|
+
return c.json({
|
|
729
|
+
error: "validation_failed",
|
|
730
|
+
details: { character: "character field is required" },
|
|
731
|
+
}, 400);
|
|
732
|
+
}
|
|
733
|
+
const prevCharacter = config.character;
|
|
734
|
+
const result = await applyConfigUpdates(config, settingsStore, {
|
|
735
|
+
character: bodyRecord.character,
|
|
736
|
+
});
|
|
737
|
+
if (Object.keys(result.errors).length > 0 && result.updated.length === 0) {
|
|
738
|
+
return c.json({ error: "validation_failed", details: result.errors }, 400);
|
|
739
|
+
}
|
|
740
|
+
if (result.updated.includes("character") && config.character !== prevCharacter) {
|
|
741
|
+
fanOutCharacterToActiveSessions();
|
|
742
|
+
}
|
|
743
|
+
return c.json({
|
|
744
|
+
status: "updated",
|
|
745
|
+
character: config.character,
|
|
746
|
+
updated: result.updated,
|
|
747
|
+
errors: result.errors,
|
|
748
|
+
});
|
|
749
|
+
});
|
|
750
|
+
app.put("/secrets/slack", async (c) => {
|
|
751
|
+
const parsedBody = await readJsonBody(c);
|
|
752
|
+
if (!parsedBody.ok)
|
|
753
|
+
return parsedBody.response;
|
|
754
|
+
const body = parsedBody.body;
|
|
755
|
+
const botToken = typeof body?.botToken === "string" ? body.botToken.trim() : "";
|
|
756
|
+
const appToken = typeof body?.appToken === "string" ? body.appToken.trim() : "";
|
|
757
|
+
const validationErrors = {};
|
|
758
|
+
if (!botToken && !appToken) {
|
|
759
|
+
return c.json({
|
|
760
|
+
status: "validation_failed",
|
|
761
|
+
configured: false,
|
|
762
|
+
requiresRestart: false,
|
|
763
|
+
validationErrors: {
|
|
764
|
+
botToken: "Provide at least one Slack token to save.",
|
|
765
|
+
appToken: "Provide at least one Slack token to save.",
|
|
766
|
+
},
|
|
767
|
+
}, 400);
|
|
768
|
+
}
|
|
769
|
+
if (botToken)
|
|
770
|
+
await secretBroker.set("slackBotToken", botToken);
|
|
771
|
+
if (appToken)
|
|
772
|
+
await secretBroker.set("slackAppToken", appToken);
|
|
773
|
+
await notifySecretChange("slack");
|
|
774
|
+
return c.json({
|
|
775
|
+
status: "updated",
|
|
776
|
+
configured: (await getSecretConfigSummary()).slackConfigured,
|
|
777
|
+
requiresRestart: false,
|
|
778
|
+
validationErrors,
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
app.put("/secrets/telegram", async (c) => {
|
|
782
|
+
const parsedBody = await readJsonBody(c);
|
|
783
|
+
if (!parsedBody.ok)
|
|
784
|
+
return parsedBody.response;
|
|
785
|
+
const body = parsedBody.body;
|
|
786
|
+
const botToken = typeof body?.botToken === "string" ? body.botToken.trim() : "";
|
|
787
|
+
if (!botToken) {
|
|
788
|
+
return c.json({
|
|
789
|
+
status: "validation_failed",
|
|
790
|
+
configured: false,
|
|
791
|
+
requiresRestart: false,
|
|
792
|
+
validationErrors: { botToken: "Telegram bot token is required." },
|
|
793
|
+
}, 400);
|
|
794
|
+
}
|
|
795
|
+
await secretBroker.set("telegramBotToken", botToken);
|
|
796
|
+
await notifySecretChange("telegram");
|
|
797
|
+
return c.json({
|
|
798
|
+
status: "updated",
|
|
799
|
+
configured: (await getSecretConfigSummary()).telegramConfigured,
|
|
800
|
+
requiresRestart: false,
|
|
801
|
+
validationErrors: {},
|
|
802
|
+
});
|
|
803
|
+
});
|
|
804
|
+
app.put("/secrets/discord", async (c) => {
|
|
805
|
+
const parsedBody = await readJsonBody(c);
|
|
806
|
+
if (!parsedBody.ok)
|
|
807
|
+
return parsedBody.response;
|
|
808
|
+
const body = parsedBody.body;
|
|
809
|
+
const botToken = typeof body?.botToken === "string" ? body.botToken.trim() : "";
|
|
810
|
+
if (!botToken) {
|
|
811
|
+
return c.json({
|
|
812
|
+
status: "validation_failed",
|
|
813
|
+
configured: false,
|
|
814
|
+
requiresRestart: false,
|
|
815
|
+
validationErrors: { botToken: "Discord bot token is required." },
|
|
816
|
+
}, 400);
|
|
817
|
+
}
|
|
818
|
+
await secretBroker.set("discordBotToken", botToken);
|
|
819
|
+
await notifySecretChange("discord");
|
|
820
|
+
return c.json({
|
|
821
|
+
status: "updated",
|
|
822
|
+
configured: (await getSecretConfigSummary()).discordConfigured,
|
|
823
|
+
requiresRestart: false,
|
|
824
|
+
validationErrors: {},
|
|
825
|
+
});
|
|
826
|
+
});
|
|
827
|
+
app.put("/secrets/notion", async (c) => {
|
|
828
|
+
const parsedBody = await readJsonBody(c);
|
|
829
|
+
if (!parsedBody.ok)
|
|
830
|
+
return parsedBody.response;
|
|
831
|
+
const body = parsedBody.body;
|
|
832
|
+
const apiKey = typeof body?.apiKey === "string" ? body.apiKey.trim() : "";
|
|
833
|
+
if (!apiKey) {
|
|
834
|
+
return c.json({
|
|
835
|
+
status: "validation_failed",
|
|
836
|
+
configured: false,
|
|
837
|
+
requiresRestart: false,
|
|
838
|
+
validationErrors: { apiKey: "Notion API key is required." },
|
|
839
|
+
}, 400);
|
|
840
|
+
}
|
|
841
|
+
await secretBroker.set("notionApiKey", apiKey);
|
|
842
|
+
await notifySecretChange("notion");
|
|
843
|
+
return c.json({
|
|
844
|
+
status: "updated",
|
|
845
|
+
configured: (await getSecretConfigSummary()).notionConfigured,
|
|
846
|
+
requiresRestart: false,
|
|
847
|
+
validationErrors: {},
|
|
848
|
+
});
|
|
849
|
+
});
|
|
850
|
+
app.put("/secrets/github", async (c) => {
|
|
851
|
+
const parsedBody = await readJsonBody(c);
|
|
852
|
+
if (!parsedBody.ok)
|
|
853
|
+
return parsedBody.response;
|
|
854
|
+
const body = parsedBody.body;
|
|
855
|
+
const token = typeof body?.token === "string" ? body.token.trim() : "";
|
|
856
|
+
const webhookSecret = typeof body?.webhookSecret === "string" ? body.webhookSecret.trim() : "";
|
|
857
|
+
if (!token && !webhookSecret) {
|
|
858
|
+
return c.json({
|
|
859
|
+
status: "validation_failed",
|
|
860
|
+
configured: false,
|
|
861
|
+
requiresRestart: false,
|
|
862
|
+
validationErrors: {
|
|
863
|
+
token: "Provide a GitHub token and/or webhook secret.",
|
|
864
|
+
webhookSecret: "Provide a GitHub token and/or webhook secret.",
|
|
865
|
+
},
|
|
866
|
+
}, 400);
|
|
867
|
+
}
|
|
868
|
+
if (token)
|
|
869
|
+
await secretBroker.set("githubToken", token);
|
|
870
|
+
if (webhookSecret)
|
|
871
|
+
await secretBroker.set("githubWebhookSecret", webhookSecret);
|
|
872
|
+
await notifySecretChange("github");
|
|
873
|
+
const summary = await getSecretConfigSummary();
|
|
874
|
+
return c.json({
|
|
875
|
+
status: "updated",
|
|
876
|
+
configured: summary.githubConfigured || summary.githubWebhookSecretConfigured,
|
|
877
|
+
requiresRestart: false,
|
|
878
|
+
validationErrors: {},
|
|
879
|
+
});
|
|
880
|
+
});
|
|
881
|
+
app.put("/secrets/google/credentials", async (c) => {
|
|
882
|
+
const parsedBody = await readJsonBody(c);
|
|
883
|
+
if (!parsedBody.ok)
|
|
884
|
+
return parsedBody.response;
|
|
885
|
+
const body = parsedBody.body;
|
|
886
|
+
const raw = typeof body?.json === "string" ? body.json : "";
|
|
887
|
+
if (!raw) {
|
|
888
|
+
return c.json({
|
|
889
|
+
status: "validation_failed",
|
|
890
|
+
configured: false,
|
|
891
|
+
requiresRestart: false,
|
|
892
|
+
validationErrors: { json: "Credentials JSON is required." },
|
|
893
|
+
}, 400);
|
|
894
|
+
}
|
|
895
|
+
let parsed;
|
|
896
|
+
try {
|
|
897
|
+
parsed = JSON.parse(raw);
|
|
898
|
+
}
|
|
899
|
+
catch {
|
|
900
|
+
return c.json({
|
|
901
|
+
status: "validation_failed",
|
|
902
|
+
configured: false,
|
|
903
|
+
requiresRestart: false,
|
|
904
|
+
validationErrors: { json: "Invalid JSON file" },
|
|
905
|
+
}, 400);
|
|
906
|
+
}
|
|
907
|
+
if (!parsed.installed && !parsed.web && parsed.type !== "service_account") {
|
|
908
|
+
return c.json({
|
|
909
|
+
status: "validation_failed",
|
|
910
|
+
configured: false,
|
|
911
|
+
requiresRestart: false,
|
|
912
|
+
validationErrors: {
|
|
913
|
+
json: "Invalid credentials format. Expected OAuth2 credentials JSON or a service account JSON.",
|
|
914
|
+
},
|
|
915
|
+
}, 400);
|
|
916
|
+
}
|
|
917
|
+
await secretBroker.set("googleCredentialsJson", raw);
|
|
918
|
+
if (parsed.type === "service_account") {
|
|
919
|
+
await secretBroker.delete("googleTokenJson");
|
|
920
|
+
}
|
|
921
|
+
await notifySecretChange("google");
|
|
922
|
+
deps.onGoogleServicesReady?.();
|
|
923
|
+
const summary = await getSecretConfigSummary();
|
|
924
|
+
return c.json({
|
|
925
|
+
status: "updated",
|
|
926
|
+
configured: summary.googleCalendarCredentialsConfigured,
|
|
927
|
+
requiresRestart: false,
|
|
928
|
+
validationErrors: {},
|
|
929
|
+
});
|
|
930
|
+
});
|
|
931
|
+
app.put("/secrets/google/token", async (c) => {
|
|
932
|
+
const parsedBody = await readJsonBody(c);
|
|
933
|
+
if (!parsedBody.ok)
|
|
934
|
+
return parsedBody.response;
|
|
935
|
+
const body = parsedBody.body;
|
|
936
|
+
const raw = typeof body?.json === "string" ? body.json : "";
|
|
937
|
+
if (!raw) {
|
|
938
|
+
return c.json({
|
|
939
|
+
status: "validation_failed",
|
|
940
|
+
configured: false,
|
|
941
|
+
requiresRestart: false,
|
|
942
|
+
validationErrors: { json: "Token JSON is required." },
|
|
943
|
+
}, 400);
|
|
944
|
+
}
|
|
945
|
+
try {
|
|
946
|
+
JSON.parse(raw);
|
|
947
|
+
}
|
|
948
|
+
catch {
|
|
949
|
+
return c.json({
|
|
950
|
+
status: "validation_failed",
|
|
951
|
+
configured: false,
|
|
952
|
+
requiresRestart: false,
|
|
953
|
+
validationErrors: { json: "Invalid JSON file" },
|
|
954
|
+
}, 400);
|
|
955
|
+
}
|
|
956
|
+
await secretBroker.saveGoogleTokenJson(raw);
|
|
957
|
+
await notifySecretChange("google");
|
|
958
|
+
deps.onGoogleServicesReady?.();
|
|
959
|
+
const summary = await getSecretConfigSummary();
|
|
960
|
+
return c.json({
|
|
961
|
+
status: "updated",
|
|
962
|
+
configured: summary.googleCalendarTokenConfigured,
|
|
963
|
+
requiresRestart: false,
|
|
964
|
+
validationErrors: {},
|
|
965
|
+
});
|
|
966
|
+
});
|
|
967
|
+
app.delete("/secrets/:name", async (c) => {
|
|
968
|
+
const name = c.req.param("name");
|
|
969
|
+
if (name === "apiToken") {
|
|
970
|
+
return c.json({
|
|
971
|
+
error: "api_token_not_deletable",
|
|
972
|
+
message: "The daemon API token cannot be deleted from the API. Rotate it explicitly instead.",
|
|
973
|
+
}, 400);
|
|
974
|
+
}
|
|
975
|
+
const secretNameByParam = {
|
|
976
|
+
slackBotToken: "slackBotToken",
|
|
977
|
+
slackAppToken: "slackAppToken",
|
|
978
|
+
telegramBotToken: "telegramBotToken",
|
|
979
|
+
discordBotToken: "discordBotToken",
|
|
980
|
+
notionApiKey: "notionApiKey",
|
|
981
|
+
githubToken: "githubToken",
|
|
982
|
+
githubWebhookSecret: "githubWebhookSecret",
|
|
983
|
+
googleCredentialsJson: "googleCredentialsJson",
|
|
984
|
+
googleTokenJson: "googleTokenJson",
|
|
985
|
+
};
|
|
986
|
+
const secretName = secretNameByParam[name];
|
|
987
|
+
if (!secretName) {
|
|
988
|
+
return c.json({ error: "unknown_secret" }, 404);
|
|
989
|
+
}
|
|
990
|
+
await secretBroker.delete(secretName);
|
|
991
|
+
const scopeBySecret = {
|
|
992
|
+
slackBotToken: "slack",
|
|
993
|
+
slackAppToken: "slack",
|
|
994
|
+
telegramBotToken: "telegram",
|
|
995
|
+
discordBotToken: "discord",
|
|
996
|
+
notionApiKey: "notion",
|
|
997
|
+
githubToken: "github",
|
|
998
|
+
githubWebhookSecret: "github",
|
|
999
|
+
googleCredentialsJson: "google",
|
|
1000
|
+
googleTokenJson: "google",
|
|
1001
|
+
};
|
|
1002
|
+
await notifySecretChange(scopeBySecret[secretName]);
|
|
1003
|
+
return c.json({
|
|
1004
|
+
status: "deleted",
|
|
1005
|
+
configured: false,
|
|
1006
|
+
requiresRestart: false,
|
|
1007
|
+
validationErrors: {},
|
|
1008
|
+
});
|
|
1009
|
+
});
|
|
1010
|
+
app.get("/dashboard/next-check", (c) => {
|
|
1011
|
+
return c.json(getNextHourlyCheck(config));
|
|
1012
|
+
});
|
|
1013
|
+
// STAGE-C-DM-FRESHNESS-PLAN §Task 4 — DM freshness aggregate. Powered
|
|
1014
|
+
// by `agent_actions.detail.dm_freshness.*` rows the DM dispatch path
|
|
1015
|
+
// writes via AuditLogger.logAction. Window defaults to 7 days; query
|
|
1016
|
+
// param `days` overrides for ad-hoc inspection (clamped to 1..90).
|
|
1017
|
+
app.get("/dashboard/dm-freshness", (c) => {
|
|
1018
|
+
const daysParam = c.req.query("days");
|
|
1019
|
+
let windowDays = 7;
|
|
1020
|
+
if (daysParam !== undefined) {
|
|
1021
|
+
const parsed = Number(daysParam);
|
|
1022
|
+
if (!Number.isFinite(parsed) || parsed < 1 || parsed > 90) {
|
|
1023
|
+
return c.json({
|
|
1024
|
+
error: "invalid_window",
|
|
1025
|
+
message: "days must be a number between 1 and 90",
|
|
1026
|
+
}, 400);
|
|
1027
|
+
}
|
|
1028
|
+
windowDays = Math.round(parsed);
|
|
1029
|
+
}
|
|
1030
|
+
const aggregate = computeDmFreshnessAggregate(deps.db, windowDays);
|
|
1031
|
+
return c.json(aggregate);
|
|
1032
|
+
});
|
|
1033
|
+
/**
|
|
1034
|
+
* POST /messaging/whatsapp/pair
|
|
1035
|
+
*
|
|
1036
|
+
* Triggers Baileys pairing and waits up to ~10s for the first scannable QR.
|
|
1037
|
+
* If WhatsApp isn't enabled yet, returns 409 with a clear hint instead of
|
|
1038
|
+
* silently 404'ing — this surfaces the original setup-flow bug where users
|
|
1039
|
+
* clicked Pair without first enabling.
|
|
1040
|
+
*/
|
|
1041
|
+
app.post("/messaging/whatsapp/pair", async (c) => {
|
|
1042
|
+
if (!deps.whatsappControls) {
|
|
1043
|
+
return c.json({ error: "whatsapp_not_available" }, 404);
|
|
1044
|
+
}
|
|
1045
|
+
if (!config.whatsappEnabled) {
|
|
1046
|
+
return c.json({
|
|
1047
|
+
error: "whatsapp_not_enabled",
|
|
1048
|
+
message: "Enable WhatsApp first (toggle the Enable button), then click Pair.",
|
|
1049
|
+
}, 409);
|
|
1050
|
+
}
|
|
1051
|
+
if (!config.whatsappOwnerPhone) {
|
|
1052
|
+
return c.json({
|
|
1053
|
+
error: "whatsapp_phone_missing",
|
|
1054
|
+
message: "Set the owner phone (E.164, e.g. +818012345678) and save before pairing.",
|
|
1055
|
+
}, 409);
|
|
1056
|
+
}
|
|
1057
|
+
try {
|
|
1058
|
+
const response = await deps.whatsappControls.waitForQr(10_000);
|
|
1059
|
+
return c.json(response);
|
|
1060
|
+
}
|
|
1061
|
+
catch (err) {
|
|
1062
|
+
const message = toSafeErrorMessage(err, "Unknown WhatsApp error");
|
|
1063
|
+
return c.json({
|
|
1064
|
+
error: "whatsapp_pair_failed",
|
|
1065
|
+
message,
|
|
1066
|
+
state: deps.whatsappControls.getQrResponse().state,
|
|
1067
|
+
}, 500);
|
|
1068
|
+
}
|
|
1069
|
+
});
|
|
1070
|
+
/**
|
|
1071
|
+
* GET /messaging/whatsapp/qr
|
|
1072
|
+
*
|
|
1073
|
+
* Returns the current QR snapshot WITHOUT triggering a fresh pair flow.
|
|
1074
|
+
* Dashboard polls this every ~3s while pairing is in progress so the user
|
|
1075
|
+
* always sees the latest QR (Baileys rotates them every ~20s).
|
|
1076
|
+
*/
|
|
1077
|
+
app.get("/messaging/whatsapp/qr", (c) => {
|
|
1078
|
+
if (!deps.whatsappControls) {
|
|
1079
|
+
return c.json({ error: "whatsapp_not_available" }, 404);
|
|
1080
|
+
}
|
|
1081
|
+
const response = deps.whatsappControls.getQrResponse();
|
|
1082
|
+
return c.json({
|
|
1083
|
+
...response,
|
|
1084
|
+
error: response.error ? toSafeErrorMessage(response.error) : null,
|
|
1085
|
+
});
|
|
1086
|
+
});
|
|
1087
|
+
/**
|
|
1088
|
+
* GET /messaging/whatsapp/status
|
|
1089
|
+
*
|
|
1090
|
+
* Lightweight health probe — connection state + last error, no QR fetch.
|
|
1091
|
+
*/
|
|
1092
|
+
app.get("/messaging/whatsapp/status", (c) => {
|
|
1093
|
+
if (!deps.whatsappControls) {
|
|
1094
|
+
return c.json({ error: "whatsapp_not_available" }, 404);
|
|
1095
|
+
}
|
|
1096
|
+
const response = deps.whatsappControls.getQrResponse();
|
|
1097
|
+
return c.json({
|
|
1098
|
+
enabled: config.whatsappEnabled,
|
|
1099
|
+
initialized: deps.whatsappControls.isInitialized(),
|
|
1100
|
+
state: response.state,
|
|
1101
|
+
error: response.error ? toSafeErrorMessage(response.error) : null,
|
|
1102
|
+
});
|
|
1103
|
+
});
|
|
1104
|
+
// ── Telegram pairing ──────────────────────────────────────────────────
|
|
1105
|
+
//
|
|
1106
|
+
// Three endpoints support the dashboard's QR-deep-link pairing flow:
|
|
1107
|
+
// POST /messaging/telegram/test-token — getMe (validate token)
|
|
1108
|
+
// POST /messaging/telegram/start-pairing — generate token + QR + deep link
|
|
1109
|
+
// GET /messaging/telegram/pairing-status — poll until paired
|
|
1110
|
+
//
|
|
1111
|
+
// The QR encodes `https://t.me/<bot>?start=<token>`. When the user scans
|
|
1112
|
+
// it, Telegram opens the bot and sends `/start <token>`; the adapter
|
|
1113
|
+
// matches the token, captures the chat ID via discovery mode, and the
|
|
1114
|
+
// daemon writes the ID into .env via the onOwnerDetected callback.
|
|
1115
|
+
app.post("/messaging/telegram/test-token", async (c) => {
|
|
1116
|
+
if (!deps.messagingControls?.telegram) {
|
|
1117
|
+
return c.json({ error: "telegram_not_configured" }, 404);
|
|
1118
|
+
}
|
|
1119
|
+
// Accept an optional candidate token in the request body so the
|
|
1120
|
+
// dashboard can validate an UNSAVED draft before persisting it.
|
|
1121
|
+
const body = await c.req.json().catch(() => ({}));
|
|
1122
|
+
const candidate = typeof body?.token === "string" && body.token.length > 0
|
|
1123
|
+
? body.token
|
|
1124
|
+
: undefined;
|
|
1125
|
+
try {
|
|
1126
|
+
const info = await deps.messagingControls.telegram.testToken(candidate);
|
|
1127
|
+
return c.json(info);
|
|
1128
|
+
}
|
|
1129
|
+
catch (err) {
|
|
1130
|
+
return c.json({
|
|
1131
|
+
error: "telegram_test_failed",
|
|
1132
|
+
message: toSafeErrorMessage(err, "Telegram token validation failed"),
|
|
1133
|
+
}, 400);
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
app.post("/messaging/telegram/start-pairing", async (c) => {
|
|
1137
|
+
if (!deps.messagingControls?.telegram) {
|
|
1138
|
+
return c.json({ error: "telegram_not_configured" }, 404);
|
|
1139
|
+
}
|
|
1140
|
+
try {
|
|
1141
|
+
const result = await deps.messagingControls.telegram.startPairing();
|
|
1142
|
+
return c.json(result);
|
|
1143
|
+
}
|
|
1144
|
+
catch (err) {
|
|
1145
|
+
return c.json({
|
|
1146
|
+
error: "telegram_pair_start_failed",
|
|
1147
|
+
message: toSafeErrorMessage(err, "Telegram pairing could not start"),
|
|
1148
|
+
}, 500);
|
|
1149
|
+
}
|
|
1150
|
+
});
|
|
1151
|
+
app.get("/messaging/telegram/pairing-status", (c) => {
|
|
1152
|
+
if (!deps.messagingControls?.telegram) {
|
|
1153
|
+
return c.json({ error: "telegram_not_configured" }, 404);
|
|
1154
|
+
}
|
|
1155
|
+
return c.json(deps.messagingControls.telegram.getPairingStatus());
|
|
1156
|
+
});
|
|
1157
|
+
app.post("/messaging/telegram/cancel-pairing", (c) => {
|
|
1158
|
+
if (!deps.messagingControls?.telegram) {
|
|
1159
|
+
return c.json({ error: "telegram_not_configured" }, 404);
|
|
1160
|
+
}
|
|
1161
|
+
deps.messagingControls.telegram.cancelPairing();
|
|
1162
|
+
return c.json({ status: "cancelled" });
|
|
1163
|
+
});
|
|
1164
|
+
// ── Slack pairing ─────────────────────────────────────────────────────
|
|
1165
|
+
//
|
|
1166
|
+
// Slack has no QR/deep-link mechanism, so we offer two helpers:
|
|
1167
|
+
// 1. Token validation via auth.test
|
|
1168
|
+
// 2. A pre-built app manifest (one-click app creation at api.slack.com)
|
|
1169
|
+
// 3. Discovery mode for owner user ID — user DMs the bot, daemon captures
|
|
1170
|
+
//
|
|
1171
|
+
// The manifest uses Aitne's required scopes (im:history,
|
|
1172
|
+
// chat:write, app_mentions:read) + Socket Mode + bot scopes. We do NOT
|
|
1173
|
+
// include any oauth_redirect_url since Socket Mode bots don't need one.
|
|
1174
|
+
app.post("/messaging/slack/test-token", async (c) => {
|
|
1175
|
+
if (!deps.messagingControls?.slack) {
|
|
1176
|
+
return c.json({ error: "slack_not_configured" }, 404);
|
|
1177
|
+
}
|
|
1178
|
+
const body = await c.req.json().catch(() => ({}));
|
|
1179
|
+
const candidate = typeof body?.token === "string" && body.token.length > 0
|
|
1180
|
+
? body.token
|
|
1181
|
+
: undefined;
|
|
1182
|
+
try {
|
|
1183
|
+
const info = await deps.messagingControls.slack.testToken(candidate);
|
|
1184
|
+
return c.json(info);
|
|
1185
|
+
}
|
|
1186
|
+
catch (err) {
|
|
1187
|
+
return c.json({
|
|
1188
|
+
error: "slack_test_failed",
|
|
1189
|
+
message: toSafeErrorMessage(err, "Slack token validation failed"),
|
|
1190
|
+
}, 400);
|
|
1191
|
+
}
|
|
1192
|
+
});
|
|
1193
|
+
app.get("/messaging/slack/manifest", (c) => {
|
|
1194
|
+
// App manifest in JSON form. Slack supports both YAML and JSON in the
|
|
1195
|
+
// `?manifest_json=` and `?manifest_yaml=` query params on the new-app
|
|
1196
|
+
// create page (https://docs.slack.dev/app-manifests/...).
|
|
1197
|
+
//
|
|
1198
|
+
// Scope minimization (intentional, do not re-broaden):
|
|
1199
|
+
// - app_mentions:read — for @mentions in channels the user invited the bot to
|
|
1200
|
+
// - chat:write — required to send messages
|
|
1201
|
+
// - files:read — required to download user-uploaded files
|
|
1202
|
+
// - im:history — required to receive `message.im` events
|
|
1203
|
+
// - im:read — list/inspect direct-message channels
|
|
1204
|
+
// - im:write — open a DM channel with the owner
|
|
1205
|
+
//
|
|
1206
|
+
// We DELIBERATELY OMIT:
|
|
1207
|
+
// - channels:history — would let the bot read every message in every
|
|
1208
|
+
// channel it's added to. Aitne only DMs,
|
|
1209
|
+
// so this scope is pure attack surface.
|
|
1210
|
+
// - users:read — not needed; resolveUserChannel() uses
|
|
1211
|
+
// conversations.open with the configured user ID.
|
|
1212
|
+
const manifest = {
|
|
1213
|
+
display_information: {
|
|
1214
|
+
name: APP_NAME,
|
|
1215
|
+
description: "Local-first proactive assistant",
|
|
1216
|
+
background_color: "#1a1a2e",
|
|
1217
|
+
},
|
|
1218
|
+
features: {
|
|
1219
|
+
bot_user: {
|
|
1220
|
+
display_name: APP_NAME,
|
|
1221
|
+
always_online: true,
|
|
1222
|
+
},
|
|
1223
|
+
},
|
|
1224
|
+
oauth_config: {
|
|
1225
|
+
scopes: {
|
|
1226
|
+
bot: [
|
|
1227
|
+
"app_mentions:read",
|
|
1228
|
+
"chat:write",
|
|
1229
|
+
"files:read",
|
|
1230
|
+
"im:history",
|
|
1231
|
+
"im:read",
|
|
1232
|
+
"im:write",
|
|
1233
|
+
],
|
|
1234
|
+
},
|
|
1235
|
+
},
|
|
1236
|
+
settings: {
|
|
1237
|
+
event_subscriptions: {
|
|
1238
|
+
bot_events: ["app_mention", "message.im"],
|
|
1239
|
+
},
|
|
1240
|
+
interactivity: { is_enabled: false },
|
|
1241
|
+
org_deploy_enabled: false,
|
|
1242
|
+
socket_mode_enabled: true,
|
|
1243
|
+
token_rotation_enabled: false,
|
|
1244
|
+
},
|
|
1245
|
+
};
|
|
1246
|
+
const manifestJson = JSON.stringify(manifest);
|
|
1247
|
+
// Slack's "create app from manifest" deep link.
|
|
1248
|
+
const createAppUrl = `https://api.slack.com/apps?new_app=1&manifest_json=${encodeURIComponent(manifestJson)}`;
|
|
1249
|
+
return c.json({
|
|
1250
|
+
manifest,
|
|
1251
|
+
manifestJson,
|
|
1252
|
+
createAppUrl,
|
|
1253
|
+
instructions: [
|
|
1254
|
+
"1. Click 'Open Slack app builder' below — Slack will pre-fill the manifest.",
|
|
1255
|
+
"2. On the app page, scroll to 'Install App' and click Install to your workspace.",
|
|
1256
|
+
"3. Copy the Bot User OAuth Token (xoxb-…) from 'OAuth & Permissions' into the field below.",
|
|
1257
|
+
"4. Generate an App-Level Token (xapp-…) under 'Basic Information' → 'App-Level Tokens' with `connections:write` scope, paste it below.",
|
|
1258
|
+
"5. Click Save Slack Config, then 'Generate pairing phrase' and DM the bot with the phrase.",
|
|
1259
|
+
],
|
|
1260
|
+
});
|
|
1261
|
+
});
|
|
1262
|
+
/**
|
|
1263
|
+
* POST /messaging/slack/start-pairing
|
|
1264
|
+
*
|
|
1265
|
+
* Generates a fresh magic phrase, registers it as the Slack adapter's
|
|
1266
|
+
* pairing challenge, and returns it to the dashboard. The user must
|
|
1267
|
+
* include this phrase in the next DM they send to the bot — only that
|
|
1268
|
+
* matching DM captures the owner role. The previous "enable-discovery"
|
|
1269
|
+
* endpoint was vulnerable to a 5-minute race where any DM could
|
|
1270
|
+
* hijack ownership; the magic phrase closes that.
|
|
1271
|
+
*/
|
|
1272
|
+
app.post("/messaging/slack/start-pairing", async (c) => {
|
|
1273
|
+
if (!deps.messagingControls?.slack) {
|
|
1274
|
+
return c.json({ error: "slack_not_configured" }, 404);
|
|
1275
|
+
}
|
|
1276
|
+
try {
|
|
1277
|
+
const result = await deps.messagingControls.slack.startPairing();
|
|
1278
|
+
return c.json(result);
|
|
1279
|
+
}
|
|
1280
|
+
catch (err) {
|
|
1281
|
+
return c.json({
|
|
1282
|
+
error: "slack_pair_start_failed",
|
|
1283
|
+
message: toSafeErrorMessage(err, "Slack pairing could not start"),
|
|
1284
|
+
}, 400);
|
|
1285
|
+
}
|
|
1286
|
+
});
|
|
1287
|
+
app.post("/messaging/slack/cancel-pairing", (c) => {
|
|
1288
|
+
if (!deps.messagingControls?.slack) {
|
|
1289
|
+
return c.json({ error: "slack_not_configured" }, 404);
|
|
1290
|
+
}
|
|
1291
|
+
deps.messagingControls.slack.cancelPairing();
|
|
1292
|
+
return c.json({ status: "cancelled" });
|
|
1293
|
+
});
|
|
1294
|
+
app.get("/messaging/slack/pairing-status", (c) => {
|
|
1295
|
+
if (!deps.messagingControls?.slack) {
|
|
1296
|
+
return c.json({ error: "slack_not_configured" }, 404);
|
|
1297
|
+
}
|
|
1298
|
+
return c.json(deps.messagingControls.slack.getPairingStatus());
|
|
1299
|
+
});
|
|
1300
|
+
// ── Discord pairing ───────────────────────────────────────────────────
|
|
1301
|
+
//
|
|
1302
|
+
// Discord parity: token validation + magic-phrase pairing for owner user ID.
|
|
1303
|
+
app.post("/messaging/discord/test-token", async (c) => {
|
|
1304
|
+
if (!deps.messagingControls?.discord) {
|
|
1305
|
+
return c.json({ error: "discord_not_configured" }, 404);
|
|
1306
|
+
}
|
|
1307
|
+
const body = await c.req.json().catch(() => ({}));
|
|
1308
|
+
const candidate = typeof body?.token === "string" && body.token.length > 0
|
|
1309
|
+
? body.token
|
|
1310
|
+
: undefined;
|
|
1311
|
+
try {
|
|
1312
|
+
const info = await deps.messagingControls.discord.testToken(candidate);
|
|
1313
|
+
return c.json(info);
|
|
1314
|
+
}
|
|
1315
|
+
catch (err) {
|
|
1316
|
+
return c.json({
|
|
1317
|
+
error: "discord_test_failed",
|
|
1318
|
+
message: toSafeErrorMessage(err, "Discord token validation failed"),
|
|
1319
|
+
}, 400);
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
app.post("/messaging/discord/start-pairing", async (c) => {
|
|
1323
|
+
if (!deps.messagingControls?.discord) {
|
|
1324
|
+
return c.json({ error: "discord_not_configured" }, 404);
|
|
1325
|
+
}
|
|
1326
|
+
try {
|
|
1327
|
+
const result = await deps.messagingControls.discord.startPairing();
|
|
1328
|
+
return c.json(result);
|
|
1329
|
+
}
|
|
1330
|
+
catch (err) {
|
|
1331
|
+
return c.json({
|
|
1332
|
+
error: "discord_pair_start_failed",
|
|
1333
|
+
message: toSafeErrorMessage(err, "Discord pairing could not start"),
|
|
1334
|
+
}, 400);
|
|
1335
|
+
}
|
|
1336
|
+
});
|
|
1337
|
+
app.post("/messaging/discord/cancel-pairing", (c) => {
|
|
1338
|
+
if (!deps.messagingControls?.discord) {
|
|
1339
|
+
return c.json({ error: "discord_not_configured" }, 404);
|
|
1340
|
+
}
|
|
1341
|
+
deps.messagingControls.discord.cancelPairing();
|
|
1342
|
+
return c.json({ status: "cancelled" });
|
|
1343
|
+
});
|
|
1344
|
+
app.get("/messaging/discord/pairing-status", (c) => {
|
|
1345
|
+
if (!deps.messagingControls?.discord) {
|
|
1346
|
+
return c.json({ error: "discord_not_configured" }, 404);
|
|
1347
|
+
}
|
|
1348
|
+
return c.json(deps.messagingControls.discord.getPairingStatus());
|
|
1349
|
+
});
|
|
1350
|
+
/** POST /config/upload/google-credentials — upload Google Calendar credentials JSON */
|
|
1351
|
+
app.post("/config/upload/google-credentials", async (c) => {
|
|
1352
|
+
const body = await c.req.parseBody();
|
|
1353
|
+
const file = body["file"];
|
|
1354
|
+
if (!file || !(file instanceof File)) {
|
|
1355
|
+
return c.json({ error: "No file uploaded. Send as multipart with field name 'file'" }, 400);
|
|
1356
|
+
}
|
|
1357
|
+
if (file.size > MAX_UPLOAD_SIZE) {
|
|
1358
|
+
return c.json({ error: `File too large (max ${MAX_UPLOAD_SIZE / 1024} KB)` }, 400);
|
|
1359
|
+
}
|
|
1360
|
+
const content = await file.text();
|
|
1361
|
+
let parsed;
|
|
1362
|
+
try {
|
|
1363
|
+
parsed = JSON.parse(content);
|
|
1364
|
+
}
|
|
1365
|
+
catch {
|
|
1366
|
+
return c.json({ error: "Invalid JSON file" }, 400);
|
|
1367
|
+
}
|
|
1368
|
+
// Basic validation: must be OAuth2 (installed/web) or service account
|
|
1369
|
+
const obj = parsed;
|
|
1370
|
+
if (!obj.installed && !obj.web && obj.type !== "service_account") {
|
|
1371
|
+
return c.json({ error: "Invalid credentials format. Expected OAuth2 credentials JSON (with 'installed' or 'web' key) or a service account JSON." }, 400);
|
|
1372
|
+
}
|
|
1373
|
+
await secretBroker.set("googleCredentialsJson", content);
|
|
1374
|
+
if (parsed.type === "service_account") {
|
|
1375
|
+
await secretBroker.delete("googleTokenJson");
|
|
1376
|
+
}
|
|
1377
|
+
await notifySecretChange("google");
|
|
1378
|
+
deps.onGoogleServicesReady?.();
|
|
1379
|
+
return c.json({
|
|
1380
|
+
status: "uploaded",
|
|
1381
|
+
path: "keychain://google-credentials",
|
|
1382
|
+
requiresRestart: false,
|
|
1383
|
+
message: "Credentials saved.",
|
|
1384
|
+
});
|
|
1385
|
+
});
|
|
1386
|
+
/** POST /config/upload/google-token — upload Google Calendar OAuth token JSON */
|
|
1387
|
+
app.post("/config/upload/google-token", async (c) => {
|
|
1388
|
+
const body = await c.req.parseBody();
|
|
1389
|
+
const file = body["file"];
|
|
1390
|
+
if (!file || !(file instanceof File)) {
|
|
1391
|
+
return c.json({ error: "No file uploaded. Send as multipart with field name 'file'" }, 400);
|
|
1392
|
+
}
|
|
1393
|
+
if (file.size > MAX_UPLOAD_SIZE) {
|
|
1394
|
+
return c.json({ error: `File too large (max ${MAX_UPLOAD_SIZE / 1024} KB)` }, 400);
|
|
1395
|
+
}
|
|
1396
|
+
const content = await file.text();
|
|
1397
|
+
// Validate JSON
|
|
1398
|
+
try {
|
|
1399
|
+
JSON.parse(content);
|
|
1400
|
+
}
|
|
1401
|
+
catch {
|
|
1402
|
+
return c.json({ error: "Invalid JSON file" }, 400);
|
|
1403
|
+
}
|
|
1404
|
+
await secretBroker.saveGoogleTokenJson(content);
|
|
1405
|
+
await notifySecretChange("google");
|
|
1406
|
+
deps.onGoogleServicesReady?.();
|
|
1407
|
+
return c.json({
|
|
1408
|
+
status: "uploaded",
|
|
1409
|
+
path: "keychain://google-token",
|
|
1410
|
+
requiresRestart: false,
|
|
1411
|
+
message: "Token saved.",
|
|
1412
|
+
});
|
|
1413
|
+
});
|
|
1414
|
+
// ── Google OAuth2 Authorization Flow ──
|
|
1415
|
+
// Allows users to authenticate with just credentials.json — the daemon
|
|
1416
|
+
// handles the full OAuth2 flow and saves the token automatically.
|
|
1417
|
+
/** POST /config/google-auth/start — begin OAuth2 authorization */
|
|
1418
|
+
app.post("/config/google-auth/start", async (c) => {
|
|
1419
|
+
const credRaw = await secretBroker.getGoogleCredentialsJson();
|
|
1420
|
+
if (!credRaw) {
|
|
1421
|
+
return c.json({ error: "Upload credentials.json first" }, 400);
|
|
1422
|
+
}
|
|
1423
|
+
let cred;
|
|
1424
|
+
try {
|
|
1425
|
+
cred = parseGoogleCredentialsJson(credRaw);
|
|
1426
|
+
}
|
|
1427
|
+
catch {
|
|
1428
|
+
return c.json({ error: "Credentials JSON is invalid. Upload it again." }, 400);
|
|
1429
|
+
}
|
|
1430
|
+
// Service accounts don't need OAuth2 authorization
|
|
1431
|
+
if (cred.type === "service_account") {
|
|
1432
|
+
return c.json({ error: "Service account credentials don't require OAuth authorization. Restart the daemon to activate." }, 400);
|
|
1433
|
+
}
|
|
1434
|
+
const clientConfig = getGoogleOAuthClientConfig(cred);
|
|
1435
|
+
if (!clientConfig) {
|
|
1436
|
+
return c.json({ error: "Invalid credentials format" }, 400);
|
|
1437
|
+
}
|
|
1438
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1439
|
+
let google;
|
|
1440
|
+
try {
|
|
1441
|
+
const mod = await import("googleapis");
|
|
1442
|
+
google = mod.google;
|
|
1443
|
+
}
|
|
1444
|
+
catch {
|
|
1445
|
+
return c.json({ error: "googleapis package not installed" }, 500);
|
|
1446
|
+
}
|
|
1447
|
+
// Use daemon's own port for the OAuth callback
|
|
1448
|
+
const redirectUri = `http://localhost:${config.apiPort}/api/config/google-auth/callback`;
|
|
1449
|
+
const oauth2Client = new google.auth.OAuth2(clientConfig.client_id, clientConfig.client_secret, redirectUri);
|
|
1450
|
+
// Request scopes for Calendar + Gmail
|
|
1451
|
+
const scopes = [
|
|
1452
|
+
"https://www.googleapis.com/auth/calendar",
|
|
1453
|
+
"https://www.googleapis.com/auth/gmail.modify",
|
|
1454
|
+
"https://www.googleapis.com/auth/gmail.send",
|
|
1455
|
+
];
|
|
1456
|
+
pruneOauthStates();
|
|
1457
|
+
const state = randomUUID();
|
|
1458
|
+
// Capture the dashboard origin so the callback can postMessage to the correct window
|
|
1459
|
+
const origin = c.req.header("origin");
|
|
1460
|
+
const referer = c.req.header("referer");
|
|
1461
|
+
const dashboardOrigin = origin
|
|
1462
|
+
|| (referer ? new URL(referer).origin : `http://localhost:3000`);
|
|
1463
|
+
oauthStates.set(state, { createdAt: Date.now(), dashboardOrigin });
|
|
1464
|
+
const authUrl = oauth2Client.generateAuthUrl({
|
|
1465
|
+
access_type: "offline",
|
|
1466
|
+
scope: scopes,
|
|
1467
|
+
prompt: "consent", // Force consent to always get a refresh_token
|
|
1468
|
+
state,
|
|
1469
|
+
});
|
|
1470
|
+
return c.json({ authUrl, redirectUri, scopes });
|
|
1471
|
+
});
|
|
1472
|
+
/** GET /config/google-auth/callback — OAuth2 redirect handler */
|
|
1473
|
+
app.get("/config/google-auth/callback", async (c) => {
|
|
1474
|
+
const code = c.req.query("code");
|
|
1475
|
+
const error = c.req.query("error");
|
|
1476
|
+
const state = c.req.query("state");
|
|
1477
|
+
if (error) {
|
|
1478
|
+
return c.html(`<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
1479
|
+
<h2 style="color:#dc2626">Authorization Failed</h2>
|
|
1480
|
+
<p>${escapeHtml(error)}</p>
|
|
1481
|
+
<p style="color:#666;font-size:14px">You can close this window.</p>
|
|
1482
|
+
</body></html>`);
|
|
1483
|
+
}
|
|
1484
|
+
pruneOauthStates();
|
|
1485
|
+
const stateData = state ? oauthStates.get(state) : undefined;
|
|
1486
|
+
if (!state || !stateData) {
|
|
1487
|
+
return c.html(`<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
1488
|
+
<h2 style="color:#dc2626">Authorization Failed</h2>
|
|
1489
|
+
<p>Invalid or expired OAuth state.</p>
|
|
1490
|
+
<p style="color:#666;font-size:14px">Start the authorization flow again from the dashboard.</p>
|
|
1491
|
+
</body></html>`);
|
|
1492
|
+
}
|
|
1493
|
+
const { dashboardOrigin } = stateData;
|
|
1494
|
+
oauthStates.delete(state);
|
|
1495
|
+
if (!code) {
|
|
1496
|
+
return c.html(`<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
1497
|
+
<h2 style="color:#dc2626">Error</h2>
|
|
1498
|
+
<p>No authorization code received.</p>
|
|
1499
|
+
</body></html>`);
|
|
1500
|
+
}
|
|
1501
|
+
// Re-create OAuth2 client from stored credentials
|
|
1502
|
+
const credRaw = await secretBroker.getGoogleCredentialsJson();
|
|
1503
|
+
if (!credRaw) {
|
|
1504
|
+
return c.html(`<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
1505
|
+
<h2 style="color:#dc2626">Error</h2>
|
|
1506
|
+
<p>Credentials not configured.</p>
|
|
1507
|
+
</body></html>`);
|
|
1508
|
+
}
|
|
1509
|
+
try {
|
|
1510
|
+
const cred = parseGoogleCredentialsJson(credRaw);
|
|
1511
|
+
const clientConfig = getGoogleOAuthClientConfig(cred);
|
|
1512
|
+
if (!clientConfig)
|
|
1513
|
+
throw new Error("Invalid credentials");
|
|
1514
|
+
const mod = await import("googleapis");
|
|
1515
|
+
const google = mod.google;
|
|
1516
|
+
const redirectUri = `http://localhost:${config.apiPort}/api/config/google-auth/callback`;
|
|
1517
|
+
const oauth2Client = new google.auth.OAuth2(clientConfig.client_id, clientConfig.client_secret, redirectUri);
|
|
1518
|
+
// Exchange authorization code for tokens
|
|
1519
|
+
const { tokens } = await oauth2Client.getToken(code);
|
|
1520
|
+
await secretBroker.saveGoogleTokenJson(JSON.stringify(tokens));
|
|
1521
|
+
await notifySecretChange("google");
|
|
1522
|
+
deps.onGoogleServicesReady?.();
|
|
1523
|
+
const statusMsg = services.calendar || services.gmail
|
|
1524
|
+
? "Services activated."
|
|
1525
|
+
: "Token saved.";
|
|
1526
|
+
return c.html(`<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
1527
|
+
<h2 style="color:#059669">Authorization Successful</h2>
|
|
1528
|
+
<p>${escapeHtml(statusMsg)}</p>
|
|
1529
|
+
<p style="color:#666;font-size:14px">You can close this window.</p>
|
|
1530
|
+
<script>
|
|
1531
|
+
if (window.opener) {
|
|
1532
|
+
window.opener.postMessage({ type: "google-auth-success" }, ${JSON.stringify(dashboardOrigin)});
|
|
1533
|
+
}
|
|
1534
|
+
</script>
|
|
1535
|
+
</body></html>`);
|
|
1536
|
+
}
|
|
1537
|
+
catch (err) {
|
|
1538
|
+
const msg = toSafeErrorMessage(err, "Unknown error");
|
|
1539
|
+
return c.html(`<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
1540
|
+
<h2 style="color:#dc2626">Token Exchange Failed</h2>
|
|
1541
|
+
<p>${escapeHtml(msg)}</p>
|
|
1542
|
+
<p style="color:#666;font-size:14px">You can close this window and try again.</p>
|
|
1543
|
+
</body></html>`);
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1546
|
+
/** POST /config/reset-safety — reset disallowedTools to defaults */
|
|
1547
|
+
app.post("/config/reset-safety", async (c) => {
|
|
1548
|
+
const defaults = [...DEFAULT_DISALLOWED_TOOLS];
|
|
1549
|
+
// Actually persist the reset — update in-memory config and .env
|
|
1550
|
+
// Use null for allowedToolsOverride to match the Zod default (null = "no override")
|
|
1551
|
+
const result = await applyConfigUpdates(config, settingsStore, {
|
|
1552
|
+
disallowedTools: defaults,
|
|
1553
|
+
allowedToolsOverride: null,
|
|
1554
|
+
});
|
|
1555
|
+
return c.json({ status: "reset", disallowedTools: defaults, ...result });
|
|
1556
|
+
});
|
|
1557
|
+
// ── Events/Logs API ──
|
|
1558
|
+
/** GET /events — paginated event/action log */
|
|
1559
|
+
app.get("/events", (c) => {
|
|
1560
|
+
const page = Math.max(1, Number(c.req.query("page") ?? "1"));
|
|
1561
|
+
const limit = Math.min(Number(c.req.query("limit") ?? "50"), 100);
|
|
1562
|
+
const offset = (page - 1) * limit;
|
|
1563
|
+
const type = c.req.query("type");
|
|
1564
|
+
const result = c.req.query("result");
|
|
1565
|
+
const days = c.req.query("days"); // "1" (today), "7", "30"
|
|
1566
|
+
let whereClause = "WHERE 1=1";
|
|
1567
|
+
const params = [];
|
|
1568
|
+
if (type) {
|
|
1569
|
+
whereClause += " AND action_type = ?";
|
|
1570
|
+
params.push(type);
|
|
1571
|
+
}
|
|
1572
|
+
if (result) {
|
|
1573
|
+
whereClause += " AND result = ?";
|
|
1574
|
+
params.push(result);
|
|
1575
|
+
}
|
|
1576
|
+
if (days) {
|
|
1577
|
+
const d = Number(days);
|
|
1578
|
+
if (d > 0 && d <= 365) {
|
|
1579
|
+
// datetime(started_at) normalizes mixed ISO-8601 / SQL formats — the
|
|
1580
|
+
// delegated_proxy.invoke writer historically inserted ISO-with-T-and-Z
|
|
1581
|
+
// strings, which sort lexicographically above same-day SQL strings.
|
|
1582
|
+
whereClause += " AND datetime(started_at) > datetime('now', '-' || ? || ' days')";
|
|
1583
|
+
params.push(d);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
const total = db
|
|
1587
|
+
.prepare(`SELECT COUNT(*) as cnt FROM agent_actions ${whereClause}`)
|
|
1588
|
+
.get(...params);
|
|
1589
|
+
params.push(limit, offset);
|
|
1590
|
+
const rows = db
|
|
1591
|
+
.prepare(`SELECT id, event_id, action_type, trigger, model_used, model_usage_json, cost_usd,
|
|
1592
|
+
tokens_input, tokens_output,
|
|
1593
|
+
cache_creation_tokens, cache_read_tokens,
|
|
1594
|
+
duration_ms, num_turns,
|
|
1595
|
+
result, detail, started_at, completed_at, error
|
|
1596
|
+
FROM agent_actions ${whereClause}
|
|
1597
|
+
ORDER BY datetime(started_at) DESC, id DESC
|
|
1598
|
+
LIMIT ? OFFSET ?`)
|
|
1599
|
+
.all(...params);
|
|
1600
|
+
return c.json({
|
|
1601
|
+
events: rows,
|
|
1602
|
+
pagination: {
|
|
1603
|
+
page,
|
|
1604
|
+
limit,
|
|
1605
|
+
total: total.cnt,
|
|
1606
|
+
totalPages: Math.ceil(total.cnt / limit),
|
|
1607
|
+
},
|
|
1608
|
+
});
|
|
1609
|
+
});
|
|
1610
|
+
// ── Conversations API ──
|
|
1611
|
+
/** GET /conversations — paginated conversation sessions */
|
|
1612
|
+
app.get("/conversations", (c) => {
|
|
1613
|
+
const page = Number(c.req.query("page") ?? "1");
|
|
1614
|
+
const limit = Math.min(Number(c.req.query("limit") ?? "20"), 50);
|
|
1615
|
+
const offset = (page - 1) * limit;
|
|
1616
|
+
const platform = c.req.query("platform");
|
|
1617
|
+
const status = c.req.query("status");
|
|
1618
|
+
const scope = c.req.query("scope");
|
|
1619
|
+
const scopes = scope
|
|
1620
|
+
?.split(",")
|
|
1621
|
+
.map((value) => value.trim())
|
|
1622
|
+
.filter((value) => value.length > 0);
|
|
1623
|
+
let whereClause = "WHERE 1=1";
|
|
1624
|
+
const params = [];
|
|
1625
|
+
if (platform) {
|
|
1626
|
+
whereClause += " AND platform = ?";
|
|
1627
|
+
params.push(platform);
|
|
1628
|
+
}
|
|
1629
|
+
if (status) {
|
|
1630
|
+
whereClause += " AND status = ?";
|
|
1631
|
+
params.push(status);
|
|
1632
|
+
}
|
|
1633
|
+
if (scopes && scopes.length > 0) {
|
|
1634
|
+
if (scopes.length === 1) {
|
|
1635
|
+
whereClause += " AND scope = ?";
|
|
1636
|
+
params.push(scopes[0]);
|
|
1637
|
+
}
|
|
1638
|
+
else {
|
|
1639
|
+
whereClause += ` AND scope IN (${scopes.map(() => "?").join(", ")})`;
|
|
1640
|
+
params.push(...scopes);
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
else {
|
|
1644
|
+
// Default view excludes docs_qa: QA transcripts are short lookups
|
|
1645
|
+
// and would drown out chat in /activity. Operators opt in with the
|
|
1646
|
+
// explicit `?scope=docs_qa` filter chip.
|
|
1647
|
+
whereClause += " AND scope != ?";
|
|
1648
|
+
params.push(DOCS_QA_SCOPE);
|
|
1649
|
+
}
|
|
1650
|
+
const total = db
|
|
1651
|
+
.prepare(`SELECT COUNT(*) as cnt FROM conversation_sessions ${whereClause}`)
|
|
1652
|
+
.get(...params);
|
|
1653
|
+
params.push(limit, offset);
|
|
1654
|
+
const rows = db
|
|
1655
|
+
.prepare(`SELECT id, platform, channel_id, thread_id, scope, model, status,
|
|
1656
|
+
message_count, started_at, last_message_at, is_dm, backend_session_id
|
|
1657
|
+
FROM conversation_sessions ${whereClause}
|
|
1658
|
+
ORDER BY last_message_at DESC
|
|
1659
|
+
LIMIT ? OFFSET ?`)
|
|
1660
|
+
.all(...params);
|
|
1661
|
+
const sourcePlatformsStmt = db.prepare(`SELECT DISTINCT platform
|
|
1662
|
+
FROM messages
|
|
1663
|
+
WHERE session_id = ?
|
|
1664
|
+
ORDER BY CASE platform
|
|
1665
|
+
WHEN 'dashboard' THEN 0
|
|
1666
|
+
WHEN 'whatsapp' THEN 1
|
|
1667
|
+
WHEN 'telegram' THEN 2
|
|
1668
|
+
WHEN 'slack' THEN 3
|
|
1669
|
+
WHEN 'discord' THEN 4
|
|
1670
|
+
ELSE 99
|
|
1671
|
+
END, platform`);
|
|
1672
|
+
const conversations = rows.map((row) => {
|
|
1673
|
+
const sourcePlatforms = sourcePlatformsStmt.all(row.id).map((platformRow) => platformRow.platform);
|
|
1674
|
+
const normalizedSourcePlatforms = sourcePlatforms.length > 0
|
|
1675
|
+
? sourcePlatforms
|
|
1676
|
+
: row.platform !== "owner"
|
|
1677
|
+
? [row.platform]
|
|
1678
|
+
: [];
|
|
1679
|
+
const browserOnly = normalizedSourcePlatforms.length > 0
|
|
1680
|
+
&& normalizedSourcePlatforms.every((platform) => platform === "dashboard");
|
|
1681
|
+
return {
|
|
1682
|
+
id: row.id,
|
|
1683
|
+
platform: row.platform,
|
|
1684
|
+
channel_id: row.channel_id,
|
|
1685
|
+
thread_id: row.thread_id,
|
|
1686
|
+
model: row.model,
|
|
1687
|
+
status: row.status,
|
|
1688
|
+
message_count: row.message_count,
|
|
1689
|
+
started_at: row.started_at,
|
|
1690
|
+
last_message_at: row.last_message_at,
|
|
1691
|
+
summary: null,
|
|
1692
|
+
source_platforms: normalizedSourcePlatforms,
|
|
1693
|
+
read_only_from_dashboard: normalizedSourcePlatforms.length === 0 ||
|
|
1694
|
+
normalizedSourcePlatforms.some((platform) => platform !== "dashboard"),
|
|
1695
|
+
// A session is continuable when the dispatcher can actually
|
|
1696
|
+
// execute against it — not when its stored SDK session id is
|
|
1697
|
+
// non-null. `continueDashboardSession` legitimately writes
|
|
1698
|
+
// `backend_session_id = NULL` on the `shouldInvalidateSdkSession`
|
|
1699
|
+
// path, and the dispatcher falls back to fresh-execute + history
|
|
1700
|
+
// injection for NULL backends. The real gates are: scope,
|
|
1701
|
+
// browser-only provenance, and the workdir surviving on disk.
|
|
1702
|
+
continue_available: row.scope === DASHBOARD_CHAT_SCOPE
|
|
1703
|
+
&& browserOnly
|
|
1704
|
+
&& existsSync(getSessionWorkdirPath(config.dataDir, row.id)),
|
|
1705
|
+
};
|
|
1706
|
+
});
|
|
1707
|
+
return c.json({
|
|
1708
|
+
conversations,
|
|
1709
|
+
pagination: {
|
|
1710
|
+
page,
|
|
1711
|
+
limit,
|
|
1712
|
+
total: total.cnt,
|
|
1713
|
+
totalPages: Math.ceil(total.cnt / limit),
|
|
1714
|
+
},
|
|
1715
|
+
});
|
|
1716
|
+
});
|
|
1717
|
+
/**
|
|
1718
|
+
* DELETE /conversations — bulk-delete every non-active sidebar session.
|
|
1719
|
+
* Scope is hard-coded to `dashboard_chat` + `owner_dm` (what the chat
|
|
1720
|
+
* sidebar shows); the live active session is filtered out so deleting
|
|
1721
|
+
* "all past sessions" never kills the current chat.
|
|
1722
|
+
*/
|
|
1723
|
+
app.delete("/conversations", (c) => {
|
|
1724
|
+
const result = deleteAllChatSidebarSessions({ db, dataDir: config.dataDir });
|
|
1725
|
+
return c.json({ status: "deleted", deleted: result.deleted });
|
|
1726
|
+
});
|
|
1727
|
+
/** DELETE /conversations/:id — delete one non-active sidebar session. */
|
|
1728
|
+
app.delete("/conversations/:id", (c) => {
|
|
1729
|
+
const sessionId = Number(c.req.param("id"));
|
|
1730
|
+
if (!Number.isFinite(sessionId) || sessionId <= 0) {
|
|
1731
|
+
return c.json({ error: "invalid_session_id" }, 400);
|
|
1732
|
+
}
|
|
1733
|
+
const result = deleteChatSession({
|
|
1734
|
+
db,
|
|
1735
|
+
dataDir: config.dataDir,
|
|
1736
|
+
sessionId,
|
|
1737
|
+
});
|
|
1738
|
+
if (!result.ok) {
|
|
1739
|
+
return c.json({ error: "delete_failed", message: result.message }, result.status);
|
|
1740
|
+
}
|
|
1741
|
+
return c.json({ status: "deleted", deleted: result.deleted });
|
|
1742
|
+
});
|
|
1743
|
+
/** GET /conversations/:id/messages — messages for a specific conversation */
|
|
1744
|
+
app.get("/conversations/:id/messages", (c) => {
|
|
1745
|
+
const sessionId = Number(c.req.param("id"));
|
|
1746
|
+
const limit = Math.min(Number(c.req.query("limit") ?? "50"), 200);
|
|
1747
|
+
const before = c.req.query("before"); // cursor-based pagination
|
|
1748
|
+
let whereClause = "WHERE session_id = ?";
|
|
1749
|
+
const params = [sessionId];
|
|
1750
|
+
if (before) {
|
|
1751
|
+
whereClause += " AND id < ?";
|
|
1752
|
+
params.push(Number(before));
|
|
1753
|
+
}
|
|
1754
|
+
params.push(limit);
|
|
1755
|
+
const rows = db
|
|
1756
|
+
.prepare(`SELECT id, role, content, platform, sender_id, timestamp
|
|
1757
|
+
FROM messages ${whereClause}
|
|
1758
|
+
ORDER BY id DESC
|
|
1759
|
+
LIMIT ?`)
|
|
1760
|
+
.all(...params);
|
|
1761
|
+
// Chat-attachments Phase 1 — inline attachment refs per message so
|
|
1762
|
+
// the dashboard transcript can render thumbnails/download chips
|
|
1763
|
+
// alongside past messages without an extra round-trip per row.
|
|
1764
|
+
// Skipped when the chat_attachments table doesn't exist (older DB
|
|
1765
|
+
// snapshots / tests that don't run migrations).
|
|
1766
|
+
const hasAttachments = (() => {
|
|
1767
|
+
try {
|
|
1768
|
+
const row = db
|
|
1769
|
+
.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='chat_attachments'`)
|
|
1770
|
+
.get();
|
|
1771
|
+
return row !== undefined;
|
|
1772
|
+
}
|
|
1773
|
+
catch {
|
|
1774
|
+
return false;
|
|
1775
|
+
}
|
|
1776
|
+
})();
|
|
1777
|
+
const attachmentsByMessage = new Map();
|
|
1778
|
+
if (hasAttachments && rows.length > 0) {
|
|
1779
|
+
const ids = rows.map((r) => r.id);
|
|
1780
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
1781
|
+
const attachmentRows = db
|
|
1782
|
+
.prepare(`SELECT message_id, id, direction, original_filename, mime_type, size_bytes, caption
|
|
1783
|
+
FROM chat_attachments
|
|
1784
|
+
WHERE message_id IN (${placeholders})
|
|
1785
|
+
ORDER BY created_at ASC`)
|
|
1786
|
+
.all(...ids);
|
|
1787
|
+
for (const a of attachmentRows) {
|
|
1788
|
+
let bucket = attachmentsByMessage.get(a.message_id);
|
|
1789
|
+
if (!bucket) {
|
|
1790
|
+
bucket = [];
|
|
1791
|
+
attachmentsByMessage.set(a.message_id, bucket);
|
|
1792
|
+
}
|
|
1793
|
+
bucket.push({
|
|
1794
|
+
id: a.id,
|
|
1795
|
+
direction: a.direction,
|
|
1796
|
+
originalFilename: a.original_filename,
|
|
1797
|
+
mimeType: a.mime_type,
|
|
1798
|
+
sizeBytes: a.size_bytes,
|
|
1799
|
+
caption: a.caption,
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
const enriched = rows.map((row) => {
|
|
1804
|
+
const attachments = attachmentsByMessage.get(row.id);
|
|
1805
|
+
return attachments && attachments.length > 0
|
|
1806
|
+
? { ...row, attachments }
|
|
1807
|
+
: row;
|
|
1808
|
+
});
|
|
1809
|
+
return c.json({
|
|
1810
|
+
messages: enriched.reverse(), // Return in chronological order
|
|
1811
|
+
hasMore: rows.length === limit,
|
|
1812
|
+
});
|
|
1813
|
+
});
|
|
1814
|
+
// ── Cost API ──
|
|
1815
|
+
/** GET /cost — cost analytics */
|
|
1816
|
+
app.get("/cost", (c) => {
|
|
1817
|
+
const period = c.req.query("period") ?? "daily"; // daily, weekly, monthly
|
|
1818
|
+
const periodKey = period in COST_QUERIES
|
|
1819
|
+
? period
|
|
1820
|
+
: "daily";
|
|
1821
|
+
const queries = COST_QUERIES[periodKey];
|
|
1822
|
+
const spec = COST_PERIOD_SPECS[periodKey];
|
|
1823
|
+
const byPeriod = db.prepare(queries.byPeriod).all();
|
|
1824
|
+
const byModelRaw = db.prepare(queries.byModelRows).all();
|
|
1825
|
+
const byModel = aggregateByBilledModel(byModelRaw);
|
|
1826
|
+
const byEventType = db.prepare(queries.byEventType).all();
|
|
1827
|
+
const byBackend = db
|
|
1828
|
+
.prepare(`SELECT ${backendExpr} as backend,
|
|
1829
|
+
SUM(cost_usd) as total_cost,
|
|
1830
|
+
COUNT(*) as session_count
|
|
1831
|
+
FROM agent_actions
|
|
1832
|
+
WHERE started_at > datetime('now', ?)
|
|
1833
|
+
AND cost_usd IS NOT NULL
|
|
1834
|
+
GROUP BY 1
|
|
1835
|
+
ORDER BY total_cost DESC`)
|
|
1836
|
+
.all(spec.sinceExpr);
|
|
1837
|
+
const byBackendPeriod = db
|
|
1838
|
+
.prepare(`SELECT ${spec.bucketExpr} as period,
|
|
1839
|
+
${backendExpr} as backend,
|
|
1840
|
+
SUM(cost_usd) as total_cost,
|
|
1841
|
+
COUNT(*) as session_count
|
|
1842
|
+
FROM agent_actions
|
|
1843
|
+
WHERE started_at > datetime('now', ?)
|
|
1844
|
+
AND cost_usd IS NOT NULL
|
|
1845
|
+
GROUP BY 1, 2
|
|
1846
|
+
ORDER BY period DESC, backend ASC`)
|
|
1847
|
+
.all(spec.sinceExpr);
|
|
1848
|
+
// Today's total (timezone-aware agent day, executed sessions only).
|
|
1849
|
+
// datetime(started_at) normalizes mixed ISO-8601 / SQL formats — same
|
|
1850
|
+
// rationale as the /events ORDER BY fix above.
|
|
1851
|
+
const bounds = getAgentDayBoundsUtc(config.timezone, config.dayBoundaryHour);
|
|
1852
|
+
const today = db
|
|
1853
|
+
.prepare(`SELECT COALESCE(SUM(cost_usd), 0) as cost,
|
|
1854
|
+
COUNT(*) as sessions
|
|
1855
|
+
FROM agent_actions
|
|
1856
|
+
WHERE datetime(started_at) >= ? AND datetime(started_at) < ?
|
|
1857
|
+
AND cost_usd IS NOT NULL`)
|
|
1858
|
+
.get(bounds.start, bounds.end);
|
|
1859
|
+
return c.json({
|
|
1860
|
+
period,
|
|
1861
|
+
today: { costUsd: today.cost, sessions: today.sessions },
|
|
1862
|
+
byPeriod,
|
|
1863
|
+
byModel,
|
|
1864
|
+
byEventType,
|
|
1865
|
+
byBackend,
|
|
1866
|
+
byBackendPeriod,
|
|
1867
|
+
});
|
|
1868
|
+
});
|
|
1869
|
+
// ── Approvals API ──
|
|
1870
|
+
/** GET /approvals — list pending approval requests */
|
|
1871
|
+
app.get("/approvals", (c) => {
|
|
1872
|
+
const rows = db
|
|
1873
|
+
.prepare(`SELECT id, scheduled_for, task_type, task_description,
|
|
1874
|
+
task_context, model, status, created_at
|
|
1875
|
+
FROM agent_schedule
|
|
1876
|
+
WHERE status = 'pending' AND task_type = 'approval'
|
|
1877
|
+
ORDER BY created_at DESC`)
|
|
1878
|
+
.all();
|
|
1879
|
+
return c.json({ approvals: rows });
|
|
1880
|
+
});
|
|
1881
|
+
/** POST /approvals/:id/approve — approve a pending request */
|
|
1882
|
+
app.post("/approvals/:id/approve", (c) => {
|
|
1883
|
+
const id = Number(c.req.param("id"));
|
|
1884
|
+
const result = db
|
|
1885
|
+
.prepare("UPDATE agent_schedule SET status = 'pending', task_type = 'approved_task' WHERE id = ? AND status = 'pending' AND task_type = 'approval'")
|
|
1886
|
+
.run(id);
|
|
1887
|
+
if (result.changes === 0) {
|
|
1888
|
+
return c.json({ error: "approval not found or already processed" }, 404);
|
|
1889
|
+
}
|
|
1890
|
+
return c.json({ status: "approved", id });
|
|
1891
|
+
});
|
|
1892
|
+
/** POST /approvals/:id/deny — deny a pending request */
|
|
1893
|
+
app.post("/approvals/:id/deny", (c) => {
|
|
1894
|
+
const id = Number(c.req.param("id"));
|
|
1895
|
+
const result = db
|
|
1896
|
+
.prepare("UPDATE agent_schedule SET status = 'skipped' WHERE id = ? AND status = 'pending' AND task_type = 'approval'")
|
|
1897
|
+
.run(id);
|
|
1898
|
+
if (result.changes === 0) {
|
|
1899
|
+
return c.json({ error: "approval not found or already processed" }, 404);
|
|
1900
|
+
}
|
|
1901
|
+
return c.json({ status: "denied", id });
|
|
1902
|
+
});
|
|
1903
|
+
// ── Schedule API ──
|
|
1904
|
+
/** GET /schedule/next — next pending scheduled task */
|
|
1905
|
+
app.get("/schedule/next", (c) => {
|
|
1906
|
+
const row = db
|
|
1907
|
+
.prepare(`SELECT id, scheduled_for, task_type, task_description
|
|
1908
|
+
FROM agent_schedule
|
|
1909
|
+
WHERE status = 'pending' AND scheduled_for > datetime('now')
|
|
1910
|
+
ORDER BY scheduled_for ASC LIMIT 1`)
|
|
1911
|
+
.get();
|
|
1912
|
+
return c.json({ next: row ?? null });
|
|
1913
|
+
});
|
|
1914
|
+
/** GET /schedule/list — all scheduled tasks (paginated) */
|
|
1915
|
+
app.get("/schedule/list", (c) => {
|
|
1916
|
+
const page = Math.max(1, Number(c.req.query("page") ?? "1"));
|
|
1917
|
+
const limit = Math.min(Number(c.req.query("limit") ?? "20"), 50);
|
|
1918
|
+
const status = c.req.query("status");
|
|
1919
|
+
const type = c.req.query("type");
|
|
1920
|
+
const offset = (page - 1) * limit;
|
|
1921
|
+
let where = "1=1";
|
|
1922
|
+
const params = [];
|
|
1923
|
+
if (status) {
|
|
1924
|
+
where += " AND status = ?";
|
|
1925
|
+
params.push(status);
|
|
1926
|
+
}
|
|
1927
|
+
if (type) {
|
|
1928
|
+
where += " AND task_type = ?";
|
|
1929
|
+
params.push(type);
|
|
1930
|
+
}
|
|
1931
|
+
const total = db
|
|
1932
|
+
.prepare(`SELECT COUNT(*) as count FROM agent_schedule WHERE ${where}`)
|
|
1933
|
+
.get(...params).count;
|
|
1934
|
+
params.push(limit, offset);
|
|
1935
|
+
const schedules = db
|
|
1936
|
+
.prepare(`SELECT id, scheduled_for, task_type, task_description, task_prompt, model, status, task_context, created_at
|
|
1937
|
+
FROM agent_schedule WHERE ${where}
|
|
1938
|
+
ORDER BY scheduled_for DESC LIMIT ? OFFSET ?`)
|
|
1939
|
+
.all(...params);
|
|
1940
|
+
return c.json({
|
|
1941
|
+
schedules,
|
|
1942
|
+
pagination: { page, limit, total, totalPages: Math.ceil(total / limit) },
|
|
1943
|
+
});
|
|
1944
|
+
});
|
|
1945
|
+
// ── Search API ──
|
|
1946
|
+
/** GET /search?q= — full-text search via FTS5 */
|
|
1947
|
+
app.get("/search", (c) => {
|
|
1948
|
+
const q = c.req.query("q");
|
|
1949
|
+
if (!q || q.length < 2)
|
|
1950
|
+
return c.json({ error: "query too short" }, 400);
|
|
1951
|
+
if (q.length > 200)
|
|
1952
|
+
return c.json({ error: "query too long" }, 400);
|
|
1953
|
+
const limit = Math.min(Number(c.req.query("limit") ?? "20"), 50);
|
|
1954
|
+
// Sanitize: wrap each word in double-quotes to disable FTS5 operators (NEAR, NOT, OR, etc.)
|
|
1955
|
+
const safeQuery = q
|
|
1956
|
+
.replace(/[^\w\s\u3000-\u9FFF\uF900-\uFAFF]/g, " ") // strip punctuation except CJK
|
|
1957
|
+
.split(/\s+/)
|
|
1958
|
+
.filter(Boolean)
|
|
1959
|
+
.map((w) => `"${w}"`)
|
|
1960
|
+
.join(" ");
|
|
1961
|
+
if (!safeQuery)
|
|
1962
|
+
return c.json({ actions: [], messages: [] });
|
|
1963
|
+
let actions = [];
|
|
1964
|
+
let messages = [];
|
|
1965
|
+
try {
|
|
1966
|
+
actions = db
|
|
1967
|
+
.prepare(`SELECT a.id, a.action_type, a.started_at,
|
|
1968
|
+
highlight(fts_actions, 1, '<mark>', '</mark>') as snippet
|
|
1969
|
+
FROM fts_actions JOIN agent_actions a ON a.id = fts_actions.rowid
|
|
1970
|
+
WHERE fts_actions MATCH ? ORDER BY rank LIMIT ?`)
|
|
1971
|
+
.all(safeQuery, limit);
|
|
1972
|
+
}
|
|
1973
|
+
catch {
|
|
1974
|
+
// FTS table may not exist yet
|
|
1975
|
+
}
|
|
1976
|
+
try {
|
|
1977
|
+
messages = db
|
|
1978
|
+
.prepare(`SELECT m.id, m.role, m.timestamp, m.session_id,
|
|
1979
|
+
highlight(fts_messages, 0, '<mark>', '</mark>') as snippet
|
|
1980
|
+
FROM fts_messages JOIN messages m ON m.id = fts_messages.rowid
|
|
1981
|
+
WHERE fts_messages MATCH ? ORDER BY rank LIMIT ?`)
|
|
1982
|
+
.all(safeQuery, limit);
|
|
1983
|
+
}
|
|
1984
|
+
catch {
|
|
1985
|
+
// FTS table may not exist yet
|
|
1986
|
+
}
|
|
1987
|
+
return c.json({ actions, messages });
|
|
1988
|
+
});
|
|
1989
|
+
// ── Snapshots API ──
|
|
1990
|
+
/** GET /snapshots/content/:id — single snapshot content */
|
|
1991
|
+
app.get("/snapshots/content/:id", (c) => {
|
|
1992
|
+
const id = Number(c.req.param("id"));
|
|
1993
|
+
if (!Number.isSafeInteger(id) || id <= 0) {
|
|
1994
|
+
return c.json({ error: "invalid id" }, 400);
|
|
1995
|
+
}
|
|
1996
|
+
const row = db
|
|
1997
|
+
.prepare("SELECT id, file_path, content, trigger, created_at FROM md_file_snapshots WHERE id = ?")
|
|
1998
|
+
.get(id);
|
|
1999
|
+
if (!row)
|
|
2000
|
+
return c.json({ error: "not_found" }, 404);
|
|
2001
|
+
return c.json(row);
|
|
2002
|
+
});
|
|
2003
|
+
/** GET /snapshots/* — snapshot history for a context file */
|
|
2004
|
+
app.get("/snapshots/*", (c) => {
|
|
2005
|
+
const filePath = c.req.path.replace("/api/snapshots/", "");
|
|
2006
|
+
// Validate: reject path traversal and unsafe characters
|
|
2007
|
+
if (!filePath || /\.\./.test(filePath) || !/^[\w./-]+$/.test(filePath)) {
|
|
2008
|
+
return c.json({ error: "invalid file path" }, 400);
|
|
2009
|
+
}
|
|
2010
|
+
const limit = Math.min(Number(c.req.query("limit") ?? "20"), 50);
|
|
2011
|
+
const rows = db
|
|
2012
|
+
.prepare(`SELECT id, file_path, trigger, session_id, created_at
|
|
2013
|
+
FROM md_file_snapshots WHERE file_path = ?
|
|
2014
|
+
ORDER BY created_at DESC LIMIT ?`)
|
|
2015
|
+
.all(filePath, limit);
|
|
2016
|
+
return c.json({ snapshots: rows });
|
|
2017
|
+
});
|
|
2018
|
+
// ── Notifications API ──
|
|
2019
|
+
/** GET /notifications — notification history (paginated) */
|
|
2020
|
+
app.get("/notifications", (c) => {
|
|
2021
|
+
const page = Math.max(1, Number(c.req.query("page") ?? "1"));
|
|
2022
|
+
const limit = Math.min(Number(c.req.query("limit") ?? "50"), 100);
|
|
2023
|
+
const status = c.req.query("status");
|
|
2024
|
+
const priority = c.req.query("priority");
|
|
2025
|
+
const offset = (page - 1) * limit;
|
|
2026
|
+
let where = "1=1";
|
|
2027
|
+
const params = [];
|
|
2028
|
+
if (status) {
|
|
2029
|
+
where += " AND status = ?";
|
|
2030
|
+
params.push(status);
|
|
2031
|
+
}
|
|
2032
|
+
if (priority) {
|
|
2033
|
+
where += " AND priority = ?";
|
|
2034
|
+
params.push(priority);
|
|
2035
|
+
}
|
|
2036
|
+
const total = db
|
|
2037
|
+
.prepare(`SELECT COUNT(*) as count FROM notification_log WHERE ${where}`)
|
|
2038
|
+
.get(...params).count;
|
|
2039
|
+
params.push(limit, offset);
|
|
2040
|
+
const notifications = db
|
|
2041
|
+
.prepare(`SELECT
|
|
2042
|
+
id,
|
|
2043
|
+
dispatch_id,
|
|
2044
|
+
content_summary AS message,
|
|
2045
|
+
platform,
|
|
2046
|
+
delivery_channel,
|
|
2047
|
+
priority,
|
|
2048
|
+
status,
|
|
2049
|
+
user_reaction,
|
|
2050
|
+
reacted_at,
|
|
2051
|
+
created_at
|
|
2052
|
+
FROM notification_log WHERE ${where}
|
|
2053
|
+
ORDER BY created_at DESC LIMIT ? OFFSET ?`)
|
|
2054
|
+
.all(...params);
|
|
2055
|
+
return c.json({
|
|
2056
|
+
notifications,
|
|
2057
|
+
pagination: { page, limit, total, totalPages: Math.ceil(total / limit) },
|
|
2058
|
+
});
|
|
2059
|
+
});
|
|
2060
|
+
return app;
|
|
2061
|
+
}
|
|
2062
|
+
//# sourceMappingURL=dashboard.js.map
|