@aitne/daemon 0.1.6 → 0.1.8
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/dist/adapters/dashboard-adapter.d.ts +18 -2
- package/dist/adapters/dashboard-adapter.d.ts.map +1 -1
- package/dist/adapters/dashboard-adapter.js +101 -51
- package/dist/adapters/dashboard-adapter.js.map +1 -1
- package/dist/adapters/discord.d.ts +8 -0
- package/dist/adapters/discord.d.ts.map +1 -1
- package/dist/adapters/discord.js +100 -21
- package/dist/adapters/discord.js.map +1 -1
- package/dist/adapters/message-hub.d.ts.map +1 -1
- package/dist/adapters/message-hub.js +7 -1
- package/dist/adapters/message-hub.js.map +1 -1
- package/dist/adapters/notification-manager.d.ts +102 -2
- package/dist/adapters/notification-manager.d.ts.map +1 -1
- package/dist/adapters/notification-manager.js +228 -8
- package/dist/adapters/notification-manager.js.map +1 -1
- package/dist/adapters/outbound-text.d.ts +16 -0
- package/dist/adapters/outbound-text.d.ts.map +1 -1
- package/dist/adapters/outbound-text.js +118 -1
- package/dist/adapters/outbound-text.js.map +1 -1
- package/dist/adapters/primary-platform-resolver.d.ts +69 -0
- package/dist/adapters/primary-platform-resolver.d.ts.map +1 -0
- package/dist/adapters/primary-platform-resolver.js +55 -0
- package/dist/adapters/primary-platform-resolver.js.map +1 -0
- package/dist/adapters/slack-adapter.d.ts +28 -0
- package/dist/adapters/slack-adapter.d.ts.map +1 -1
- package/dist/adapters/slack-adapter.js +134 -35
- package/dist/adapters/slack-adapter.js.map +1 -1
- package/dist/adapters/telegram-adapter.d.ts +7 -1
- package/dist/adapters/telegram-adapter.d.ts.map +1 -1
- package/dist/adapters/telegram-adapter.js +49 -18
- package/dist/adapters/telegram-adapter.js.map +1 -1
- package/dist/adapters/whatsapp-adapter.d.ts +33 -0
- package/dist/adapters/whatsapp-adapter.d.ts.map +1 -1
- package/dist/adapters/whatsapp-adapter.js +84 -0
- package/dist/adapters/whatsapp-adapter.js.map +1 -1
- package/dist/api/directory-picker.d.ts.map +1 -1
- package/dist/api/directory-picker.js +14 -0
- package/dist/api/directory-picker.js.map +1 -1
- package/dist/api/env-writer.d.ts.map +1 -1
- package/dist/api/env-writer.js +6 -1
- package/dist/api/env-writer.js.map +1 -1
- package/dist/api/helpers/agent-errors.d.ts +2600 -0
- package/dist/api/helpers/agent-errors.d.ts.map +1 -0
- package/dist/api/helpers/agent-errors.js +2506 -0
- package/dist/api/helpers/agent-errors.js.map +1 -0
- package/dist/api/integration-route-gate.d.ts.map +1 -1
- package/dist/api/integration-route-gate.js +10 -3
- package/dist/api/integration-route-gate.js.map +1 -1
- package/dist/api/routes/agent-schedule-plan-match.d.ts +5 -0
- package/dist/api/routes/agent-schedule-plan-match.d.ts.map +1 -0
- package/dist/api/routes/agent-schedule-plan-match.js +101 -0
- package/dist/api/routes/agent-schedule-plan-match.js.map +1 -0
- package/dist/api/routes/agent-schedule.d.ts +4 -0
- package/dist/api/routes/agent-schedule.d.ts.map +1 -0
- package/dist/api/routes/agent-schedule.js +750 -0
- package/dist/api/routes/agent-schedule.js.map +1 -0
- package/dist/api/routes/agent.d.ts.map +1 -1
- package/dist/api/routes/agent.js +209 -366
- package/dist/api/routes/agent.js.map +1 -1
- package/dist/api/routes/apple-calendar.d.ts.map +1 -1
- package/dist/api/routes/apple-calendar.js +109 -27
- package/dist/api/routes/apple-calendar.js.map +1 -1
- package/dist/api/routes/attachments.d.ts.map +1 -1
- package/dist/api/routes/attachments.js +113 -21
- package/dist/api/routes/attachments.js.map +1 -1
- package/dist/api/routes/backends.d.ts.map +1 -1
- package/dist/api/routes/backends.js +100 -4
- package/dist/api/routes/backends.js.map +1 -1
- package/dist/api/routes/books.d.ts.map +1 -1
- package/dist/api/routes/books.js +58 -18
- package/dist/api/routes/books.js.map +1 -1
- package/dist/api/routes/calendar.d.ts +3 -2
- package/dist/api/routes/calendar.d.ts.map +1 -1
- package/dist/api/routes/calendar.js +330 -55
- package/dist/api/routes/calendar.js.map +1 -1
- package/dist/api/routes/commands.d.ts.map +1 -1
- package/dist/api/routes/commands.js +20 -1
- package/dist/api/routes/commands.js.map +1 -1
- package/dist/api/routes/context/index.d.ts +33 -0
- package/dist/api/routes/context/index.d.ts.map +1 -0
- package/dist/api/routes/context/index.js +193 -0
- package/dist/api/routes/context/index.js.map +1 -0
- package/dist/api/routes/context/locks.d.ts +4 -0
- package/dist/api/routes/context/locks.d.ts.map +1 -0
- package/dist/api/routes/context/locks.js +136 -0
- package/dist/api/routes/context/locks.js.map +1 -0
- package/dist/api/routes/context/path-resolve.d.ts +15 -0
- package/dist/api/routes/context/path-resolve.d.ts.map +1 -0
- package/dist/api/routes/context/path-resolve.js +109 -0
- package/dist/api/routes/context/path-resolve.js.map +1 -0
- package/dist/api/routes/context/permissions.d.ts +35 -0
- package/dist/api/routes/context/permissions.d.ts.map +1 -0
- package/dist/api/routes/context/permissions.js +192 -0
- package/dist/api/routes/context/permissions.js.map +1 -0
- package/dist/api/routes/context/read.d.ts +4 -0
- package/dist/api/routes/context/read.d.ts.map +1 -0
- package/dist/api/routes/context/read.js +295 -0
- package/dist/api/routes/context/read.js.map +1 -0
- package/dist/api/routes/context/repair.d.ts +4 -0
- package/dist/api/routes/context/repair.d.ts.map +1 -0
- package/dist/api/routes/context/repair.js +114 -0
- package/dist/api/routes/context/repair.js.map +1 -0
- package/dist/api/routes/context/snapshots.d.ts +4 -0
- package/dist/api/routes/context/snapshots.d.ts.map +1 -0
- package/dist/api/routes/context/snapshots.js +177 -0
- package/dist/api/routes/context/snapshots.js.map +1 -0
- package/dist/api/routes/context/write.d.ts +4 -0
- package/dist/api/routes/context/write.d.ts.map +1 -0
- package/dist/api/routes/context/write.js +570 -0
- package/dist/api/routes/context/write.js.map +1 -0
- package/dist/api/routes/context.d.ts +2 -43
- package/dist/api/routes/context.d.ts.map +1 -1
- package/dist/api/routes/context.js +415 -558
- package/dist/api/routes/context.js.map +1 -1
- package/dist/api/routes/dashboard/config.d.ts +4 -0
- package/dist/api/routes/dashboard/config.d.ts.map +1 -0
- package/dist/api/routes/dashboard/config.js +499 -0
- package/dist/api/routes/dashboard/config.js.map +1 -0
- package/dist/api/routes/dashboard/conversations.d.ts +4 -0
- package/dist/api/routes/dashboard/conversations.d.ts.map +1 -0
- package/dist/api/routes/dashboard/conversations.js +309 -0
- package/dist/api/routes/dashboard/conversations.js.map +1 -0
- package/dist/api/routes/dashboard/cost-approvals.d.ts +29 -0
- package/dist/api/routes/dashboard/cost-approvals.d.ts.map +1 -0
- package/dist/api/routes/dashboard/cost-approvals.js +259 -0
- package/dist/api/routes/dashboard/cost-approvals.js.map +1 -0
- package/dist/api/routes/dashboard/index.d.ts +27 -0
- package/dist/api/routes/dashboard/index.d.ts.map +1 -0
- package/dist/api/routes/dashboard/index.js +47 -0
- package/dist/api/routes/dashboard/index.js.map +1 -0
- package/dist/api/routes/dashboard/messaging.d.ts +4 -0
- package/dist/api/routes/dashboard/messaging.d.ts.map +1 -0
- package/dist/api/routes/dashboard/messaging.js +351 -0
- package/dist/api/routes/dashboard/messaging.js.map +1 -0
- package/dist/api/routes/dashboard/notifications.d.ts +4 -0
- package/dist/api/routes/dashboard/notifications.d.ts.map +1 -0
- package/dist/api/routes/dashboard/notifications.js +109 -0
- package/dist/api/routes/dashboard/notifications.js.map +1 -0
- package/dist/api/routes/dashboard/oauth-google.d.ts +4 -0
- package/dist/api/routes/dashboard/oauth-google.d.ts.map +1 -0
- package/dist/api/routes/dashboard/oauth-google.js +293 -0
- package/dist/api/routes/dashboard/oauth-google.js.map +1 -0
- package/dist/api/routes/dashboard/schedule-readonly.d.ts +4 -0
- package/dist/api/routes/dashboard/schedule-readonly.d.ts.map +1 -0
- package/dist/api/routes/dashboard/schedule-readonly.js +46 -0
- package/dist/api/routes/dashboard/schedule-readonly.js.map +1 -0
- package/dist/api/routes/dashboard/secrets.d.ts +24 -0
- package/dist/api/routes/dashboard/secrets.d.ts.map +1 -0
- package/dist/api/routes/dashboard/secrets.js +307 -0
- package/dist/api/routes/dashboard/secrets.js.map +1 -0
- package/dist/api/routes/dashboard/snapshots.d.ts +4 -0
- package/dist/api/routes/dashboard/snapshots.d.ts.map +1 -0
- package/dist/api/routes/dashboard/snapshots.js +33 -0
- package/dist/api/routes/dashboard/snapshots.js.map +1 -0
- package/dist/api/routes/dashboard.d.ts.map +1 -1
- package/dist/api/routes/dashboard.js +20 -12
- package/dist/api/routes/dashboard.js.map +1 -1
- package/dist/api/routes/delegated.d.ts +5 -4
- package/dist/api/routes/delegated.d.ts.map +1 -1
- package/dist/api/routes/delegated.js +6 -5
- package/dist/api/routes/delegated.js.map +1 -1
- package/dist/api/routes/docs.d.ts.map +1 -1
- package/dist/api/routes/docs.js +72 -9
- package/dist/api/routes/docs.js.map +1 -1
- package/dist/api/routes/entities.d.ts.map +1 -1
- package/dist/api/routes/entities.js +112 -43
- package/dist/api/routes/entities.js.map +1 -1
- package/dist/api/routes/fs.d.ts.map +1 -1
- package/dist/api/routes/fs.js +27 -12
- package/dist/api/routes/fs.js.map +1 -1
- package/dist/api/routes/git-templates.d.ts.map +1 -1
- package/dist/api/routes/git-templates.js +107 -27
- package/dist/api/routes/git-templates.js.map +1 -1
- package/dist/api/routes/git.d.ts.map +1 -1
- package/dist/api/routes/git.js +55 -11
- package/dist/api/routes/git.js.map +1 -1
- package/dist/api/routes/github.d.ts.map +1 -1
- package/dist/api/routes/github.js +110 -17
- package/dist/api/routes/github.js.map +1 -1
- package/dist/api/routes/integrations/crud-patch.d.ts +17 -0
- package/dist/api/routes/integrations/crud-patch.d.ts.map +1 -0
- package/dist/api/routes/integrations/crud-patch.js +600 -0
- package/dist/api/routes/integrations/crud-patch.js.map +1 -0
- package/dist/api/routes/integrations/crud.d.ts +16 -0
- package/dist/api/routes/integrations/crud.d.ts.map +1 -0
- package/dist/api/routes/integrations/crud.js +158 -0
- package/dist/api/routes/integrations/crud.js.map +1 -0
- package/dist/api/routes/integrations/exec.d.ts +23 -0
- package/dist/api/routes/integrations/exec.d.ts.map +1 -0
- package/dist/api/routes/integrations/exec.js +356 -0
- package/dist/api/routes/integrations/exec.js.map +1 -0
- package/dist/api/routes/integrations/index.d.ts +62 -0
- package/dist/api/routes/integrations/index.d.ts.map +1 -0
- package/dist/api/routes/integrations/index.js +70 -0
- package/dist/api/routes/integrations/index.js.map +1 -0
- package/dist/api/routes/integrations/integrations/crud.d.ts +16 -0
- package/dist/api/routes/integrations/integrations/crud.d.ts.map +1 -0
- package/dist/api/routes/integrations/integrations/crud.js +158 -0
- package/dist/api/routes/integrations/integrations/crud.js.map +1 -0
- package/dist/api/routes/integrations/integrations/index.d.ts +55 -0
- package/dist/api/routes/integrations/integrations/index.d.ts.map +1 -0
- package/dist/api/routes/integrations/integrations/index.js +65 -0
- package/dist/api/routes/integrations/integrations/index.js.map +1 -0
- package/dist/api/routes/integrations/integrations/invoke.d.ts +38 -0
- package/dist/api/routes/integrations/integrations/invoke.d.ts.map +1 -0
- package/dist/api/routes/integrations/integrations/invoke.js +320 -0
- package/dist/api/routes/integrations/integrations/invoke.js.map +1 -0
- package/dist/api/routes/integrations/integrations/probe.d.ts +21 -0
- package/dist/api/routes/integrations/integrations/probe.d.ts.map +1 -0
- package/dist/api/routes/integrations/integrations/probe.js +247 -0
- package/dist/api/routes/integrations/integrations/probe.js.map +1 -0
- package/dist/api/routes/integrations/invoke.d.ts +38 -0
- package/dist/api/routes/integrations/invoke.d.ts.map +1 -0
- package/dist/api/routes/integrations/invoke.js +320 -0
- package/dist/api/routes/integrations/invoke.js.map +1 -0
- package/dist/api/routes/integrations/probe.d.ts +21 -0
- package/dist/api/routes/integrations/probe.d.ts.map +1 -0
- package/dist/api/routes/integrations/probe.js +247 -0
- package/dist/api/routes/integrations/probe.js.map +1 -0
- package/dist/api/routes/integrations.d.ts.map +1 -1
- package/dist/api/routes/integrations.js +65 -13
- package/dist/api/routes/integrations.js.map +1 -1
- package/dist/api/routes/knowledge.d.ts.map +1 -1
- package/dist/api/routes/knowledge.js +13 -2
- package/dist/api/routes/knowledge.js.map +1 -1
- package/dist/api/routes/mail/_pa_wip_mail/app-password.d.ts +4 -0
- package/dist/api/routes/mail/_pa_wip_mail/app-password.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/app-password.js +192 -0
- package/dist/api/routes/mail/_pa_wip_mail/app-password.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/body-helpers.d.ts +55 -0
- package/dist/api/routes/mail/_pa_wip_mail/body-helpers.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/body-helpers.js +91 -0
- package/dist/api/routes/mail/_pa_wip_mail/body-helpers.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/dependencies.d.ts +36 -0
- package/dist/api/routes/mail/_pa_wip_mail/dependencies.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/dependencies.js +2 -0
- package/dist/api/routes/mail/_pa_wip_mail/dependencies.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/gating.d.ts +45 -0
- package/dist/api/routes/mail/_pa_wip_mail/gating.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/gating.js +98 -0
- package/dist/api/routes/mail/_pa_wip_mail/gating.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/accounts.d.ts +4 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/accounts.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/accounts.js +289 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/accounts.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/app-password.d.ts +4 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/app-password.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/app-password.js +192 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/app-password.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/body-helpers.d.ts +55 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/body-helpers.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/body-helpers.js +91 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/body-helpers.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/dependencies.d.ts +36 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/dependencies.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/dependencies.js +2 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/dependencies.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/drafts.d.ts +5 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/drafts.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/drafts.js +139 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/drafts.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/gating.d.ts +45 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/gating.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/gating.js +98 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/gating.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/index.d.ts +18 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/index.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/index.js +40 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/index.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/messages.d.ts +15 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/messages.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/messages.js +239 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/messages.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/outlook-config.d.ts +4 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/outlook-config.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/outlook-config.js +73 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/outlook-config.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/provider-resolver.d.ts +64 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/provider-resolver.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/provider-resolver.js +286 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/provider-resolver.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/providers.d.ts +4 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/providers.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/providers.js +73 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/providers.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/tags-folders.d.ts +5 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/tags-folders.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/tags-folders.js +35 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/tags-folders.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/validators.d.ts +23 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/validators.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/validators.js +131 -0
- package/dist/api/routes/mail/_pa_wip_mail/mail/validators.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/provider-resolver.d.ts +64 -0
- package/dist/api/routes/mail/_pa_wip_mail/provider-resolver.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/provider-resolver.js +286 -0
- package/dist/api/routes/mail/_pa_wip_mail/provider-resolver.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/search-health.d.ts +4 -0
- package/dist/api/routes/mail/_pa_wip_mail/search-health.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/search-health.js +131 -0
- package/dist/api/routes/mail/_pa_wip_mail/search-health.js.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/validators.d.ts +23 -0
- package/dist/api/routes/mail/_pa_wip_mail/validators.d.ts.map +1 -0
- package/dist/api/routes/mail/_pa_wip_mail/validators.js +131 -0
- package/dist/api/routes/mail/_pa_wip_mail/validators.js.map +1 -0
- package/dist/api/routes/mail/accounts.d.ts +4 -0
- package/dist/api/routes/mail/accounts.d.ts.map +1 -0
- package/dist/api/routes/mail/accounts.js +289 -0
- package/dist/api/routes/mail/accounts.js.map +1 -0
- package/dist/api/routes/mail/app-password.d.ts +4 -0
- package/dist/api/routes/mail/app-password.d.ts.map +1 -0
- package/dist/api/routes/mail/app-password.js +192 -0
- package/dist/api/routes/mail/app-password.js.map +1 -0
- package/dist/api/routes/mail/body-helpers.d.ts +56 -0
- package/dist/api/routes/mail/body-helpers.d.ts.map +1 -0
- package/dist/api/routes/mail/body-helpers.js +91 -0
- package/dist/api/routes/mail/body-helpers.js.map +1 -0
- package/dist/api/routes/mail/dependencies.d.ts +36 -0
- package/dist/api/routes/mail/dependencies.d.ts.map +1 -0
- package/dist/api/routes/mail/dependencies.js +2 -0
- package/dist/api/routes/mail/dependencies.js.map +1 -0
- package/dist/api/routes/mail/drafts.d.ts +5 -0
- package/dist/api/routes/mail/drafts.d.ts.map +1 -0
- package/dist/api/routes/mail/drafts.js +139 -0
- package/dist/api/routes/mail/drafts.js.map +1 -0
- package/dist/api/routes/mail/gating.d.ts +45 -0
- package/dist/api/routes/mail/gating.d.ts.map +1 -0
- package/dist/api/routes/mail/gating.js +99 -0
- package/dist/api/routes/mail/gating.js.map +1 -0
- package/dist/api/routes/mail/index.d.ts +18 -0
- package/dist/api/routes/mail/index.d.ts.map +1 -0
- package/dist/api/routes/mail/index.js +40 -0
- package/dist/api/routes/mail/index.js.map +1 -0
- package/dist/api/routes/mail/messages.d.ts +15 -0
- package/dist/api/routes/mail/messages.d.ts.map +1 -0
- package/dist/api/routes/mail/messages.js +239 -0
- package/dist/api/routes/mail/messages.js.map +1 -0
- package/dist/api/routes/mail/outlook-config.d.ts +4 -0
- package/dist/api/routes/mail/outlook-config.d.ts.map +1 -0
- package/dist/api/routes/mail/outlook-config.js +73 -0
- package/dist/api/routes/mail/outlook-config.js.map +1 -0
- package/dist/api/routes/mail/provider-resolver.d.ts +64 -0
- package/dist/api/routes/mail/provider-resolver.d.ts.map +1 -0
- package/dist/api/routes/mail/provider-resolver.js +286 -0
- package/dist/api/routes/mail/provider-resolver.js.map +1 -0
- package/dist/api/routes/mail/providers.d.ts +4 -0
- package/dist/api/routes/mail/providers.d.ts.map +1 -0
- package/dist/api/routes/mail/providers.js +73 -0
- package/dist/api/routes/mail/providers.js.map +1 -0
- package/dist/api/routes/mail/search-health.d.ts +4 -0
- package/dist/api/routes/mail/search-health.d.ts.map +1 -0
- package/dist/api/routes/mail/search-health.js +131 -0
- package/dist/api/routes/mail/search-health.js.map +1 -0
- package/dist/api/routes/mail/tags-folders.d.ts +5 -0
- package/dist/api/routes/mail/tags-folders.d.ts.map +1 -0
- package/dist/api/routes/mail/tags-folders.js +35 -0
- package/dist/api/routes/mail/tags-folders.js.map +1 -0
- package/dist/api/routes/mail/validators.d.ts +23 -0
- package/dist/api/routes/mail/validators.d.ts.map +1 -0
- package/dist/api/routes/mail/validators.js +131 -0
- package/dist/api/routes/mail/validators.js.map +1 -0
- package/dist/api/routes/mail.d.ts.map +1 -1
- package/dist/api/routes/mail.js +259 -67
- package/dist/api/routes/mail.js.map +1 -1
- package/dist/api/routes/managed-tasks.d.ts.map +1 -1
- package/dist/api/routes/managed-tasks.js +142 -54
- package/dist/api/routes/managed-tasks.js.map +1 -1
- package/dist/api/routes/mcp.d.ts.map +1 -1
- package/dist/api/routes/mcp.js +115 -47
- package/dist/api/routes/mcp.js.map +1 -1
- package/dist/api/routes/metrics.d.ts +1 -1
- package/dist/api/routes/metrics.js +2 -2
- package/dist/api/routes/notion.d.ts.map +1 -1
- package/dist/api/routes/notion.js +230 -54
- package/dist/api/routes/notion.js.map +1 -1
- package/dist/api/routes/observations.d.ts.map +1 -1
- package/dist/api/routes/observations.js +40 -169
- package/dist/api/routes/observations.js.map +1 -1
- package/dist/api/routes/obsidian.d.ts.map +1 -1
- package/dist/api/routes/obsidian.js +193 -32
- package/dist/api/routes/obsidian.js.map +1 -1
- package/dist/api/routes/profile-questions.d.ts.map +1 -1
- package/dist/api/routes/profile-questions.js +19 -3
- package/dist/api/routes/profile-questions.js.map +1 -1
- package/dist/api/routes/receipts.d.ts.map +1 -1
- package/dist/api/routes/receipts.js +64 -24
- package/dist/api/routes/receipts.js.map +1 -1
- package/dist/api/routes/recurring-schedules.d.ts.map +1 -1
- package/dist/api/routes/recurring-schedules.js +243 -13
- package/dist/api/routes/recurring-schedules.js.map +1 -1
- package/dist/api/routes/repositories.d.ts.map +1 -1
- package/dist/api/routes/repositories.js +278 -104
- package/dist/api/routes/repositories.js.map +1 -1
- package/dist/api/routes/schedule-model-resolver.d.ts +153 -0
- package/dist/api/routes/schedule-model-resolver.d.ts.map +1 -0
- package/dist/api/routes/schedule-model-resolver.js +282 -0
- package/dist/api/routes/schedule-model-resolver.js.map +1 -0
- package/dist/api/routes/schedule-options.d.ts +25 -0
- package/dist/api/routes/schedule-options.d.ts.map +1 -0
- package/dist/api/routes/schedule-options.js +77 -0
- package/dist/api/routes/schedule-options.js.map +1 -0
- package/dist/api/routes/schedule-validation.d.ts +146 -0
- package/dist/api/routes/schedule-validation.d.ts.map +1 -0
- package/dist/api/routes/schedule-validation.js +153 -0
- package/dist/api/routes/schedule-validation.js.map +1 -0
- package/dist/api/routes/setup.d.ts.map +1 -1
- package/dist/api/routes/setup.js +100 -26
- package/dist/api/routes/setup.js.map +1 -1
- package/dist/api/routes/skills.d.ts.map +1 -1
- package/dist/api/routes/skills.js +81 -30
- package/dist/api/routes/skills.js.map +1 -1
- package/dist/api/routes/sot-bindings.d.ts.map +1 -1
- package/dist/api/routes/sot-bindings.js +46 -11
- package/dist/api/routes/sot-bindings.js.map +1 -1
- package/dist/api/routes/sse.d.ts.map +1 -1
- package/dist/api/routes/sse.js +6 -1
- package/dist/api/routes/sse.js.map +1 -1
- package/dist/api/routes/system.d.ts.map +1 -1
- package/dist/api/routes/system.js +15 -2
- package/dist/api/routes/system.js.map +1 -1
- package/dist/api/routes/travel-bookings.d.ts.map +1 -1
- package/dist/api/routes/travel-bookings.js +26 -9
- package/dist/api/routes/travel-bookings.js.map +1 -1
- package/dist/api/routes/travel-time.d.ts.map +1 -1
- package/dist/api/routes/travel-time.js +50 -10
- package/dist/api/routes/travel-time.js.map +1 -1
- package/dist/api/routes/wiki.d.ts.map +1 -1
- package/dist/api/routes/wiki.js +49 -8
- package/dist/api/routes/wiki.js.map +1 -1
- package/dist/api/server.d.ts +15 -3
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +32 -10
- package/dist/api/server.js.map +1 -1
- package/dist/bootstrap/adapters.d.ts.map +1 -1
- package/dist/bootstrap/adapters.js +7 -4
- package/dist/bootstrap/adapters.js.map +1 -1
- package/dist/bootstrap/api.d.ts +205 -0
- package/dist/bootstrap/api.d.ts.map +1 -0
- package/dist/bootstrap/api.js +443 -0
- package/dist/bootstrap/api.js.map +1 -0
- package/dist/bootstrap/db.d.ts +119 -0
- package/dist/bootstrap/db.d.ts.map +1 -0
- package/dist/bootstrap/db.js +294 -0
- package/dist/bootstrap/db.js.map +1 -0
- package/dist/bootstrap/event-pipeline.d.ts +308 -0
- package/dist/bootstrap/event-pipeline.d.ts.map +1 -0
- package/dist/bootstrap/event-pipeline.js +704 -0
- package/dist/bootstrap/event-pipeline.js.map +1 -0
- package/dist/bootstrap/observers.d.ts +148 -0
- package/dist/bootstrap/observers.d.ts.map +1 -0
- package/dist/bootstrap/observers.js +558 -0
- package/dist/bootstrap/observers.js.map +1 -0
- package/dist/bootstrap/schedule-helpers.d.ts +122 -0
- package/dist/bootstrap/schedule-helpers.d.ts.map +1 -1
- package/dist/bootstrap/schedule-helpers.js +202 -4
- package/dist/bootstrap/schedule-helpers.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -3
- package/dist/config.js.map +1 -1
- package/dist/core/abort-utils.d.ts +14 -0
- package/dist/core/abort-utils.d.ts.map +1 -0
- package/dist/core/abort-utils.js +36 -0
- package/dist/core/abort-utils.js.map +1 -0
- package/dist/core/agent-core.d.ts +22 -3
- package/dist/core/agent-core.d.ts.map +1 -1
- package/dist/core/agent-core.js +3 -1
- package/dist/core/agent-core.js.map +1 -1
- package/dist/core/backends/auth-health-monitor.js +2 -3
- package/dist/core/backends/auth-health-monitor.js.map +1 -1
- package/dist/core/backends/backend-router.d.ts +11 -1
- package/dist/core/backends/backend-router.d.ts.map +1 -1
- package/dist/core/backends/backend-router.js +97 -2
- package/dist/core/backends/backend-router.js.map +1 -1
- package/dist/core/backends/claude-code-core.d.ts +51 -0
- package/dist/core/backends/claude-code-core.d.ts.map +1 -1
- package/dist/core/backends/claude-code-core.js +134 -11
- package/dist/core/backends/claude-code-core.js.map +1 -1
- package/dist/core/backends/claude-tool-collection.js +1 -1
- package/dist/core/backends/codex-core.d.ts +13 -1
- package/dist/core/backends/codex-core.d.ts.map +1 -1
- package/dist/core/backends/codex-core.js +436 -22
- package/dist/core/backends/codex-core.js.map +1 -1
- package/dist/core/backends/gemini-cli-core.d.ts +5 -1
- package/dist/core/backends/gemini-cli-core.d.ts.map +1 -1
- package/dist/core/backends/gemini-cli-core.js +298 -15
- package/dist/core/backends/gemini-cli-core.js.map +1 -1
- package/dist/core/backends/install-methods.d.ts.map +1 -1
- package/dist/core/backends/install-methods.js +22 -0
- package/dist/core/backends/install-methods.js.map +1 -1
- package/dist/core/backends/model-registry.d.ts +9 -4
- package/dist/core/backends/model-registry.d.ts.map +1 -1
- package/dist/core/backends/model-registry.js +153 -23
- package/dist/core/backends/model-registry.js.map +1 -1
- package/dist/core/backends/native-skill-discovery-probe.d.ts +80 -0
- package/dist/core/backends/native-skill-discovery-probe.d.ts.map +1 -0
- package/dist/core/backends/native-skill-discovery-probe.js +175 -0
- package/dist/core/backends/native-skill-discovery-probe.js.map +1 -0
- package/dist/core/backends/opencode-basic-auth-fetch.d.ts +27 -0
- package/dist/core/backends/opencode-basic-auth-fetch.d.ts.map +1 -0
- package/dist/core/backends/opencode-basic-auth-fetch.js +40 -0
- package/dist/core/backends/opencode-basic-auth-fetch.js.map +1 -0
- package/dist/core/backends/opencode-config-builder.d.ts +86 -0
- package/dist/core/backends/opencode-config-builder.d.ts.map +1 -0
- package/dist/core/backends/opencode-config-builder.js +172 -0
- package/dist/core/backends/opencode-config-builder.js.map +1 -0
- package/dist/core/backends/opencode-core.d.ts +316 -0
- package/dist/core/backends/opencode-core.d.ts.map +1 -0
- package/dist/core/backends/opencode-core.js +1502 -0
- package/dist/core/backends/opencode-core.js.map +1 -0
- package/dist/core/backends/opencode-event-mapper.d.ts +133 -0
- package/dist/core/backends/opencode-event-mapper.d.ts.map +1 -0
- package/dist/core/backends/opencode-event-mapper.js +198 -0
- package/dist/core/backends/opencode-event-mapper.js.map +1 -0
- package/dist/core/backends/opencode-mcp.d.ts +82 -0
- package/dist/core/backends/opencode-mcp.d.ts.map +1 -0
- package/dist/core/backends/opencode-mcp.js +165 -0
- package/dist/core/backends/opencode-mcp.js.map +1 -0
- package/dist/core/backends/opencode-server-manager.d.ts +114 -0
- package/dist/core/backends/opencode-server-manager.d.ts.map +1 -0
- package/dist/core/backends/opencode-server-manager.js +222 -0
- package/dist/core/backends/opencode-server-manager.js.map +1 -0
- package/dist/core/backends/opencode-types.d.ts +46 -0
- package/dist/core/backends/opencode-types.d.ts.map +1 -0
- package/dist/core/backends/opencode-types.js +14 -0
- package/dist/core/backends/opencode-types.js.map +1 -0
- package/dist/core/backends/plan-presets.d.ts +18 -5
- package/dist/core/backends/plan-presets.d.ts.map +1 -1
- package/dist/core/backends/plan-presets.js +144 -23
- package/dist/core/backends/plan-presets.js.map +1 -1
- package/dist/core/backends/process-config-cascade.d.ts +35 -0
- package/dist/core/backends/process-config-cascade.d.ts.map +1 -1
- package/dist/core/backends/process-config-cascade.js +35 -1
- package/dist/core/backends/process-config-cascade.js.map +1 -1
- package/dist/core/backends/prompt-utils.d.ts.map +1 -1
- package/dist/core/backends/prompt-utils.js +0 -2
- package/dist/core/backends/prompt-utils.js.map +1 -1
- package/dist/core/backends/quota-reset-hints.d.ts +44 -0
- package/dist/core/backends/quota-reset-hints.d.ts.map +1 -0
- package/dist/core/backends/quota-reset-hints.js +117 -0
- package/dist/core/backends/quota-reset-hints.js.map +1 -0
- package/dist/core/bang-commands/commands-close.d.ts +24 -0
- package/dist/core/bang-commands/commands-close.d.ts.map +1 -0
- package/dist/core/bang-commands/commands-close.js +24 -0
- package/dist/core/bang-commands/commands-close.js.map +1 -0
- package/dist/core/bang-commands/commands-cost.d.ts.map +1 -1
- package/dist/core/bang-commands/commands-cost.js +13 -0
- package/dist/core/bang-commands/commands-cost.js.map +1 -1
- package/dist/core/bang-commands/commands-help.d.ts.map +1 -1
- package/dist/core/bang-commands/commands-help.js +44 -5
- package/dist/core/bang-commands/commands-help.js.map +1 -1
- package/dist/core/bang-commands/commands-report.d.ts.map +1 -1
- package/dist/core/bang-commands/commands-report.js +1 -0
- package/dist/core/bang-commands/commands-report.js.map +1 -1
- package/dist/core/bang-commands/commands-stop-start.d.ts.map +1 -1
- package/dist/core/bang-commands/commands-stop-start.js +2 -0
- package/dist/core/bang-commands/commands-stop-start.js.map +1 -1
- package/dist/core/bang-commands/commands-wiki.d.ts.map +1 -1
- package/dist/core/bang-commands/commands-wiki.js +12 -1
- package/dist/core/bang-commands/commands-wiki.js.map +1 -1
- package/dist/core/bang-commands/format-utils.d.ts +13 -1
- package/dist/core/bang-commands/format-utils.d.ts.map +1 -1
- package/dist/core/bang-commands/format-utils.js +21 -2
- package/dist/core/bang-commands/format-utils.js.map +1 -1
- package/dist/core/bang-commands/index.d.ts +1 -0
- package/dist/core/bang-commands/index.d.ts.map +1 -1
- package/dist/core/bang-commands/index.js +3 -0
- package/dist/core/bang-commands/index.js.map +1 -1
- package/dist/core/bang-commands/registry.d.ts +50 -0
- package/dist/core/bang-commands/registry.d.ts.map +1 -1
- package/dist/core/bang-commands/registry.js +164 -19
- package/dist/core/bang-commands/registry.js.map +1 -1
- package/dist/core/channel-timeline.d.ts +18 -1
- package/dist/core/channel-timeline.d.ts.map +1 -1
- package/dist/core/channel-timeline.js +44 -0
- package/dist/core/channel-timeline.js.map +1 -1
- package/dist/core/context/activity-view-runner.js +9 -1
- package/dist/core/context/activity-view-runner.js.map +1 -1
- package/dist/core/context/default-schedules-runner.js +44 -4
- package/dist/core/context/default-schedules-runner.js.map +1 -1
- package/dist/core/context/domain-index-runner.js +9 -1
- package/dist/core/context/domain-index-runner.js.map +1 -1
- package/dist/core/context/entity-source-rename.d.ts.map +1 -1
- package/dist/core/context/entity-source-rename.js +9 -1
- package/dist/core/context/entity-source-rename.js.map +1 -1
- package/dist/core/context/policy-index-runner.js +9 -1
- package/dist/core/context/policy-index-runner.js.map +1 -1
- package/dist/core/context/reconciler-runner.js +9 -1
- package/dist/core/context/reconciler-runner.js.map +1 -1
- package/dist/core/context-builder.d.ts +97 -2
- package/dist/core/context-builder.d.ts.map +1 -1
- package/dist/core/context-builder.js +303 -30
- package/dist/core/context-builder.js.map +1 -1
- package/dist/core/context-frontmatter.d.ts +6 -0
- package/dist/core/context-frontmatter.d.ts.map +1 -1
- package/dist/core/context-frontmatter.js +120 -8
- package/dist/core/context-frontmatter.js.map +1 -1
- package/dist/core/context-health.js +21 -9
- package/dist/core/context-health.js.map +1 -1
- package/dist/core/context-validation/_pa_wip_context_validation/index.d.ts +19 -0
- package/dist/core/context-validation/_pa_wip_context_validation/index.d.ts.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/index.js +19 -0
- package/dist/core/context-validation/_pa_wip_context_validation/index.js.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/prepare-write.d.ts +94 -0
- package/dist/core/context-validation/_pa_wip_context_validation/prepare-write.d.ts.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/prepare-write.js +130 -0
- package/dist/core/context-validation/_pa_wip_context_validation/prepare-write.js.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/routine-rulebook.d.ts +60 -0
- package/dist/core/context-validation/_pa_wip_context_validation/routine-rulebook.d.ts.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/routine-rulebook.js +156 -0
- package/dist/core/context-validation/_pa_wip_context_validation/routine-rulebook.js.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/section.d.ts +41 -0
- package/dist/core/context-validation/_pa_wip_context_validation/section.d.ts.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/section.js +82 -0
- package/dist/core/context-validation/_pa_wip_context_validation/section.js.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/snapshot-debounce.d.ts +52 -0
- package/dist/core/context-validation/_pa_wip_context_validation/snapshot-debounce.d.ts.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/snapshot-debounce.js +110 -0
- package/dist/core/context-validation/_pa_wip_context_validation/snapshot-debounce.js.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/today.d.ts +85 -0
- package/dist/core/context-validation/_pa_wip_context_validation/today.d.ts.map +1 -0
- package/dist/core/context-validation/_pa_wip_context_validation/today.js +162 -0
- package/dist/core/context-validation/_pa_wip_context_validation/today.js.map +1 -0
- package/dist/core/context-validation/index.d.ts +19 -0
- package/dist/core/context-validation/index.d.ts.map +1 -0
- package/dist/core/context-validation/index.js +19 -0
- package/dist/core/context-validation/index.js.map +1 -0
- package/dist/core/context-validation/prepare-write.d.ts +95 -0
- package/dist/core/context-validation/prepare-write.d.ts.map +1 -0
- package/dist/core/context-validation/prepare-write.js +135 -0
- package/dist/core/context-validation/prepare-write.js.map +1 -0
- package/dist/core/context-validation/routine-rulebook.d.ts +60 -0
- package/dist/core/context-validation/routine-rulebook.d.ts.map +1 -0
- package/dist/core/context-validation/routine-rulebook.js +156 -0
- package/dist/core/context-validation/routine-rulebook.js.map +1 -0
- package/dist/core/context-validation/section.d.ts +41 -0
- package/dist/core/context-validation/section.d.ts.map +1 -0
- package/dist/core/context-validation/section.js +82 -0
- package/dist/core/context-validation/section.js.map +1 -0
- package/dist/core/context-validation/snapshot-debounce.d.ts +52 -0
- package/dist/core/context-validation/snapshot-debounce.d.ts.map +1 -0
- package/dist/core/context-validation/snapshot-debounce.js +110 -0
- package/dist/core/context-validation/snapshot-debounce.js.map +1 -0
- package/dist/core/context-validation/today.d.ts +85 -0
- package/dist/core/context-validation/today.d.ts.map +1 -0
- package/dist/core/context-validation/today.js +168 -0
- package/dist/core/context-validation/today.js.map +1 -0
- package/dist/core/daemon-api-cli.d.ts +6 -5
- package/dist/core/daemon-api-cli.d.ts.map +1 -1
- package/dist/core/daemon-api-cli.js +73 -32
- package/dist/core/daemon-api-cli.js.map +1 -1
- package/dist/core/dispatcher-error-handling.d.ts +13 -0
- package/dist/core/dispatcher-error-handling.d.ts.map +1 -1
- package/dist/core/dispatcher-error-handling.js +69 -0
- package/dist/core/dispatcher-error-handling.js.map +1 -1
- package/dist/core/dispatcher-hourly-check.d.ts +73 -1
- package/dist/core/dispatcher-hourly-check.d.ts.map +1 -1
- package/dist/core/dispatcher-hourly-check.js +249 -151
- package/dist/core/dispatcher-hourly-check.js.map +1 -1
- package/dist/core/dispatcher-message-handler.d.ts +11 -1
- package/dist/core/dispatcher-message-handler.d.ts.map +1 -1
- package/dist/core/dispatcher-message-handler.js +165 -47
- package/dist/core/dispatcher-message-handler.js.map +1 -1
- package/dist/core/dispatcher-morning-routine.d.ts +38 -30
- package/dist/core/dispatcher-morning-routine.d.ts.map +1 -1
- package/dist/core/dispatcher-morning-routine.js +162 -104
- package/dist/core/dispatcher-morning-routine.js.map +1 -1
- package/dist/core/dispatcher-prompt.d.ts +4 -1
- package/dist/core/dispatcher-prompt.d.ts.map +1 -1
- package/dist/core/dispatcher-prompt.js +18 -2
- package/dist/core/dispatcher-prompt.js.map +1 -1
- package/dist/core/dispatcher-repository-helpers.d.ts.map +1 -1
- package/dist/core/dispatcher-repository-helpers.js +5 -1
- package/dist/core/dispatcher-repository-helpers.js.map +1 -1
- package/dist/core/dispatcher-result-processor.d.ts.map +1 -1
- package/dist/core/dispatcher-result-processor.js +9 -4
- package/dist/core/dispatcher-result-processor.js.map +1 -1
- package/dist/core/dispatcher-scheduled-tasks.d.ts +1 -1
- package/dist/core/dispatcher-scheduled-tasks.d.ts.map +1 -1
- package/dist/core/dispatcher-scheduled-tasks.js +79 -16
- package/dist/core/dispatcher-scheduled-tasks.js.map +1 -1
- package/dist/core/dispatcher-types.d.ts +84 -12
- package/dist/core/dispatcher-types.d.ts.map +1 -1
- package/dist/core/dispatcher-types.js.map +1 -1
- package/dist/core/dispatcher.d.ts +50 -1
- package/dist/core/dispatcher.d.ts.map +1 -1
- package/dist/core/dispatcher.js +143 -8
- package/dist/core/dispatcher.js.map +1 -1
- package/dist/core/dm-freshness-metrics.d.ts +6 -5
- package/dist/core/dm-freshness-metrics.d.ts.map +1 -1
- package/dist/core/dm-freshness-metrics.js +7 -6
- package/dist/core/dm-freshness-metrics.js.map +1 -1
- package/dist/core/evening-review-verify.d.ts +164 -0
- package/dist/core/evening-review-verify.d.ts.map +1 -0
- package/dist/core/evening-review-verify.js +637 -0
- package/dist/core/evening-review-verify.js.map +1 -0
- package/dist/core/fetch-window-prompt-loader.d.ts +47 -0
- package/dist/core/fetch-window-prompt-loader.d.ts.map +1 -0
- package/dist/core/fetch-window-prompt-loader.js +72 -0
- package/dist/core/fetch-window-prompt-loader.js.map +1 -0
- package/dist/core/management-md.d.ts.map +1 -1
- package/dist/core/management-md.js +23 -9
- package/dist/core/management-md.js.map +1 -1
- package/dist/core/management-registry.d.ts +13 -21
- package/dist/core/management-registry.d.ts.map +1 -1
- package/dist/core/management-registry.js +27 -48
- package/dist/core/management-registry.js.map +1 -1
- package/dist/core/metrics.d.ts +88 -1
- package/dist/core/metrics.d.ts.map +1 -1
- package/dist/core/metrics.js +78 -2
- package/dist/core/metrics.js.map +1 -1
- package/dist/core/morning/agent-journal-appender.d.ts +197 -0
- package/dist/core/morning/agent-journal-appender.d.ts.map +1 -0
- package/dist/core/morning/agent-journal-appender.js +458 -0
- package/dist/core/morning/agent-journal-appender.js.map +1 -0
- package/dist/core/morning/handoff-parser.d.ts +45 -0
- package/dist/core/morning/handoff-parser.d.ts.map +1 -0
- package/dist/core/morning/handoff-parser.js +117 -0
- package/dist/core/morning/handoff-parser.js.map +1 -0
- package/dist/core/morning/journal-skeleton-builder.d.ts +157 -0
- package/dist/core/morning/journal-skeleton-builder.d.ts.map +1 -0
- package/dist/core/morning/journal-skeleton-builder.js +303 -0
- package/dist/core/morning/journal-skeleton-builder.js.map +1 -0
- package/dist/core/morning/orchestrator.d.ts +312 -0
- package/dist/core/morning/orchestrator.d.ts.map +1 -0
- package/dist/core/morning/orchestrator.js +827 -0
- package/dist/core/morning/orchestrator.js.map +1 -0
- package/dist/core/morning/parent-audit-emitter.d.ts +82 -0
- package/dist/core/morning/parent-audit-emitter.d.ts.map +1 -0
- package/dist/core/morning/parent-audit-emitter.js +120 -0
- package/dist/core/morning/parent-audit-emitter.js.map +1 -0
- package/dist/core/morning/roadmap-skeleton-builder.d.ts +159 -0
- package/dist/core/morning/roadmap-skeleton-builder.d.ts.map +1 -0
- package/dist/core/morning/roadmap-skeleton-builder.js +338 -0
- package/dist/core/morning/roadmap-skeleton-builder.js.map +1 -0
- package/dist/core/output-language-policy.js +1 -1
- package/dist/core/output-language-policy.js.map +1 -1
- package/dist/core/policy-files.d.ts +19 -2
- package/dist/core/policy-files.d.ts.map +1 -1
- package/dist/core/policy-files.js +65 -7
- package/dist/core/policy-files.js.map +1 -1
- package/dist/core/pre-pass-freshness.d.ts +28 -0
- package/dist/core/pre-pass-freshness.d.ts.map +1 -0
- package/dist/core/pre-pass-freshness.js +10 -0
- package/dist/core/pre-pass-freshness.js.map +1 -0
- package/dist/core/previous-week-digest.d.ts +130 -0
- package/dist/core/previous-week-digest.d.ts.map +1 -0
- package/dist/core/previous-week-digest.js +257 -0
- package/dist/core/previous-week-digest.js.map +1 -0
- package/dist/core/prompts.js +3 -3
- package/dist/core/prompts.js.map +1 -1
- package/dist/core/quiet-hours-sync.d.ts.map +1 -1
- package/dist/core/quiet-hours-sync.js +7 -0
- package/dist/core/quiet-hours-sync.js.map +1 -1
- package/dist/core/recurrence.d.ts +13 -0
- package/dist/core/recurrence.d.ts.map +1 -1
- package/dist/core/recurrence.js +108 -13
- package/dist/core/recurrence.js.map +1 -1
- package/dist/core/release-assets.d.ts +21 -1
- package/dist/core/release-assets.d.ts.map +1 -1
- package/dist/core/release-assets.js +58 -3
- package/dist/core/release-assets.js.map +1 -1
- package/dist/core/repository-management-docs.d.ts.map +1 -1
- package/dist/core/repository-management-docs.js +14 -4
- package/dist/core/repository-management-docs.js.map +1 -1
- package/dist/core/review-context.d.ts.map +1 -1
- package/dist/core/review-context.js +29 -1
- package/dist/core/review-context.js.map +1 -1
- package/dist/core/roadmap-maintenance.d.ts +213 -0
- package/dist/core/roadmap-maintenance.d.ts.map +1 -0
- package/dist/core/roadmap-maintenance.js +706 -0
- package/dist/core/roadmap-maintenance.js.map +1 -0
- package/dist/core/roadmap-validate.d.ts +5 -0
- package/dist/core/roadmap-validate.d.ts.map +1 -1
- package/dist/core/roadmap-validate.js +6 -69
- package/dist/core/roadmap-validate.js.map +1 -1
- package/dist/core/routine-acquisition-plan.d.ts +43 -7
- package/dist/core/routine-acquisition-plan.d.ts.map +1 -1
- package/dist/core/routine-acquisition-plan.js +99 -8
- package/dist/core/routine-acquisition-plan.js.map +1 -1
- package/dist/core/routine-fetch-window-retry.d.ts +41 -2
- package/dist/core/routine-fetch-window-retry.d.ts.map +1 -1
- package/dist/core/routine-fetch-window-retry.js +91 -8
- package/dist/core/routine-fetch-window-retry.js.map +1 -1
- package/dist/core/routine-fetch-window-runner.d.ts +55 -21
- package/dist/core/routine-fetch-window-runner.d.ts.map +1 -1
- package/dist/core/routine-fetch-window-runner.js +258 -35
- package/dist/core/routine-fetch-window-runner.js.map +1 -1
- package/dist/core/routine-windows.d.ts +17 -13
- package/dist/core/routine-windows.d.ts.map +1 -1
- package/dist/core/routine-windows.js +78 -36
- package/dist/core/routine-windows.js.map +1 -1
- package/dist/core/scheduler.d.ts +121 -37
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +359 -80
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/session-manager.d.ts +25 -6
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +32 -15
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/skeleton.d.ts.map +1 -1
- package/dist/core/skeleton.js +23 -23
- package/dist/core/skeleton.js.map +1 -1
- package/dist/core/skills-compiler.d.ts +275 -25
- package/dist/core/skills-compiler.d.ts.map +1 -1
- package/dist/core/skills-compiler.js +844 -205
- package/dist/core/skills-compiler.js.map +1 -1
- package/dist/core/skills-manifest.d.ts +104 -0
- package/dist/core/skills-manifest.d.ts.map +1 -1
- package/dist/core/skills-manifest.js +350 -39
- package/dist/core/skills-manifest.js.map +1 -1
- package/dist/core/wiki/git-precompile.d.ts +9 -0
- package/dist/core/wiki/git-precompile.d.ts.map +1 -1
- package/dist/core/wiki/git-precompile.js +7 -1
- package/dist/core/wiki/git-precompile.js.map +1 -1
- package/dist/core/workdir.d.ts +30 -1
- package/dist/core/workdir.d.ts.map +1 -1
- package/dist/core/workdir.js +140 -15
- package/dist/core/workdir.js.map +1 -1
- package/dist/db/entities-store.d.ts +5 -5
- package/dist/db/entities-store.js +5 -5
- package/dist/db/hourly-check-signals.d.ts.map +1 -1
- package/dist/db/hourly-check-signals.js +121 -35
- package/dist/db/hourly-check-signals.js.map +1 -1
- package/dist/db/observations.d.ts +1 -1
- package/dist/db/observations.js +1 -1
- package/dist/db/observations.js.map +1 -1
- package/dist/db/recurring-schedules.d.ts +32 -1
- package/dist/db/recurring-schedules.d.ts.map +1 -1
- package/dist/db/recurring-schedules.js +29 -10
- package/dist/db/recurring-schedules.js.map +1 -1
- package/dist/db/repositories-store.d.ts +2 -1
- package/dist/db/repositories-store.d.ts.map +1 -1
- package/dist/db/repositories-store.js +38 -3
- package/dist/db/repositories-store.js.map +1 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +157 -51
- package/dist/db/schema.js.map +1 -1
- package/dist/db/wiki-store.d.ts.map +1 -1
- package/dist/db/wiki-store.js +3 -0
- package/dist/db/wiki-store.js.map +1 -1
- package/dist/index.js +308 -1473
- package/dist/index.js.map +1 -1
- package/dist/messaging/magic-phrase.d.ts +16 -0
- package/dist/messaging/magic-phrase.d.ts.map +1 -1
- package/dist/messaging/magic-phrase.js +53 -0
- package/dist/messaging/magic-phrase.js.map +1 -1
- package/dist/messaging/owner-channels.d.ts +24 -0
- package/dist/messaging/owner-channels.d.ts.map +1 -1
- package/dist/messaging/owner-channels.js +38 -0
- package/dist/messaging/owner-channels.js.map +1 -1
- package/dist/messaging/setup-welcome-dm.d.ts +30 -0
- package/dist/messaging/setup-welcome-dm.d.ts.map +1 -0
- package/dist/messaging/setup-welcome-dm.js +86 -0
- package/dist/messaging/setup-welcome-dm.js.map +1 -0
- package/dist/observers/calendar-poller.d.ts +2 -0
- package/dist/observers/calendar-poller.d.ts.map +1 -1
- package/dist/observers/calendar-poller.js +76 -54
- package/dist/observers/calendar-poller.js.map +1 -1
- package/dist/observers/delegated-sync-worker.d.ts +62 -0
- package/dist/observers/delegated-sync-worker.d.ts.map +1 -1
- package/dist/observers/delegated-sync-worker.js +128 -1
- package/dist/observers/delegated-sync-worker.js.map +1 -1
- package/dist/observers/git-watcher.d.ts +22 -0
- package/dist/observers/git-watcher.d.ts.map +1 -1
- package/dist/observers/git-watcher.js +31 -7
- package/dist/observers/git-watcher.js.map +1 -1
- package/dist/observers/imminent-event-scheduler.d.ts +2 -0
- package/dist/observers/imminent-event-scheduler.d.ts.map +1 -1
- package/dist/observers/imminent-event-scheduler.js +29 -0
- package/dist/observers/imminent-event-scheduler.js.map +1 -1
- package/dist/observers/notion-poller.d.ts +2 -0
- package/dist/observers/notion-poller.d.ts.map +1 -1
- package/dist/observers/notion-poller.js +44 -6
- package/dist/observers/notion-poller.js.map +1 -1
- package/dist/observers/poll-guard.d.ts +63 -0
- package/dist/observers/poll-guard.d.ts.map +1 -0
- package/dist/observers/poll-guard.js +89 -0
- package/dist/observers/poll-guard.js.map +1 -0
- package/dist/safety/absolute-block-audit.d.ts +17 -0
- package/dist/safety/absolute-block-audit.d.ts.map +1 -1
- package/dist/safety/absolute-block-audit.js +28 -2
- package/dist/safety/absolute-block-audit.js.map +1 -1
- package/dist/safety/agent-write-tracker.d.ts +42 -1
- package/dist/safety/agent-write-tracker.d.ts.map +1 -1
- package/dist/safety/agent-write-tracker.js +81 -1
- package/dist/safety/agent-write-tracker.js.map +1 -1
- package/dist/safety/always-disallowed.d.ts +34 -0
- package/dist/safety/always-disallowed.d.ts.map +1 -1
- package/dist/safety/always-disallowed.js +114 -7
- package/dist/safety/always-disallowed.js.map +1 -1
- package/dist/safety/audit.d.ts +20 -0
- package/dist/safety/audit.d.ts.map +1 -1
- package/dist/safety/audit.js +126 -0
- package/dist/safety/audit.js.map +1 -1
- package/dist/safety/risk-classifier.d.ts +17 -1
- package/dist/safety/risk-classifier.d.ts.map +1 -1
- package/dist/safety/risk-classifier.js +75 -7
- package/dist/safety/risk-classifier.js.map +1 -1
- package/dist/safety/subprocess-block-scanner.d.ts +89 -0
- package/dist/safety/subprocess-block-scanner.d.ts.map +1 -0
- package/dist/safety/subprocess-block-scanner.js +177 -0
- package/dist/safety/subprocess-block-scanner.js.map +1 -0
- package/dist/scheduler/hourly-check-gate.d.ts +23 -9
- package/dist/scheduler/hourly-check-gate.d.ts.map +1 -1
- package/dist/scheduler/hourly-check-gate.js +11 -6
- package/dist/scheduler/hourly-check-gate.js.map +1 -1
- package/dist/secrets/backend-api-key-env.d.ts.map +1 -1
- package/dist/secrets/backend-api-key-env.js +1 -0
- package/dist/secrets/backend-api-key-env.js.map +1 -1
- package/dist/services/delegated-backend-invoker.d.ts.map +1 -1
- package/dist/services/delegated-backend-invoker.js +8 -1
- package/dist/services/delegated-backend-invoker.js.map +1 -1
- package/dist/services/delegated-invoker-audit.d.ts.map +1 -1
- package/dist/services/delegated-invoker-audit.js +5 -1
- package/dist/services/delegated-invoker-audit.js.map +1 -1
- package/dist/services/delegated-proxy-config.d.ts +3 -2
- package/dist/services/delegated-proxy-config.d.ts.map +1 -1
- package/dist/services/delegated-proxy-config.js.map +1 -1
- package/dist/services/integrations/extract-write-item-id.d.ts +5 -2
- package/dist/services/integrations/extract-write-item-id.d.ts.map +1 -1
- package/dist/services/integrations/extract-write-item-id.js.map +1 -1
- package/dist/services/mcp/generators/index.d.ts +1 -0
- package/dist/services/mcp/generators/index.d.ts.map +1 -1
- package/dist/services/mcp/generators/index.js +3 -0
- package/dist/services/mcp/generators/index.js.map +1 -1
- package/dist/services/mcp/sdk-observations-server.d.ts +60 -0
- package/dist/services/mcp/sdk-observations-server.d.ts.map +1 -0
- package/dist/services/mcp/sdk-observations-server.js +161 -0
- package/dist/services/mcp/sdk-observations-server.js.map +1 -0
- package/dist/services/mcp/session-materializer.d.ts.map +1 -1
- package/dist/services/mcp/session-materializer.js +13 -9
- package/dist/services/mcp/session-materializer.js.map +1 -1
- package/dist/services/mcp/types.d.ts +1 -0
- package/dist/services/mcp/types.d.ts.map +1 -1
- package/dist/services/notion.d.ts +19 -1
- package/dist/services/notion.d.ts.map +1 -1
- package/dist/services/notion.js +41 -2
- package/dist/services/notion.js.map +1 -1
- package/dist/services/observations-batch.d.ts +100 -0
- package/dist/services/observations-batch.d.ts.map +1 -0
- package/dist/services/observations-batch.js +258 -0
- package/dist/services/observations-batch.js.map +1 -0
- package/dist/services/voice/transcriber.d.ts +23 -0
- package/dist/services/voice/transcriber.d.ts.map +1 -1
- package/dist/services/voice/transcriber.js +55 -0
- package/dist/services/voice/transcriber.js.map +1 -1
- package/dist/settings/runtime-settings.d.ts +9 -6
- package/dist/settings/runtime-settings.d.ts.map +1 -1
- package/dist/settings/runtime-settings.js +50 -17
- package/dist/settings/runtime-settings.js.map +1 -1
- package/package.json +3 -2
- package/dist/api/delegated-proxy-helper.d.ts +0 -33
- package/dist/api/delegated-proxy-helper.d.ts.map +0 -1
- package/dist/api/delegated-proxy-helper.js +0 -54
- package/dist/api/delegated-proxy-helper.js.map +0 -1
- package/dist/core/roadmap-merge.d.ts +0 -7
- package/dist/core/roadmap-merge.d.ts.map +0 -1
- package/dist/core/roadmap-merge.js +0 -187
- package/dist/core/roadmap-merge.js.map +0 -1
- package/dist/db/test-schemas.d.ts +0 -23
- package/dist/db/test-schemas.d.ts.map +0 -1
- package/dist/db/test-schemas.js +0 -111
- package/dist/db/test-schemas.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,95 +1,36 @@
|
|
|
1
|
-
import { serve } from "@hono/node-server";
|
|
2
1
|
import { join, resolve } from "node:path";
|
|
3
|
-
import { rmSync } from "node:fs";
|
|
4
2
|
import { randomBytes } from "node:crypto";
|
|
5
|
-
import { loadConfig, getContextDir,
|
|
6
|
-
import { getDegradedMode, isSetupCompleted,
|
|
7
|
-
import { createDefaultBangCommandRegistry } from "./core/bang-commands/index.js";
|
|
3
|
+
import { loadConfig, getContextDir, runVaultHealthProbe, validateExternalObsidianVaultPath, } from "./config.js";
|
|
4
|
+
import { getDegradedMode, isSetupCompleted, isDegraded as readDegradedMode, } from "./db/runtime-state.js";
|
|
8
5
|
import { initDirectories } from "./init.js";
|
|
9
|
-
import { createDatabase } from "./db/client.js";
|
|
10
|
-
import { applySchema } from "./db/schema.js";
|
|
11
|
-
import { readIntegrations } from "./db/integrations-store.js";
|
|
12
|
-
import { getRepositoryByGithub, getRepositoryByLocalPath, listRepositories, selectGithubRepoSlugs, selectGitWatchedRepos, } from "./db/repositories-store.js";
|
|
13
|
-
import { dispatchMatchingTriggers } from "./core/trigger-dispatch.js";
|
|
14
6
|
import { EventBus } from "./core/event-bus.js";
|
|
15
7
|
import { AgentScheduler } from "./core/scheduler.js";
|
|
16
8
|
import { CustomRoutineScheduler } from "./core/custom-routine-scheduler.js";
|
|
17
9
|
import { HealthMonitor } from "./core/health-monitor.js";
|
|
18
10
|
import { Heartbeat } from "./core/heartbeat.js";
|
|
19
11
|
import { MessageHub } from "./adapters/message-hub.js";
|
|
20
|
-
import {
|
|
21
|
-
import { ObsidianWatcher } from "./observers/obsidian-watcher.js";
|
|
22
|
-
import { PrimaryVaultWatcher } from "./observers/primary-vault-watcher.js";
|
|
23
|
-
import { ContextIndexReconcilerObserver } from "./observers/context-index-reconciler-observer.js";
|
|
24
|
-
import { EntityMirrorObserver } from "./observers/entity-mirror-observer.js";
|
|
25
|
-
import { GitWatcher } from "./observers/git-watcher.js";
|
|
26
|
-
import { GitHubPoller } from "./observers/github-poller.js";
|
|
27
|
-
import { GitAccountRegistry } from "./services/git-account-registry.js";
|
|
28
|
-
import { GitDelegatedCronObserver, hasActiveDelegatedGitLifecycleIntegration, } from "./observers/git-delegated-cron.js";
|
|
29
|
-
import { RepositoryManagementCron } from "./observers/repository-management-cron.js";
|
|
30
|
-
import { ObservationSummarizerWorker, AnthropicSummarizerClient, UnsupportedSummarizerClient, } from "./observers/observation-summarizer/index.js";
|
|
31
|
-
import { CalendarPoller } from "./observers/calendar-poller.js";
|
|
32
|
-
import { ImminentEventScheduler } from "./observers/imminent-event-scheduler.js";
|
|
33
|
-
import { DelegatedSyncWorker, hasActiveDelegatedSyncIntegration, } from "./observers/delegated-sync-worker.js";
|
|
34
|
-
import { applyIntegrationModeChange, shouldStartObserversFor, } from "./core/integration-lifecycle.js";
|
|
35
|
-
import { NotionPoller } from "./observers/notion-poller.js";
|
|
12
|
+
import { resolvePrimaryPlatform } from "./adapters/primary-platform-resolver.js";
|
|
36
13
|
import { DiscordAdapter } from "./adapters/discord.js";
|
|
37
14
|
import { SlackAdapter } from "./adapters/slack-adapter.js";
|
|
38
15
|
import { TelegramAdapter } from "./adapters/telegram-adapter.js";
|
|
39
16
|
import { DashboardAdapter } from "./adapters/dashboard-adapter.js";
|
|
40
17
|
import { ObsidianService } from "./services/obsidian.js";
|
|
41
18
|
import { createServiceRegistry } from "./services/service-registry.js";
|
|
42
|
-
import { SignalDetector } from "./core/signal-detector.js";
|
|
43
|
-
import { EventDispatcher } from "./core/dispatcher.js";
|
|
44
|
-
import { ClaudeCodeCore } from "./core/backends/claude-code-core.js";
|
|
45
|
-
import { BackendRouter } from "./core/backends/backend-router.js";
|
|
46
|
-
import { ensureBackendMaterialized, syncAllUserSkills, buildConfiguredServices, refreshDmSessionWorkdirs, validateDelegatedStartup, } from "./core/workdir.js";
|
|
47
|
-
import { setWikiWorkspaceTokenResolver } from "./core/skills-compiler.js";
|
|
48
|
-
import { CodexCore } from "./core/backends/codex-core.js";
|
|
49
|
-
import { GeminiCliCore } from "./core/backends/gemini-cli-core.js";
|
|
50
|
-
import { PriceFetcher } from "./core/backends/price-fetcher.js";
|
|
51
|
-
import { AuthTelemetry } from "./core/backends/auth-telemetry.js";
|
|
52
|
-
import { AuthHealthMonitor, AUTH_PROBE_NOTIFICATION_CATEGORY } from "./core/backends/auth-health-monitor.js";
|
|
53
|
-
import { AuthRecovery } from "./core/backends/auth-recovery.js";
|
|
54
|
-
import { ContextBuilder } from "./core/context-builder.js";
|
|
55
|
-
import { getTaskFlow, initTaskFlows } from "./core/prompts.js";
|
|
56
|
-
import { listWikiWorkspaces, readDefaultWikiWorkspace, readWikiWorkspaceByName, } from "./core/wiki/workspaces.js";
|
|
57
|
-
import { backfillWikiFulltext } from "./core/wiki/wiki-fts.js";
|
|
58
19
|
import { ensureSkeletonFiles, resolveTemplatesRoot } from "./core/skeleton.js";
|
|
59
|
-
import { normalizeGitWatchedRepos, queueGitProjectUpdate, queueMissingGitProjectInits, seedGitProjectDocTemplates, } from "./core/git-project-docs.js";
|
|
60
20
|
import { reconcileTemplateAssets, recordInstructionAssetStatus, recordSkillAssetStatus, } from "./core/release-assets.js";
|
|
61
|
-
import { SessionManager } from "./core/session-manager.js";
|
|
62
|
-
import { MessageRecorder } from "./core/message-recorder.js";
|
|
63
|
-
import { ScopedReadSensitiveTokenManager } from "./core/read-sensitive-token-manager.js";
|
|
64
|
-
import { NotificationManager } from "./adapters/notification-manager.js";
|
|
65
|
-
import { recordProactiveForwardDeliveries } from "./core/channel-timeline.js";
|
|
66
|
-
import { continueDashboardSession as continueDashboardSessionFromHistory, endDashboardSession as endDashboardSessionFromChannel, markContextChanged, } from "./core/dashboard-session-controls.js";
|
|
67
|
-
import { AuditLogger } from "./safety/audit.js";
|
|
68
21
|
import { bootstrapManagementMd, startManagementMdWatcher, } from "./core/management-md.js";
|
|
69
22
|
import { bootstrapManagementRegistry, startManagementRegistryWatcher, } from "./core/management-registry.js";
|
|
70
|
-
import { bootstrapManagedTaskSeq } from "./db/managed-tasks-store.js";
|
|
71
23
|
import { startDocsIndexer, } from "./core/docs/indexer.js";
|
|
72
|
-
import { makeDbLookup as makeDocsCitationLookup } from "./core/docs/citation-validator.js";
|
|
73
|
-
import { createDocsRoutes } from "./api/routes/docs.js";
|
|
74
|
-
import { DocsQAAdapter } from "./adapters/docs-qa-adapter.js";
|
|
75
|
-
import { CompositeDashboardStream } from "./adapters/composite-dashboard-stream.js";
|
|
76
|
-
import { createApp } from "./api/server.js";
|
|
77
|
-
import { EventBroadcaster } from "./api/routes/sse.js";
|
|
78
24
|
import { APP_NAME, EventPriority, getBackendIds, } from "@aitne/shared";
|
|
79
|
-
import { getOwnerChannel } from "./messaging/owner-channels.js";
|
|
25
|
+
import { getOwnerChannel, selectFirstPairedPlatform, } from "./messaging/owner-channels.js";
|
|
80
26
|
import { SUPPORTED_MESSAGING_PLATFORMS, } from "./messaging/constants.js";
|
|
81
27
|
import { AgentWriteTracker } from "./safety/agent-write-tracker.js";
|
|
82
|
-
import {
|
|
83
|
-
import { applyPromptContextStaleness, } from "./core/context-staleness.js";
|
|
28
|
+
import { InMemoryTodayWriteLockManager, getTodayWriteLockTimeoutMs, } from "./core/today-write-lock.js";
|
|
84
29
|
import { InMemoryRoadmapWriteLockManager, getRoadmapWriteLockTimeoutMs, } from "./core/roadmap-write-lock.js";
|
|
30
|
+
import { runRoadmapMechanicalMaintenance } from "./core/roadmap-maintenance.js";
|
|
85
31
|
import { sweepExpiredMigrationBackups } from "./api/routes/setup-migrate.js";
|
|
86
|
-
import { createSettingsStore } from "./settings/settings-store.js";
|
|
87
32
|
import { PlatformSecretStore } from "./secrets/platform-secret-store.js";
|
|
88
33
|
import { FileEncryptedBlobStore } from "./secrets/encrypted-blob-store.js";
|
|
89
|
-
import { AttachmentStore } from "./services/attachments/store.js";
|
|
90
|
-
import { VoiceTranscriber } from "./services/voice/transcriber.js";
|
|
91
|
-
import { DelegatedBackendInvoker, runDelegatedTaskOrphanJanitor, runProxyTempdirJanitor, } from "./services/delegated-backend-invoker.js";
|
|
92
|
-
import { runSessionPoolTempdirJanitor } from "./services/delegated-task-session-pool.js";
|
|
93
34
|
import { MailAccountRegistry } from "./services/mail/account-registry.js";
|
|
94
35
|
import { loadOutlookClientConfig, OutlookClientConfigMissingError, } from "./services/mail/outlook/client-config.js";
|
|
95
36
|
import { createRuntimeMsalApp } from "./services/mail/outlook/msal-app-factory.js";
|
|
@@ -98,15 +39,16 @@ import { parseImapAccountSecret } from "./services/mail/imap/app-password.js";
|
|
|
98
39
|
import { ICloudImapProvider } from "./services/mail/imap/icloud-provider.js";
|
|
99
40
|
import { YahooImapProvider } from "./services/mail/imap/yahoo-provider.js";
|
|
100
41
|
import { GmailProvider } from "./services/mail/gmail/gmail-provider.js";
|
|
101
|
-
import { MailPoller } from "./observers/mail-poller.js";
|
|
102
|
-
import { MailReconciliationJob } from "./observers/mail-reconciliation.js";
|
|
103
42
|
import { SecretBroker } from "./secrets/secret-broker.js";
|
|
104
43
|
import { captureOriginalShellEnv, syncBackendApiKeyToEnv, } from "./secrets/backend-api-key-env.js";
|
|
105
44
|
import { createLogger, toSafeErrorMessage } from "./logging.js";
|
|
106
45
|
import { runCatchup, runPostMessagingCatchup, } from "./bootstrap/catchup.js";
|
|
107
|
-
import {
|
|
108
|
-
import { createAdapterReloaders, whatsappQrResponseFromAdapter, } from "./bootstrap/adapters.js";
|
|
46
|
+
import { createAdapterReloaders, } from "./bootstrap/adapters.js";
|
|
109
47
|
import { createInitialSecretState, createServiceReloaders, } from "./bootstrap/services.js";
|
|
48
|
+
import { initDatabase } from "./bootstrap/db.js";
|
|
49
|
+
import { createObservers } from "./bootstrap/observers.js";
|
|
50
|
+
import { startApiServer } from "./bootstrap/api.js";
|
|
51
|
+
import { createEventPipeline } from "./bootstrap/event-pipeline.js";
|
|
110
52
|
const logger = createLogger("daemon", {
|
|
111
53
|
transport: {
|
|
112
54
|
target: "pino-pretty",
|
|
@@ -141,106 +83,11 @@ async function startup() {
|
|
|
141
83
|
// ── 2. Directory structure ──
|
|
142
84
|
initDirectories(config);
|
|
143
85
|
// ── 3. Database ──
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return null;
|
|
149
|
-
// Match `context-builder.ts`'s per-event lookup: prefer the named
|
|
150
|
-
// workspace, fall back to the default. Without this, multi-workspace
|
|
151
|
-
// installs would render the `<wiki_workspace>` XML against the target
|
|
152
|
-
// workspace while skill prose (`{{vault_path}}` etc.) referenced the
|
|
153
|
-
// default — the agent would then operate on the wrong vault.
|
|
154
|
-
const workspace = (workspaceName ? readWikiWorkspaceByName(db, workspaceName) : null)
|
|
155
|
-
?? readDefaultWikiWorkspace(db);
|
|
156
|
-
if (!workspace)
|
|
157
|
-
return null;
|
|
158
|
-
return {
|
|
159
|
-
vault_path: workspace.root_path,
|
|
160
|
-
language: workspace.language,
|
|
161
|
-
workspace_name: workspace.name,
|
|
162
|
-
schema_version: String(workspace.schema_version),
|
|
163
|
-
};
|
|
86
|
+
// Schema apply + boot-time backfills + settings merge + delegated-task-mode
|
|
87
|
+
// default-correction. See `bootstrap/db.ts` for the per-step rationale.
|
|
88
|
+
const { db, settingsStore, persistedSettings, attachmentStore } = initDatabase({
|
|
89
|
+
config,
|
|
164
90
|
});
|
|
165
|
-
// WIKI_BUILDER_DESIGN.md §P4.A — boot-time FTS backfill. The
|
|
166
|
-
// `fts_wiki` virtual table is content-less and lives outside the
|
|
167
|
-
// mail-style trigger chain (the source is the filesystem, not a SQL
|
|
168
|
-
// table), so a fresh DB or a workspace seeded before P4 landed needs
|
|
169
|
-
// a one-shot rebuild. Per-workspace gate inside `backfillWikiFulltext`
|
|
170
|
-
// keeps this near-free in steady state.
|
|
171
|
-
backfillWikiFulltext(db, listWikiWorkspaces(db));
|
|
172
|
-
// §12 ("managed_tasks.id collision after restore from backup") — ensure
|
|
173
|
-
// `managed_task_seq.next_id` is greater than the max existing mt id so a
|
|
174
|
-
// backup-restored DB cannot collide with the seq counter on the next
|
|
175
|
-
// POST. No-op when the table is empty (steady-state cost: one SELECT).
|
|
176
|
-
bootstrapManagedTaskSeq(db);
|
|
177
|
-
// Close any dashboard_chat sessions that were left `active` from before
|
|
178
|
-
// the daemon restart. They cannot be resumed cleanly: the SSE channel is
|
|
179
|
-
// gone, and `Dispatcher.currentSetupMode` is in-process state lost on
|
|
180
|
-
// restart, so a setup conversation half-way through would otherwise be
|
|
181
|
-
// re-adopted by `findActiveDashboardSessionId` and processed as regular
|
|
182
|
-
// chat against stale prompts. The setup wizard's resume path on the
|
|
183
|
-
// client-side checks active status; closing here flips the check so the
|
|
184
|
-
// wizard correctly falls through to a fresh /setup/start.
|
|
185
|
-
try {
|
|
186
|
-
const result = db
|
|
187
|
-
.prepare(`UPDATE conversation_sessions
|
|
188
|
-
SET status = 'closed'
|
|
189
|
-
WHERE scope = 'dashboard_chat' AND status = 'active'`)
|
|
190
|
-
.run();
|
|
191
|
-
if (result.changes > 0) {
|
|
192
|
-
logger.info({ closed: result.changes }, "Closed orphaned dashboard_chat sessions from previous run");
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
catch (err) {
|
|
196
|
-
logger.warn({ err }, "Failed to close orphaned dashboard_chat sessions");
|
|
197
|
-
}
|
|
198
|
-
// Chat attachment store — constructed early so adapter reload functions
|
|
199
|
-
// can reference it in closure without TypeScript "used before declaration" issues.
|
|
200
|
-
const attachmentStore = new AttachmentStore(db, config.dataDir);
|
|
201
|
-
attachmentStore.reapOrphans(24);
|
|
202
|
-
void new PriceFetcher(config.dataDir, db).refresh();
|
|
203
|
-
const settingsStore = createSettingsStore(db);
|
|
204
|
-
const persistedSettings = settingsStore.getAll();
|
|
205
|
-
mergeRuntimeSettingsFromDb(config, persistedSettings);
|
|
206
|
-
try {
|
|
207
|
-
seedGitProjectDocTemplates(config.dataDir, config.workspaceDir);
|
|
208
|
-
}
|
|
209
|
-
catch (err) {
|
|
210
|
-
logger.warn({ err }, "Failed to seed git project document templates");
|
|
211
|
-
}
|
|
212
|
-
// ── Default-correction for `delegatedTaskModeEnabled` ──
|
|
213
|
-
// The legacy `/integrations/:key/invoke` RPC was retired 2026-05-01
|
|
214
|
-
// and every delegated skill / task flow now goes through `/exec`,
|
|
215
|
-
// which is gated by this flag. Its Phase-1 canary default of `false`
|
|
216
|
-
// is now a footgun: any user with delegated integrations from before
|
|
217
|
-
// the runtime PATCH-time auto-enable landed will hit 503 on every
|
|
218
|
-
// /exec call.
|
|
219
|
-
//
|
|
220
|
-
// Heal once at boot, only when the operator never explicitly chose:
|
|
221
|
-
// - `delegatedTaskModeEnabled` row is *absent* from settings (the
|
|
222
|
-
// `in` check distinguishes "never set" from "explicitly false"),
|
|
223
|
-
// - and at least one integration is currently in `delegated` mode.
|
|
224
|
-
//
|
|
225
|
-
// An explicit `false` row in `settings` is treated as operator intent
|
|
226
|
-
// and respected — emergency-disable still works.
|
|
227
|
-
if (!("delegatedTaskModeEnabled" in persistedSettings)
|
|
228
|
-
&& !config.delegatedTaskModeEnabled) {
|
|
229
|
-
const integrationsAtBoot = readIntegrations(db);
|
|
230
|
-
const delegatedKeys = Object.entries(integrationsAtBoot)
|
|
231
|
-
.filter(([, state]) => state.mode === "delegated")
|
|
232
|
-
.map(([key]) => key);
|
|
233
|
-
if (delegatedKeys.length > 0) {
|
|
234
|
-
try {
|
|
235
|
-
settingsStore.set("delegatedTaskModeEnabled", true);
|
|
236
|
-
config.delegatedTaskModeEnabled = true;
|
|
237
|
-
logger.info({ delegatedKeys }, "auto-enabled delegatedTaskModeEnabled at startup — delegated integrations exist and the flag was never explicitly set");
|
|
238
|
-
}
|
|
239
|
-
catch (err) {
|
|
240
|
-
logger.error({ err, delegatedKeys }, "startup auto-enable of delegatedTaskModeEnabled failed; /exec calls may continue to 503 until PATCH /api/config sets the flag");
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
91
|
// ── Integration Delegation Framework (Phase 1) ──
|
|
245
92
|
// Reconcile `<dataDir>/integrations.md` with the DB integrations map.
|
|
246
93
|
// Creates the file on first run, parses hand-edits if present, and
|
|
@@ -311,10 +158,10 @@ async function startup() {
|
|
|
311
158
|
// ── Management Registry boot reconcile (design 21 §7.2 / P2) ──
|
|
312
159
|
// Mirrors `bootstrapManagementMd` (which owns integrations.md). Reads
|
|
313
160
|
// `<contextDir>/rules/management.md` and reconciles its A-section with
|
|
314
|
-
// `settings.sot_bindings`; renders a fresh
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
//
|
|
161
|
+
// `settings.sot_bindings`; renders a fresh file when the on-disk
|
|
162
|
+
// schema_version does not match the current daemon's. Run after
|
|
163
|
+
// `ensureSkeletonFiles` so the seeded template is the parse target
|
|
164
|
+
// on first install.
|
|
318
165
|
try {
|
|
319
166
|
await bootstrapManagementRegistry(contextDir, db);
|
|
320
167
|
}
|
|
@@ -413,17 +260,61 @@ async function startup() {
|
|
|
413
260
|
});
|
|
414
261
|
if (Object.keys(result.errors).length > 0) {
|
|
415
262
|
logger.error({ platform, ownerId, errors: result.errors }, "Failed to persist detected owner ID to .env");
|
|
416
|
-
|
|
263
|
+
// B-1: throw so the adapter's captureOwner rolls back mutableOwnerId.
|
|
264
|
+
// Without this, the adapter would silently accept owner DMs in
|
|
265
|
+
// memory while .env shows no pairing — and the next daemon restart
|
|
266
|
+
// would lose the binding. The user's matcher stays armed
|
|
267
|
+
// (cancelPairing was not called) so they can retry by resending
|
|
268
|
+
// the phrase once the underlying env-write issue is resolved.
|
|
269
|
+
const errorKeys = Object.keys(result.errors).join(", ");
|
|
270
|
+
throw new Error(`Failed to persist ${platform} owner ID to .env: ${errorKeys}`);
|
|
417
271
|
}
|
|
418
272
|
logger.info({ platform, ownerId }, "auto-paired owner from discovery");
|
|
419
|
-
// Greet the user so they know pairing landed.
|
|
420
|
-
//
|
|
421
|
-
//
|
|
273
|
+
// Greet the user so they know pairing landed. P2-05: the inline
|
|
274
|
+
// "Pairing successful — this channel is now linked..." line used to
|
|
275
|
+
// fire here AND `sendSetupWelcomeDm` (WELCOME_DM_TEXT with menu) fired
|
|
276
|
+
// from the setup wizard's onSetupComplete — the operator got two
|
|
277
|
+
// greetings in quick succession when pairing happened during setup. We
|
|
278
|
+
// now prefer the consolidated welcome path so that initial pairing
|
|
279
|
+
// produces a single, menu-bearing DM rather than ack + welcome.
|
|
280
|
+
//
|
|
281
|
+
// Three-way UX contract:
|
|
282
|
+
//
|
|
283
|
+
// 1. First-time pairing (no latch yet) — `sendSetupWelcomeDm` fires
|
|
284
|
+
// the full WELCOME_DM_TEXT (includes ack + bang-command menu) and
|
|
285
|
+
// sets the latch. No inline ack needed.
|
|
286
|
+
//
|
|
287
|
+
// 2. Re-pairing onto a DIFFERENT platform (latch set on a prior
|
|
288
|
+
// platform) — the welcome path is latched globally and returns
|
|
289
|
+
// null. Without a fallback the operator would hear nothing back
|
|
290
|
+
// from the new platform, indistinguishable from a failed
|
|
291
|
+
// pairing. We send a short per-platform "Pairing successful" ack
|
|
292
|
+
// ONLY in this branch so the newly-paired platform confirms
|
|
293
|
+
// pairing landed without re-firing the full menu.
|
|
294
|
+
//
|
|
295
|
+
// 3. Re-pairing the SAME platform — same as case 2 (welcome latched,
|
|
296
|
+
// short ack fires). The ack is harmless even if the operator
|
|
297
|
+
// remembers the menu from before.
|
|
422
298
|
//
|
|
423
|
-
//
|
|
424
|
-
//
|
|
299
|
+
// Best-effort throughout: env-write already succeeded so the pairing
|
|
300
|
+
// is durable; a transient send failure must NOT roll back the
|
|
301
|
+
// persisted owner ID.
|
|
425
302
|
try {
|
|
426
|
-
|
|
303
|
+
const { sendSetupWelcomeDm } = await import("./messaging/setup-welcome-dm.js");
|
|
304
|
+
const welcomeDeliveries = await sendSetupWelcomeDm({ db, messageHub });
|
|
305
|
+
if (welcomeDeliveries === null) {
|
|
306
|
+
// Latched or no eligible at the time of first run — fall back to
|
|
307
|
+
// the targeted ack so the newly-paired platform doesn't end up
|
|
308
|
+
// silent. Scoped to JUST the platform that paired (not fan-out)
|
|
309
|
+
// because the welcome ALREADY covered the other configured
|
|
310
|
+
// platforms on the original pairing event.
|
|
311
|
+
try {
|
|
312
|
+
await messageHub.sendToPlatform(platform, "user", `Pairing successful — this channel is now linked as your owner DM.`);
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
logger.warn({ err, platform }, "Failed to deliver inline pairing ack (welcome was latched)");
|
|
316
|
+
}
|
|
317
|
+
}
|
|
427
318
|
}
|
|
428
319
|
catch (err) {
|
|
429
320
|
logger.warn({ err, platform }, "Failed to deliver welcome DM after auto-pairing");
|
|
@@ -604,12 +495,15 @@ async function startup() {
|
|
|
604
495
|
// the normalized phrase) accepts only DMs containing it. Defeats
|
|
605
496
|
// the previous "first DM wins" race entirely because attackers
|
|
606
497
|
// who can't see the dashboard can't see the phrase.
|
|
607
|
-
const { generateMagicPhrase, buildPhraseMatcher } = await import("./messaging/magic-phrase.js");
|
|
498
|
+
const { generateMagicPhrase, buildPhraseMatcher, isPhraseWrappedInExtraText } = await import("./messaging/magic-phrase.js");
|
|
608
499
|
const phrase = generateMagicPhrase();
|
|
609
500
|
const expiresAt = Date.now() + ttlMs;
|
|
610
501
|
adapter.startPairing({
|
|
611
502
|
match: buildPhraseMatcher(phrase),
|
|
612
503
|
expiresAt,
|
|
504
|
+
hintReply: (text) => isPhraseWrappedInExtraText(phrase, text)
|
|
505
|
+
? "Send the pairing phrase by itself, with no other text."
|
|
506
|
+
: null,
|
|
613
507
|
});
|
|
614
508
|
return { phrase, expiresAt };
|
|
615
509
|
},
|
|
@@ -645,12 +539,15 @@ async function startup() {
|
|
|
645
539
|
if (!adapter) {
|
|
646
540
|
throw new Error("Discord adapter is not initialized. Save the token and retry.");
|
|
647
541
|
}
|
|
648
|
-
const { generateMagicPhrase, buildPhraseMatcher } = await import("./messaging/magic-phrase.js");
|
|
542
|
+
const { generateMagicPhrase, buildPhraseMatcher, isPhraseWrappedInExtraText } = await import("./messaging/magic-phrase.js");
|
|
649
543
|
const phrase = generateMagicPhrase();
|
|
650
544
|
const expiresAt = Date.now() + ttlMs;
|
|
651
545
|
adapter.startPairing({
|
|
652
546
|
match: buildPhraseMatcher(phrase),
|
|
653
547
|
expiresAt,
|
|
548
|
+
hintReply: (text) => isPhraseWrappedInExtraText(phrase, text)
|
|
549
|
+
? "Send the pairing phrase by itself, with no other text."
|
|
550
|
+
: null,
|
|
654
551
|
});
|
|
655
552
|
return { phrase, expiresAt };
|
|
656
553
|
},
|
|
@@ -879,466 +776,34 @@ async function startup() {
|
|
|
879
776
|
}));
|
|
880
777
|
};
|
|
881
778
|
// ── 7. Observers ──
|
|
882
|
-
|
|
883
|
-
//
|
|
884
|
-
//
|
|
885
|
-
//
|
|
886
|
-
//
|
|
887
|
-
//
|
|
779
|
+
// The §7 block (5 hot-register builders + secondary observer
|
|
780
|
+
// registrations + the entity-mirror / context-index / MCP-auto-probe /
|
|
781
|
+
// observation-summarizer chain) lives in `bootstrap/observers.ts`.
|
|
782
|
+
// Mutable indirection: observers are constructed inside the factory,
|
|
783
|
+
// but the dispatcher (owner of `emitRoadmapRefresh`) is created later
|
|
784
|
+
// in §10. Pollers store the `triggerRoadmapRefresh` callback below
|
|
785
|
+
// and only invoke it from their poll loops, which run after
|
|
786
|
+
// `observerManager.startAll()` — by then the dispatcher has been
|
|
787
|
+
// wired via the assignment in §13 and the indirection resolves.
|
|
888
788
|
// ROADMAP-REDESIGN §3.4 RFC-C.
|
|
889
789
|
let emitRoadmapRefreshSink = null;
|
|
890
790
|
const triggerRoadmapRefresh = (source) => {
|
|
891
791
|
emitRoadmapRefreshSink?.(source);
|
|
892
792
|
};
|
|
893
|
-
const
|
|
894
|
-
// P5 multi-account — registry resolves `gitAccounts[<alias>]` to a
|
|
895
|
-
// `{GH_TOKEN, GIT_ASKPASS, ...}` env overlay each observer applies
|
|
896
|
-
// per-call. The `getAccounts` thunk reads `config.gitAccounts` lazily
|
|
897
|
-
// so a `PATCH /api/config` that mutates `config` in place via
|
|
898
|
-
// `applyConfigUpdates`'s `Object.assign(config, runtimeUpdates)`
|
|
899
|
-
// flows through to the next resolver call without re-instantiation
|
|
900
|
-
// — which is why `gitAccounts` is NOT in `RESTART_REQUIRED_KEY_TUPLE`.
|
|
901
|
-
// Per-repo PAT secrets live in the OS keychain at
|
|
902
|
-
// `git.account.<alias>` (see secret-names.ts ScopedSecretName).
|
|
903
|
-
const gitAccountRegistry = new GitAccountRegistry({
|
|
904
|
-
dataDir: config.dataDir,
|
|
905
|
-
secretBroker,
|
|
906
|
-
getAccounts: () => config.gitAccounts,
|
|
907
|
-
});
|
|
908
|
-
// One-time info note: github-side rows without a local clone always
|
|
909
|
-
// poll under the default `gh` profile when the row's `github_account`
|
|
910
|
-
// is null. Surface this if both `gitAccounts` and github-only rows
|
|
911
|
-
// exist so a user staring at unaccounted-for traffic from "the wrong
|
|
912
|
-
// account" sees it in `aitne logs` rather than guessing.
|
|
913
|
-
const githubOnlyRows = selectGithubRepoSlugs(db).length;
|
|
914
|
-
if (Object.keys(config.gitAccounts ?? {}).length > 0
|
|
915
|
-
&& githubOnlyRows > 0) {
|
|
916
|
-
logger.info({
|
|
917
|
-
gitAccounts: Object.keys(config.gitAccounts).length,
|
|
918
|
-
githubRepos: githubOnlyRows,
|
|
919
|
-
}, "GitHub-side repository rows fall back to the default gh profile when github_account is unset. Set the row's account alias from /api/repositories or the dashboard.");
|
|
920
|
-
}
|
|
921
|
-
const lookupRepoAlias = (repoPath, fullName) => {
|
|
922
|
-
const repos = getNormalizedGitRepos();
|
|
923
|
-
if (repoPath) {
|
|
924
|
-
const byPath = repos.find((r) => r.path === repoPath);
|
|
925
|
-
if (byPath?.accountAlias)
|
|
926
|
-
return byPath.accountAlias;
|
|
927
|
-
}
|
|
928
|
-
if (fullName) {
|
|
929
|
-
const byOrgRepo = repos.find((r) => {
|
|
930
|
-
if (!r.org)
|
|
931
|
-
return false;
|
|
932
|
-
// Repos resolved from `githubRepos` (not local paths) match by full name.
|
|
933
|
-
return fullName.toLowerCase() === `${r.org}/${r.slug}`.toLowerCase();
|
|
934
|
-
});
|
|
935
|
-
if (byOrgRepo?.accountAlias)
|
|
936
|
-
return byOrgRepo.accountAlias;
|
|
937
|
-
}
|
|
938
|
-
return undefined;
|
|
939
|
-
};
|
|
940
|
-
const queueGitProjectInitsForCurrentConfig = (source) => {
|
|
941
|
-
if (!isSetupCompleted(db) || readDegradedMode(db))
|
|
942
|
-
return;
|
|
943
|
-
const repos = getNormalizedGitRepos();
|
|
944
|
-
if (repos.length === 0)
|
|
945
|
-
return;
|
|
946
|
-
try {
|
|
947
|
-
const inserted = queueMissingGitProjectInits({
|
|
948
|
-
db,
|
|
949
|
-
contextDir: getContextDir(config, db),
|
|
950
|
-
dataDir: config.dataDir,
|
|
951
|
-
workspaceDir: config.workspaceDir,
|
|
952
|
-
repos,
|
|
953
|
-
});
|
|
954
|
-
if (inserted > 0) {
|
|
955
|
-
logger.info({ inserted, source }, "Queued missing git project documentation init tasks");
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
catch (err) {
|
|
959
|
-
logger.warn({ err, source }, "Failed to queue git project documentation init tasks");
|
|
960
|
-
}
|
|
961
|
-
};
|
|
962
|
-
const gitWatchedRepos = getNormalizedGitRepos();
|
|
963
|
-
const gitRepoPaths = gitWatchedRepos.map((repo) => repo.path);
|
|
964
|
-
let gitWatcher = null;
|
|
965
|
-
const buildGitWatcher = () => {
|
|
966
|
-
if (gitRepoPaths.length === 0)
|
|
967
|
-
return null;
|
|
968
|
-
// Per-row poll cadence (unified-repositories §5). Sourced from each
|
|
969
|
-
// row's `poll_interval_sec` column; rows with null fall through to
|
|
970
|
-
// the global `gitPollIntervalSeconds`.
|
|
971
|
-
const repoIntervals = new Map(gitWatchedRepos.map((row) => [row.path, row.pollIntervalSec ?? null]));
|
|
972
|
-
const watcher = new GitWatcher(gitRepoPaths, db, config.gitPollIntervalSeconds, {
|
|
973
|
-
eventBus,
|
|
974
|
-
pushOverdueMinutes: config.gitPushOverdueMinutes,
|
|
975
|
-
repoIntervals,
|
|
976
|
-
repoEnvResolver: async (repoPath) => {
|
|
977
|
-
const alias = lookupRepoAlias(repoPath);
|
|
978
|
-
if (!alias)
|
|
979
|
-
return undefined;
|
|
980
|
-
return (await gitAccountRegistry.buildSpawnEnv(alias)) ?? undefined;
|
|
981
|
-
},
|
|
982
|
-
onRepoBaseline: (repoPath) => {
|
|
983
|
-
const repo = getNormalizedGitRepos().find((item) => item.path === repoPath);
|
|
984
|
-
if (!repo)
|
|
985
|
-
return;
|
|
986
|
-
queueGitProjectInitsForCurrentConfig("git-baseline");
|
|
987
|
-
},
|
|
988
|
-
onLifecycleObservation: (classification) => {
|
|
989
|
-
if (!isSetupCompleted(db) || readDegradedMode(db))
|
|
990
|
-
return;
|
|
991
|
-
const repoPath = typeof classification.payload.repoPath === "string"
|
|
992
|
-
? classification.payload.repoPath
|
|
993
|
-
: classification.source.replace(/^git:/, "");
|
|
994
|
-
const repo = getNormalizedGitRepos().find((item) => item.path === repoPath);
|
|
995
|
-
if (!repo)
|
|
996
|
-
return;
|
|
997
|
-
const result = queueGitProjectUpdate({
|
|
998
|
-
db,
|
|
999
|
-
dataDir: config.dataDir,
|
|
1000
|
-
workspaceDir: config.workspaceDir,
|
|
1001
|
-
repo,
|
|
1002
|
-
event: classification,
|
|
1003
|
-
debounceMinutes: config.gitProjectUpdateDebounceMinutes,
|
|
1004
|
-
});
|
|
1005
|
-
if (result === "queued" || result === "merged") {
|
|
1006
|
-
logger.info({
|
|
1007
|
-
repo: repo.path,
|
|
1008
|
-
eventType: classification.eventType,
|
|
1009
|
-
result,
|
|
1010
|
-
}, "Queued git project documentation update");
|
|
1011
|
-
}
|
|
1012
|
-
// Unified-repositories §4.4 — fire any per-repo triggers
|
|
1013
|
-
// configured for this lifecycle event. Triggers ride alongside
|
|
1014
|
-
// the task-flow pipeline above; they do not consume the event.
|
|
1015
|
-
const repositoryRow = getRepositoryByLocalPath(db, repoPath);
|
|
1016
|
-
if (repositoryRow) {
|
|
1017
|
-
void dispatchMatchingTriggers({ db, eventBus }, repositoryRow.id, classification.eventType, classification.payload);
|
|
1018
|
-
}
|
|
1019
|
-
},
|
|
1020
|
-
});
|
|
1021
|
-
gitWatcher = watcher;
|
|
1022
|
-
return watcher;
|
|
1023
|
-
};
|
|
1024
|
-
if (shouldStartObserversFor(db, "git")) {
|
|
1025
|
-
const watcher = buildGitWatcher();
|
|
1026
|
-
if (watcher)
|
|
1027
|
-
observerManager.register(watcher);
|
|
1028
|
-
}
|
|
1029
|
-
// GitHubPoller — daemon-side notification + workflow_run polling via the
|
|
1030
|
-
// user's `gh auth login` keychain entry. Replaces the webhook receiver
|
|
1031
|
-
// for local-first installs where exposing a public URL is impractical.
|
|
1032
|
-
// Registered only while github.mode === "direct" now that GitHub is a
|
|
1033
|
-
// first-class integration. Direct remains the default, preserving the
|
|
1034
|
-
// historical "notifications on when gh is authenticated" behaviour.
|
|
1035
|
-
const buildGithubPoller = () => {
|
|
1036
|
-
// Per-row poll cadence (unified-repositories §5). The map is keyed by
|
|
1037
|
-
// `owner/repo` to match `RepoBinding.fullName`; rows are sourced from
|
|
1038
|
-
// the unified table. Local-only rows have no `owner/repo` and fall
|
|
1039
|
-
// out of the map naturally.
|
|
1040
|
-
const repoIntervals = new Map();
|
|
1041
|
-
for (const row of listRepositories(db, { hasGithub: true })) {
|
|
1042
|
-
if (row.githubOwner && row.githubRepo) {
|
|
1043
|
-
repoIntervals.set(`${row.githubOwner}/${row.githubRepo}`, row.pollIntervalSec ?? null);
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
return new GitHubPoller({
|
|
1047
|
-
db,
|
|
1048
|
-
eventBus,
|
|
1049
|
-
repoPaths: gitRepoPaths,
|
|
1050
|
-
repoFullNames: selectGithubRepoSlugs(db),
|
|
1051
|
-
pollIntervalSeconds: config.githubPollIntervalSeconds,
|
|
1052
|
-
repoIntervals,
|
|
1053
|
-
repoAccountAliasResolver: ({ localPath, fullName }) => lookupRepoAlias(localPath, fullName),
|
|
1054
|
-
accountResolver: async (binding) => {
|
|
1055
|
-
if (!binding.accountAlias)
|
|
1056
|
-
return undefined;
|
|
1057
|
-
return ((await gitAccountRegistry.buildSpawnEnv(binding.accountAlias)) ?? undefined);
|
|
1058
|
-
},
|
|
1059
|
-
// Unified-repositories §4.4 — resolve the binding's owner/repo to a
|
|
1060
|
-
// repositories.id and fire any per-repo triggers configured for
|
|
1061
|
-
// this event type. Failures are logged inside dispatch and do not
|
|
1062
|
-
// bubble out so a misconfigured trigger cannot stall the poll loop.
|
|
1063
|
-
onTriggerableEvent: async (event) => {
|
|
1064
|
-
if (!isSetupCompleted(db) || readDegradedMode(db))
|
|
1065
|
-
return;
|
|
1066
|
-
let repoRow = null;
|
|
1067
|
-
if (event.binding) {
|
|
1068
|
-
repoRow = getRepositoryByGithub(db, event.binding.owner, event.binding.repo);
|
|
1069
|
-
}
|
|
1070
|
-
if (!repoRow) {
|
|
1071
|
-
// Notifications without a `directNotificationRepos` match still
|
|
1072
|
-
// arrive here when a `repository.full_name` is in the payload.
|
|
1073
|
-
const fullName = typeof event.payload.repository === "string"
|
|
1074
|
-
? event.payload.repository
|
|
1075
|
-
: null;
|
|
1076
|
-
if (fullName) {
|
|
1077
|
-
const [owner, repo] = fullName.split("/");
|
|
1078
|
-
if (owner && repo) {
|
|
1079
|
-
repoRow = getRepositoryByGithub(db, owner, repo);
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
if (!repoRow)
|
|
1084
|
-
return;
|
|
1085
|
-
await dispatchMatchingTriggers({ db, eventBus }, repoRow.id, event.eventType, event.payload);
|
|
1086
|
-
},
|
|
1087
|
-
});
|
|
1088
|
-
};
|
|
1089
|
-
if (shouldStartObserversFor(db, "github")) {
|
|
1090
|
-
observerManager.register(buildGithubPoller());
|
|
1091
|
-
}
|
|
1092
|
-
// Each call returns a fresh observer so the integration-lifecycle helper
|
|
1093
|
-
// re-registers a new instance after a mode flip — picking up any
|
|
1094
|
-
// gitPollIntervalSeconds / gitPushOverdueMinutes / hourlyCheckEnabled
|
|
1095
|
-
// PATCH that landed while the cron was idle.
|
|
1096
|
-
const buildGitDelegatedCronObserver = () => new GitDelegatedCronObserver({
|
|
1097
|
-
db,
|
|
1098
|
-
eventBus,
|
|
1099
|
-
repoPaths: gitRepoPaths,
|
|
1100
|
-
githubRepos: selectGithubRepoSlugs(db),
|
|
1101
|
-
cadenceSeconds: config.gitPollIntervalSeconds,
|
|
1102
|
-
pushOverdueMinutes: config.gitPushOverdueMinutes,
|
|
1103
|
-
hourlyCheckEnabled: config.hourlyCheckEnabled,
|
|
1104
|
-
});
|
|
1105
|
-
if (hasActiveDelegatedGitLifecycleIntegration(db)) {
|
|
1106
|
-
observerManager.register(buildGitDelegatedCronObserver());
|
|
1107
|
-
}
|
|
1108
|
-
// Unified-repositories daily management cron — see
|
|
1109
|
-
// docs/design/appendices/unified-repositories.md §4.5. Iterates rows
|
|
1110
|
-
// whose `repository_management.enabled = 1` and writes the required
|
|
1111
|
-
// journal/overview markdown for each row that's due.
|
|
1112
|
-
observerManager.register(new RepositoryManagementCron({
|
|
793
|
+
const observers = await createObservers({
|
|
1113
794
|
db,
|
|
795
|
+
config,
|
|
1114
796
|
eventBus,
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
writeTracker,
|
|
1118
|
-
}));
|
|
1119
|
-
// Coexistence note: the legacy /webhook/github handler also calls
|
|
1120
|
-
// recordObservation + EventBus.put, so a user with both webhooks AND
|
|
1121
|
-
// the poller live will receive two events per `review_requested`. This
|
|
1122
|
-
// is a low-probability scenario (webhooks need a public URL most users
|
|
1123
|
-
// don't expose), so we log a one-time warning rather than disabling
|
|
1124
|
-
// either path automatically.
|
|
1125
|
-
if (secretState.githubWebhookConfigured && shouldStartObserversFor(db, "github")) {
|
|
1126
|
-
logger.warn("GitHub webhook secret configured AND GitHubPoller running — "
|
|
1127
|
-
+ "duplicate events possible. Remove the webhook secret or unregister "
|
|
1128
|
-
+ "the GitHub webhook on github.com to silence.");
|
|
1129
|
-
}
|
|
1130
|
-
// SETUP-FLOW-REDESIGN-PLAN §6.3 — `externalObsidianWatch` is a kill
|
|
1131
|
-
// switch for the external-vault branch of the watcher. When false the
|
|
1132
|
-
// path is preserved (the Obsidian CLI skill still sees it via
|
|
1133
|
-
// `config.externalObsidianVaultPath`) but no chokidar instance is
|
|
1134
|
-
// registered. Sized for power users with very large vaults that would
|
|
1135
|
-
// otherwise produce noisy observation churn (§13 open question).
|
|
1136
|
-
if (config.externalObsidianVaultPath && config.externalObsidianWatch) {
|
|
1137
|
-
observerManager.register(new ObsidianWatcher(config.externalObsidianVaultPath, db, config.obsidianDebounceSeconds, writeTracker, { source: "obsidian:external", name: "obsidian:external" }));
|
|
1138
|
-
}
|
|
1139
|
-
// Primary-vault watcher — registered unconditionally. Stays dormant
|
|
1140
|
-
// until `setVaultPath` points it at a real directory. The migration
|
|
1141
|
-
// endpoint's `onPrimaryVaultPathChange` callback calls setVaultPath
|
|
1142
|
-
// explicitly after every commit, so plain → obsidian transitions
|
|
1143
|
-
// and obsidian-path changes both re-target without dynamic
|
|
1144
|
-
// register/unregister plumbing.
|
|
1145
|
-
const primaryVaultWatcher = new PrimaryVaultWatcher(db, config.obsidianDebounceSeconds, writeTracker);
|
|
1146
|
-
await primaryVaultWatcher.setVaultPath(config.vaultMode === "obsidian" ? config.primaryVaultPath : null);
|
|
1147
|
-
observerManager.register(primaryVaultWatcher);
|
|
1148
|
-
// Build CalendarPoller from current services. Returns null when
|
|
1149
|
-
// `services.calendar` is unavailable so the integration-lifecycle
|
|
1150
|
-
// module can no-op (for example: integration flips to direct before
|
|
1151
|
-
// OAuth is set up). The §4.5.1 gate `google_calendar.mode === "direct"`
|
|
1152
|
-
// is checked BEFORE invoking the builder.
|
|
1153
|
-
const buildCalendarPoller = () => {
|
|
1154
|
-
if (!services.calendar)
|
|
1155
|
-
return null;
|
|
1156
|
-
return new CalendarPoller(services.calendar, db, config.calendarPollIntervalSeconds, config.googleCalendarId, writeTracker, triggerRoadmapRefresh, morningRoutineLock, config.timezone);
|
|
1157
|
-
};
|
|
1158
|
-
if (services.calendar && shouldStartObserversFor(db, "google_calendar")) {
|
|
1159
|
-
const poller = buildCalendarPoller();
|
|
1160
|
-
if (poller)
|
|
1161
|
-
observerManager.register(poller);
|
|
1162
|
-
}
|
|
1163
|
-
observerManager.register(new ImminentEventScheduler(db, eventBus, config.googleCalendarId));
|
|
1164
|
-
// Build NotionPoller from current services + config. Returns null when
|
|
1165
|
-
// `services.notion` is unavailable or no databases are configured so
|
|
1166
|
-
// the integration-lifecycle module can no-op (e.g. integration flips
|
|
1167
|
-
// to direct before the API key is set up). The §4.5.1 gate
|
|
1168
|
-
// `notion.mode === "direct"` is checked BEFORE invoking the builder.
|
|
1169
|
-
const buildNotionPoller = () => {
|
|
1170
|
-
if (!services.notion)
|
|
1171
|
-
return null;
|
|
1172
|
-
if (Object.keys(config.notionDatabaseIds).length === 0)
|
|
1173
|
-
return null;
|
|
1174
|
-
return new NotionPoller({
|
|
1175
|
-
notionService: services.notion,
|
|
1176
|
-
databaseIds: config.notionDatabaseIds,
|
|
1177
|
-
pollIntervalSeconds: config.notionPollIntervalSeconds,
|
|
1178
|
-
db,
|
|
1179
|
-
writeTracker,
|
|
1180
|
-
});
|
|
1181
|
-
};
|
|
1182
|
-
if (services.notion
|
|
1183
|
-
&& Object.keys(config.notionDatabaseIds).length > 0
|
|
1184
|
-
&& shouldStartObserversFor(db, "notion")) {
|
|
1185
|
-
const poller = buildNotionPoller();
|
|
1186
|
-
if (poller)
|
|
1187
|
-
observerManager.register(poller);
|
|
1188
|
-
}
|
|
1189
|
-
if (services.mail) {
|
|
1190
|
-
observerManager.register(new MailPoller({
|
|
1191
|
-
registry: services.mail,
|
|
1192
|
-
db,
|
|
1193
|
-
writeTracker,
|
|
1194
|
-
pollIntervalSeconds: config.mailPollIntervalSeconds,
|
|
1195
|
-
maxMessagesPerPoll: config.mailMaxMessagesPerPoll,
|
|
1196
|
-
authFailureRetryHours: config.mailAuthFailureRetryHours,
|
|
1197
|
-
providerPollIntervalsSeconds: {
|
|
1198
|
-
gmail: config.gmailPollIntervalSeconds,
|
|
1199
|
-
},
|
|
1200
|
-
notifyOwner: async (message) => {
|
|
1201
|
-
await messageHub.sendToUser(message);
|
|
1202
|
-
},
|
|
1203
|
-
triggerRoadmapRefresh,
|
|
1204
|
-
}));
|
|
1205
|
-
observerManager.register(new MailReconciliationJob({
|
|
1206
|
-
registry: services.mail,
|
|
1207
|
-
db,
|
|
1208
|
-
}));
|
|
1209
|
-
}
|
|
1210
|
-
// ── 7.04 Skill-curation observers (P22 — appendix p22-skill-self-optimization.md) ──
|
|
1211
|
-
// Hourly walker accumulates `structure_diff` signals for the curation
|
|
1212
|
-
// cohort. Outcomes/feedback collection was dropped from the Preview scope
|
|
1213
|
-
// — the feature optimizes silently in the background, no metrics surface.
|
|
1214
|
-
{
|
|
1215
|
-
const { SkillCurationWalker } = await import("./observers/skill-curation-walker.js");
|
|
1216
|
-
observerManager.register(new SkillCurationWalker(db, getContextDir(config), join(config.workspaceDir, "agent-assets", "skills"), config.dataDir));
|
|
1217
|
-
// §5.4 — boot-time orphan-overlay scan. Emits one log line per orphan
|
|
1218
|
-
// and seeds `runtime_state.skill_curation.orphan_overlays` so the
|
|
1219
|
-
// dashboard banner can read it without re-walking the FS.
|
|
1220
|
-
try {
|
|
1221
|
-
const { scanAndRecordOrphanOverlays } = await import("./core/skill-curation/orphan-overlay.js");
|
|
1222
|
-
scanAndRecordOrphanOverlays(db, config.dataDir, join(config.workspaceDir, "agent-assets", "skills"));
|
|
1223
|
-
}
|
|
1224
|
-
catch (err) {
|
|
1225
|
-
logger.warn({ err }, "Skill-curation orphan-overlay scan failed at boot");
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
// ── 7.05 Context-index reconciler (B-004 Phase 2a) ──
|
|
1229
|
-
// Keeps `context/context-index.md` in sync with the filesystem so the
|
|
1230
|
-
// per-flow review-context loader can treat the index as authoritative.
|
|
1231
|
-
// Combines: startup one-shot (30 s after boot), internal chokidar
|
|
1232
|
-
// watcher on contextDir (10 s debounce), cron nightly (wired via
|
|
1233
|
-
// `AgentScheduler.setContextIndexReconcilerCallback`), and API-route
|
|
1234
|
-
// hints via `onIndexableContextChange` below.
|
|
1235
|
-
let contextIndexReconcilerPromptSink = null;
|
|
1236
|
-
const contextIndexReconciler = new ContextIndexReconcilerObserver({
|
|
1237
|
-
db,
|
|
1238
|
-
contextDir: getContextDir(config),
|
|
797
|
+
secretBroker,
|
|
798
|
+
services,
|
|
1239
799
|
writeTracker,
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
// prompt-cache invalidation through the same handler every other
|
|
1243
|
-
// context write uses. The real handler is installed in §11
|
|
1244
|
-
// (`onPromptContextChanged` ApiDependency); this indirection lets
|
|
1245
|
-
// the observer start at §7 before the handler exists.
|
|
1246
|
-
contextIndexReconcilerPromptSink?.(path, reason, tier, metadata);
|
|
1247
|
-
},
|
|
800
|
+
blobStore,
|
|
801
|
+
messageHub,
|
|
1248
802
|
morningRoutineLock,
|
|
1249
|
-
|
|
803
|
+
secretState,
|
|
804
|
+
triggerRoadmapRefresh,
|
|
1250
805
|
});
|
|
1251
|
-
observerManager
|
|
1252
|
-
// docs/design/21-management-registry-and-entities.md §7.6 P5 —
|
|
1253
|
-
// entity-mirror watcher. Owns its own chokidar watcher (independent
|
|
1254
|
-
// of the context-index reconciler's debounce path) so single-file
|
|
1255
|
-
// L2 writes converge into the SQLite mirror within NFR-9's 500 ms
|
|
1256
|
-
// budget — the §7.6 lookup contract relies on this freshness at
|
|
1257
|
-
// scheduled-task fire time. Boot pass + watcher lifecycle handled
|
|
1258
|
-
// by the observer wrapper.
|
|
1259
|
-
//
|
|
1260
|
-
// §7.2 chain — fan an L2 entity delta out to the context-index
|
|
1261
|
-
// observer's `requestReconcile` so the rendered domain-index +
|
|
1262
|
-
// activity-view files refresh on the same 10 s debounce as other
|
|
1263
|
-
// fs_event triggers. Without this, those views only converged on
|
|
1264
|
-
// the nightly cron + 30 s startup pass because `shouldIndexPath`
|
|
1265
|
-
// filters L2 paths out of the context-index's own watcher
|
|
1266
|
-
// (followups item 7).
|
|
1267
|
-
observerManager.register(new EntityMirrorObserver({
|
|
1268
|
-
db,
|
|
1269
|
-
contextDir: getContextDir(config),
|
|
1270
|
-
writeTracker,
|
|
1271
|
-
onEntityChanged: () => contextIndexReconciler.requestReconcile("fs_event"),
|
|
1272
|
-
}));
|
|
1273
|
-
// ── 7.1 MCP auto-probe (B-003 Phase 4.3) ──
|
|
1274
|
-
// Walks enabled mcp_servers rows every `mcpAutoProbeIntervalMinutes` and
|
|
1275
|
-
// re-runs the probe sandbox. Set the interval to 0 to disable. The
|
|
1276
|
-
// observer never flips `enabled` on its own — failure surfaces through
|
|
1277
|
-
// the dashboard card's status dot, user decides whether to disable.
|
|
1278
|
-
{
|
|
1279
|
-
const { McpAutoProbe } = await import("./services/mcp/auto-probe.js");
|
|
1280
|
-
observerManager.register(new McpAutoProbe({
|
|
1281
|
-
db,
|
|
1282
|
-
blobStore,
|
|
1283
|
-
dataDir: config.dataDir,
|
|
1284
|
-
intervalMinutes: config.mcpAutoProbeIntervalMinutes,
|
|
1285
|
-
}));
|
|
1286
|
-
}
|
|
1287
|
-
// ── 7.2 Observation summarizer (cost-reduction-structural §A) ──
|
|
1288
|
-
// Drains pending observation rows asynchronously: pre-filter → per-
|
|
1289
|
-
// source LLM call → `summary_text` + `novelty_score` written back to
|
|
1290
|
-
// the row. The hourly_check skill consumes summaries instead of
|
|
1291
|
-
// re-fetching raw content. Disabled cleanly via
|
|
1292
|
-
// `observationSummarizerEnabled` — when off, observations stay
|
|
1293
|
-
// pending and the skill drops to legacy fetch-on-doubt.
|
|
1294
|
-
if (config.observationSummarizerEnabled) {
|
|
1295
|
-
const summarizerBinding = (() => {
|
|
1296
|
-
try {
|
|
1297
|
-
const row = db
|
|
1298
|
-
.prepare(`SELECT main_backend, main_model FROM process_backend_config WHERE process_key = 'observation.summarize'`)
|
|
1299
|
-
.get();
|
|
1300
|
-
if (!row?.main_backend || !row.main_model)
|
|
1301
|
-
return null;
|
|
1302
|
-
return { backendId: row.main_backend, modelId: row.main_model };
|
|
1303
|
-
}
|
|
1304
|
-
catch (err) {
|
|
1305
|
-
logger.debug({ err }, "Failed to read observation.summarize binding; using fallback");
|
|
1306
|
-
return null;
|
|
1307
|
-
}
|
|
1308
|
-
})();
|
|
1309
|
-
const summarizerClient = (() => {
|
|
1310
|
-
const fallbackBackend = summarizerBinding?.backendId ?? "claude";
|
|
1311
|
-
const fallbackModel = summarizerBinding?.modelId ?? "claude-haiku-4-5-20251001";
|
|
1312
|
-
if (fallbackBackend === "claude") {
|
|
1313
|
-
return new AnthropicSummarizerClient({
|
|
1314
|
-
modelId: fallbackModel,
|
|
1315
|
-
getApiKey: async () => {
|
|
1316
|
-
const direct = await secretBroker.getBackendApiKey("claude");
|
|
1317
|
-
if (direct)
|
|
1318
|
-
return direct;
|
|
1319
|
-
// Fall back to env (matches the daemon's API-key bridging policy).
|
|
1320
|
-
return process.env.ANTHROPIC_API_KEY ?? null;
|
|
1321
|
-
},
|
|
1322
|
-
});
|
|
1323
|
-
}
|
|
1324
|
-
// Codex / Gemini summarizer support is not yet implemented; the
|
|
1325
|
-
// worker translates `unsupported_backend` into a 'skipped' row so
|
|
1326
|
-
// the hourly_check skill drops to its legacy fetch path.
|
|
1327
|
-
return new UnsupportedSummarizerClient(fallbackBackend, fallbackModel);
|
|
1328
|
-
})();
|
|
1329
|
-
observerManager.register(new ObservationSummarizerWorker({
|
|
1330
|
-
db,
|
|
1331
|
-
client: summarizerClient,
|
|
1332
|
-
concurrency: config.observationSummarizerConcurrency,
|
|
1333
|
-
perCallTimeoutMs: config.observationSummarizerTimeoutMs,
|
|
1334
|
-
maxLlmCallsPerMinute: config.observationSummarizerMaxCallsPerMinute,
|
|
1335
|
-
queueDepthLimit: config.observationSummarizerQueueLimit,
|
|
1336
|
-
preFilter: { vipMailSenders: config.vipMailSenders },
|
|
1337
|
-
}));
|
|
1338
|
-
}
|
|
1339
|
-
else {
|
|
1340
|
-
logger.info("Observation summarizer disabled — pending rows stay pending");
|
|
1341
|
-
}
|
|
806
|
+
const { observerManager, primaryVaultWatcher, contextIndexReconciler, gitAccountRegistry, buildGitWatcher, buildGithubPoller, buildGitDelegatedCronObserver, buildCalendarPoller, buildNotionPoller, queueGitProjectInitsForCurrentConfig, } = observers;
|
|
1342
807
|
// ── 8. Health Monitor ──
|
|
1343
808
|
const healthMonitor = new HealthMonitor({
|
|
1344
809
|
db,
|
|
@@ -1363,613 +828,125 @@ async function startup() {
|
|
|
1363
828
|
eventBus,
|
|
1364
829
|
timezone: config.timezone || undefined,
|
|
1365
830
|
});
|
|
1366
|
-
// ── 9.5 Signal Detector ──
|
|
1367
|
-
const signalDetector = new SignalDetector(config);
|
|
1368
831
|
// ── 10. Event Processing Pipeline ──
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
//
|
|
1373
|
-
//
|
|
1374
|
-
//
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
//
|
|
1380
|
-
//
|
|
1381
|
-
//
|
|
1382
|
-
//
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
// rows that were `in_progress` when the daemon last crashed. Without
|
|
1393
|
-
// this, the dashboard's in-flight counter and audit views drift forever.
|
|
1394
|
-
const taskOrphansClosed = runDelegatedTaskOrphanJanitor(db);
|
|
1395
|
-
if (taskOrphansClosed > 0) {
|
|
1396
|
-
logger.info({ closed: taskOrphansClosed }, "Boot janitor closed orphaned delegated_task in-progress rows");
|
|
1397
|
-
}
|
|
1398
|
-
const delegatedBackendInvoker = new DelegatedBackendInvoker({
|
|
832
|
+
// §9.5 SignalDetector + §10 event-processing pipeline (agent cores,
|
|
833
|
+
// BackendRouter, dispatcher + setters, NotificationManager,
|
|
834
|
+
// AuthHealthMonitor + recovery, DelegatedBackendInvoker / sync worker,
|
|
835
|
+
// VoiceTranscriber, DocsQAAdapter, rematerializeActiveDmWorkdirs,
|
|
836
|
+
// handleSecretChange, handleGoogleServicesReady) live in
|
|
837
|
+
// `bootstrap/event-pipeline.ts`. The factory closes over the existing
|
|
838
|
+
// adapter + service reloaders and observer builders so secret-change
|
|
839
|
+
// hot-reload routing remains a single dispatch table.
|
|
840
|
+
//
|
|
841
|
+
// The factory also installs the real `onMailScopeChanged` handler and
|
|
842
|
+
// the roadmap-refresh sink via the setter callbacks below — both are
|
|
843
|
+
// forward-references kept open by `let` slots above (mail) and at the
|
|
844
|
+
// observers factory call (roadmap).
|
|
845
|
+
// Declared BEFORE the event-pipeline factory call so the
|
|
846
|
+
// `isStartupComplete` getter passed below closes over the live latch.
|
|
847
|
+
// The latch flips to `true` at the end of §13 once every subsystem is
|
|
848
|
+
// started; until then `handleSecretChange("notion")` defers calling
|
|
849
|
+
// `poller.start()` to avoid double-starting the timer that
|
|
850
|
+
// `observerManager.startAll()` is about to start (see the matching
|
|
851
|
+
// comment in event-pipeline.ts:SecretChangeHandlerDeps).
|
|
852
|
+
let startupComplete = false;
|
|
853
|
+
let pendingGoogleServicesReady = false;
|
|
854
|
+
const eventPipeline = await createEventPipeline({
|
|
1399
855
|
db,
|
|
1400
856
|
config,
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
{
|
|
1431
|
-
const { DelegatedProbeObserver } = await import("./observers/delegated-probe-observer.js");
|
|
1432
|
-
observerManager.register(new DelegatedProbeObserver({
|
|
1433
|
-
db,
|
|
1434
|
-
agentBackends: [agentCore, codexCore, geminiCore],
|
|
1435
|
-
intervalMinutes: config.delegatedProbeIntervalMinutes,
|
|
1436
|
-
}));
|
|
1437
|
-
}
|
|
1438
|
-
const notificationManager = new NotificationManager(messageHub, db, config);
|
|
1439
|
-
const authTelemetry = new AuthTelemetry(db);
|
|
1440
|
-
// Shared notifier factory for auth-health-monitor and auth-recovery (D3 fix).
|
|
1441
|
-
// Maps `kind` to notification_type + category so both callers share the
|
|
1442
|
-
// same routing / quiet-hours-bypass logic without duplicating 30+ lines.
|
|
1443
|
-
//
|
|
1444
|
-
// Probe-failure and recovery DMs bypass NotificationManager's own quiet-hours
|
|
1445
|
-
// + rate-limit gates via `category: "error"` (SAFETY_CATEGORIES member).
|
|
1446
|
-
// Keepalive DMs stay on the standard path. See Phase 4 self-critique B2 for
|
|
1447
|
-
// the anti-spam reasoning (clock-driven, ≤1 DM per cron tick).
|
|
1448
|
-
const makeAuthNotifier = (source) => ({
|
|
1449
|
-
send: async (message, options) => {
|
|
1450
|
-
const kind = options?.kind ?? "keepalive";
|
|
1451
|
-
const typeMap = {
|
|
1452
|
-
probe_failure: "auth.probe_failure",
|
|
1453
|
-
recovery: "auth.recovery",
|
|
1454
|
-
keepalive: "auth.keepalive_reminder",
|
|
1455
|
-
};
|
|
1456
|
-
const notificationType = typeMap[kind] ?? "auth.keepalive_reminder";
|
|
1457
|
-
// probe_failure and recovery bypass quiet-hours; keepalive does not.
|
|
1458
|
-
const category = kind === "keepalive" ? "auth-health" : AUTH_PROBE_NOTIFICATION_CATEGORY;
|
|
1459
|
-
await notificationManager.send(message, {
|
|
1460
|
-
type: notificationType,
|
|
1461
|
-
source,
|
|
1462
|
-
priority: EventPriority.NORMAL,
|
|
1463
|
-
timestamp: new Date(),
|
|
1464
|
-
data: {},
|
|
1465
|
-
correlationId: randomBytes(8).toString("hex"),
|
|
1466
|
-
}, {
|
|
1467
|
-
priority: "normal",
|
|
1468
|
-
category,
|
|
1469
|
-
destinationMode: "configured_only",
|
|
1470
|
-
});
|
|
857
|
+
eventBus,
|
|
858
|
+
secretBroker,
|
|
859
|
+
blobStore,
|
|
860
|
+
writeTracker,
|
|
861
|
+
services,
|
|
862
|
+
messageHub,
|
|
863
|
+
dashboardAdapter,
|
|
864
|
+
attachmentStore,
|
|
865
|
+
morningRoutineLock,
|
|
866
|
+
roadmapWriteLock,
|
|
867
|
+
secretState,
|
|
868
|
+
observerManager,
|
|
869
|
+
buildCalendarPoller,
|
|
870
|
+
buildNotionPoller,
|
|
871
|
+
getGitWatcher: observers.getGitWatcher,
|
|
872
|
+
reloadDiscordAdapter,
|
|
873
|
+
reloadSlackAdapter,
|
|
874
|
+
reloadTelegramAdapter,
|
|
875
|
+
reloadGoogleServices,
|
|
876
|
+
reloadAppleCalendarService,
|
|
877
|
+
reloadNotionService,
|
|
878
|
+
reloadGitHubService,
|
|
879
|
+
scheduler,
|
|
880
|
+
isStartupComplete: () => startupComplete,
|
|
881
|
+
setMailScopeChangedHandler: (cb) => {
|
|
882
|
+
onMailScopeChanged = cb;
|
|
883
|
+
},
|
|
884
|
+
setRoadmapRefreshSink: (cb) => {
|
|
885
|
+
emitRoadmapRefreshSink = cb;
|
|
1471
886
|
},
|
|
1472
887
|
});
|
|
1473
|
-
const authHealthMonitor
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
notifier: makeAuthNotifier("auth-health-monitor"),
|
|
1479
|
-
// Forward references — these gate closures are registered here
|
|
1480
|
-
// but only fire once `scheduler.start()` ticks the hourly cron,
|
|
1481
|
-
// by which time `dispatcher` is fully constructed (see the
|
|
1482
|
-
// declaration further down in this file). Calling any of these
|
|
1483
|
-
// before then would hit TDZ; in practice the constructor and
|
|
1484
|
-
// `reconcilePendingRecoveries` / `runKeepaliveSweep` never do.
|
|
1485
|
-
isMorningRoutineActive: () => dispatcher.isMorningRoutineActive(),
|
|
1486
|
-
isQuietHours: () => notificationManager.isQuietHours(),
|
|
1487
|
-
probeDisabled: () => config.authProbeDisabled,
|
|
1488
|
-
});
|
|
1489
|
-
// Reset any recoveries that were in-flight when the daemon was last killed.
|
|
1490
|
-
const recovered = authHealthMonitor.reconcilePendingRecoveries();
|
|
1491
|
-
if (recovered > 0) {
|
|
1492
|
-
logger.info({ count: recovered }, "Reconciled stuck auth recoveries on startup");
|
|
1493
|
-
}
|
|
1494
|
-
// Run the 60-day keepalive sweep once on startup. Hourly probe is
|
|
1495
|
-
// registered via scheduler.setAuthProbeCallback — see §9.5.4.
|
|
1496
|
-
void authHealthMonitor.runKeepaliveSweep().catch((err) => {
|
|
1497
|
-
logger.warn({ err }, "Initial auth keepalive sweep failed");
|
|
1498
|
-
});
|
|
1499
|
-
const keepaliveTimer = setInterval(() => {
|
|
1500
|
-
void authHealthMonitor.runKeepaliveSweep().catch((err) => {
|
|
1501
|
-
logger.warn({ err }, "Periodic auth keepalive sweep failed");
|
|
1502
|
-
});
|
|
1503
|
-
}, 24 * 60 * 60 * 1000);
|
|
1504
|
-
keepaliveTimer.unref?.();
|
|
1505
|
-
// Phase 5/6: Interactive auth recovery manager. Uses the same notifier
|
|
1506
|
-
// sink as the AuthHealthMonitor so recovery DMs flow through the same
|
|
1507
|
-
// notification pipeline with the same anti-spam guarantees.
|
|
1508
|
-
const authRecovery = new AuthRecovery(db, authTelemetry, authHealthMonitor, makeAuthNotifier("auth-recovery"), {
|
|
1509
|
-
claudeRecoveryTimeoutMin: 10,
|
|
1510
|
-
codexRecoveryTimeoutMin: 15,
|
|
1511
|
-
geminiRecoveryTimeoutMin: 5,
|
|
1512
|
-
});
|
|
1513
|
-
// ── Scoped read tokens for ReadSensitive API endpoints ──
|
|
1514
|
-
// Tokens rotate per session/workdir execution and are only injected into
|
|
1515
|
-
// backend subprocess env, never into prompt-visible instruction files.
|
|
1516
|
-
const readTokenManager = new ScopedReadSensitiveTokenManager();
|
|
1517
|
-
const agentRouter = new BackendRouter(db, config, [agentCore, codexCore, geminiCore], notificationManager, authTelemetry,
|
|
1518
|
-
// Callback to materialize instruction files for a fallback backend in an
|
|
1519
|
-
// existing session workdir. Without this, a Claude→Codex heavy-tier
|
|
1520
|
-
// fallback would leave the dir with only CLAUDE.md and no AGENTS.md.
|
|
1521
|
-
// After materializing built-in files, re-sync user-authored skills so
|
|
1522
|
-
// the newly created backend-specific dir (e.g. .codex/skills/) also
|
|
1523
|
-
// receives user skills. The dispatcher's syncAllUserSkills ran BEFORE
|
|
1524
|
-
// router.execute(), so the fallback dir didn't exist at that point.
|
|
1525
|
-
(sessionDir, backendId, eventType, processKey, wikiWorkspaceName) => {
|
|
1526
|
-
// services is the mutable ServiceRegistry — reading .calendar here
|
|
1527
|
-
// picks up the current availability (e.g. after mid-flight OAuth).
|
|
1528
|
-
// GitHub presence is read fresh from the unified `repositories` table
|
|
1529
|
-
// (rows with a github side); legacy `githubRepos` config is gone.
|
|
1530
|
-
const cfgServices = buildConfiguredServices(config, {
|
|
1531
|
-
...services,
|
|
1532
|
-
github: selectGithubRepoSlugs(db).length > 0,
|
|
1533
|
-
});
|
|
1534
|
-
const mailAccounts = services.mail?.listActiveAccounts() ?? [];
|
|
1535
|
-
ensureBackendMaterialized(config.workspaceDir, sessionDir, backendId, eventType, processKey, cfgServices, mailAccounts, readIntegrations(db), config.character, wikiWorkspaceName);
|
|
1536
|
-
syncAllUserSkills(sessionDir, join(config.dataDir, "skills"));
|
|
1537
|
-
});
|
|
1538
|
-
// Startup validation — warn if any delegated-mode variant files are
|
|
1539
|
-
// missing. Now checks both skill and task-flow variants for every
|
|
1540
|
-
// currently-delegated integration against its configured `delegatedBackend`
|
|
1541
|
-
// (not the union of all possible backends — see validateDelegatedStartup
|
|
1542
|
-
// docstring). Never throws; the PATCH route + /health do the hard-
|
|
1543
|
-
// rejection and user-surfacing downstream.
|
|
888
|
+
const { dispatcher, sessionManager, notificationManager, signalDetector, eventBroadcaster, auditLogger, docsQAAdapter, agentBackends, opencodeServerManager, delegatedBackendInvoker, authHealthMonitor, authRecovery, authTelemetry, readTokenManager, migrationLock, contextWriteGate, buildDelegatedSyncWorker, getDelegatedSyncWorker, rematerializeActiveDmWorkdirs, handleSecretChange, handleGoogleServicesReady, handlePromptContextChanged, keepaliveTimer, } = eventPipeline;
|
|
889
|
+
// ── 11. Hono HTTP Server ──
|
|
890
|
+
// Enable webhook fallback: when GitHub webhook is configured at boot,
|
|
891
|
+
// upgrade the existing GitWatcher to webhook mode. (The runtime
|
|
892
|
+
// `handleSecretChange("github")` branch handles the post-boot case.)
|
|
1544
893
|
{
|
|
1545
|
-
const
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
logger.warn({ missingSkills: missing.skills, missingTaskFlows: missing.taskFlows }, "Delegated-mode variant files missing — agent will fall back to SKILL.md / direct task-flow for affected entries; surface in /health.integrationModes");
|
|
894
|
+
const startupGitWatcher = observers.getGitWatcher();
|
|
895
|
+
if (startupGitWatcher && secretState.githubWebhookConfigured) {
|
|
896
|
+
startupGitWatcher.enableWebhookMode();
|
|
1549
897
|
}
|
|
1550
898
|
}
|
|
1551
|
-
|
|
1552
|
-
//
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
// active DM workdirs — refresh them in place." Used by:
|
|
1563
|
-
// - `onMailScopeChanged` (MailAccountRegistry scope-change hook)
|
|
1564
|
-
// - the integration-mode lifecycle (DELEGATED-PROXY-API-DESIGN.md
|
|
1565
|
-
// Phase F §4.8 — every mode flip re-materializes so the unified
|
|
1566
|
-
// skill body and per-backend instruction file reflect the new
|
|
1567
|
-
// state on the next turn without tearing down the SDK session)
|
|
1568
|
-
//
|
|
1569
|
-
// Returns null when there's no active DM session to refresh; otherwise
|
|
1570
|
-
// the per-session summary so callers can attach it to a broadcast or
|
|
1571
|
-
// structured log. Per-session failures stay inside the helper.
|
|
1572
|
-
const rematerializeActiveDmWorkdirs = (reason) => {
|
|
1573
|
-
const sessions = sessionManager.listActiveDmSessions();
|
|
1574
|
-
if (sessions.length === 0) {
|
|
1575
|
-
logger.debug({ reason }, "DM workdir refresh requested — no active DM sessions");
|
|
1576
|
-
return null;
|
|
1577
|
-
}
|
|
1578
|
-
const cfgServices = buildConfiguredServices(config, {
|
|
1579
|
-
...services,
|
|
1580
|
-
github: selectGithubRepoSlugs(db).length > 0,
|
|
1581
|
-
});
|
|
1582
|
-
const mailAccounts = services.mail?.listActiveAccounts() ?? [];
|
|
1583
|
-
// Read integration state fresh inside the closure so a Phase F mode
|
|
1584
|
-
// flip's pre-`writeIntegrations` row is not what gets baked. The
|
|
1585
|
-
// `SkillsCompiler` uses this for variant resolution (non-proxy
|
|
1586
|
-
// integrations like Notion need `SKILL.delegated.<backend>.md`) and
|
|
1587
|
-
// to re-emit `applyAllDeniedToolsForSkill` soft-deny prose. Passing
|
|
1588
|
-
// an empty object would silently regress to the latent staleness bug
|
|
1589
|
-
// that Phase F surfaced.
|
|
1590
|
-
const integrations = readIntegrations(db);
|
|
1591
|
-
const summary = refreshDmSessionWorkdirs({
|
|
1592
|
-
projectRoot: config.workspaceDir,
|
|
1593
|
-
dataDir: config.dataDir,
|
|
1594
|
-
sessions,
|
|
1595
|
-
configuredServices: cfgServices,
|
|
1596
|
-
mailAccounts,
|
|
1597
|
-
integrations,
|
|
1598
|
-
character: config.character,
|
|
1599
|
-
});
|
|
1600
|
-
return { summary, mailAccounts };
|
|
1601
|
-
};
|
|
1602
|
-
// Real implementation of the mail-scope-changed hook. Wired by the
|
|
1603
|
-
// MailAccountRegistry constructor above through a forward-reference so the
|
|
1604
|
-
// registry can be built before sessionManager / eventBroadcaster exist.
|
|
1605
|
-
// Re-materializes every active DM session workdir so `accounts.md` and the
|
|
1606
|
-
// `external-services` skill reflect the new scope on the next turn without
|
|
1607
|
-
// tearing down the SDK session.
|
|
1608
|
-
onMailScopeChanged = (reason) => {
|
|
1609
|
-
const result = rematerializeActiveDmWorkdirs(reason);
|
|
1610
|
-
if (!result)
|
|
1611
|
-
return;
|
|
1612
|
-
logger.info({ reason, ...result.summary }, "Mail scope changed — DM session workdirs re-materialized");
|
|
1613
|
-
eventBroadcaster.broadcastEvent({
|
|
1614
|
-
kind: "mail_scope_changed",
|
|
1615
|
-
reason,
|
|
1616
|
-
activeAccounts: result.mailAccounts.length,
|
|
1617
|
-
...result.summary,
|
|
1618
|
-
});
|
|
1619
|
-
};
|
|
1620
|
-
// Management Mode Phase 2 — shared migration primitives. Long timeout
|
|
1621
|
-
// because cross-fs copies of large vaults may legitimately run
|
|
1622
|
-
// multiple minutes; the lock itself is cheap and only blocks a
|
|
1623
|
-
// second concurrent /api/setup/migrate-context call.
|
|
1624
|
-
const migrationLock = new MigrationLock(60 * 60 * 1000);
|
|
1625
|
-
const contextWriteGate = new ContextWriteGate();
|
|
1626
|
-
initTaskFlows(config.workspaceDir, config.dataDir);
|
|
1627
|
-
const dispatcher = new EventDispatcher(eventBus, agentRouter, contextBuilder, getTaskFlow, notificationManager, sessionManager, messageRecorder, auditLogger, db, config, morningRoutineLock, services, roadmapWriteLock, writeTracker);
|
|
1628
|
-
dispatcher.setSignalDetector(signalDetector);
|
|
1629
|
-
// DOCS_QA_B7_DESIGN.md §11.1 — persistence-side citation validator
|
|
1630
|
-
// for docs_qa sessions. Lookup runs over fts_docs (indexed by the
|
|
1631
|
-
// docs indexer); the dispatcher only consults it when
|
|
1632
|
-
// `isDocsQAMessage(event)` is true, so this hook is inert for
|
|
1633
|
-
// chat/DM/routine flows and for installs that haven't ingested docs.
|
|
1634
|
-
const docsCitationLookup = makeDocsCitationLookup(db);
|
|
1635
|
-
dispatcher.setDocsCitationLookup(docsCitationLookup);
|
|
1636
|
-
// Docs-QA SSE adapter — DOCS_QA_B7_DESIGN.md §S4 / §S8. Sits
|
|
1637
|
-
// alongside `dashboardAdapter` on the same `platform="dashboard"`
|
|
1638
|
-
// surface; the `intent: "docs_qa"` discriminator on inbound events
|
|
1639
|
-
// forks dispatch into the docs-qa task flow + skill set + light
|
|
1640
|
-
// tier clamp. The adapter is exposed to `createDocsRoutes` for the
|
|
1641
|
-
// QA POST/SSE endpoints; outbound text reaches it via the dispatcher's
|
|
1642
|
-
// `IDashboardStream` slot fanned out by `CompositeDashboardStream`.
|
|
1643
|
-
//
|
|
1644
|
-
// It is intentionally NOT registered with `messageHub`: the hub keys
|
|
1645
|
-
// adapters by `platformName`, and both `DashboardAdapter` and this
|
|
1646
|
-
// adapter declare `platformName="dashboard"`. A second registration
|
|
1647
|
-
// would silently replace `dashboardAdapter` in the hub map (only a
|
|
1648
|
-
// warn-log), breaking `getAdapter("dashboard")`, the
|
|
1649
|
-
// start/stop lifecycle for the chat adapter, and any
|
|
1650
|
-
// `sendToPlatform("dashboard", ...)` caller (DocsQAAdapter.sendMessage
|
|
1651
|
-
// throws — it's streaming-only). DocsQAAdapter's lifecycle is owned
|
|
1652
|
-
// by the SSE route itself: clients register on `GET /docs/qa/stream`
|
|
1653
|
-
// and unregister on the request's `onAbort`.
|
|
1654
|
-
const docsQAAdapter = new DocsQAAdapter((event) => void eventBus.put(event), docsCitationLookup);
|
|
1655
|
-
// Fan-out: the dispatcher's single `IDashboardStream` slot drives
|
|
1656
|
-
// both the chat and docs-QA adapters. Each adapter no-ops on
|
|
1657
|
-
// unknown channelIds (per F3.2), so only the adapter that owns
|
|
1658
|
-
// the destination channelId actually emits — fan-out is naturally
|
|
1659
|
-
// safe (DOCS_QA_B7_DESIGN.md §9 F3.4 / §11.4).
|
|
1660
|
-
dispatcher.setDashboardStream(new CompositeDashboardStream([dashboardAdapter, docsQAAdapter]));
|
|
1661
|
-
dispatcher.setAttachmentStore(attachmentStore);
|
|
1662
|
-
// Real-time routine progress for the dashboard. `dispatchSafe` emits
|
|
1663
|
-
// `kind: "routine_started"` / `"routine_completed"` on the default
|
|
1664
|
-
// SSE `event` channel — same pipe as `kind: "main_backend_changed"`
|
|
1665
|
-
// — so the setup wizard's "今日の状況を生成中…" indicator can render
|
|
1666
|
-
// without waiting on `/api/events` REST polling. Failure containment
|
|
1667
|
-
// lives in `broadcastRoutineProgress` (swallows + warns).
|
|
1668
|
-
dispatcher.setEventBroadcaster(eventBroadcaster);
|
|
1669
|
-
// Local-Whisper voice transcription for inbound audio attachments.
|
|
1670
|
-
// See docs/design/appendices/voice-transcription.md.
|
|
1671
|
-
//
|
|
1672
|
-
// `enabled` is driven by the `voiceTranscriptionEnabled` runtime setting
|
|
1673
|
-
// (default `false`). The flag is opt-in via the dashboard's Voice Mode
|
|
1674
|
-
// card, which goes through `POST /api/voice/install` so the model
|
|
1675
|
-
// download and the daemon restart happen atomically — the constructor
|
|
1676
|
-
// here observes the persisted flag on the next boot.
|
|
1677
|
-
//
|
|
1678
|
-
// Env vars stay live for advanced operators who want to override the
|
|
1679
|
-
// model id, language, or duration cap without a settings round-trip.
|
|
1680
|
-
// `PA_VOICE_TRANSCRIPTION_ENABLED` is honoured as a fallback when the
|
|
1681
|
-
// setting is unset (legacy behaviour for installs predating the flag).
|
|
1682
|
-
const voiceTranscriberMaxDuration = Number(process.env.PA_VOICE_TRANSCRIPTION_MAX_DURATION_SEC ?? "600");
|
|
1683
|
-
const voiceEnvOverride = process.env.PA_VOICE_TRANSCRIPTION_ENABLED;
|
|
1684
|
-
// When `PA_VOICE_TRANSCRIPTION_ENABLED` is set, env wins (operator
|
|
1685
|
-
// override). Otherwise read live from `config` so the dashboard's
|
|
1686
|
-
// voice install flow — which mutates `config.voiceTranscriptionEnabled`
|
|
1687
|
-
// and persists the setting in the same boot — takes effect on the
|
|
1688
|
-
// next inbound audio attachment without waiting for a daemon restart.
|
|
1689
|
-
const voiceTranscriberEnabled = voiceEnvOverride !== undefined
|
|
1690
|
-
? voiceEnvOverride.toLowerCase() !== "false"
|
|
1691
|
-
: () => config.voiceTranscriptionEnabled;
|
|
1692
|
-
// Primary-language fallback: env override → runtime setting → null.
|
|
1693
|
-
// The getter form is essential — operators can pick a language from the
|
|
1694
|
-
// dashboard at any time and the next inbound voice attachment honours
|
|
1695
|
-
// it without requiring a daemon restart, mirroring the `enabled` knob.
|
|
1696
|
-
const voicePrimaryEnvOverride = process.env.PA_VOICE_TRANSCRIPTION_PRIMARY_LANGUAGE;
|
|
1697
|
-
const voiceTranscriberPrimaryLanguage = voicePrimaryEnvOverride !== undefined
|
|
1698
|
-
? voicePrimaryEnvOverride.trim() || null
|
|
1699
|
-
: () => config.voiceTranscriptionPrimaryLanguage;
|
|
1700
|
-
dispatcher.setVoiceTranscriber(new VoiceTranscriber({
|
|
1701
|
-
db,
|
|
1702
|
-
modelDir: join(config.dataDir, "models", "whisper"),
|
|
1703
|
-
enabled: voiceTranscriberEnabled,
|
|
1704
|
-
model: process.env.PA_VOICE_TRANSCRIPTION_MODEL,
|
|
1705
|
-
language: process.env.PA_VOICE_TRANSCRIPTION_LANGUAGE ?? null,
|
|
1706
|
-
primaryLanguage: voiceTranscriberPrimaryLanguage,
|
|
1707
|
-
maxDurationSec: Number.isFinite(voiceTranscriberMaxDuration)
|
|
1708
|
-
? voiceTranscriberMaxDuration
|
|
1709
|
-
: 600,
|
|
1710
|
-
}));
|
|
1711
|
-
dispatcher.setAuthRecovery(authRecovery);
|
|
1712
|
-
dispatcher.setAuthHealthMonitor(authHealthMonitor);
|
|
1713
|
-
// Wire the delegated-sync refresh callback. The thunk reads the live
|
|
1714
|
-
// `delegatedSyncWorker` reference each call so the dispatcher tracks
|
|
1715
|
-
// re-registration when an integration mode flips. When no delegated
|
|
1716
|
-
// integration is present, the worker is null and the call is a no-op
|
|
1717
|
-
// — the hourly check proceeds without extra latency.
|
|
1718
|
-
// See `docs/design/appendices/delegated-sync-opt-in.md` and the
|
|
1719
|
-
// worker's `runDisabledCadencesForHourlyCheck` doc-comment.
|
|
1720
|
-
dispatcher.setDelegatedSyncRefresh(async () => {
|
|
1721
|
-
await delegatedSyncWorker?.runDisabledCadencesForHourlyCheck();
|
|
1722
|
-
});
|
|
1723
|
-
// Messaging bang-commands (`!stop`/`!start`/`!cost`/`!report`) — owner DM
|
|
1724
|
-
// chokepoint that runs ahead of every other interceptor in handleMessage.
|
|
1725
|
-
// See docs/design/backlog/messaging-bang-commands.md.
|
|
1726
|
-
dispatcher.setBangCommandRegistry(createDefaultBangCommandRegistry());
|
|
1727
|
-
// P22 — wire the optimizer-workdir hooks. The `materialize` callback
|
|
1728
|
-
// captures `db`, `dataDir`, `workspaceDir`, `contextDir`, and `secretStore`
|
|
1729
|
-
// so the dispatcher branch can invoke it without importing the workdir
|
|
1730
|
-
// module directly. `teardown` cleans up under PA_DATA_DIR/optimizer-workdir/.
|
|
1731
|
-
{
|
|
1732
|
-
const { materializeOptimizerWorkdir, teardownOptimizerWorkdir } = await import("./core/skill-curation/workdir.js");
|
|
1733
|
-
dispatcher.setSkillCurationHooks({
|
|
1734
|
-
materialize: (opts) => materializeOptimizerWorkdir({
|
|
1735
|
-
db,
|
|
1736
|
-
dataDir: config.dataDir,
|
|
1737
|
-
workspaceDir: config.workspaceDir,
|
|
1738
|
-
contextDir: getContextDir(config),
|
|
1739
|
-
secretStore: secretBroker,
|
|
1740
|
-
cadence: readSkillCurationCadence(db),
|
|
1741
|
-
...(opts?.manual ? { manual: true } : {}),
|
|
1742
|
-
...(opts?.targetSkillsOverride ? { targetSkillsOverride: opts.targetSkillsOverride } : {}),
|
|
1743
|
-
}),
|
|
1744
|
-
teardown: teardownOptimizerWorkdir,
|
|
1745
|
-
});
|
|
1746
|
-
}
|
|
1747
|
-
if (isUserPaused(db)) {
|
|
1748
|
-
logger.info("Restored user-paused state, autonomous work remains paused");
|
|
1749
|
-
}
|
|
1750
|
-
emitRoadmapRefreshSink = (source) => dispatcher.emitRoadmapRefresh(source);
|
|
1751
|
-
agentCore.setReadTokenManager?.(readTokenManager);
|
|
1752
|
-
geminiCore.setReadTokenManager?.(readTokenManager);
|
|
1753
|
-
notificationManager.setSignalDetector(signalDetector);
|
|
1754
|
-
let startupComplete = false;
|
|
1755
|
-
let pendingGoogleServicesReady = false;
|
|
1756
|
-
const handleGoogleServicesReady = () => {
|
|
1757
|
-
// Start CalendarPoller if calendar was just hot-loaded AND the
|
|
1758
|
-
// google_calendar integration is in `direct` mode. When the integration
|
|
1759
|
-
// is `delegated`/`disabled` we keep the poller dormant — OAuth is wired
|
|
1760
|
-
// up but the user has explicitly chosen not to poll.
|
|
1761
|
-
if (services.calendar
|
|
1762
|
-
&& !observerManager.has("calendar")
|
|
1763
|
-
&& shouldStartObserversFor(db, "google_calendar")) {
|
|
1764
|
-
const poller = buildCalendarPoller();
|
|
1765
|
-
if (poller) {
|
|
1766
|
-
observerManager.register(poller);
|
|
1767
|
-
void poller.start();
|
|
1768
|
-
logger.info("CalendarPoller started via hot-reload");
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
// Trigger morning_routine catchup if today.md is stale or missing
|
|
1772
|
-
// (same logic as runCatchup, ensures schedule generation after first auth)
|
|
1773
|
-
const contextDir = getContextDir(config);
|
|
1774
|
-
const todayMdPath = join(contextDir, "today.md");
|
|
1775
|
-
const needsMorning = !hasFreshAgentDayTodayMd(todayMdPath, config.timezone || undefined, config.dayBoundaryHour);
|
|
1776
|
-
if (needsMorning) {
|
|
1777
|
-
// Morning routine's post-completion hook will also check roadmap staleness.
|
|
1778
|
-
logger.info("Google services ready — today.md stale, queueing morning_routine wake");
|
|
1779
|
-
scheduler.queueMorningRoutineWake("google_auth_ready");
|
|
1780
|
-
return;
|
|
1781
|
-
}
|
|
1782
|
-
// Only refresh roadmap independently when today.md is already current.
|
|
1783
|
-
// If morning_routine is needed, its post-completion hook will handle stale
|
|
1784
|
-
// roadmap regeneration after the day context has been rebuilt.
|
|
1785
|
-
if (isRoadmapStale(contextDir)) {
|
|
1786
|
-
logger.info("Google services ready — roadmap stale, emitting roadmap_refresh");
|
|
1787
|
-
dispatcher.emitRoadmapRefresh("google_auth_ready");
|
|
1788
|
-
}
|
|
1789
|
-
};
|
|
1790
|
-
const handleSecretChange = async (scope) => {
|
|
1791
|
-
switch (scope) {
|
|
1792
|
-
case "slack":
|
|
1793
|
-
await reloadSlackAdapter(true);
|
|
1794
|
-
return;
|
|
1795
|
-
case "telegram":
|
|
1796
|
-
await reloadTelegramAdapter(true);
|
|
1797
|
-
return;
|
|
1798
|
-
case "discord":
|
|
1799
|
-
await reloadDiscordAdapter(true);
|
|
1800
|
-
return;
|
|
1801
|
-
case "notion":
|
|
1802
|
-
await reloadNotionService();
|
|
1803
|
-
// Hot-reload: if the user just added the Notion API key while
|
|
1804
|
-
// the integration is already in `direct` mode, register the
|
|
1805
|
-
// poller now so they don't have to restart the daemon.
|
|
1806
|
-
// Mirrors the calendar-side `handleGoogleServicesReady` path —
|
|
1807
|
-
// the mode-flip route covers `delegated→direct`, and this
|
|
1808
|
-
// covers the orthogonal "key arrives after direct was set"
|
|
1809
|
-
// case. Idempotent via observerManager.has().
|
|
1810
|
-
if (services.notion
|
|
1811
|
-
&& !observerManager.has("notion-poller")
|
|
1812
|
-
&& Object.keys(config.notionDatabaseIds).length > 0
|
|
1813
|
-
&& shouldStartObserversFor(db, "notion")) {
|
|
1814
|
-
const poller = buildNotionPoller();
|
|
1815
|
-
if (poller) {
|
|
1816
|
-
observerManager.register(poller);
|
|
1817
|
-
void poller.start();
|
|
1818
|
-
logger.info("NotionPoller started via hot-reload");
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
return;
|
|
1822
|
-
case "github":
|
|
1823
|
-
await reloadGitHubService();
|
|
1824
|
-
if (gitWatcher && secretState.githubWebhookConfigured) {
|
|
1825
|
-
gitWatcher.enableWebhookMode();
|
|
1826
|
-
}
|
|
1827
|
-
return;
|
|
1828
|
-
case "google":
|
|
1829
|
-
await reloadGoogleServices();
|
|
1830
|
-
return;
|
|
1831
|
-
case "apple_calendar":
|
|
1832
|
-
await reloadAppleCalendarService();
|
|
1833
|
-
return;
|
|
1834
|
-
case "apiToken":
|
|
1835
|
-
default:
|
|
1836
|
-
return;
|
|
1837
|
-
}
|
|
1838
|
-
};
|
|
1839
|
-
// ── 11. Hono HTTP Server ──
|
|
1840
|
-
// Enable webhook fallback: when GitHub webhook is configured, reduce GitWatcher frequency
|
|
1841
|
-
const startupGitWatcher = gitWatcher;
|
|
1842
|
-
if (startupGitWatcher && secretState.githubWebhookConfigured) {
|
|
1843
|
-
startupGitWatcher.enableWebhookMode();
|
|
1844
|
-
}
|
|
1845
|
-
const handlePromptContextChanged = (path, reason, tier, metadata) => {
|
|
1846
|
-
const setupMode = dispatcher.getCurrentSetupMode();
|
|
1847
|
-
const decision = applyPromptContextStaleness({ path, reason, tier, metadata }, {
|
|
1848
|
-
dmStalenessStrict: config.dmStalenessStrict,
|
|
1849
|
-
setupInProgress: setupMode !== null,
|
|
1850
|
-
markContextChanged: () => markContextChanged(db),
|
|
1851
|
-
markActiveDmSessionsStale: (staleReason) => sessionManager.markActiveDmSessionsStale(staleReason),
|
|
1852
|
-
});
|
|
1853
|
-
logger.debug({
|
|
1854
|
-
path,
|
|
1855
|
-
reason,
|
|
1856
|
-
tier_decided: decision.effectiveTier,
|
|
1857
|
-
tier_requested: decision.requestedTier,
|
|
1858
|
-
tier_reason: metadata?.tierReason,
|
|
1859
|
-
dmStalenessStrict: config.dmStalenessStrict,
|
|
1860
|
-
mode: setupMode,
|
|
1861
|
-
invalidatesDmSessions: decision.invalidatesDmSessions,
|
|
1862
|
-
skippedForSetup: decision.skippedForSetup,
|
|
1863
|
-
}, "Prompt context staleness classified");
|
|
1864
|
-
if (decision.skippedForSetup) {
|
|
1865
|
-
logger.info({ path, reason, mode: setupMode }, "Skipping DM session stale flag - setup in progress");
|
|
1866
|
-
}
|
|
1867
|
-
};
|
|
1868
|
-
const app = createApp({
|
|
899
|
+
// §11 Hono server — composed via `bootstrap/api.ts` per
|
|
900
|
+
// `docs/design/appendices/index-bootstrap-stage-split.md` Phase B-3.
|
|
901
|
+
// The factory assembles `ApiDependencies` from the live subsystem
|
|
902
|
+
// refs + the cross-stage closures (`handleSecretChange`,
|
|
903
|
+
// `handleGoogleServicesReady`, `handlePromptContextChanged`,
|
|
904
|
+
// `rematerializeActiveDmWorkdirs`, `fireRoadmapMaintenance`) that
|
|
905
|
+
// remain in this scope until Phase B-4 lifts them into
|
|
906
|
+
// `bootstrap/event-pipeline.ts`. The `overrideGlobalObjects: false`
|
|
907
|
+
// workaround for `@huggingface/transformers`'s cache-put path stays
|
|
908
|
+
// wired inside the factory — see the inline comment there.
|
|
909
|
+
const { server } = startApiServer({
|
|
1869
910
|
db,
|
|
1870
911
|
config,
|
|
1871
912
|
secretBroker,
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
agentBackends
|
|
913
|
+
services,
|
|
914
|
+
blobStore,
|
|
915
|
+
agentBackends,
|
|
1875
916
|
authHealthMonitor,
|
|
1876
917
|
authRecovery,
|
|
1877
918
|
authTelemetry,
|
|
1878
919
|
eventBus,
|
|
920
|
+
readTokenManager,
|
|
1879
921
|
morningRoutineLock,
|
|
1880
922
|
roadmapWriteLock,
|
|
1881
923
|
migrationLock,
|
|
1882
924
|
contextWriteGate,
|
|
925
|
+
dispatcher,
|
|
926
|
+
sessionManager,
|
|
927
|
+
scheduler,
|
|
928
|
+
customRoutineScheduler,
|
|
929
|
+
healthMonitor,
|
|
930
|
+
heartbeat,
|
|
931
|
+
messageHub,
|
|
1883
932
|
observerManager,
|
|
1884
|
-
|
|
933
|
+
contextIndexReconciler,
|
|
934
|
+
primaryVaultWatcher,
|
|
935
|
+
delegatedBackendInvoker,
|
|
1885
936
|
gitAccountRegistry,
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
eventBusSize: status.eventBusSize,
|
|
1894
|
-
activeSessions: status.activeSessions,
|
|
1895
|
-
connectedPlatforms: status.connectedPlatforms,
|
|
1896
|
-
registeredObservers: status.registeredObservers,
|
|
1897
|
-
missingContextFiles: status.missingContextFiles,
|
|
1898
|
-
contextFilesOk: status.contextFilesOk,
|
|
1899
|
-
};
|
|
1900
|
-
},
|
|
1901
|
-
getLastTickAt: () => heartbeat.getLastTickAt(),
|
|
1902
|
-
services,
|
|
1903
|
-
isStartupComplete: () => startupComplete,
|
|
937
|
+
writeTracker,
|
|
938
|
+
auditLogger,
|
|
939
|
+
attachmentStore,
|
|
940
|
+
dashboardAdapter,
|
|
941
|
+
docsQAAdapter,
|
|
942
|
+
docsIndexer,
|
|
943
|
+
eventBroadcaster,
|
|
1904
944
|
getIntegrationStatus,
|
|
1905
945
|
getMessagingStatus,
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
getAutonomousState: () => dispatcher.isAutonomousAllowed() ?? "ok",
|
|
1911
|
-
getNotificationDestinations: () => ({
|
|
1912
|
-
defaultPlatforms: config.defaultNotificationPlatforms,
|
|
1913
|
-
effectiveFallbackPlatforms: messageHub.getEffectiveFallbackPlatforms(),
|
|
1914
|
-
}),
|
|
1915
|
-
getIntegrationDriftSyncStatus: () => delegatedSyncWorker?.getStatus() ?? {
|
|
1916
|
-
workerRunning: false,
|
|
1917
|
-
lastSuccessAt: null,
|
|
1918
|
-
circuitState: "ok",
|
|
1919
|
-
activeHours: { startHour: 4, endHour: 24 },
|
|
1920
|
-
withinActiveHours: false,
|
|
1921
|
-
cadences: {},
|
|
1922
|
-
unrecognizedIntervalKeys: [],
|
|
1923
|
-
ttlContractViolations: [],
|
|
1924
|
-
},
|
|
1925
|
-
// delegated-sync opt-in routes consume the live worker reference for
|
|
1926
|
-
// cadence Run Now + status snapshot. When no integration is in
|
|
1927
|
-
// delegated mode the worker is null and the routes report a
|
|
1928
|
-
// worker_unavailable / empty-status response — see
|
|
1929
|
-
// `docs/design/appendices/delegated-sync-opt-in.md`.
|
|
1930
|
-
get delegatedSyncWorker() {
|
|
1931
|
-
return delegatedSyncWorker ?? undefined;
|
|
1932
|
-
},
|
|
1933
|
-
sendNotification: async ({ message, platforms, priority, notificationType, originSessionId, }) => {
|
|
1934
|
-
const dispatchId = randomBytes(16).toString("hex");
|
|
1935
|
-
const deliveries = await messageHub.sendToUser(message, platforms, {
|
|
1936
|
-
dispatchId,
|
|
1937
|
-
notificationType: notificationType ?? "agent",
|
|
1938
|
-
priority: priority ?? "normal",
|
|
1939
|
-
contentSummary: message.slice(0, 200),
|
|
1940
|
-
});
|
|
1941
|
-
if (deliveries.length > 0) {
|
|
1942
|
-
const insert = db.prepare(`INSERT INTO notification_log (
|
|
1943
|
-
dispatch_id,
|
|
1944
|
-
notification_type,
|
|
1945
|
-
priority,
|
|
1946
|
-
platform,
|
|
1947
|
-
delivery_channel,
|
|
1948
|
-
delivery_message_id,
|
|
1949
|
-
content_summary,
|
|
1950
|
-
status,
|
|
1951
|
-
delivered_at
|
|
1952
|
-
)
|
|
1953
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, 'delivered', CURRENT_TIMESTAMP)`);
|
|
1954
|
-
for (const delivery of deliveries) {
|
|
1955
|
-
insert.run(dispatchId, notificationType ?? "agent", priority ?? "normal", delivery.platform, delivery.channel, delivery.messageId ?? null, message.slice(0, 200));
|
|
1956
|
-
}
|
|
1957
|
-
recordProactiveForwardDeliveries({
|
|
1958
|
-
db,
|
|
1959
|
-
config,
|
|
1960
|
-
deliveries,
|
|
1961
|
-
content: message,
|
|
1962
|
-
dispatchId,
|
|
1963
|
-
dispatchIds: [dispatchId],
|
|
1964
|
-
originSessionIds: originSessionId !== undefined ? [originSessionId] : [],
|
|
1965
|
-
notificationType: "proactive_forward",
|
|
1966
|
-
});
|
|
1967
|
-
}
|
|
1968
|
-
return { dispatchId, deliveries };
|
|
1969
|
-
},
|
|
1970
|
-
markEventNotified: (correlationId) => {
|
|
1971
|
-
dispatcher.markEventNotified(correlationId);
|
|
1972
|
-
},
|
|
946
|
+
isStartupComplete: () => startupComplete,
|
|
947
|
+
getDelegatedSyncWorker,
|
|
948
|
+
handleSecretChange,
|
|
949
|
+
handlePromptContextChanged,
|
|
1973
950
|
onGoogleServicesReady: () => {
|
|
1974
951
|
if (!startupComplete) {
|
|
1975
952
|
pendingGoogleServicesReady = true;
|
|
@@ -1978,255 +955,24 @@ async function startup() {
|
|
|
1978
955
|
}
|
|
1979
956
|
handleGoogleServicesReady();
|
|
1980
957
|
},
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
db,
|
|
1999
|
-
observerManager,
|
|
2000
|
-
buildObserver,
|
|
2001
|
-
buildDelegatedSyncWorker,
|
|
2002
|
-
buildGitDelegatedCronObserver,
|
|
2003
|
-
// DELEGATED-PROXY-API-DESIGN.md Phase F (§4.8) — every mode
|
|
2004
|
-
// change re-materializes active DM workdirs so the next turn
|
|
2005
|
-
// picks up the new skill body / accounts.md / instruction file
|
|
2006
|
-
// without tearing down the SDK session.
|
|
2007
|
-
rematerializeDmSessions: (reason) => {
|
|
2008
|
-
const result = rematerializeActiveDmWorkdirs(reason);
|
|
2009
|
-
if (!result)
|
|
2010
|
-
return;
|
|
2011
|
-
logger.info({ reason, ...result.summary }, "Integration mode changed — DM session workdirs re-materialized");
|
|
2012
|
-
},
|
|
2013
|
-
}, key, prev, next);
|
|
2014
|
-
if (key === "git" && next.mode !== "direct") {
|
|
2015
|
-
gitWatcher = null;
|
|
2016
|
-
}
|
|
2017
|
-
},
|
|
2018
|
-
onMainBackendChange: (reason) => {
|
|
2019
|
-
// DELEGATED-MODE-V2-DESIGN.md §4.4 — every main-backend flip
|
|
2020
|
-
// re-materializes active DM workdirs so the next turn's skill
|
|
2021
|
-
// variant and instruction file reflect the new same- vs.
|
|
2022
|
-
// cross-backend topology. Mirrors the `onMailScopeChanged`
|
|
2023
|
-
// pattern: helper handles the "no active sessions" no-op + per-
|
|
2024
|
-
// session failure containment, and we broadcast a structured
|
|
2025
|
-
// event so the dashboard can refresh without polling.
|
|
2026
|
-
const result = rematerializeActiveDmWorkdirs(reason);
|
|
2027
|
-
if (!result)
|
|
2028
|
-
return;
|
|
2029
|
-
logger.info({ reason, ...result.summary }, "Main backend changed — DM session workdirs re-materialized");
|
|
2030
|
-
eventBroadcaster.broadcastEvent({
|
|
2031
|
-
kind: "main_backend_changed",
|
|
2032
|
-
reason,
|
|
2033
|
-
...result.summary,
|
|
2034
|
-
});
|
|
2035
|
-
},
|
|
2036
|
-
onSetupStart: (mode) => {
|
|
2037
|
-
dispatcher.beginSetupMode(mode);
|
|
2038
|
-
},
|
|
2039
|
-
onSecretChanged: handleSecretChange,
|
|
2040
|
-
onSetupComplete: () => {
|
|
2041
|
-
dispatcher.clearSetupMode();
|
|
2042
|
-
// Kick off an immediate morning routine so today.md is generated
|
|
2043
|
-
// right away — otherwise the user completes setup mid-day and sits
|
|
2044
|
-
// without a populated today.md until 04:00 next morning. We go
|
|
2045
|
-
// through the scheduler's queueMorningRoutineWake so:
|
|
2046
|
-
// - the dedup check prevents a double-run if startup catchup was
|
|
2047
|
-
// about to kick off the same routine (race on first boot after
|
|
2048
|
-
// setup completes)
|
|
2049
|
-
// - the wake task is durable: if the daemon crashes before the
|
|
2050
|
-
// routine runs, it replays on restart via ScheduleWatcher
|
|
2051
|
-
// - ScheduleWatcher obeys the autonomous-work gate, so in the
|
|
2052
|
-
// unlikely case clearSetupMode fails to persist, the gate
|
|
2053
|
-
// still prevents the routine from running mid-setup.
|
|
2054
|
-
// Don't emit roadmap_refresh here — skeleton has "(Not yet configured)"
|
|
2055
|
-
// which isRoadmapStale() detects. The refresh will be triggered by:
|
|
2056
|
-
// - morning_routine's post-completion hook, or
|
|
2057
|
-
// - onGoogleServicesReady (once calendar auth completes)
|
|
2058
|
-
// This avoids generating a roadmap before calendar data is available.
|
|
2059
|
-
try {
|
|
2060
|
-
scheduler.queueMorningRoutineWake("setup_complete");
|
|
2061
|
-
}
|
|
2062
|
-
catch (err) {
|
|
2063
|
-
logger.error({ err }, "Failed to queue post-setup morning routine — today.md will not be generated until next 04:00");
|
|
2064
|
-
}
|
|
2065
|
-
},
|
|
2066
|
-
onPromptContextChanged: (path, reason, tier, metadata) => {
|
|
2067
|
-
// Layer-3 defense for the Customize Your Rules bug: even if the
|
|
2068
|
-
// setup conversation's own agent writes to today/roadmap/management-
|
|
2069
|
-
// rules mid-flight (not typical, but possible via skills), we must
|
|
2070
|
-
// NOT mark the owner-DM session stale. Marking stale would refresh
|
|
2071
|
-
// the conversation_sessions row on the next turn, drop the stored
|
|
2072
|
-
// Claude SDK session_id, and force a fresh `setup.initial` execute
|
|
2073
|
-
// that loses prior Q&A history. Layers 1 (autonomous-work gate)
|
|
2074
|
-
// and 2 (scope-agnostic currentSetupMode) keep prompt selection
|
|
2075
|
-
// correct, but only layer 3 preserves in-conversation continuity.
|
|
2076
|
-
// For loud-tier changes, persist the change moment FIRST so a crash
|
|
2077
|
-
// between the DB write and stale-flag update still leaves the durable
|
|
2078
|
-
// signal in place — the in-memory flag on SessionManager is lost on
|
|
2079
|
-
// restart, so if it were written before the DB write we could lose
|
|
2080
|
-
// the signal entirely on a process crash mid-hook.
|
|
2081
|
-
//
|
|
2082
|
-
// The persisted `dashboard_context_changed_at` is consulted by both
|
|
2083
|
-
// `continueDashboardSession` (resume path) and `getOrCreateDm`
|
|
2084
|
-
// (every DM turn) to decide whether the stored SDK session has gone
|
|
2085
|
-
// stale and must be discarded before resume.
|
|
2086
|
-
handlePromptContextChanged(path, reason, tier, metadata);
|
|
2087
|
-
},
|
|
2088
|
-
onIndexableContextChange: (_path) => {
|
|
2089
|
-
// API-route hint: any successful PUT/PATCH/DELETE under `/context/*`
|
|
2090
|
-
// queues a reconcile. The observer's own chokidar watcher already
|
|
2091
|
-
// catches manual edits the API bypasses (e.g. the user editing via
|
|
2092
|
-
// Obsidian when contextDir *is* the Obsidian vault) — this hint
|
|
2093
|
-
// shortens reconcile latency for API-origin writes from chokidar
|
|
2094
|
-
// debounce + stabilityThreshold to the observer's 10s debounce. The
|
|
2095
|
-
// reconciler short-circuits when nothing changed, so firing for
|
|
2096
|
-
// non-indexed paths is harmless.
|
|
2097
|
-
contextIndexReconciler.requestReconcile("manual");
|
|
2098
|
-
},
|
|
2099
|
-
onCustomRoutinesChanged: () => {
|
|
2100
|
-
try {
|
|
2101
|
-
customRoutineScheduler.reload();
|
|
2102
|
-
}
|
|
2103
|
-
catch (err) {
|
|
2104
|
-
logger.error({ err }, "Custom routine reload failed");
|
|
2105
|
-
}
|
|
2106
|
-
},
|
|
2107
|
-
triggerHourlyCheck: (source, options) => dispatcher.triggerHourlyCheck(source, options),
|
|
2108
|
-
triggerRoadmapRefresh: (source, options) => dispatcher.emitRoadmapRefresh(source, options),
|
|
2109
|
-
endDashboardSession: (channelId) => endDashboardSessionFromChannel({
|
|
2110
|
-
sessionManager,
|
|
2111
|
-
channelId,
|
|
2112
|
-
}),
|
|
2113
|
-
continueDashboardSession: async (sessionId) => continueDashboardSessionFromHistory({
|
|
2114
|
-
db,
|
|
2115
|
-
dataDir: config.dataDir,
|
|
2116
|
-
sessionManager,
|
|
2117
|
-
sessionId,
|
|
2118
|
-
}),
|
|
2119
|
-
writeTracker,
|
|
2120
|
-
blobStore,
|
|
2121
|
-
dashboardAdapter,
|
|
2122
|
-
eventBroadcaster,
|
|
2123
|
-
attachmentStore,
|
|
2124
|
-
auditLogger,
|
|
2125
|
-
validateAttachmentTurnToken: (token) => dispatcher.validateAttachmentTurnToken(token),
|
|
2126
|
-
whatsappControls: {
|
|
2127
|
-
isInitialized: () => adapterState.whatsapp !== null,
|
|
2128
|
-
enable: async () => {
|
|
2129
|
-
const adapter = buildWhatsAppAdapter();
|
|
2130
|
-
if (adapter.getStatus() === "disabled") {
|
|
2131
|
-
await adapter.start();
|
|
2132
|
-
}
|
|
2133
|
-
},
|
|
2134
|
-
disable: async () => {
|
|
2135
|
-
await teardownWhatsAppAdapter();
|
|
2136
|
-
},
|
|
2137
|
-
requestQr: async () => {
|
|
2138
|
-
if (!adapterState.whatsapp) {
|
|
2139
|
-
await enableWhatsAppAdapter();
|
|
2140
|
-
}
|
|
2141
|
-
await adapterState.whatsapp.requestQR();
|
|
2142
|
-
},
|
|
2143
|
-
waitForQr: async (timeoutMs = 10_000) => {
|
|
2144
|
-
if (!adapterState.whatsapp) {
|
|
2145
|
-
await enableWhatsAppAdapter();
|
|
2146
|
-
}
|
|
2147
|
-
const snapshot = await adapterState.whatsapp.waitForQr(timeoutMs);
|
|
2148
|
-
return whatsappQrResponseFromAdapter(adapterState.whatsapp, snapshot);
|
|
2149
|
-
},
|
|
2150
|
-
getQrResponse: () => whatsappQrResponseFromAdapter(adapterState.whatsapp),
|
|
2151
|
-
reset: async (timeoutMs = 10_000) => {
|
|
2152
|
-
// 1. Stop + unregister any live adapter so no Baileys callbacks fire
|
|
2153
|
-
// against the auth dir while we delete it.
|
|
2154
|
-
await teardownWhatsAppAdapter();
|
|
2155
|
-
// 2. Wipe Baileys' multi-file auth state. Without this, a fresh
|
|
2156
|
-
// enable() would re-load the stale creds and never emit a QR —
|
|
2157
|
-
// which is exactly the "前のデータが残っているのか pair できない"
|
|
2158
|
-
// failure mode the dashboard's "Reset connection" button exists
|
|
2159
|
-
// to recover from. Recursive + force so a partially-written dir
|
|
2160
|
-
// (e.g. only qr.txt present, no creds.json yet) still wipes
|
|
2161
|
-
// cleanly. `force: true` also no-ops if the dir is already gone.
|
|
2162
|
-
const authDir = config.whatsappAuthDir ?? join(config.dataDir, "whatsapp", "auth");
|
|
2163
|
-
try {
|
|
2164
|
-
rmSync(authDir, { recursive: true, force: true });
|
|
2165
|
-
}
|
|
2166
|
-
catch (err) {
|
|
2167
|
-
logger.warn({ err, authDir }, "Failed to wipe WhatsApp auth directory during reset");
|
|
2168
|
-
}
|
|
2169
|
-
// 3. Drop the cached owner_channels mapping so a freshly-paired
|
|
2170
|
-
// session re-discovers the channel id from the inbound auth
|
|
2171
|
-
// handshake rather than reusing the prior LID alias.
|
|
2172
|
-
try {
|
|
2173
|
-
db
|
|
2174
|
-
.prepare("DELETE FROM owner_channels WHERE platform = ?")
|
|
2175
|
-
.run("whatsapp");
|
|
2176
|
-
}
|
|
2177
|
-
catch (err) {
|
|
2178
|
-
logger.warn({ err }, "Failed to clear WhatsApp owner_channels row during reset");
|
|
2179
|
-
}
|
|
2180
|
-
// 4. If the integration is still enabled, rebuild the adapter and
|
|
2181
|
-
// await the first scannable QR so the dashboard can render it
|
|
2182
|
-
// in the same request that triggered the reset.
|
|
2183
|
-
if (!config.whatsappEnabled) {
|
|
2184
|
-
return whatsappQrResponseFromAdapter(null);
|
|
2185
|
-
}
|
|
2186
|
-
await enableWhatsAppAdapter();
|
|
2187
|
-
const snapshot = await adapterState.whatsapp.waitForQr(timeoutMs);
|
|
2188
|
-
return whatsappQrResponseFromAdapter(adapterState.whatsapp, snapshot);
|
|
2189
|
-
},
|
|
2190
|
-
},
|
|
2191
|
-
messagingControls: {
|
|
2192
|
-
telegram: buildTelegramControls(),
|
|
2193
|
-
slack: buildSlackControls(),
|
|
2194
|
-
discord: buildDiscordControls(),
|
|
2195
|
-
},
|
|
958
|
+
rematerializeActiveDmWorkdirs,
|
|
959
|
+
fireRoadmapMaintenance,
|
|
960
|
+
buildCalendarPoller,
|
|
961
|
+
buildNotionPoller,
|
|
962
|
+
buildGitWatcher,
|
|
963
|
+
buildGithubPoller,
|
|
964
|
+
buildDelegatedSyncWorker,
|
|
965
|
+
buildGitDelegatedCronObserver,
|
|
966
|
+
clearGitWatcher: observers.clearGitWatcher,
|
|
967
|
+
adapterState,
|
|
968
|
+
buildWhatsAppAdapter,
|
|
969
|
+
teardownWhatsAppAdapter,
|
|
970
|
+
enableWhatsAppAdapter,
|
|
971
|
+
buildTelegramControls,
|
|
972
|
+
buildSlackControls,
|
|
973
|
+
buildDiscordControls,
|
|
974
|
+
queueGitProjectInitsForCurrentConfig,
|
|
2196
975
|
});
|
|
2197
|
-
// Mount /api/docs/* (DOCS_QA_DESIGN.md §10.4 + DOCS_QA_B7_DESIGN.md
|
|
2198
|
-
// §S5–S6) after createApp so the indexer handle and the QA SSE
|
|
2199
|
-
// adapter can be threaded in without extending ApiDependencies. The
|
|
2200
|
-
// read endpoints don't need messaging/dispatcher deps; the QA
|
|
2201
|
-
// POST/SSE pair leans on `docsQAAdapter` to register clients and
|
|
2202
|
-
// enqueue docs_qa events.
|
|
2203
|
-
app.route("/api", createDocsRoutes({
|
|
2204
|
-
db,
|
|
2205
|
-
...(docsIndexer ? { indexer: docsIndexer } : {}),
|
|
2206
|
-
docsQAAdapter,
|
|
2207
|
-
}));
|
|
2208
|
-
const server = serve({
|
|
2209
|
-
fetch: app.fetch,
|
|
2210
|
-
hostname: "127.0.0.1",
|
|
2211
|
-
port: config.apiPort,
|
|
2212
|
-
// @hono/node-server's getRequestListener defaults to replacing
|
|
2213
|
-
// `globalThis.Request` / `globalThis.Response` with its own lazy
|
|
2214
|
-
// wrapper classes (named `_Request` / `_Response`) for response-
|
|
2215
|
-
// body materialization performance. The wrappers are prototype-
|
|
2216
|
-
// chained to the native classes — fine for Hono's own response
|
|
2217
|
-
// path — but they break `instanceof Response` checks for objects
|
|
2218
|
-
// returned by native `fetch()`, because a native Response's
|
|
2219
|
-
// prototype chain doesn't include `_Response.prototype`. This
|
|
2220
|
-
// makes `@huggingface/transformers`'s `toCacheResponse` check
|
|
2221
|
-
// (`response instanceof Response && response.status === 200`)
|
|
2222
|
-
// evaluate to false on fresh fetches, which silently skips
|
|
2223
|
-
// `cache.put` and then throws "Unable to get model file path or
|
|
2224
|
-
// buffer." Disabling the override keeps the native globals
|
|
2225
|
-
// intact and costs us nothing — we don't construct Hono's
|
|
2226
|
-
// `Response` instances directly anywhere in the daemon.
|
|
2227
|
-
overrideGlobalObjects: false,
|
|
2228
|
-
});
|
|
2229
|
-
logger.info({ port: config.apiPort }, "API server listening");
|
|
2230
976
|
void dispatcher.run(); // Start consuming dashboard events as soon as the API is live
|
|
2231
977
|
// Notifications Center heartbeat (docs/design/20-notifications-center.md
|
|
2232
978
|
// §"Daemon heartbeat"). MUST start immediately after the API server is
|
|
@@ -2268,7 +1014,38 @@ async function startup() {
|
|
|
2268
1014
|
// means a reconcile during setup.initial does not destroy in-flight
|
|
2269
1015
|
// setup session state — see the matching `onPromptContextChanged`
|
|
2270
1016
|
// handler in the createApp dependencies above for the layered guards.
|
|
2271
|
-
|
|
1017
|
+
observers.setPromptContextChangedSink(handlePromptContextChanged);
|
|
1018
|
+
// Evening-review slimdown §2.2 — daily mechanical roadmap.md
|
|
1019
|
+
// maintenance at 17:45 local. The pass acquires the same
|
|
1020
|
+
// `roadmapWriteLock` singleton the dispatcher uses for
|
|
1021
|
+
// `routine.roadmap_refresh` so a refresh mid-flight (rare at that
|
|
1022
|
+
// time of day) defers the maintenance to the next tick instead of
|
|
1023
|
+
// racing. `writeTracker.markWriting` tags the resulting fs event as
|
|
1024
|
+
// agent-originated so the Obsidian / Git observers do not loop on
|
|
1025
|
+
// their own output.
|
|
1026
|
+
// Shared closure used by both the 17:45 cron callback above and the
|
|
1027
|
+
// synchronous `triggerRoadmapMaintenance` API dependency wired into
|
|
1028
|
+
// `createApp`. Keeping a single fire site means the cron path and
|
|
1029
|
+
// the `aitne run-now roadmap_maintenance` path operate on identical
|
|
1030
|
+
// deps — no drift between the scheduled and the manual surface.
|
|
1031
|
+
function fireRoadmapMaintenance() {
|
|
1032
|
+
return runRoadmapMechanicalMaintenance({
|
|
1033
|
+
db,
|
|
1034
|
+
contextDir: getContextDir(config, db),
|
|
1035
|
+
roadmapWriteLock,
|
|
1036
|
+
writeTracker,
|
|
1037
|
+
timezone: config.timezone || undefined,
|
|
1038
|
+
onIndexableContextChange: () => contextIndexReconciler.requestReconcile("manual"),
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
scheduler.setRoadmapMaintenanceCallback(() => {
|
|
1042
|
+
try {
|
|
1043
|
+
fireRoadmapMaintenance();
|
|
1044
|
+
}
|
|
1045
|
+
catch (err) {
|
|
1046
|
+
logger.error({ err }, "runRoadmapMechanicalMaintenance threw");
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
2272
1049
|
// Phase 4 auth probe — runs BEFORE the hourly check on each cron
|
|
2273
1050
|
// tick so auth health detection happens independently of the
|
|
2274
1051
|
// observation-threshold gate. checkAll() owns its own kill switch
|
|
@@ -2280,6 +1057,14 @@ async function startup() {
|
|
|
2280
1057
|
// racing with the dashboard setup flow and triggering the stale-session
|
|
2281
1058
|
// bug that killed setup mode mid-conversation.
|
|
2282
1059
|
scheduler.setAutonomousGate(() => dispatcher.isAutonomousAllowed());
|
|
1060
|
+
// Pre-routine morning_routine gate (sleep-skip recovery). When the
|
|
1061
|
+
// current agent-day's morning_routine has not completed yet — typical
|
|
1062
|
+
// cause: Mac slept through the 04:00 cron tick — hourly_check and the
|
|
1063
|
+
// review routines enqueue a wake row instead of running on stale state.
|
|
1064
|
+
// Wired here after both `dispatcher` and `scheduler` exist so the
|
|
1065
|
+
// binding is a single, stable function reference for the duration of
|
|
1066
|
+
// the process.
|
|
1067
|
+
dispatcher.setQueueMorningRoutineWake((source, options) => scheduler.queueMorningRoutineWake(source, options));
|
|
2283
1068
|
const startupCatchup = await runCatchup(db, dispatcher, config);
|
|
2284
1069
|
// ── 13. Start all components ──
|
|
2285
1070
|
await messageHub.startAll();
|
|
@@ -2287,15 +1072,58 @@ async function startup() {
|
|
|
2287
1072
|
customRoutineScheduler.start();
|
|
2288
1073
|
signalDetector.start();
|
|
2289
1074
|
const registeredPlatforms = messageHub.getPlatforms();
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
1075
|
+
// Single-app installs (Telegram-only / Discord-only / etc.) would
|
|
1076
|
+
// otherwise log "Primary platform is not registered, falling back" on
|
|
1077
|
+
// every boot because the schema default is "slack" and the fallback was
|
|
1078
|
+
// never persisted. The resolver checks whether the operator ever made
|
|
1079
|
+
// an explicit choice (DB settings row or `PA_PRIMARY_PLATFORM` env);
|
|
1080
|
+
// when they didn't, we adopt and persist the first eligible adapter so
|
|
1081
|
+
// the next boot is silent.
|
|
1082
|
+
//
|
|
1083
|
+
// "First set up" semantics for the multi-adapter case (spec: when
|
|
1084
|
+
// multiple adapters are configured, the first one paired wins) come from
|
|
1085
|
+
// `selectFirstPairedPlatform`, which reads `owner_channels.rowid` ASC —
|
|
1086
|
+
// a chronological proxy that captures the first platform to complete
|
|
1087
|
+
// the cred+pairing loop. The single-adapter case (the common one)
|
|
1088
|
+
// collapses to "the only eligible adapter" without touching the DB.
|
|
1089
|
+
const explicitEnvPrimary = process.env.PA_PRIMARY_PLATFORM?.trim();
|
|
1090
|
+
const action = resolvePrimaryPlatform({
|
|
1091
|
+
configuredPrimary: config.primaryPlatform,
|
|
1092
|
+
primaryAdapterRegistered: !!messageHub.getAdapter(config.primaryPlatform),
|
|
1093
|
+
registeredPlatforms,
|
|
1094
|
+
effectiveFallback: selectFirstPairedPlatform(db, messageHub.getEffectiveFallbackPlatforms()),
|
|
1095
|
+
userExplicitlySetPrimary: "primaryPlatform" in persistedSettings
|
|
1096
|
+
|| (explicitEnvPrimary !== undefined && explicitEnvPrimary.length > 0),
|
|
1097
|
+
});
|
|
1098
|
+
if (action.kind === "switch") {
|
|
1099
|
+
if (action.reason === "auto-resolve") {
|
|
1100
|
+
logger.info({
|
|
1101
|
+
previousPrimary: config.primaryPlatform,
|
|
1102
|
+
autoResolvedPrimary: action.newPrimary,
|
|
1103
|
+
}, "Primary platform unset; auto-resolving to first configured messaging app");
|
|
1104
|
+
}
|
|
1105
|
+
else {
|
|
1106
|
+
logger.warn({
|
|
1107
|
+
requestedPrimary: config.primaryPlatform,
|
|
1108
|
+
fallbackPrimary: action.newPrimary,
|
|
1109
|
+
}, "Primary platform is not registered, falling back (preference kept; restore the adapter to revert)");
|
|
1110
|
+
}
|
|
1111
|
+
messageHub.setPrimaryPlatform(action.newPrimary);
|
|
1112
|
+
config.primaryPlatform = action.newPrimary;
|
|
1113
|
+
if (action.persist) {
|
|
1114
|
+
try {
|
|
1115
|
+
settingsStore.set("primaryPlatform", action.newPrimary);
|
|
1116
|
+
}
|
|
1117
|
+
catch (err) {
|
|
1118
|
+
logger.warn({ err }, "Failed to persist auto-resolved primaryPlatform; next boot will repeat the resolution");
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
else if (action.kind === "no-fallback") {
|
|
1123
|
+
logger.warn({
|
|
1124
|
+
configuredPrimary: config.primaryPlatform,
|
|
1125
|
+
registeredPlatforms,
|
|
1126
|
+
}, "Primary platform adapter not registered and no eligible messaging fallback found");
|
|
2299
1127
|
}
|
|
2300
1128
|
await observerManager.startAll();
|
|
2301
1129
|
// Start the integrations.md fs-watcher after the observer manager is up so
|
|
@@ -2409,7 +1237,14 @@ async function startup() {
|
|
|
2409
1237
|
signalDetector.stop();
|
|
2410
1238
|
notificationManager.stop(); // Clear pending batch-flush timer
|
|
2411
1239
|
authRecovery.shutdown(); // Kill any active recovery subprocesses
|
|
1240
|
+
// docs/design/appendices/opencode-backend.md Phase 2 — stop the loopback opencode
|
|
1241
|
+
// server (if any) so the spawned child releases its port. shutdown()
|
|
1242
|
+
// is idempotent; lazy-spawned managers that never booted no-op.
|
|
1243
|
+
await opencodeServerManager.shutdown().catch((err) => {
|
|
1244
|
+
logger.warn({ err }, "opencode server manager shutdown failed");
|
|
1245
|
+
});
|
|
2412
1246
|
clearInterval(vaultHealthTimer);
|
|
1247
|
+
clearInterval(keepaliveTimer);
|
|
2413
1248
|
clearTimeout(migrationBackupSweepInitial);
|
|
2414
1249
|
clearInterval(migrationBackupSweepTimer);
|
|
2415
1250
|
if (managementMdWatcher) {
|