@aitne/daemon 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/adapters/composite-dashboard-stream.d.ts +42 -0
- package/dist/adapters/composite-dashboard-stream.d.ts.map +1 -0
- package/dist/adapters/composite-dashboard-stream.js +49 -0
- package/dist/adapters/composite-dashboard-stream.js.map +1 -0
- package/dist/adapters/dashboard-adapter.d.ts +104 -0
- package/dist/adapters/dashboard-adapter.d.ts.map +1 -0
- package/dist/adapters/dashboard-adapter.js +216 -0
- package/dist/adapters/dashboard-adapter.js.map +1 -0
- package/dist/adapters/discord.d.ts +77 -0
- package/dist/adapters/discord.d.ts.map +1 -0
- package/dist/adapters/discord.js +339 -0
- package/dist/adapters/discord.js.map +1 -0
- package/dist/adapters/docs-qa-adapter.d.ts +123 -0
- package/dist/adapters/docs-qa-adapter.d.ts.map +1 -0
- package/dist/adapters/docs-qa-adapter.js +218 -0
- package/dist/adapters/docs-qa-adapter.js.map +1 -0
- package/dist/adapters/message-hub.d.ts +70 -0
- package/dist/adapters/message-hub.d.ts.map +1 -0
- package/dist/adapters/message-hub.js +359 -0
- package/dist/adapters/message-hub.js.map +1 -0
- package/dist/adapters/notification-manager.d.ts +99 -0
- package/dist/adapters/notification-manager.d.ts.map +1 -0
- package/dist/adapters/notification-manager.js +498 -0
- package/dist/adapters/notification-manager.js.map +1 -0
- package/dist/adapters/outbound-text.d.ts +28 -0
- package/dist/adapters/outbound-text.d.ts.map +1 -0
- package/dist/adapters/outbound-text.js +58 -0
- package/dist/adapters/outbound-text.js.map +1 -0
- package/dist/adapters/slack-adapter.d.ts +82 -0
- package/dist/adapters/slack-adapter.d.ts.map +1 -0
- package/dist/adapters/slack-adapter.js +359 -0
- package/dist/adapters/slack-adapter.js.map +1 -0
- package/dist/adapters/telegram-adapter.d.ts +107 -0
- package/dist/adapters/telegram-adapter.d.ts.map +1 -0
- package/dist/adapters/telegram-adapter.js +477 -0
- package/dist/adapters/telegram-adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +92 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/whatsapp-adapter.d.ts +213 -0
- package/dist/adapters/whatsapp-adapter.d.ts.map +1 -0
- package/dist/adapters/whatsapp-adapter.js +1216 -0
- package/dist/adapters/whatsapp-adapter.js.map +1 -0
- package/dist/api/chat-binding-query.d.ts +36 -0
- package/dist/api/chat-binding-query.d.ts.map +1 -0
- package/dist/api/chat-binding-query.js +63 -0
- package/dist/api/chat-binding-query.js.map +1 -0
- package/dist/api/chat-session-resume.d.ts +12 -0
- package/dist/api/chat-session-resume.d.ts.map +1 -0
- package/dist/api/chat-session-resume.js +21 -0
- package/dist/api/chat-session-resume.js.map +1 -0
- package/dist/api/delegated-proxy-helper.d.ts +33 -0
- package/dist/api/delegated-proxy-helper.d.ts.map +1 -0
- package/dist/api/delegated-proxy-helper.js +54 -0
- package/dist/api/delegated-proxy-helper.js.map +1 -0
- package/dist/api/directory-picker.d.ts +38 -0
- package/dist/api/directory-picker.d.ts.map +1 -0
- package/dist/api/directory-picker.js +278 -0
- package/dist/api/directory-picker.js.map +1 -0
- package/dist/api/env-writer.d.ts +25 -0
- package/dist/api/env-writer.d.ts.map +1 -0
- package/dist/api/env-writer.js +421 -0
- package/dist/api/env-writer.js.map +1 -0
- package/dist/api/integration-route-gate.d.ts +60 -0
- package/dist/api/integration-route-gate.d.ts.map +1 -0
- package/dist/api/integration-route-gate.js +83 -0
- package/dist/api/integration-route-gate.js.map +1 -0
- package/dist/api/json-body.d.ts +29 -0
- package/dist/api/json-body.d.ts.map +1 -0
- package/dist/api/json-body.js +87 -0
- package/dist/api/json-body.js.map +1 -0
- package/dist/api/routes/activity-sources.d.ts +20 -0
- package/dist/api/routes/activity-sources.d.ts.map +1 -0
- package/dist/api/routes/activity-sources.js +18 -0
- package/dist/api/routes/activity-sources.js.map +1 -0
- package/dist/api/routes/agent.d.ts +4 -0
- package/dist/api/routes/agent.d.ts.map +1 -0
- package/dist/api/routes/agent.js +619 -0
- package/dist/api/routes/agent.js.map +1 -0
- package/dist/api/routes/apple-calendar.d.ts +31 -0
- package/dist/api/routes/apple-calendar.d.ts.map +1 -0
- package/dist/api/routes/apple-calendar.js +310 -0
- package/dist/api/routes/apple-calendar.js.map +1 -0
- package/dist/api/routes/attachments.d.ts +36 -0
- package/dist/api/routes/attachments.d.ts.map +1 -0
- package/dist/api/routes/attachments.js +305 -0
- package/dist/api/routes/attachments.js.map +1 -0
- package/dist/api/routes/backends.d.ts +4 -0
- package/dist/api/routes/backends.d.ts.map +1 -0
- package/dist/api/routes/backends.js +1132 -0
- package/dist/api/routes/backends.js.map +1 -0
- package/dist/api/routes/books.d.ts +63 -0
- package/dist/api/routes/books.d.ts.map +1 -0
- package/dist/api/routes/books.js +467 -0
- package/dist/api/routes/books.js.map +1 -0
- package/dist/api/routes/calendar.d.ts +36 -0
- package/dist/api/routes/calendar.d.ts.map +1 -0
- package/dist/api/routes/calendar.js +351 -0
- package/dist/api/routes/calendar.js.map +1 -0
- package/dist/api/routes/commands.d.ts +4 -0
- package/dist/api/routes/commands.d.ts.map +1 -0
- package/dist/api/routes/commands.js +251 -0
- package/dist/api/routes/commands.js.map +1 -0
- package/dist/api/routes/context.d.ts +57 -0
- package/dist/api/routes/context.d.ts.map +1 -0
- package/dist/api/routes/context.js +1765 -0
- package/dist/api/routes/context.js.map +1 -0
- package/dist/api/routes/dashboard.d.ts +29 -0
- package/dist/api/routes/dashboard.d.ts.map +1 -0
- package/dist/api/routes/dashboard.js +2062 -0
- package/dist/api/routes/dashboard.js.map +1 -0
- package/dist/api/routes/delegated-sync.d.ts +4 -0
- package/dist/api/routes/delegated-sync.d.ts.map +1 -0
- package/dist/api/routes/delegated-sync.js +192 -0
- package/dist/api/routes/delegated-sync.js.map +1 -0
- package/dist/api/routes/delegated.d.ts +42 -0
- package/dist/api/routes/delegated.d.ts.map +1 -0
- package/dist/api/routes/delegated.js +250 -0
- package/dist/api/routes/delegated.js.map +1 -0
- package/dist/api/routes/docs.d.ts +34 -0
- package/dist/api/routes/docs.d.ts.map +1 -0
- package/dist/api/routes/docs.js +580 -0
- package/dist/api/routes/docs.js.map +1 -0
- package/dist/api/routes/entities.d.ts +9 -0
- package/dist/api/routes/entities.d.ts.map +1 -0
- package/dist/api/routes/entities.js +176 -0
- package/dist/api/routes/entities.js.map +1 -0
- package/dist/api/routes/git-accounts.d.ts +23 -0
- package/dist/api/routes/git-accounts.d.ts.map +1 -0
- package/dist/api/routes/git-accounts.js +227 -0
- package/dist/api/routes/git-accounts.js.map +1 -0
- package/dist/api/routes/git-templates.d.ts +50 -0
- package/dist/api/routes/git-templates.d.ts.map +1 -0
- package/dist/api/routes/git-templates.js +276 -0
- package/dist/api/routes/git-templates.js.map +1 -0
- package/dist/api/routes/git.d.ts +34 -0
- package/dist/api/routes/git.d.ts.map +1 -0
- package/dist/api/routes/git.js +126 -0
- package/dist/api/routes/git.js.map +1 -0
- package/dist/api/routes/github.d.ts +34 -0
- package/dist/api/routes/github.d.ts.map +1 -0
- package/dist/api/routes/github.js +465 -0
- package/dist/api/routes/github.js.map +1 -0
- package/dist/api/routes/health.d.ts +4 -0
- package/dist/api/routes/health.d.ts.map +1 -0
- package/dist/api/routes/health.js +257 -0
- package/dist/api/routes/health.js.map +1 -0
- package/dist/api/routes/integrations-reconcile.d.ts +33 -0
- package/dist/api/routes/integrations-reconcile.d.ts.map +1 -0
- package/dist/api/routes/integrations-reconcile.js +463 -0
- package/dist/api/routes/integrations-reconcile.js.map +1 -0
- package/dist/api/routes/integrations.d.ts +19 -0
- package/dist/api/routes/integrations.d.ts.map +1 -0
- package/dist/api/routes/integrations.js +1384 -0
- package/dist/api/routes/integrations.js.map +1 -0
- package/dist/api/routes/knowledge.d.ts +4 -0
- package/dist/api/routes/knowledge.d.ts.map +1 -0
- package/dist/api/routes/knowledge.js +224 -0
- package/dist/api/routes/knowledge.js.map +1 -0
- package/dist/api/routes/mail.d.ts +39 -0
- package/dist/api/routes/mail.d.ts.map +1 -0
- package/dist/api/routes/mail.js +1406 -0
- package/dist/api/routes/mail.js.map +1 -0
- package/dist/api/routes/managed-tasks.d.ts +48 -0
- package/dist/api/routes/managed-tasks.d.ts.map +1 -0
- package/dist/api/routes/managed-tasks.js +844 -0
- package/dist/api/routes/managed-tasks.js.map +1 -0
- package/dist/api/routes/mcp.d.ts +50 -0
- package/dist/api/routes/mcp.d.ts.map +1 -0
- package/dist/api/routes/mcp.js +470 -0
- package/dist/api/routes/mcp.js.map +1 -0
- package/dist/api/routes/metrics.d.ts +13 -0
- package/dist/api/routes/metrics.d.ts.map +1 -0
- package/dist/api/routes/metrics.js +117 -0
- package/dist/api/routes/metrics.js.map +1 -0
- package/dist/api/routes/notion.d.ts +35 -0
- package/dist/api/routes/notion.d.ts.map +1 -0
- package/dist/api/routes/notion.js +442 -0
- package/dist/api/routes/notion.js.map +1 -0
- package/dist/api/routes/observations.d.ts +4 -0
- package/dist/api/routes/observations.d.ts.map +1 -0
- package/dist/api/routes/observations.js +177 -0
- package/dist/api/routes/observations.js.map +1 -0
- package/dist/api/routes/obsidian.d.ts +16 -0
- package/dist/api/routes/obsidian.d.ts.map +1 -0
- package/dist/api/routes/obsidian.js +321 -0
- package/dist/api/routes/obsidian.js.map +1 -0
- package/dist/api/routes/profile-questions.d.ts +17 -0
- package/dist/api/routes/profile-questions.d.ts.map +1 -0
- package/dist/api/routes/profile-questions.js +115 -0
- package/dist/api/routes/profile-questions.js.map +1 -0
- package/dist/api/routes/receipts.d.ts +4 -0
- package/dist/api/routes/receipts.d.ts.map +1 -0
- package/dist/api/routes/receipts.js +155 -0
- package/dist/api/routes/receipts.js.map +1 -0
- package/dist/api/routes/recurring-schedules.d.ts +4 -0
- package/dist/api/routes/recurring-schedules.d.ts.map +1 -0
- package/dist/api/routes/recurring-schedules.js +137 -0
- package/dist/api/routes/recurring-schedules.js.map +1 -0
- package/dist/api/routes/repositories.d.ts +40 -0
- package/dist/api/routes/repositories.d.ts.map +1 -0
- package/dist/api/routes/repositories.js +857 -0
- package/dist/api/routes/repositories.js.map +1 -0
- package/dist/api/routes/setup-migrate.d.ts +74 -0
- package/dist/api/routes/setup-migrate.d.ts.map +1 -0
- package/dist/api/routes/setup-migrate.js +944 -0
- package/dist/api/routes/setup-migrate.js.map +1 -0
- package/dist/api/routes/setup.d.ts +4 -0
- package/dist/api/routes/setup.d.ts.map +1 -0
- package/dist/api/routes/setup.js +443 -0
- package/dist/api/routes/setup.js.map +1 -0
- package/dist/api/routes/skill-curation.d.ts +5 -0
- package/dist/api/routes/skill-curation.d.ts.map +1 -0
- package/dist/api/routes/skill-curation.js +728 -0
- package/dist/api/routes/skill-curation.js.map +1 -0
- package/dist/api/routes/skills.d.ts +52 -0
- package/dist/api/routes/skills.d.ts.map +1 -0
- package/dist/api/routes/skills.js +429 -0
- package/dist/api/routes/skills.js.map +1 -0
- package/dist/api/routes/sot-bindings.d.ts +20 -0
- package/dist/api/routes/sot-bindings.d.ts.map +1 -0
- package/dist/api/routes/sot-bindings.js +163 -0
- package/dist/api/routes/sot-bindings.js.map +1 -0
- package/dist/api/routes/sse.d.ts +86 -0
- package/dist/api/routes/sse.d.ts.map +1 -0
- package/dist/api/routes/sse.js +378 -0
- package/dist/api/routes/sse.js.map +1 -0
- package/dist/api/routes/system.d.ts +4 -0
- package/dist/api/routes/system.d.ts.map +1 -0
- package/dist/api/routes/system.js +207 -0
- package/dist/api/routes/system.js.map +1 -0
- package/dist/api/routes/task-flows.d.ts +30 -0
- package/dist/api/routes/task-flows.d.ts.map +1 -0
- package/dist/api/routes/task-flows.js +155 -0
- package/dist/api/routes/task-flows.js.map +1 -0
- package/dist/api/routes/travel-bookings.d.ts +4 -0
- package/dist/api/routes/travel-bookings.d.ts.map +1 -0
- package/dist/api/routes/travel-bookings.js +142 -0
- package/dist/api/routes/travel-bookings.js.map +1 -0
- package/dist/api/routes/travel-time.d.ts +8 -0
- package/dist/api/routes/travel-time.d.ts.map +1 -0
- package/dist/api/routes/travel-time.js +87 -0
- package/dist/api/routes/travel-time.js.map +1 -0
- package/dist/api/routes/triggers.d.ts +4 -0
- package/dist/api/routes/triggers.d.ts.map +1 -0
- package/dist/api/routes/triggers.js +101 -0
- package/dist/api/routes/triggers.js.map +1 -0
- package/dist/api/routes/voice.d.ts +48 -0
- package/dist/api/routes/voice.d.ts.map +1 -0
- package/dist/api/routes/voice.js +232 -0
- package/dist/api/routes/voice.js.map +1 -0
- package/dist/api/server.d.ts +428 -0
- package/dist/api/server.d.ts.map +1 -0
- package/dist/api/server.js +558 -0
- package/dist/api/server.js.map +1 -0
- package/dist/config.d.ts +136 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +699 -0
- package/dist/config.js.map +1 -0
- package/dist/core/agent-core.d.ts +517 -0
- package/dist/core/agent-core.d.ts.map +1 -0
- package/dist/core/agent-core.js +102 -0
- package/dist/core/agent-core.js.map +1 -0
- package/dist/core/alerts.d.ts +86 -0
- package/dist/core/alerts.d.ts.map +1 -0
- package/dist/core/alerts.js +304 -0
- package/dist/core/alerts.js.map +1 -0
- package/dist/core/atomic-write.d.ts +51 -0
- package/dist/core/atomic-write.d.ts.map +1 -0
- package/dist/core/atomic-write.js +135 -0
- package/dist/core/atomic-write.js.map +1 -0
- package/dist/core/backends/api-key-probe.d.ts +40 -0
- package/dist/core/backends/api-key-probe.d.ts.map +1 -0
- package/dist/core/backends/api-key-probe.js +116 -0
- package/dist/core/backends/api-key-probe.js.map +1 -0
- package/dist/core/backends/auth-health-monitor.d.ts +373 -0
- package/dist/core/backends/auth-health-monitor.d.ts.map +1 -0
- package/dist/core/backends/auth-health-monitor.js +950 -0
- package/dist/core/backends/auth-health-monitor.js.map +1 -0
- package/dist/core/backends/auth-recovery.d.ts +263 -0
- package/dist/core/backends/auth-recovery.d.ts.map +1 -0
- package/dist/core/backends/auth-recovery.js +1086 -0
- package/dist/core/backends/auth-recovery.js.map +1 -0
- package/dist/core/backends/auth-telemetry.d.ts +81 -0
- package/dist/core/backends/auth-telemetry.d.ts.map +1 -0
- package/dist/core/backends/auth-telemetry.js +108 -0
- package/dist/core/backends/auth-telemetry.js.map +1 -0
- package/dist/core/backends/backend-router.d.ts +272 -0
- package/dist/core/backends/backend-router.d.ts.map +1 -0
- package/dist/core/backends/backend-router.js +759 -0
- package/dist/core/backends/backend-router.js.map +1 -0
- package/dist/core/backends/claude-code-core.d.ts +299 -0
- package/dist/core/backends/claude-code-core.d.ts.map +1 -0
- package/dist/core/backends/claude-code-core.js +2541 -0
- package/dist/core/backends/claude-code-core.js.map +1 -0
- package/dist/core/backends/claude-credentials-store.d.ts +83 -0
- package/dist/core/backends/claude-credentials-store.d.ts.map +1 -0
- package/dist/core/backends/claude-credentials-store.js +243 -0
- package/dist/core/backends/claude-credentials-store.js.map +1 -0
- package/dist/core/backends/cli-utils.d.ts +95 -0
- package/dist/core/backends/cli-utils.d.ts.map +1 -0
- package/dist/core/backends/cli-utils.js +464 -0
- package/dist/core/backends/cli-utils.js.map +1 -0
- package/dist/core/backends/codex-core.d.ts +127 -0
- package/dist/core/backends/codex-core.d.ts.map +1 -0
- package/dist/core/backends/codex-core.js +1693 -0
- package/dist/core/backends/codex-core.js.map +1 -0
- package/dist/core/backends/gemini-cli-core.d.ts +367 -0
- package/dist/core/backends/gemini-cli-core.d.ts.map +1 -0
- package/dist/core/backends/gemini-cli-core.js +2331 -0
- package/dist/core/backends/gemini-cli-core.js.map +1 -0
- package/dist/core/backends/idle-watchdog.d.ts +77 -0
- package/dist/core/backends/idle-watchdog.d.ts.map +1 -0
- package/dist/core/backends/idle-watchdog.js +94 -0
- package/dist/core/backends/idle-watchdog.js.map +1 -0
- package/dist/core/backends/install-methods.d.ts +93 -0
- package/dist/core/backends/install-methods.d.ts.map +1 -0
- package/dist/core/backends/install-methods.js +267 -0
- package/dist/core/backends/install-methods.js.map +1 -0
- package/dist/core/backends/model-registry.d.ts +58 -0
- package/dist/core/backends/model-registry.d.ts.map +1 -0
- package/dist/core/backends/model-registry.js +539 -0
- package/dist/core/backends/model-registry.js.map +1 -0
- package/dist/core/backends/plan-presets.d.ts +123 -0
- package/dist/core/backends/plan-presets.d.ts.map +1 -0
- package/dist/core/backends/plan-presets.js +235 -0
- package/dist/core/backends/plan-presets.js.map +1 -0
- package/dist/core/backends/price-fetcher.d.ts +48 -0
- package/dist/core/backends/price-fetcher.d.ts.map +1 -0
- package/dist/core/backends/price-fetcher.js +248 -0
- package/dist/core/backends/price-fetcher.js.map +1 -0
- package/dist/core/backends/process-config-cascade.d.ts +68 -0
- package/dist/core/backends/process-config-cascade.d.ts.map +1 -0
- package/dist/core/backends/process-config-cascade.js +173 -0
- package/dist/core/backends/process-config-cascade.js.map +1 -0
- package/dist/core/backends/prompt-utils.d.ts +6 -0
- package/dist/core/backends/prompt-utils.d.ts.map +1 -0
- package/dist/core/backends/prompt-utils.js +80 -0
- package/dist/core/backends/prompt-utils.js.map +1 -0
- package/dist/core/backends/proxy-model-registry.d.ts +110 -0
- package/dist/core/backends/proxy-model-registry.d.ts.map +1 -0
- package/dist/core/backends/proxy-model-registry.js +195 -0
- package/dist/core/backends/proxy-model-registry.js.map +1 -0
- package/dist/core/backends/silent-api-error-detector.d.ts +31 -0
- package/dist/core/backends/silent-api-error-detector.d.ts.map +1 -0
- package/dist/core/backends/silent-api-error-detector.js +44 -0
- package/dist/core/backends/silent-api-error-detector.js.map +1 -0
- package/dist/core/bang-commands/commands-cost.d.ts +13 -0
- package/dist/core/bang-commands/commands-cost.d.ts.map +1 -0
- package/dist/core/bang-commands/commands-cost.js +91 -0
- package/dist/core/bang-commands/commands-cost.js.map +1 -0
- package/dist/core/bang-commands/commands-report.d.ts +18 -0
- package/dist/core/bang-commands/commands-report.d.ts.map +1 -0
- package/dist/core/bang-commands/commands-report.js +105 -0
- package/dist/core/bang-commands/commands-report.js.map +1 -0
- package/dist/core/bang-commands/commands-stop-start.d.ts +4 -0
- package/dist/core/bang-commands/commands-stop-start.d.ts.map +1 -0
- package/dist/core/bang-commands/commands-stop-start.js +88 -0
- package/dist/core/bang-commands/commands-stop-start.js.map +1 -0
- package/dist/core/bang-commands/format-utils.d.ts +34 -0
- package/dist/core/bang-commands/format-utils.d.ts.map +1 -0
- package/dist/core/bang-commands/format-utils.js +118 -0
- package/dist/core/bang-commands/format-utils.js.map +1 -0
- package/dist/core/bang-commands/index.d.ts +20 -0
- package/dist/core/bang-commands/index.d.ts.map +1 -0
- package/dist/core/bang-commands/index.js +31 -0
- package/dist/core/bang-commands/index.js.map +1 -0
- package/dist/core/bang-commands/registry.d.ts +72 -0
- package/dist/core/bang-commands/registry.d.ts.map +1 -0
- package/dist/core/bang-commands/registry.js +174 -0
- package/dist/core/bang-commands/registry.js.map +1 -0
- package/dist/core/bang-commands/user-commands.d.ts +86 -0
- package/dist/core/bang-commands/user-commands.d.ts.map +1 -0
- package/dist/core/bang-commands/user-commands.js +212 -0
- package/dist/core/bang-commands/user-commands.js.map +1 -0
- package/dist/core/channel-timeline.d.ts +28 -0
- package/dist/core/channel-timeline.d.ts.map +1 -0
- package/dist/core/channel-timeline.js +117 -0
- package/dist/core/channel-timeline.js.map +1 -0
- package/dist/core/character-block.d.ts +37 -0
- package/dist/core/character-block.d.ts.map +1 -0
- package/dist/core/character-block.js +162 -0
- package/dist/core/character-block.js.map +1 -0
- package/dist/core/context/activity-sources.d.ts +37 -0
- package/dist/core/context/activity-sources.d.ts.map +1 -0
- package/dist/core/context/activity-sources.js +69 -0
- package/dist/core/context/activity-sources.js.map +1 -0
- package/dist/core/context/activity-view-reconciler.d.ts +110 -0
- package/dist/core/context/activity-view-reconciler.d.ts.map +1 -0
- package/dist/core/context/activity-view-reconciler.js +252 -0
- package/dist/core/context/activity-view-reconciler.js.map +1 -0
- package/dist/core/context/activity-view-runner.d.ts +38 -0
- package/dist/core/context/activity-view-runner.d.ts.map +1 -0
- package/dist/core/context/activity-view-runner.js +402 -0
- package/dist/core/context/activity-view-runner.js.map +1 -0
- package/dist/core/context/default-schedules-reconciler.d.ts +85 -0
- package/dist/core/context/default-schedules-reconciler.d.ts.map +1 -0
- package/dist/core/context/default-schedules-reconciler.js +153 -0
- package/dist/core/context/default-schedules-reconciler.js.map +1 -0
- package/dist/core/context/default-schedules-runner.d.ts +40 -0
- package/dist/core/context/default-schedules-runner.d.ts.map +1 -0
- package/dist/core/context/default-schedules-runner.js +233 -0
- package/dist/core/context/default-schedules-runner.js.map +1 -0
- package/dist/core/context/domain-index-reconciler.d.ts +81 -0
- package/dist/core/context/domain-index-reconciler.d.ts.map +1 -0
- package/dist/core/context/domain-index-reconciler.js +199 -0
- package/dist/core/context/domain-index-reconciler.js.map +1 -0
- package/dist/core/context/domain-index-runner.d.ts +35 -0
- package/dist/core/context/domain-index-runner.d.ts.map +1 -0
- package/dist/core/context/domain-index-runner.js +223 -0
- package/dist/core/context/domain-index-runner.js.map +1 -0
- package/dist/core/context/entity-mirror.d.ts +227 -0
- package/dist/core/context/entity-mirror.d.ts.map +1 -0
- package/dist/core/context/entity-mirror.js +629 -0
- package/dist/core/context/entity-mirror.js.map +1 -0
- package/dist/core/context/entity-source-rename.d.ts +61 -0
- package/dist/core/context/entity-source-rename.d.ts.map +1 -0
- package/dist/core/context/entity-source-rename.js +237 -0
- package/dist/core/context/entity-source-rename.js.map +1 -0
- package/dist/core/context/index-reconciler.d.ts +61 -0
- package/dist/core/context/index-reconciler.d.ts.map +1 -0
- package/dist/core/context/index-reconciler.js +329 -0
- package/dist/core/context/index-reconciler.js.map +1 -0
- package/dist/core/context/policy-index-reconciler.d.ts +102 -0
- package/dist/core/context/policy-index-reconciler.d.ts.map +1 -0
- package/dist/core/context/policy-index-reconciler.js +202 -0
- package/dist/core/context/policy-index-reconciler.js.map +1 -0
- package/dist/core/context/policy-index-runner.d.ts +66 -0
- package/dist/core/context/policy-index-runner.d.ts.map +1 -0
- package/dist/core/context/policy-index-runner.js +406 -0
- package/dist/core/context/policy-index-runner.js.map +1 -0
- package/dist/core/context/reconciler-runner.d.ts +44 -0
- package/dist/core/context/reconciler-runner.d.ts.map +1 -0
- package/dist/core/context/reconciler-runner.js +273 -0
- package/dist/core/context/reconciler-runner.js.map +1 -0
- package/dist/core/context-builder.d.ts +115 -0
- package/dist/core/context-builder.d.ts.map +1 -0
- package/dist/core/context-builder.js +1148 -0
- package/dist/core/context-builder.js.map +1 -0
- package/dist/core/context-frontmatter-backfill.d.ts +33 -0
- package/dist/core/context-frontmatter-backfill.d.ts.map +1 -0
- package/dist/core/context-frontmatter-backfill.js +111 -0
- package/dist/core/context-frontmatter-backfill.js.map +1 -0
- package/dist/core/context-frontmatter.d.ts +13 -0
- package/dist/core/context-frontmatter.d.ts.map +1 -0
- package/dist/core/context-frontmatter.js +325 -0
- package/dist/core/context-frontmatter.js.map +1 -0
- package/dist/core/context-health.d.ts +51 -0
- package/dist/core/context-health.d.ts.map +1 -0
- package/dist/core/context-health.js +304 -0
- package/dist/core/context-health.js.map +1 -0
- package/dist/core/context-paths.d.ts +183 -0
- package/dist/core/context-paths.d.ts.map +1 -0
- package/dist/core/context-paths.js +241 -0
- package/dist/core/context-paths.js.map +1 -0
- package/dist/core/context-staleness.d.ts +45 -0
- package/dist/core/context-staleness.d.ts.map +1 -0
- package/dist/core/context-staleness.js +88 -0
- package/dist/core/context-staleness.js.map +1 -0
- package/dist/core/custom-routine-scheduler.d.ts +151 -0
- package/dist/core/custom-routine-scheduler.d.ts.map +1 -0
- package/dist/core/custom-routine-scheduler.js +335 -0
- package/dist/core/custom-routine-scheduler.js.map +1 -0
- package/dist/core/daemon-api-cli.d.ts +33 -0
- package/dist/core/daemon-api-cli.d.ts.map +1 -0
- package/dist/core/daemon-api-cli.js +614 -0
- package/dist/core/daemon-api-cli.js.map +1 -0
- package/dist/core/dashboard-session-cleanup.d.ts +39 -0
- package/dist/core/dashboard-session-cleanup.d.ts.map +1 -0
- package/dist/core/dashboard-session-cleanup.js +108 -0
- package/dist/core/dashboard-session-cleanup.js.map +1 -0
- package/dist/core/dashboard-session-controls.d.ts +41 -0
- package/dist/core/dashboard-session-controls.d.ts.map +1 -0
- package/dist/core/dashboard-session-controls.js +154 -0
- package/dist/core/dashboard-session-controls.js.map +1 -0
- package/dist/core/delegated-connector-health.d.ts +63 -0
- package/dist/core/delegated-connector-health.d.ts.map +1 -0
- package/dist/core/delegated-connector-health.js +157 -0
- package/dist/core/delegated-connector-health.js.map +1 -0
- package/dist/core/dispatcher.d.ts +999 -0
- package/dist/core/dispatcher.d.ts.map +1 -0
- package/dist/core/dispatcher.js +4378 -0
- package/dist/core/dispatcher.js.map +1 -0
- package/dist/core/dm-freshness-metrics.d.ts +73 -0
- package/dist/core/dm-freshness-metrics.d.ts.map +1 -0
- package/dist/core/dm-freshness-metrics.js +138 -0
- package/dist/core/dm-freshness-metrics.js.map +1 -0
- package/dist/core/docs/citation-validator.d.ts +73 -0
- package/dist/core/docs/citation-validator.d.ts.map +1 -0
- package/dist/core/docs/citation-validator.js +195 -0
- package/dist/core/docs/citation-validator.js.map +1 -0
- package/dist/core/docs/extract-terms.d.ts +78 -0
- package/dist/core/docs/extract-terms.d.ts.map +1 -0
- package/dist/core/docs/extract-terms.js +147 -0
- package/dist/core/docs/extract-terms.js.map +1 -0
- package/dist/core/docs/indexer.d.ts +104 -0
- package/dist/core/docs/indexer.d.ts.map +1 -0
- package/dist/core/docs/indexer.js +340 -0
- package/dist/core/docs/indexer.js.map +1 -0
- package/dist/core/drift-effects.d.ts +30 -0
- package/dist/core/drift-effects.d.ts.map +1 -0
- package/dist/core/drift-effects.js +384 -0
- package/dist/core/drift-effects.js.map +1 -0
- package/dist/core/event-bus.d.ts +56 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +135 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/git-project-docs.d.ts +77 -0
- package/dist/core/git-project-docs.d.ts.map +1 -0
- package/dist/core/git-project-docs.js +439 -0
- package/dist/core/git-project-docs.js.map +1 -0
- package/dist/core/health-monitor.d.ts +57 -0
- package/dist/core/health-monitor.d.ts.map +1 -0
- package/dist/core/health-monitor.js +137 -0
- package/dist/core/health-monitor.js.map +1 -0
- package/dist/core/heartbeat.d.ts +26 -0
- package/dist/core/heartbeat.d.ts.map +1 -0
- package/dist/core/heartbeat.js +48 -0
- package/dist/core/heartbeat.js.map +1 -0
- package/dist/core/integration-health.d.ts +49 -0
- package/dist/core/integration-health.d.ts.map +1 -0
- package/dist/core/integration-health.js +89 -0
- package/dist/core/integration-health.js.map +1 -0
- package/dist/core/integration-lifecycle.d.ts +79 -0
- package/dist/core/integration-lifecycle.d.ts.map +1 -0
- package/dist/core/integration-lifecycle.js +153 -0
- package/dist/core/integration-lifecycle.js.map +1 -0
- package/dist/core/integration-main-backend.d.ts +36 -0
- package/dist/core/integration-main-backend.d.ts.map +1 -0
- package/dist/core/integration-main-backend.js +59 -0
- package/dist/core/integration-main-backend.js.map +1 -0
- package/dist/core/integration-probe.d.ts +98 -0
- package/dist/core/integration-probe.d.ts.map +1 -0
- package/dist/core/integration-probe.js +152 -0
- package/dist/core/integration-probe.js.map +1 -0
- package/dist/core/management-md-write-lock.d.ts +68 -0
- package/dist/core/management-md-write-lock.d.ts.map +1 -0
- package/dist/core/management-md-write-lock.js +93 -0
- package/dist/core/management-md-write-lock.js.map +1 -0
- package/dist/core/management-md.d.ts +186 -0
- package/dist/core/management-md.d.ts.map +1 -0
- package/dist/core/management-md.js +652 -0
- package/dist/core/management-md.js.map +1 -0
- package/dist/core/management-registry.d.ts +245 -0
- package/dist/core/management-registry.d.ts.map +1 -0
- package/dist/core/management-registry.js +906 -0
- package/dist/core/management-registry.js.map +1 -0
- package/dist/core/management-telemetry.d.ts +100 -0
- package/dist/core/management-telemetry.d.ts.map +1 -0
- package/dist/core/management-telemetry.js +156 -0
- package/dist/core/management-telemetry.js.map +1 -0
- package/dist/core/message-recorder.d.ts +38 -0
- package/dist/core/message-recorder.d.ts.map +1 -0
- package/dist/core/message-recorder.js +88 -0
- package/dist/core/message-recorder.js.map +1 -0
- package/dist/core/metrics.d.ts +338 -0
- package/dist/core/metrics.d.ts.map +1 -0
- package/dist/core/metrics.js +747 -0
- package/dist/core/metrics.js.map +1 -0
- package/dist/core/migration-backup.d.ts +218 -0
- package/dist/core/migration-backup.d.ts.map +1 -0
- package/dist/core/migration-backup.js +934 -0
- package/dist/core/migration-backup.js.map +1 -0
- package/dist/core/overview-write-lock.d.ts +48 -0
- package/dist/core/overview-write-lock.d.ts.map +1 -0
- package/dist/core/overview-write-lock.js +56 -0
- package/dist/core/overview-write-lock.js.map +1 -0
- package/dist/core/path-compat.d.ts +22 -0
- package/dist/core/path-compat.d.ts.map +1 -0
- package/dist/core/path-compat.js +67 -0
- package/dist/core/path-compat.js.map +1 -0
- package/dist/core/path-rewrite.d.ts +58 -0
- package/dist/core/path-rewrite.d.ts.map +1 -0
- package/dist/core/path-rewrite.js +141 -0
- package/dist/core/path-rewrite.js.map +1 -0
- package/dist/core/policy-files.d.ts +108 -0
- package/dist/core/policy-files.d.ts.map +1 -0
- package/dist/core/policy-files.js +198 -0
- package/dist/core/policy-files.js.map +1 -0
- package/dist/core/profile-questions/seed.d.ts +44 -0
- package/dist/core/profile-questions/seed.d.ts.map +1 -0
- package/dist/core/profile-questions/seed.js +173 -0
- package/dist/core/profile-questions/seed.js.map +1 -0
- package/dist/core/profile-questions/slot-filled.d.ts +51 -0
- package/dist/core/profile-questions/slot-filled.d.ts.map +1 -0
- package/dist/core/profile-questions/slot-filled.js +118 -0
- package/dist/core/profile-questions/slot-filled.js.map +1 -0
- package/dist/core/prompts.d.ts +111 -0
- package/dist/core/prompts.d.ts.map +1 -0
- package/dist/core/prompts.js +267 -0
- package/dist/core/prompts.js.map +1 -0
- package/dist/core/quiet-hours-sync.d.ts +15 -0
- package/dist/core/quiet-hours-sync.d.ts.map +1 -0
- package/dist/core/quiet-hours-sync.js +51 -0
- package/dist/core/quiet-hours-sync.js.map +1 -0
- package/dist/core/read-sensitive-token-manager.d.ts +19 -0
- package/dist/core/read-sensitive-token-manager.d.ts.map +1 -0
- package/dist/core/read-sensitive-token-manager.js +29 -0
- package/dist/core/read-sensitive-token-manager.js.map +1 -0
- package/dist/core/recurrence.d.ts +24 -0
- package/dist/core/recurrence.d.ts.map +1 -0
- package/dist/core/recurrence.js +162 -0
- package/dist/core/recurrence.js.map +1 -0
- package/dist/core/reinstall.d.ts +107 -0
- package/dist/core/reinstall.d.ts.map +1 -0
- package/dist/core/reinstall.js +163 -0
- package/dist/core/reinstall.js.map +1 -0
- package/dist/core/release-assets.d.ts +106 -0
- package/dist/core/release-assets.d.ts.map +1 -0
- package/dist/core/release-assets.js +434 -0
- package/dist/core/release-assets.js.map +1 -0
- package/dist/core/repository-management-docs.d.ts +216 -0
- package/dist/core/repository-management-docs.d.ts.map +1 -0
- package/dist/core/repository-management-docs.js +855 -0
- package/dist/core/repository-management-docs.js.map +1 -0
- package/dist/core/retention.d.ts +164 -0
- package/dist/core/retention.d.ts.map +1 -0
- package/dist/core/retention.js +1008 -0
- package/dist/core/retention.js.map +1 -0
- package/dist/core/review-context.d.ts +48 -0
- package/dist/core/review-context.d.ts.map +1 -0
- package/dist/core/review-context.js +282 -0
- package/dist/core/review-context.js.map +1 -0
- package/dist/core/roadmap-horizon.d.ts +48 -0
- package/dist/core/roadmap-horizon.d.ts.map +1 -0
- package/dist/core/roadmap-horizon.js +213 -0
- package/dist/core/roadmap-horizon.js.map +1 -0
- package/dist/core/roadmap-ids.d.ts +57 -0
- package/dist/core/roadmap-ids.d.ts.map +1 -0
- package/dist/core/roadmap-ids.js +118 -0
- package/dist/core/roadmap-ids.js.map +1 -0
- package/dist/core/roadmap-merge.d.ts +7 -0
- package/dist/core/roadmap-merge.d.ts.map +1 -0
- package/dist/core/roadmap-merge.js +187 -0
- package/dist/core/roadmap-merge.js.map +1 -0
- package/dist/core/roadmap-refresh-triggers.d.ts +32 -0
- package/dist/core/roadmap-refresh-triggers.d.ts.map +1 -0
- package/dist/core/roadmap-refresh-triggers.js +51 -0
- package/dist/core/roadmap-refresh-triggers.js.map +1 -0
- package/dist/core/roadmap-truncate.d.ts +49 -0
- package/dist/core/roadmap-truncate.d.ts.map +1 -0
- package/dist/core/roadmap-truncate.js +152 -0
- package/dist/core/roadmap-truncate.js.map +1 -0
- package/dist/core/roadmap-validate.d.ts +31 -0
- package/dist/core/roadmap-validate.d.ts.map +1 -0
- package/dist/core/roadmap-validate.js +403 -0
- package/dist/core/roadmap-validate.js.map +1 -0
- package/dist/core/roadmap-write-lock.d.ts +53 -0
- package/dist/core/roadmap-write-lock.d.ts.map +1 -0
- package/dist/core/roadmap-write-lock.js +59 -0
- package/dist/core/roadmap-write-lock.js.map +1 -0
- package/dist/core/schedule-insert-helper.d.ts +46 -0
- package/dist/core/schedule-insert-helper.d.ts.map +1 -0
- package/dist/core/schedule-insert-helper.js +52 -0
- package/dist/core/schedule-insert-helper.js.map +1 -0
- package/dist/core/schedule-maintenance.d.ts +22 -0
- package/dist/core/schedule-maintenance.d.ts.map +1 -0
- package/dist/core/schedule-maintenance.js +57 -0
- package/dist/core/schedule-maintenance.js.map +1 -0
- package/dist/core/scheduler.d.ts +208 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +896 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/semaphore.d.ts +13 -0
- package/dist/core/semaphore.d.ts.map +1 -0
- package/dist/core/semaphore.js +31 -0
- package/dist/core/semaphore.js.map +1 -0
- package/dist/core/session-gate.d.ts +37 -0
- package/dist/core/session-gate.d.ts.map +1 -0
- package/dist/core/session-gate.js +69 -0
- package/dist/core/session-gate.js.map +1 -0
- package/dist/core/session-manager.d.ts +252 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +716 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/signal-detector.d.ts +97 -0
- package/dist/core/signal-detector.d.ts.map +1 -0
- package/dist/core/signal-detector.js +215 -0
- package/dist/core/signal-detector.js.map +1 -0
- package/dist/core/skeleton.d.ts +83 -0
- package/dist/core/skeleton.d.ts.map +1 -0
- package/dist/core/skeleton.js +255 -0
- package/dist/core/skeleton.js.map +1 -0
- package/dist/core/skill-curation/apply-proposal.d.ts +71 -0
- package/dist/core/skill-curation/apply-proposal.d.ts.map +1 -0
- package/dist/core/skill-curation/apply-proposal.js +175 -0
- package/dist/core/skill-curation/apply-proposal.js.map +1 -0
- package/dist/core/skill-curation/auto-revert.d.ts +43 -0
- package/dist/core/skill-curation/auto-revert.d.ts.map +1 -0
- package/dist/core/skill-curation/auto-revert.js +155 -0
- package/dist/core/skill-curation/auto-revert.js.map +1 -0
- package/dist/core/skill-curation/classify-diff.d.ts +27 -0
- package/dist/core/skill-curation/classify-diff.d.ts.map +1 -0
- package/dist/core/skill-curation/classify-diff.js +0 -0
- package/dist/core/skill-curation/classify-diff.js.map +1 -0
- package/dist/core/skill-curation/declarations.d.ts +32 -0
- package/dist/core/skill-curation/declarations.d.ts.map +1 -0
- package/dist/core/skill-curation/declarations.js +171 -0
- package/dist/core/skill-curation/declarations.js.map +1 -0
- package/dist/core/skill-curation/knowledge-map.d.ts +26 -0
- package/dist/core/skill-curation/knowledge-map.d.ts.map +1 -0
- package/dist/core/skill-curation/knowledge-map.js +154 -0
- package/dist/core/skill-curation/knowledge-map.js.map +1 -0
- package/dist/core/skill-curation/orphan-overlay.d.ts +35 -0
- package/dist/core/skill-curation/orphan-overlay.d.ts.map +1 -0
- package/dist/core/skill-curation/orphan-overlay.js +167 -0
- package/dist/core/skill-curation/orphan-overlay.js.map +1 -0
- package/dist/core/skill-curation/overlay-store.d.ts +41 -0
- package/dist/core/skill-curation/overlay-store.d.ts.map +1 -0
- package/dist/core/skill-curation/overlay-store.js +143 -0
- package/dist/core/skill-curation/overlay-store.js.map +1 -0
- package/dist/core/skill-curation/render/convention-notes.d.ts +4 -0
- package/dist/core/skill-curation/render/convention-notes.d.ts.map +1 -0
- package/dist/core/skill-curation/render/convention-notes.js +13 -0
- package/dist/core/skill-curation/render/convention-notes.js.map +1 -0
- package/dist/core/skill-curation/render/cross-references.d.ts +4 -0
- package/dist/core/skill-curation/render/cross-references.d.ts.map +1 -0
- package/dist/core/skill-curation/render/cross-references.js +10 -0
- package/dist/core/skill-curation/render/cross-references.js.map +1 -0
- package/dist/core/skill-curation/render/frontmatter-schema.d.ts +4 -0
- package/dist/core/skill-curation/render/frontmatter-schema.d.ts.map +1 -0
- package/dist/core/skill-curation/render/frontmatter-schema.js +25 -0
- package/dist/core/skill-curation/render/frontmatter-schema.js.map +1 -0
- package/dist/core/skill-curation/render/index.d.ts +5 -0
- package/dist/core/skill-curation/render/index.d.ts.map +1 -0
- package/dist/core/skill-curation/render/index.js +42 -0
- package/dist/core/skill-curation/render/index.js.map +1 -0
- package/dist/core/skill-curation/render/knowledge-layout.d.ts +4 -0
- package/dist/core/skill-curation/render/knowledge-layout.d.ts.map +1 -0
- package/dist/core/skill-curation/render/knowledge-layout.js +36 -0
- package/dist/core/skill-curation/render/knowledge-layout.js.map +1 -0
- package/dist/core/skill-curation/render/routing-table.d.ts +4 -0
- package/dist/core/skill-curation/render/routing-table.d.ts.map +1 -0
- package/dist/core/skill-curation/render/routing-table.js +37 -0
- package/dist/core/skill-curation/render/routing-table.js.map +1 -0
- package/dist/core/skill-curation/render/search-recipes.d.ts +4 -0
- package/dist/core/skill-curation/render/search-recipes.d.ts.map +1 -0
- package/dist/core/skill-curation/render/search-recipes.js +39 -0
- package/dist/core/skill-curation/render/search-recipes.js.map +1 -0
- package/dist/core/skill-curation/run-token.d.ts +27 -0
- package/dist/core/skill-curation/run-token.d.ts.map +1 -0
- package/dist/core/skill-curation/run-token.js +81 -0
- package/dist/core/skill-curation/run-token.js.map +1 -0
- package/dist/core/skill-curation/signals.d.ts +49 -0
- package/dist/core/skill-curation/signals.d.ts.map +1 -0
- package/dist/core/skill-curation/signals.js +149 -0
- package/dist/core/skill-curation/signals.js.map +1 -0
- package/dist/core/skill-curation/smoke-test.d.ts +39 -0
- package/dist/core/skill-curation/smoke-test.d.ts.map +1 -0
- package/dist/core/skill-curation/smoke-test.js +313 -0
- package/dist/core/skill-curation/smoke-test.js.map +1 -0
- package/dist/core/skill-curation/splicer.d.ts +16 -0
- package/dist/core/skill-curation/splicer.d.ts.map +1 -0
- package/dist/core/skill-curation/splicer.js +78 -0
- package/dist/core/skill-curation/splicer.js.map +1 -0
- package/dist/core/skill-curation/workdir.d.ts +40 -0
- package/dist/core/skill-curation/workdir.d.ts.map +1 -0
- package/dist/core/skill-curation/workdir.js +242 -0
- package/dist/core/skill-curation/workdir.js.map +1 -0
- package/dist/core/skills-compiler.d.ts +391 -0
- package/dist/core/skills-compiler.d.ts.map +1 -0
- package/dist/core/skills-compiler.js +1271 -0
- package/dist/core/skills-compiler.js.map +1 -0
- package/dist/core/skills-manifest.d.ts +8 -0
- package/dist/core/skills-manifest.d.ts.map +1 -0
- package/dist/core/skills-manifest.js +408 -0
- package/dist/core/skills-manifest.js.map +1 -0
- package/dist/core/system-reset.d.ts +268 -0
- package/dist/core/system-reset.d.ts.map +1 -0
- package/dist/core/system-reset.js +816 -0
- package/dist/core/system-reset.js.map +1 -0
- package/dist/core/template-store.d.ts +170 -0
- package/dist/core/template-store.d.ts.map +1 -0
- package/dist/core/template-store.js +388 -0
- package/dist/core/template-store.js.map +1 -0
- package/dist/core/template-versions.d.ts +95 -0
- package/dist/core/template-versions.d.ts.map +1 -0
- package/dist/core/template-versions.js +175 -0
- package/dist/core/template-versions.js.map +1 -0
- package/dist/core/today-agent-plan.d.ts +33 -0
- package/dist/core/today-agent-plan.d.ts.map +1 -0
- package/dist/core/today-agent-plan.js +120 -0
- package/dist/core/today-agent-plan.js.map +1 -0
- package/dist/core/today-direct-writer.d.ts +62 -0
- package/dist/core/today-direct-writer.d.ts.map +1 -0
- package/dist/core/today-direct-writer.js +132 -0
- package/dist/core/today-direct-writer.js.map +1 -0
- package/dist/core/today-write-lock.d.ts +89 -0
- package/dist/core/today-write-lock.d.ts.map +1 -0
- package/dist/core/today-write-lock.js +154 -0
- package/dist/core/today-write-lock.js.map +1 -0
- package/dist/core/trigger-dispatch.d.ts +31 -0
- package/dist/core/trigger-dispatch.d.ts.map +1 -0
- package/dist/core/trigger-dispatch.js +100 -0
- package/dist/core/trigger-dispatch.js.map +1 -0
- package/dist/core/trigger-evaluator.d.ts +59 -0
- package/dist/core/trigger-evaluator.d.ts.map +1 -0
- package/dist/core/trigger-evaluator.js +243 -0
- package/dist/core/trigger-evaluator.js.map +1 -0
- package/dist/core/workdir.d.ts +241 -0
- package/dist/core/workdir.d.ts.map +1 -0
- package/dist/core/workdir.js +565 -0
- package/dist/core/workdir.js.map +1 -0
- package/dist/db/automation-triggers.d.ts +90 -0
- package/dist/db/automation-triggers.d.ts.map +1 -0
- package/dist/db/automation-triggers.js +199 -0
- package/dist/db/automation-triggers.js.map +1 -0
- package/dist/db/client.d.ts +6 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +47 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/entities-store.d.ts +92 -0
- package/dist/db/entities-store.d.ts.map +1 -0
- package/dist/db/entities-store.js +180 -0
- package/dist/db/entities-store.js.map +1 -0
- package/dist/db/hourly-check-signals.d.ts +78 -0
- package/dist/db/hourly-check-signals.d.ts.map +1 -0
- package/dist/db/hourly-check-signals.js +289 -0
- package/dist/db/hourly-check-signals.js.map +1 -0
- package/dist/db/integration-probe-store.d.ts +27 -0
- package/dist/db/integration-probe-store.d.ts.map +1 -0
- package/dist/db/integration-probe-store.js +75 -0
- package/dist/db/integration-probe-store.js.map +1 -0
- package/dist/db/integrations-store.d.ts +19 -0
- package/dist/db/integrations-store.d.ts.map +1 -0
- package/dist/db/integrations-store.js +85 -0
- package/dist/db/integrations-store.js.map +1 -0
- package/dist/db/managed-tasks-store.d.ts +130 -0
- package/dist/db/managed-tasks-store.d.ts.map +1 -0
- package/dist/db/managed-tasks-store.js +238 -0
- package/dist/db/managed-tasks-store.js.map +1 -0
- package/dist/db/management-parse-failures-store.d.ts +45 -0
- package/dist/db/management-parse-failures-store.d.ts.map +1 -0
- package/dist/db/management-parse-failures-store.js +36 -0
- package/dist/db/management-parse-failures-store.js.map +1 -0
- package/dist/db/observations.d.ts +145 -0
- package/dist/db/observations.d.ts.map +1 -0
- package/dist/db/observations.js +287 -0
- package/dist/db/observations.js.map +1 -0
- package/dist/db/recurring-schedules.d.ts +70 -0
- package/dist/db/recurring-schedules.d.ts.map +1 -0
- package/dist/db/recurring-schedules.js +213 -0
- package/dist/db/recurring-schedules.js.map +1 -0
- package/dist/db/repositories-store.d.ts +296 -0
- package/dist/db/repositories-store.d.ts.map +1 -0
- package/dist/db/repositories-store.js +754 -0
- package/dist/db/repositories-store.js.map +1 -0
- package/dist/db/runtime-state.d.ts +61 -0
- package/dist/db/runtime-state.d.ts.map +1 -0
- package/dist/db/runtime-state.js +104 -0
- package/dist/db/runtime-state.js.map +1 -0
- package/dist/db/schema.d.ts +4 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +1338 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/sot-bindings-store.d.ts +41 -0
- package/dist/db/sot-bindings-store.d.ts.map +1 -0
- package/dist/db/sot-bindings-store.js +64 -0
- package/dist/db/sot-bindings-store.js.map +1 -0
- package/dist/db/test-schemas.d.ts +23 -0
- package/dist/db/test-schemas.d.ts.map +1 -0
- package/dist/db/test-schemas.js +111 -0
- package/dist/db/test-schemas.js.map +1 -0
- package/dist/db/voice-transcripts-store.d.ts +28 -0
- package/dist/db/voice-transcripts-store.d.ts.map +1 -0
- package/dist/db/voice-transcripts-store.js +43 -0
- package/dist/db/voice-transcripts-store.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2913 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +7 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +32 -0
- package/dist/init.js.map +1 -0
- package/dist/log-buffer.d.ts +71 -0
- package/dist/log-buffer.d.ts.map +1 -0
- package/dist/log-buffer.js +201 -0
- package/dist/log-buffer.js.map +1 -0
- package/dist/logging.d.ts +5 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +130 -0
- package/dist/logging.js.map +1 -0
- package/dist/management-rules.d.ts +2 -0
- package/dist/management-rules.d.ts.map +1 -0
- package/dist/management-rules.js +62 -0
- package/dist/management-rules.js.map +1 -0
- package/dist/messaging/constants.d.ts +33 -0
- package/dist/messaging/constants.d.ts.map +1 -0
- package/dist/messaging/constants.js +52 -0
- package/dist/messaging/constants.js.map +1 -0
- package/dist/messaging/magic-phrase.d.ts +16 -0
- package/dist/messaging/magic-phrase.d.ts.map +1 -0
- package/dist/messaging/magic-phrase.js +103 -0
- package/dist/messaging/magic-phrase.js.map +1 -0
- package/dist/messaging/owner-channels.d.ts +20 -0
- package/dist/messaging/owner-channels.d.ts.map +1 -0
- package/dist/messaging/owner-channels.js +41 -0
- package/dist/messaging/owner-channels.js.map +1 -0
- package/dist/observers/calendar-poller.d.ts +51 -0
- package/dist/observers/calendar-poller.d.ts.map +1 -0
- package/dist/observers/calendar-poller.js +128 -0
- package/dist/observers/calendar-poller.js.map +1 -0
- package/dist/observers/context-index-reconciler-observer.d.ts +72 -0
- package/dist/observers/context-index-reconciler-observer.d.ts.map +1 -0
- package/dist/observers/context-index-reconciler-observer.js +253 -0
- package/dist/observers/context-index-reconciler-observer.js.map +1 -0
- package/dist/observers/delegated-probe-observer.d.ts +83 -0
- package/dist/observers/delegated-probe-observer.d.ts.map +1 -0
- package/dist/observers/delegated-probe-observer.js +237 -0
- package/dist/observers/delegated-probe-observer.js.map +1 -0
- package/dist/observers/delegated-sync-worker.d.ts +375 -0
- package/dist/observers/delegated-sync-worker.d.ts.map +1 -0
- package/dist/observers/delegated-sync-worker.js +1087 -0
- package/dist/observers/delegated-sync-worker.js.map +1 -0
- package/dist/observers/entity-mirror-observer.d.ts +55 -0
- package/dist/observers/entity-mirror-observer.d.ts.map +1 -0
- package/dist/observers/entity-mirror-observer.js +73 -0
- package/dist/observers/entity-mirror-observer.js.map +1 -0
- package/dist/observers/git-delegated-cron.d.ts +41 -0
- package/dist/observers/git-delegated-cron.d.ts.map +1 -0
- package/dist/observers/git-delegated-cron.js +159 -0
- package/dist/observers/git-delegated-cron.js.map +1 -0
- package/dist/observers/git-event-classifier.d.ts +52 -0
- package/dist/observers/git-event-classifier.d.ts.map +1 -0
- package/dist/observers/git-event-classifier.js +70 -0
- package/dist/observers/git-event-classifier.js.map +1 -0
- package/dist/observers/git-watcher.d.ts +162 -0
- package/dist/observers/git-watcher.d.ts.map +1 -0
- package/dist/observers/git-watcher.js +768 -0
- package/dist/observers/git-watcher.js.map +1 -0
- package/dist/observers/github-poller-classifier.d.ts +101 -0
- package/dist/observers/github-poller-classifier.d.ts.map +1 -0
- package/dist/observers/github-poller-classifier.js +199 -0
- package/dist/observers/github-poller-classifier.js.map +1 -0
- package/dist/observers/github-poller.d.ts +291 -0
- package/dist/observers/github-poller.d.ts.map +1 -0
- package/dist/observers/github-poller.js +609 -0
- package/dist/observers/github-poller.js.map +1 -0
- package/dist/observers/imminent-event-scheduler.d.ts +34 -0
- package/dist/observers/imminent-event-scheduler.d.ts.map +1 -0
- package/dist/observers/imminent-event-scheduler.js +125 -0
- package/dist/observers/imminent-event-scheduler.js.map +1 -0
- package/dist/observers/mail-poller.d.ts +133 -0
- package/dist/observers/mail-poller.d.ts.map +1 -0
- package/dist/observers/mail-poller.js +563 -0
- package/dist/observers/mail-poller.js.map +1 -0
- package/dist/observers/mail-reconciliation.d.ts +87 -0
- package/dist/observers/mail-reconciliation.d.ts.map +1 -0
- package/dist/observers/mail-reconciliation.js +241 -0
- package/dist/observers/mail-reconciliation.js.map +1 -0
- package/dist/observers/manager.d.ts +67 -0
- package/dist/observers/manager.d.ts.map +1 -0
- package/dist/observers/manager.js +136 -0
- package/dist/observers/manager.js.map +1 -0
- package/dist/observers/notion-poller.d.ts +43 -0
- package/dist/observers/notion-poller.d.ts.map +1 -0
- package/dist/observers/notion-poller.js +184 -0
- package/dist/observers/notion-poller.js.map +1 -0
- package/dist/observers/observation-summarizer/index.d.ts +13 -0
- package/dist/observers/observation-summarizer/index.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/index.js +13 -0
- package/dist/observers/observation-summarizer/index.js.map +1 -0
- package/dist/observers/observation-summarizer/pre-filter.d.ts +62 -0
- package/dist/observers/observation-summarizer/pre-filter.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/pre-filter.js +189 -0
- package/dist/observers/observation-summarizer/pre-filter.js.map +1 -0
- package/dist/observers/observation-summarizer/response-parser.d.ts +30 -0
- package/dist/observers/observation-summarizer/response-parser.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/response-parser.js +106 -0
- package/dist/observers/observation-summarizer/response-parser.js.map +1 -0
- package/dist/observers/observation-summarizer/summarizer-client.d.ts +83 -0
- package/dist/observers/observation-summarizer/summarizer-client.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/summarizer-client.js +185 -0
- package/dist/observers/observation-summarizer/summarizer-client.js.map +1 -0
- package/dist/observers/observation-summarizer/summarizer-prompts.d.ts +51 -0
- package/dist/observers/observation-summarizer/summarizer-prompts.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/summarizer-prompts.js +286 -0
- package/dist/observers/observation-summarizer/summarizer-prompts.js.map +1 -0
- package/dist/observers/observation-summarizer/worker.d.ts +106 -0
- package/dist/observers/observation-summarizer/worker.d.ts.map +1 -0
- package/dist/observers/observation-summarizer/worker.js +311 -0
- package/dist/observers/observation-summarizer/worker.js.map +1 -0
- package/dist/observers/obsidian-watcher.d.ts +90 -0
- package/dist/observers/obsidian-watcher.d.ts.map +1 -0
- package/dist/observers/obsidian-watcher.js +166 -0
- package/dist/observers/obsidian-watcher.js.map +1 -0
- package/dist/observers/primary-vault-watcher.d.ts +73 -0
- package/dist/observers/primary-vault-watcher.d.ts.map +1 -0
- package/dist/observers/primary-vault-watcher.js +115 -0
- package/dist/observers/primary-vault-watcher.js.map +1 -0
- package/dist/observers/repository-management-cron.d.ts +70 -0
- package/dist/observers/repository-management-cron.d.ts.map +1 -0
- package/dist/observers/repository-management-cron.js +166 -0
- package/dist/observers/repository-management-cron.js.map +1 -0
- package/dist/observers/skill-curation-walker.d.ts +33 -0
- package/dist/observers/skill-curation-walker.d.ts.map +1 -0
- package/dist/observers/skill-curation-walker.js +216 -0
- package/dist/observers/skill-curation-walker.js.map +1 -0
- package/dist/safety/absolute-block-audit.d.ts +22 -0
- package/dist/safety/absolute-block-audit.d.ts.map +1 -0
- package/dist/safety/absolute-block-audit.js +32 -0
- package/dist/safety/absolute-block-audit.js.map +1 -0
- package/dist/safety/agent-write-tracker.d.ts +42 -0
- package/dist/safety/agent-write-tracker.d.ts.map +1 -0
- package/dist/safety/agent-write-tracker.js +82 -0
- package/dist/safety/agent-write-tracker.js.map +1 -0
- package/dist/safety/always-disallowed.d.ts +66 -0
- package/dist/safety/always-disallowed.d.ts.map +1 -0
- package/dist/safety/always-disallowed.js +347 -0
- package/dist/safety/always-disallowed.js.map +1 -0
- package/dist/safety/audit.d.ts +118 -0
- package/dist/safety/audit.d.ts.map +1 -0
- package/dist/safety/audit.js +324 -0
- package/dist/safety/audit.js.map +1 -0
- package/dist/safety/integration-write-tracker.d.ts +58 -0
- package/dist/safety/integration-write-tracker.d.ts.map +1 -0
- package/dist/safety/integration-write-tracker.js +41 -0
- package/dist/safety/integration-write-tracker.js.map +1 -0
- package/dist/safety/risk-classifier.d.ts +65 -0
- package/dist/safety/risk-classifier.d.ts.map +1 -0
- package/dist/safety/risk-classifier.js +763 -0
- package/dist/safety/risk-classifier.js.map +1 -0
- package/dist/scheduler/hourly-check-gate.d.ts +73 -0
- package/dist/scheduler/hourly-check-gate.d.ts.map +1 -0
- package/dist/scheduler/hourly-check-gate.js +128 -0
- package/dist/scheduler/hourly-check-gate.js.map +1 -0
- package/dist/secrets/backend-api-key-env.d.ts +104 -0
- package/dist/secrets/backend-api-key-env.d.ts.map +1 -0
- package/dist/secrets/backend-api-key-env.js +197 -0
- package/dist/secrets/backend-api-key-env.js.map +1 -0
- package/dist/secrets/codex-home-materializer.d.ts +35 -0
- package/dist/secrets/codex-home-materializer.d.ts.map +1 -0
- package/dist/secrets/codex-home-materializer.js +76 -0
- package/dist/secrets/codex-home-materializer.js.map +1 -0
- package/dist/secrets/encrypted-blob-store.d.ts +20 -0
- package/dist/secrets/encrypted-blob-store.d.ts.map +1 -0
- package/dist/secrets/encrypted-blob-store.js +80 -0
- package/dist/secrets/encrypted-blob-store.js.map +1 -0
- package/dist/secrets/platform-secret-store.d.ts +17 -0
- package/dist/secrets/platform-secret-store.d.ts.map +1 -0
- package/dist/secrets/platform-secret-store.js +37 -0
- package/dist/secrets/platform-secret-store.js.map +1 -0
- package/dist/secrets/redaction.d.ts +2 -0
- package/dist/secrets/redaction.d.ts.map +1 -0
- package/dist/secrets/redaction.js +2 -0
- package/dist/secrets/redaction.js.map +1 -0
- package/dist/secrets/secret-broker.d.ts +61 -0
- package/dist/secrets/secret-broker.d.ts.map +1 -0
- package/dist/secrets/secret-broker.js +160 -0
- package/dist/secrets/secret-broker.js.map +1 -0
- package/dist/secrets/secret-names.d.ts +34 -0
- package/dist/secrets/secret-names.d.ts.map +1 -0
- package/dist/secrets/secret-names.js +39 -0
- package/dist/secrets/secret-names.js.map +1 -0
- package/dist/secrets/secret-store.d.ts +8 -0
- package/dist/secrets/secret-store.d.ts.map +1 -0
- package/dist/secrets/secret-store.js +2 -0
- package/dist/secrets/secret-store.js.map +1 -0
- package/dist/secrets/types.d.ts +7 -0
- package/dist/secrets/types.d.ts.map +1 -0
- package/dist/secrets/types.js +2 -0
- package/dist/secrets/types.js.map +1 -0
- package/dist/services/apple-calendar/caldav-client.d.ts +48 -0
- package/dist/services/apple-calendar/caldav-client.d.ts.map +1 -0
- package/dist/services/apple-calendar/caldav-client.js +86 -0
- package/dist/services/apple-calendar/caldav-client.js.map +1 -0
- package/dist/services/apple-calendar/caldav-codec.d.ts +67 -0
- package/dist/services/apple-calendar/caldav-codec.d.ts.map +1 -0
- package/dist/services/apple-calendar/caldav-codec.js +341 -0
- package/dist/services/apple-calendar/caldav-codec.js.map +1 -0
- package/dist/services/apple-calendar/index.d.ts +3 -0
- package/dist/services/apple-calendar/index.d.ts.map +1 -0
- package/dist/services/apple-calendar/index.js +2 -0
- package/dist/services/apple-calendar/index.js.map +1 -0
- package/dist/services/apple-calendar/service.d.ts +75 -0
- package/dist/services/apple-calendar/service.d.ts.map +1 -0
- package/dist/services/apple-calendar/service.js +374 -0
- package/dist/services/apple-calendar/service.js.map +1 -0
- package/dist/services/apple-calendar/types.d.ts +78 -0
- package/dist/services/apple-calendar/types.d.ts.map +1 -0
- package/dist/services/apple-calendar/types.js +17 -0
- package/dist/services/apple-calendar/types.js.map +1 -0
- package/dist/services/attachments/hardlink.d.ts +11 -0
- package/dist/services/attachments/hardlink.d.ts.map +1 -0
- package/dist/services/attachments/hardlink.js +56 -0
- package/dist/services/attachments/hardlink.js.map +1 -0
- package/dist/services/attachments/sanitize.d.ts +21 -0
- package/dist/services/attachments/sanitize.d.ts.map +1 -0
- package/dist/services/attachments/sanitize.js +128 -0
- package/dist/services/attachments/sanitize.js.map +1 -0
- package/dist/services/attachments/store.d.ts +146 -0
- package/dist/services/attachments/store.d.ts.map +1 -0
- package/dist/services/attachments/store.js +477 -0
- package/dist/services/attachments/store.js.map +1 -0
- package/dist/services/calendar/outlook/graph-calendar-client.d.ts +114 -0
- package/dist/services/calendar/outlook/graph-calendar-client.d.ts.map +1 -0
- package/dist/services/calendar/outlook/graph-calendar-client.js +146 -0
- package/dist/services/calendar/outlook/graph-calendar-client.js.map +1 -0
- package/dist/services/calendar.d.ts +115 -0
- package/dist/services/calendar.d.ts.map +1 -0
- package/dist/services/calendar.js +281 -0
- package/dist/services/calendar.js.map +1 -0
- package/dist/services/delegated-backend-invoker.d.ts +414 -0
- package/dist/services/delegated-backend-invoker.d.ts.map +1 -0
- package/dist/services/delegated-backend-invoker.js +2372 -0
- package/dist/services/delegated-backend-invoker.js.map +1 -0
- package/dist/services/delegated-proxy-config.d.ts +93 -0
- package/dist/services/delegated-proxy-config.d.ts.map +1 -0
- package/dist/services/delegated-proxy-config.js +98 -0
- package/dist/services/delegated-proxy-config.js.map +1 -0
- package/dist/services/delegated-task-result-cache.d.ts +176 -0
- package/dist/services/delegated-task-result-cache.d.ts.map +1 -0
- package/dist/services/delegated-task-result-cache.js +0 -0
- package/dist/services/delegated-task-result-cache.js.map +1 -0
- package/dist/services/delegated-task-runtime.d.ts +346 -0
- package/dist/services/delegated-task-runtime.d.ts.map +1 -0
- package/dist/services/delegated-task-runtime.js +589 -0
- package/dist/services/delegated-task-runtime.js.map +1 -0
- package/dist/services/delegated-task-session-pool.d.ts +182 -0
- package/dist/services/delegated-task-session-pool.d.ts.map +1 -0
- package/dist/services/delegated-task-session-pool.js +292 -0
- package/dist/services/delegated-task-session-pool.js.map +1 -0
- package/dist/services/delegated-tool-runtime.d.ts +50 -0
- package/dist/services/delegated-tool-runtime.d.ts.map +1 -0
- package/dist/services/delegated-tool-runtime.js +120 -0
- package/dist/services/delegated-tool-runtime.js.map +1 -0
- package/dist/services/fts5.d.ts +40 -0
- package/dist/services/fts5.d.ts.map +1 -0
- package/dist/services/fts5.js +54 -0
- package/dist/services/fts5.js.map +1 -0
- package/dist/services/git-account-registry.d.ts +164 -0
- package/dist/services/git-account-registry.d.ts.map +1 -0
- package/dist/services/git-account-registry.js +297 -0
- package/dist/services/git-account-registry.js.map +1 -0
- package/dist/services/github.d.ts +49 -0
- package/dist/services/github.d.ts.map +1 -0
- package/dist/services/github.js +123 -0
- package/dist/services/github.js.map +1 -0
- package/dist/services/gmail-classifier.d.ts +62 -0
- package/dist/services/gmail-classifier.d.ts.map +1 -0
- package/dist/services/gmail-classifier.js +221 -0
- package/dist/services/gmail-classifier.js.map +1 -0
- package/dist/services/gmail.d.ts +192 -0
- package/dist/services/gmail.d.ts.map +1 -0
- package/dist/services/gmail.js +678 -0
- package/dist/services/gmail.js.map +1 -0
- package/dist/services/google-auth.d.ts +16 -0
- package/dist/services/google-auth.d.ts.map +1 -0
- package/dist/services/google-auth.js +37 -0
- package/dist/services/google-auth.js.map +1 -0
- package/dist/services/google-maps.d.ts +35 -0
- package/dist/services/google-maps.d.ts.map +1 -0
- package/dist/services/google-maps.js +82 -0
- package/dist/services/google-maps.js.map +1 -0
- package/dist/services/integrations/extract-write-item-id.d.ts +64 -0
- package/dist/services/integrations/extract-write-item-id.d.ts.map +1 -0
- package/dist/services/integrations/extract-write-item-id.js +188 -0
- package/dist/services/integrations/extract-write-item-id.js.map +1 -0
- package/dist/services/integrations/reconcile.d.ts +136 -0
- package/dist/services/integrations/reconcile.d.ts.map +1 -0
- package/dist/services/integrations/reconcile.js +218 -0
- package/dist/services/integrations/reconcile.js.map +1 -0
- package/dist/services/integrations/snapshot-partitions.d.ts +40 -0
- package/dist/services/integrations/snapshot-partitions.d.ts.map +1 -0
- package/dist/services/integrations/snapshot-partitions.js +113 -0
- package/dist/services/integrations/snapshot-partitions.js.map +1 -0
- package/dist/services/journal/render.d.ts +15 -0
- package/dist/services/journal/render.d.ts.map +1 -0
- package/dist/services/journal/render.js +17 -0
- package/dist/services/journal/render.js.map +1 -0
- package/dist/services/journal/writer.d.ts +26 -0
- package/dist/services/journal/writer.d.ts.map +1 -0
- package/dist/services/journal/writer.js +50 -0
- package/dist/services/journal/writer.js.map +1 -0
- package/dist/services/mail/account-registry.d.ts +208 -0
- package/dist/services/mail/account-registry.d.ts.map +1 -0
- package/dist/services/mail/account-registry.js +554 -0
- package/dist/services/mail/account-registry.js.map +1 -0
- package/dist/services/mail/gmail/auth-failure-classifier.d.ts +24 -0
- package/dist/services/mail/gmail/auth-failure-classifier.d.ts.map +1 -0
- package/dist/services/mail/gmail/auth-failure-classifier.js +67 -0
- package/dist/services/mail/gmail/auth-failure-classifier.js.map +1 -0
- package/dist/services/mail/gmail/gmail-provider.d.ts +58 -0
- package/dist/services/mail/gmail/gmail-provider.d.ts.map +1 -0
- package/dist/services/mail/gmail/gmail-provider.js +434 -0
- package/dist/services/mail/gmail/gmail-provider.js.map +1 -0
- package/dist/services/mail/gmail/legacy-row.d.ts +24 -0
- package/dist/services/mail/gmail/legacy-row.d.ts.map +1 -0
- package/dist/services/mail/gmail/legacy-row.js +71 -0
- package/dist/services/mail/gmail/legacy-row.js.map +1 -0
- package/dist/services/mail/gmail/poll-cursor.d.ts +12 -0
- package/dist/services/mail/gmail/poll-cursor.d.ts.map +1 -0
- package/dist/services/mail/gmail/poll-cursor.js +32 -0
- package/dist/services/mail/gmail/poll-cursor.js.map +1 -0
- package/dist/services/mail/html-to-plaintext.d.ts +27 -0
- package/dist/services/mail/html-to-plaintext.d.ts.map +1 -0
- package/dist/services/mail/html-to-plaintext.js +163 -0
- package/dist/services/mail/html-to-plaintext.js.map +1 -0
- package/dist/services/mail/imap/app-password.d.ts +27 -0
- package/dist/services/mail/imap/app-password.d.ts.map +1 -0
- package/dist/services/mail/imap/app-password.js +86 -0
- package/dist/services/mail/imap/app-password.js.map +1 -0
- package/dist/services/mail/imap/auth-failure-classifier.d.ts +21 -0
- package/dist/services/mail/imap/auth-failure-classifier.d.ts.map +1 -0
- package/dist/services/mail/imap/auth-failure-classifier.js +54 -0
- package/dist/services/mail/imap/auth-failure-classifier.js.map +1 -0
- package/dist/services/mail/imap/capabilities.d.ts +30 -0
- package/dist/services/mail/imap/capabilities.d.ts.map +1 -0
- package/dist/services/mail/imap/capabilities.js +70 -0
- package/dist/services/mail/imap/capabilities.js.map +1 -0
- package/dist/services/mail/imap/client.d.ts +15 -0
- package/dist/services/mail/imap/client.d.ts.map +1 -0
- package/dist/services/mail/imap/client.js +60 -0
- package/dist/services/mail/imap/client.js.map +1 -0
- package/dist/services/mail/imap/cursor.d.ts +19 -0
- package/dist/services/mail/imap/cursor.d.ts.map +1 -0
- package/dist/services/mail/imap/cursor.js +47 -0
- package/dist/services/mail/imap/cursor.js.map +1 -0
- package/dist/services/mail/imap/folder-resolver.d.ts +24 -0
- package/dist/services/mail/imap/folder-resolver.d.ts.map +1 -0
- package/dist/services/mail/imap/folder-resolver.js +58 -0
- package/dist/services/mail/imap/folder-resolver.js.map +1 -0
- package/dist/services/mail/imap/icloud-provider.d.ts +5 -0
- package/dist/services/mail/imap/icloud-provider.d.ts.map +1 -0
- package/dist/services/mail/imap/icloud-provider.js +5 -0
- package/dist/services/mail/imap/icloud-provider.js.map +1 -0
- package/dist/services/mail/imap/imap-provider-base.d.ts +173 -0
- package/dist/services/mail/imap/imap-provider-base.d.ts.map +1 -0
- package/dist/services/mail/imap/imap-provider-base.js +1004 -0
- package/dist/services/mail/imap/imap-provider-base.js.map +1 -0
- package/dist/services/mail/imap/query-translator.d.ts +13 -0
- package/dist/services/mail/imap/query-translator.d.ts.map +1 -0
- package/dist/services/mail/imap/query-translator.js +114 -0
- package/dist/services/mail/imap/query-translator.js.map +1 -0
- package/dist/services/mail/imap/reconcile-planner.d.ts +56 -0
- package/dist/services/mail/imap/reconcile-planner.d.ts.map +1 -0
- package/dist/services/mail/imap/reconcile-planner.js +52 -0
- package/dist/services/mail/imap/reconcile-planner.js.map +1 -0
- package/dist/services/mail/imap/reply-mime.d.ts +24 -0
- package/dist/services/mail/imap/reply-mime.d.ts.map +1 -0
- package/dist/services/mail/imap/reply-mime.js +77 -0
- package/dist/services/mail/imap/reply-mime.js.map +1 -0
- package/dist/services/mail/imap/yahoo-provider.d.ts +5 -0
- package/dist/services/mail/imap/yahoo-provider.d.ts.map +1 -0
- package/dist/services/mail/imap/yahoo-provider.js +5 -0
- package/dist/services/mail/imap/yahoo-provider.js.map +1 -0
- package/dist/services/mail/mail-search.d.ts +35 -0
- package/dist/services/mail/mail-search.d.ts.map +1 -0
- package/dist/services/mail/mail-search.js +59 -0
- package/dist/services/mail/mail-search.js.map +1 -0
- package/dist/services/mail/outlook/auth-failure-classifier.d.ts +38 -0
- package/dist/services/mail/outlook/auth-failure-classifier.d.ts.map +1 -0
- package/dist/services/mail/outlook/auth-failure-classifier.js +91 -0
- package/dist/services/mail/outlook/auth-failure-classifier.js.map +1 -0
- package/dist/services/mail/outlook/client-config.d.ts +34 -0
- package/dist/services/mail/outlook/client-config.d.ts.map +1 -0
- package/dist/services/mail/outlook/client-config.js +58 -0
- package/dist/services/mail/outlook/client-config.js.map +1 -0
- package/dist/services/mail/outlook/delta-cursor.d.ts +66 -0
- package/dist/services/mail/outlook/delta-cursor.d.ts.map +1 -0
- package/dist/services/mail/outlook/delta-cursor.js +85 -0
- package/dist/services/mail/outlook/delta-cursor.js.map +1 -0
- package/dist/services/mail/outlook/graph-client.d.ts +98 -0
- package/dist/services/mail/outlook/graph-client.d.ts.map +1 -0
- package/dist/services/mail/outlook/graph-client.js +198 -0
- package/dist/services/mail/outlook/graph-client.js.map +1 -0
- package/dist/services/mail/outlook/msal-app-factory.d.ts +20 -0
- package/dist/services/mail/outlook/msal-app-factory.d.ts.map +1 -0
- package/dist/services/mail/outlook/msal-app-factory.js +62 -0
- package/dist/services/mail/outlook/msal-app-factory.js.map +1 -0
- package/dist/services/mail/outlook/msal-cache-plugin.d.ts +19 -0
- package/dist/services/mail/outlook/msal-cache-plugin.d.ts.map +1 -0
- package/dist/services/mail/outlook/msal-cache-plugin.js +30 -0
- package/dist/services/mail/outlook/msal-cache-plugin.js.map +1 -0
- package/dist/services/mail/outlook/oauth-device-code.d.ts +26 -0
- package/dist/services/mail/outlook/oauth-device-code.d.ts.map +1 -0
- package/dist/services/mail/outlook/oauth-device-code.js +32 -0
- package/dist/services/mail/outlook/oauth-device-code.js.map +1 -0
- package/dist/services/mail/outlook/oauth-loopback.d.ts +41 -0
- package/dist/services/mail/outlook/oauth-loopback.d.ts.map +1 -0
- package/dist/services/mail/outlook/oauth-loopback.js +223 -0
- package/dist/services/mail/outlook/oauth-loopback.js.map +1 -0
- package/dist/services/mail/outlook/outlook-provider.d.ts +100 -0
- package/dist/services/mail/outlook/outlook-provider.d.ts.map +1 -0
- package/dist/services/mail/outlook/outlook-provider.js +619 -0
- package/dist/services/mail/outlook/outlook-provider.js.map +1 -0
- package/dist/services/mail/outlook/query-translator.d.ts +10 -0
- package/dist/services/mail/outlook/query-translator.d.ts.map +1 -0
- package/dist/services/mail/outlook/query-translator.js +103 -0
- package/dist/services/mail/outlook/query-translator.js.map +1 -0
- package/dist/services/mail/provider.d.ts +267 -0
- package/dist/services/mail/provider.d.ts.map +1 -0
- package/dist/services/mail/provider.js +34 -0
- package/dist/services/mail/provider.js.map +1 -0
- package/dist/services/mail/query-utils.d.ts +13 -0
- package/dist/services/mail/query-utils.d.ts.map +1 -0
- package/dist/services/mail/query-utils.js +18 -0
- package/dist/services/mail/query-utils.js.map +1 -0
- package/dist/services/mail-classifier.d.ts +25 -0
- package/dist/services/mail-classifier.d.ts.map +1 -0
- package/dist/services/mail-classifier.js +52 -0
- package/dist/services/mail-classifier.js.map +1 -0
- package/dist/services/mail-ingestion.d.ts +139 -0
- package/dist/services/mail-ingestion.d.ts.map +1 -0
- package/dist/services/mail-ingestion.js +223 -0
- package/dist/services/mail-ingestion.js.map +1 -0
- package/dist/services/mcp/auto-probe.d.ts +76 -0
- package/dist/services/mcp/auto-probe.d.ts.map +1 -0
- package/dist/services/mcp/auto-probe.js +147 -0
- package/dist/services/mcp/auto-probe.js.map +1 -0
- package/dist/services/mcp/generators/claude.d.ts +18 -0
- package/dist/services/mcp/generators/claude.d.ts.map +1 -0
- package/dist/services/mcp/generators/claude.js +90 -0
- package/dist/services/mcp/generators/claude.js.map +1 -0
- package/dist/services/mcp/generators/codex.d.ts +22 -0
- package/dist/services/mcp/generators/codex.d.ts.map +1 -0
- package/dist/services/mcp/generators/codex.js +102 -0
- package/dist/services/mcp/generators/codex.js.map +1 -0
- package/dist/services/mcp/generators/gemini.d.ts +20 -0
- package/dist/services/mcp/generators/gemini.d.ts.map +1 -0
- package/dist/services/mcp/generators/gemini.js +97 -0
- package/dist/services/mcp/generators/gemini.js.map +1 -0
- package/dist/services/mcp/generators/index.d.ts +20 -0
- package/dist/services/mcp/generators/index.d.ts.map +1 -0
- package/dist/services/mcp/generators/index.js +29 -0
- package/dist/services/mcp/generators/index.js.map +1 -0
- package/dist/services/mcp/generators/types.d.ts +47 -0
- package/dist/services/mcp/generators/types.d.ts.map +1 -0
- package/dist/services/mcp/generators/types.js +40 -0
- package/dist/services/mcp/generators/types.js.map +1 -0
- package/dist/services/mcp/probe.d.ts +31 -0
- package/dist/services/mcp/probe.d.ts.map +1 -0
- package/dist/services/mcp/probe.js +437 -0
- package/dist/services/mcp/probe.js.map +1 -0
- package/dist/services/mcp/registry.d.ts +84 -0
- package/dist/services/mcp/registry.d.ts.map +1 -0
- package/dist/services/mcp/registry.js +387 -0
- package/dist/services/mcp/registry.js.map +1 -0
- package/dist/services/mcp/risk.d.ts +82 -0
- package/dist/services/mcp/risk.d.ts.map +1 -0
- package/dist/services/mcp/risk.js +126 -0
- package/dist/services/mcp/risk.js.map +1 -0
- package/dist/services/mcp/session-materializer.d.ts +123 -0
- package/dist/services/mcp/session-materializer.d.ts.map +1 -0
- package/dist/services/mcp/session-materializer.js +361 -0
- package/dist/services/mcp/session-materializer.js.map +1 -0
- package/dist/services/mcp/tool-audit.d.ts +53 -0
- package/dist/services/mcp/tool-audit.d.ts.map +1 -0
- package/dist/services/mcp/tool-audit.js +74 -0
- package/dist/services/mcp/tool-audit.js.map +1 -0
- package/dist/services/mcp/types.d.ts +88 -0
- package/dist/services/mcp/types.d.ts.map +1 -0
- package/dist/services/mcp/types.js +94 -0
- package/dist/services/mcp/types.js.map +1 -0
- package/dist/services/notion.d.ts +134 -0
- package/dist/services/notion.d.ts.map +1 -0
- package/dist/services/notion.js +350 -0
- package/dist/services/notion.js.map +1 -0
- package/dist/services/obsidian.d.ts +116 -0
- package/dist/services/obsidian.d.ts.map +1 -0
- package/dist/services/obsidian.js +305 -0
- package/dist/services/obsidian.js.map +1 -0
- package/dist/services/service-registry.d.ts +31 -0
- package/dist/services/service-registry.d.ts.map +1 -0
- package/dist/services/service-registry.js +15 -0
- package/dist/services/service-registry.js.map +1 -0
- package/dist/services/voice/transcriber-impl.d.ts +15 -0
- package/dist/services/voice/transcriber-impl.d.ts.map +1 -0
- package/dist/services/voice/transcriber-impl.js +129 -0
- package/dist/services/voice/transcriber-impl.js.map +1 -0
- package/dist/services/voice/transcriber.d.ts +117 -0
- package/dist/services/voice/transcriber.d.ts.map +1 -0
- package/dist/services/voice/transcriber.js +201 -0
- package/dist/services/voice/transcriber.js.map +1 -0
- package/dist/settings/runtime-settings.d.ts +232 -0
- package/dist/settings/runtime-settings.d.ts.map +1 -0
- package/dist/settings/runtime-settings.js +769 -0
- package/dist/settings/runtime-settings.js.map +1 -0
- package/dist/settings/settings-store.d.ts +13 -0
- package/dist/settings/settings-store.d.ts.map +1 -0
- package/dist/settings/settings-store.js +87 -0
- package/dist/settings/settings-store.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,1765 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { readFileSync, existsSync, statSync, readdirSync, unlinkSync, realpathSync, lstatSync, readlinkSync, } from "node:fs";
|
|
3
|
+
import { basename, join, dirname, resolve, relative, isAbsolute } from "node:path";
|
|
4
|
+
import { writeFileAtomically } from "../../core/atomic-write.js";
|
|
5
|
+
import { contextPutSchema, contextPatchSchema, getAgentDayDateStr, localDateStr, nowInTimezone, } from "@aitne/shared";
|
|
6
|
+
import { getContextDir } from "../../config.js";
|
|
7
|
+
import { getDegradedMode } from "../../db/runtime-state.js";
|
|
8
|
+
import { InMemoryTodayWriteLockManager, getTodayWriteLockTimeoutMs, } from "../../core/today-write-lock.js";
|
|
9
|
+
import { InMemoryRoadmapWriteLockManager, getRoadmapWriteLockTimeoutMs, } from "../../core/roadmap-write-lock.js";
|
|
10
|
+
import { CONTEXT_BASE_FILE_STEMS, CONTEXT_FILE_EXTENSIONS, } from "../../core/context-paths.js";
|
|
11
|
+
import { REPAIRABLE_STUB_TARGETS, buildContextHealthReport, normalizeRepairStubPath, } from "../../core/context-health.js";
|
|
12
|
+
import { validateContextFileFrontmatter } from "../../core/context-frontmatter.js";
|
|
13
|
+
import { classifyContextWriteStaleness } from "../../core/context-staleness.js";
|
|
14
|
+
import { resolveTemplatesRoot } from "../../core/skeleton.js";
|
|
15
|
+
import { parseCustomRoutineSpec, } from "../../core/custom-routine-scheduler.js";
|
|
16
|
+
import { normalizeRoadmapForWrite, validateRoadmap, validateRoadmapTransition, } from "../../core/roadmap-validate.js";
|
|
17
|
+
import { isValidYmd, } from "../../core/roadmap-horizon.js";
|
|
18
|
+
import { extractRoadmapIds, generateRoadmapId, RoadmapIdGenerationError, } from "../../core/roadmap-ids.js";
|
|
19
|
+
import { buildTodayAgentPlanMetadata, extractTodayAgentPlanRows, extractTodayDate, readTodayAgentPlanMetadata, } from "../../core/today-agent-plan.js";
|
|
20
|
+
import { createLogger } from "../../logging.js";
|
|
21
|
+
import { readJsonBody } from "../json-body.js";
|
|
22
|
+
const logger = createLogger("context-api");
|
|
23
|
+
const CONTEXT_BASE_FILE_STEM_SET = new Set(CONTEXT_BASE_FILE_STEMS);
|
|
24
|
+
function resolveContextTarget(userPath) {
|
|
25
|
+
for (const ext of CONTEXT_FILE_EXTENSIONS) {
|
|
26
|
+
if (userPath.endsWith(ext)) {
|
|
27
|
+
return { base: userPath.slice(0, -ext.length), ext };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (CONTEXT_BASE_FILE_STEM_SET.has(userPath)) {
|
|
31
|
+
return { base: userPath, ext: ".base" };
|
|
32
|
+
}
|
|
33
|
+
return { base: userPath, ext: ".md" };
|
|
34
|
+
}
|
|
35
|
+
function normalizeContextPath(userPath) {
|
|
36
|
+
return resolveContextTarget(userPath).base;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Subpath prefixes inside contextDir that the API never exposes.
|
|
40
|
+
* Relative paths from `path.relative` never contain a trailing slash for
|
|
41
|
+
* the leaf element, so we match on "<name>" exactly OR "<name>/" prefix.
|
|
42
|
+
*
|
|
43
|
+
* - `.git` — local repo artifacts the daemon must not touch
|
|
44
|
+
* - `.DS_Store` — macOS filesystem cruft
|
|
45
|
+
* - `.obsidian` — Obsidian's own state directory
|
|
46
|
+
*
|
|
47
|
+
* `.obsidian` stays denied in every mode. `vaultMode="obsidian"` means the
|
|
48
|
+
* directory may exist on disk and should be preserved by the daemon, not that
|
|
49
|
+
* the agent may read or edit Obsidian's workspace state through this API.
|
|
50
|
+
*/
|
|
51
|
+
const DENIED_SUBPATH_ROOTS = [".git", ".DS_Store", ".obsidian"];
|
|
52
|
+
function isDeniedPath(relativePath) {
|
|
53
|
+
for (const root of DENIED_SUBPATH_ROOTS) {
|
|
54
|
+
if (relativePath === root || relativePath.startsWith(`${root}/`)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
function escapesBase(base, candidate) {
|
|
61
|
+
const rel = relative(base, candidate);
|
|
62
|
+
return rel.startsWith("..") || isAbsolute(rel);
|
|
63
|
+
}
|
|
64
|
+
function resolveRealPathBestEffort(path, seen = new Set()) {
|
|
65
|
+
const abs = resolve(path);
|
|
66
|
+
try {
|
|
67
|
+
const stat = lstatSync(abs);
|
|
68
|
+
if (stat.isSymbolicLink()) {
|
|
69
|
+
if (seen.has(abs))
|
|
70
|
+
return null;
|
|
71
|
+
seen.add(abs);
|
|
72
|
+
const target = readlinkSync(abs);
|
|
73
|
+
return resolveRealPathBestEffort(isAbsolute(target) ? target : resolve(dirname(abs), target), seen);
|
|
74
|
+
}
|
|
75
|
+
return realpathSync(abs);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
const parent = dirname(abs);
|
|
79
|
+
if (parent === abs)
|
|
80
|
+
return abs;
|
|
81
|
+
const parentReal = resolveRealPathBestEffort(parent, seen);
|
|
82
|
+
return parentReal ? resolve(parentReal, basename(abs)) : null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve a user-supplied path safely within contextDir.
|
|
87
|
+
* Accepts paths with or without the trailing `.md` / `.base` extension.
|
|
88
|
+
* Returns null if the resolved path escapes contextDir (path traversal),
|
|
89
|
+
* targets a reserved `.base` stem with the wrong extension, or is on the
|
|
90
|
+
* deny list.
|
|
91
|
+
*/
|
|
92
|
+
function safePath(contextDir, userPath) {
|
|
93
|
+
const { base, ext } = resolveContextTarget(userPath);
|
|
94
|
+
if (base === "projects/_active" && ext !== ".base") {
|
|
95
|
+
logger.warn({ userPath, base, ext }, "Base file requested with wrong extension");
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const resolved = resolve(contextDir, `${base}${ext}`);
|
|
99
|
+
const rel = relative(contextDir, resolved);
|
|
100
|
+
// Reject if path escapes contextDir (starts with .. or is absolute)
|
|
101
|
+
if (escapesBase(contextDir, resolved)) {
|
|
102
|
+
logger.warn({ userPath, resolved }, "Path traversal rejected");
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
if (isDeniedPath(rel)) {
|
|
106
|
+
logger.warn({ userPath, resolved }, "Denied subpath rejected");
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const contextReal = resolveRealPathBestEffort(contextDir);
|
|
110
|
+
const resolvedReal = resolveRealPathBestEffort(resolved);
|
|
111
|
+
if (!contextReal || !resolvedReal) {
|
|
112
|
+
logger.warn({ userPath, resolved }, "Realpath resolution rejected");
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
if (escapesBase(contextReal, resolvedReal)) {
|
|
116
|
+
logger.warn({ userPath, resolved, resolvedReal }, "Symlink traversal rejected");
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
const realRel = relative(contextReal, resolvedReal);
|
|
120
|
+
if (isDeniedPath(realRel)) {
|
|
121
|
+
logger.warn({ userPath, resolved, resolvedReal }, "Denied realpath rejected");
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
return resolved;
|
|
125
|
+
}
|
|
126
|
+
// B-007 §5.1 — write-permission whitelist for the new layout.
|
|
127
|
+
const CONTEXT_WRITE_PERMISSIONS = {
|
|
128
|
+
// Top-level survivors.
|
|
129
|
+
today: ["PUT", "PATCH"],
|
|
130
|
+
yesterday: ["PUT", "PATCH"],
|
|
131
|
+
roadmap: ["PUT", "PATCH"],
|
|
132
|
+
_index: ["PUT", "PATCH"],
|
|
133
|
+
"context-index": ["PUT", "PATCH"],
|
|
134
|
+
// user/* covers fixed area files AND the §5.5 growth pattern
|
|
135
|
+
// (e.g. `user/health/sleep-log.md` after an area promotion).
|
|
136
|
+
"user/*": ["PUT", "PATCH"],
|
|
137
|
+
// Natural-language rulebooks — §5.8.
|
|
138
|
+
"rules/_index": ["PUT", "PATCH"],
|
|
139
|
+
// DELETE intentionally omitted. Policy files under `rules/policies/`
|
|
140
|
+
// use `status: removed` in lieu of physical deletion so the captured
|
|
141
|
+
// history (origin DM, why, linked routine) survives. See
|
|
142
|
+
// MANAGEMENT-POLICY-CAPTURE-PLAN.md §4.6 / §5.1.
|
|
143
|
+
"rules/*": ["PUT", "PATCH"],
|
|
144
|
+
"routines/_index": ["PUT", "PATCH"],
|
|
145
|
+
"routines/*": ["PUT", "PATCH"],
|
|
146
|
+
// B-007 §5.8 Q3 — custom routines support DELETE so the agent can
|
|
147
|
+
// retire a routine when the user asks via DM. The scheduler re-reads
|
|
148
|
+
// the directory via `onCustomRoutinesChanged` and unregisters the
|
|
149
|
+
// cron job on the next reload pass.
|
|
150
|
+
"routines/custom/*": ["PUT", "PATCH", "DELETE"],
|
|
151
|
+
// Projects (`.base` permitted via CONTEXT_FILE_EXTENSIONS).
|
|
152
|
+
"projects/_index": ["PUT", "PATCH"],
|
|
153
|
+
"projects/_active": ["PUT"],
|
|
154
|
+
"projects/*": ["PUT", "PATCH"],
|
|
155
|
+
// Lightweight registry for watched git repos that are not promoted to a
|
|
156
|
+
// full project page.
|
|
157
|
+
// @deprecated Pre-cutover layout (see docs/design/appendices/unified-repositories.md);
|
|
158
|
+
// retained for transitional reads of legacy files. New writes route to
|
|
159
|
+
// `git/<slug>/{overview,journal/<YYYY-MM-DD>}`.
|
|
160
|
+
"git-repos/*": ["PUT", "PATCH"],
|
|
161
|
+
// Unified repositories — per-repo project overview + per-day journal.
|
|
162
|
+
// The two specific patterns below carry write permission; arbitrary
|
|
163
|
+
// paths under `git/` are NOT writable to keep the layout disciplined.
|
|
164
|
+
// See docs/design/appendices/unified-repositories.md §4.5.
|
|
165
|
+
"git/{slug}/overview": ["PUT", "PATCH"],
|
|
166
|
+
"git/{slug}/journal/{date}": ["PUT", "PATCH"],
|
|
167
|
+
// Journal & reviews.
|
|
168
|
+
"daily/*": ["PUT", "PATCH"],
|
|
169
|
+
"weekly/*": ["PUT", "PATCH"],
|
|
170
|
+
"monthly/*": ["PUT", "PATCH"],
|
|
171
|
+
// Dossiers + inbox + agent self-areas.
|
|
172
|
+
"dossiers/_index": ["PUT", "PATCH"],
|
|
173
|
+
"dossiers/*": ["PUT", "PATCH"],
|
|
174
|
+
// B-007 §5.9 Step 4 / §5.3 — morning routine triages each inbox file and
|
|
175
|
+
// moves the original to `agent/scratch/inbox-YYYY-MM-DD-*.md`. Both sides
|
|
176
|
+
// of the move need DELETE: inbox for the post-triage cleanup, scratch for
|
|
177
|
+
// the eventual 48h TTL retention sweep (§6.5).
|
|
178
|
+
"inbox/*": ["PUT", "PATCH", "DELETE"],
|
|
179
|
+
"agent/journal": ["PUT", "PATCH"],
|
|
180
|
+
"agent/scratch/*": ["PUT", "PATCH", "DELETE"],
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Paths where PUT is only allowed when the file does not yet exist.
|
|
184
|
+
* Subsequent writes must go through PATCH (append). This enforces the
|
|
185
|
+
* append-only contract at the API level rather than relying on prompt
|
|
186
|
+
* compliance alone.
|
|
187
|
+
*/
|
|
188
|
+
const CREATE_ONLY_PUT = new Set(["agent/journal"]);
|
|
189
|
+
/**
|
|
190
|
+
* Slug regex shared by `{slug}` and `{date}` placeholders. Matches the
|
|
191
|
+
* sanitized output of `deriveSlug` (a-z, 0-9, dot, underscore, dash) and
|
|
192
|
+
* `YYYY-MM-DD` date strings without further validation — the route
|
|
193
|
+
* handler does the canonical date validation when it parses the URL.
|
|
194
|
+
*/
|
|
195
|
+
const PLACEHOLDER_SEGMENT_RE = /^[a-z0-9._-]+$/;
|
|
196
|
+
function patternToRegex(pattern) {
|
|
197
|
+
// Escape regex metachars except the placeholder syntax we control.
|
|
198
|
+
const escaped = pattern.replace(/[.+^$()|\\]/g, "\\$&");
|
|
199
|
+
// `{name}` → one allowed segment.
|
|
200
|
+
const withSegments = escaped.replace(/\\?\{[^}]+\\?\}/g, "[a-z0-9._-]+");
|
|
201
|
+
// `/*` at end → exactly one trailing segment.
|
|
202
|
+
const withTail = withSegments.replace(/\/\*$/, "/[^/]+");
|
|
203
|
+
return new RegExp("^" + withTail + "$");
|
|
204
|
+
}
|
|
205
|
+
function isWriteAllowed(path, method) {
|
|
206
|
+
// Check exact match first
|
|
207
|
+
if (CONTEXT_WRITE_PERMISSIONS[path]?.includes(method))
|
|
208
|
+
return true;
|
|
209
|
+
// Check wildcard patterns
|
|
210
|
+
for (const [pattern, methods] of Object.entries(CONTEXT_WRITE_PERMISSIONS)) {
|
|
211
|
+
if (!methods.includes(method))
|
|
212
|
+
continue;
|
|
213
|
+
if (pattern.endsWith("/*")) {
|
|
214
|
+
const prefix = pattern.slice(0, -2);
|
|
215
|
+
if (path.startsWith(prefix + "/")) {
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (pattern.includes("{")) {
|
|
220
|
+
if (patternToRegex(pattern).test(path)) {
|
|
221
|
+
// Defense-in-depth: each replaced placeholder must match the
|
|
222
|
+
// sanitized form. The regex already enforces that, but we
|
|
223
|
+
// double-check the character set explicitly so a future
|
|
224
|
+
// pattern with `{slug}` mid-string can't drift.
|
|
225
|
+
const segments = path.split("/");
|
|
226
|
+
const patternSegments = pattern.split("/");
|
|
227
|
+
if (segments.length !== patternSegments.length)
|
|
228
|
+
continue;
|
|
229
|
+
let allValid = true;
|
|
230
|
+
for (let i = 0; i < segments.length; i++) {
|
|
231
|
+
const lit = patternSegments[i];
|
|
232
|
+
if (lit.startsWith("{") && lit.endsWith("}")) {
|
|
233
|
+
if (!PLACEHOLDER_SEGMENT_RE.test(segments[i])) {
|
|
234
|
+
allValid = false;
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else if (lit !== segments[i]) {
|
|
239
|
+
allValid = false;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (allValid)
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Determine if a context file change should trigger a prompt context
|
|
252
|
+
* refresh consideration. The staleness classifier decides whether the
|
|
253
|
+
* matching write is loud enough to invalidate active DM sessions.
|
|
254
|
+
*
|
|
255
|
+
* B-007 §5.1 — user/profile.md is refreshed on PUT only (setup writes
|
|
256
|
+
* the full file) but NOT on PATCH (SignalDetector appends to Raw Signals
|
|
257
|
+
* frequently — refreshing on every append would thrash the owner session).
|
|
258
|
+
*
|
|
259
|
+
* The setup.initial PUT fires this, but it does NOT destroy the in-flight
|
|
260
|
+
* setup conversation — the `onPromptContextChanged` handler in index.ts
|
|
261
|
+
* skips `markActiveDmSessionsStale` while `currentSetupMode` is active.
|
|
262
|
+
*/
|
|
263
|
+
function shouldRefreshPromptContext(path, method) {
|
|
264
|
+
if (path === "today" ||
|
|
265
|
+
path === "roadmap" ||
|
|
266
|
+
path === "context-index") {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
// B-007 — any rules/*.md file feeds the policy-files injection hub, so
|
|
270
|
+
// edits to any of them should invalidate the owner-session prompt cache.
|
|
271
|
+
// Routine rulebooks (`routines/*.md`) similarly drive task-flow prompts.
|
|
272
|
+
if (path.startsWith("rules/") || path.startsWith("routines/")) {
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
if (path.startsWith("dossiers/")) {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
if (path === "user/profile" && method === "PUT") {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
function notifyPromptContextChanged(deps, path, reason, input) {
|
|
284
|
+
const classification = classifyContextWriteStaleness(input);
|
|
285
|
+
deps.onPromptContextChanged?.(path, reason, classification.tier, {
|
|
286
|
+
tierReason: classification.tierReason,
|
|
287
|
+
});
|
|
288
|
+
// STAGE-C-DM-FRESHNESS-PLAN §Task 4 — record the staleness tier in
|
|
289
|
+
// `agent_actions` so the dashboard's `dm_freshness_metrics` view can
|
|
290
|
+
// count loud vs. quiet writes that landed within a DM session's
|
|
291
|
+
// lifetime. Best-effort: a failure here must not break the write.
|
|
292
|
+
try {
|
|
293
|
+
deps.db
|
|
294
|
+
.prepare(`INSERT INTO agent_actions (action_type, trigger, result, detail, started_at, completed_at)
|
|
295
|
+
VALUES ('context_write', 'reactive', 'success', json(?), datetime('now'), datetime('now'))`)
|
|
296
|
+
.run(JSON.stringify({
|
|
297
|
+
path,
|
|
298
|
+
method: input.method,
|
|
299
|
+
tier: classification.tier,
|
|
300
|
+
tierReason: classification.tierReason,
|
|
301
|
+
reason,
|
|
302
|
+
}));
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
logger.warn({ err, path, method: input.method }, "Failed to record context_write agent_actions row (Stage C metrics)");
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Normalize a section name for matching:
|
|
310
|
+
* lowercase, spaces → underscores, strip leading ##
|
|
311
|
+
*/
|
|
312
|
+
function normalizeSection(name) {
|
|
313
|
+
return name
|
|
314
|
+
.replace(/^#+\s*/, "")
|
|
315
|
+
.toLowerCase()
|
|
316
|
+
.replace(/\s+/g, "_");
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Find a section in markdown content and return its boundaries.
|
|
320
|
+
* Returns [startOfBody, endOfBody] where body is between this ## and next ##.
|
|
321
|
+
*/
|
|
322
|
+
function findSection(content, sectionName) {
|
|
323
|
+
const normalized = normalizeSection(sectionName);
|
|
324
|
+
const lines = content.split("\n");
|
|
325
|
+
let sectionStart = -1;
|
|
326
|
+
let headerEnd = -1;
|
|
327
|
+
for (let i = 0; i < lines.length; i++) {
|
|
328
|
+
if (lines[i].startsWith("## ")) {
|
|
329
|
+
const lineNormalized = normalizeSection(lines[i]);
|
|
330
|
+
if (lineNormalized === normalized) {
|
|
331
|
+
sectionStart = i;
|
|
332
|
+
const lineStart = sumLength(lines, i);
|
|
333
|
+
const nlPos = content.indexOf("\n", lineStart);
|
|
334
|
+
// Handle file ending without trailing newline
|
|
335
|
+
headerEnd = nlPos === -1 ? content.length : nlPos + 1;
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (sectionStart === -1)
|
|
341
|
+
return null;
|
|
342
|
+
// Find end: next ## header or EOF
|
|
343
|
+
let sectionEnd = content.length;
|
|
344
|
+
for (let i = sectionStart + 1; i < lines.length; i++) {
|
|
345
|
+
if (lines[i].startsWith("## ")) {
|
|
346
|
+
sectionEnd = sumLength(lines, i);
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return { start: headerEnd, end: sectionEnd, headerEnd };
|
|
351
|
+
}
|
|
352
|
+
function sumLength(lines, upToIndex) {
|
|
353
|
+
let len = 0;
|
|
354
|
+
for (let i = 0; i < upToIndex; i++) {
|
|
355
|
+
len += lines[i].length + 1; // +1 for \n
|
|
356
|
+
}
|
|
357
|
+
return len;
|
|
358
|
+
}
|
|
359
|
+
function getAvailableSections(content) {
|
|
360
|
+
return content
|
|
361
|
+
.split("\n")
|
|
362
|
+
.filter((l) => l.startsWith("## "))
|
|
363
|
+
.map((l) => normalizeSection(l));
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Parse a timestamp from a bullet entry like `- [2026-04-10 02:32:59] ...`
|
|
367
|
+
* Returns the timestamp string or null if the line doesn't match.
|
|
368
|
+
*/
|
|
369
|
+
const ENTRY_TIMESTAMP_RE = /^- \[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]/;
|
|
370
|
+
function parseEntryTimestamp(line) {
|
|
371
|
+
const match = ENTRY_TIMESTAMP_RE.exec(line);
|
|
372
|
+
return match ? match[1] : null;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Remove entries whose `- [YYYY-MM-DD HH:MM:SS]` timestamp is ≤ cutoff.
|
|
376
|
+
* Non-matching lines (blank lines, continuation lines) are preserved.
|
|
377
|
+
* Returns the remaining section body and the count of removed entries.
|
|
378
|
+
*/
|
|
379
|
+
function clearEntriesBefore(sectionBody, cutoff) {
|
|
380
|
+
const lines = sectionBody.split("\n");
|
|
381
|
+
const kept = [];
|
|
382
|
+
let removedCount = 0;
|
|
383
|
+
let skipContinuation = false;
|
|
384
|
+
for (const line of lines) {
|
|
385
|
+
const ts = parseEntryTimestamp(line);
|
|
386
|
+
if (ts !== null) {
|
|
387
|
+
// This is a timestamped entry
|
|
388
|
+
if (ts <= cutoff) {
|
|
389
|
+
removedCount++;
|
|
390
|
+
skipContinuation = true;
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
skipContinuation = false;
|
|
394
|
+
kept.push(line);
|
|
395
|
+
}
|
|
396
|
+
else if (skipContinuation && (line.startsWith(" ") || line.trim() === "")) {
|
|
397
|
+
// Continuation or trailing blank line of a removed entry
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
skipContinuation = false;
|
|
402
|
+
kept.push(line);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return { remaining: kept.join("\n"), removedCount };
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Trim oldest bullet entries (`- ...` lines) from the top of a section
|
|
409
|
+
* body to keep at most `maxEntries` entries. Non-bullet lines (blank
|
|
410
|
+
* lines, non-`- ` prefixed lines) are preserved.
|
|
411
|
+
*/
|
|
412
|
+
function trimBulletEntries(body, maxEntries) {
|
|
413
|
+
const lines = body.split("\n");
|
|
414
|
+
// Collect indices of bullet entry start lines
|
|
415
|
+
const bulletIndices = [];
|
|
416
|
+
for (let i = 0; i < lines.length; i++) {
|
|
417
|
+
if (lines[i].startsWith("- ")) {
|
|
418
|
+
bulletIndices.push(i);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
const excess = bulletIndices.length - maxEntries;
|
|
422
|
+
if (excess <= 0) {
|
|
423
|
+
return { body, trimmed: 0 };
|
|
424
|
+
}
|
|
425
|
+
// Remove the oldest (topmost) `excess` entries and their continuations.
|
|
426
|
+
// Also remove blank lines between consecutive removed entries to avoid
|
|
427
|
+
// orphaned whitespace accumulating over many trim cycles.
|
|
428
|
+
const removeSet = new Set();
|
|
429
|
+
for (let i = 0; i < excess; i++) {
|
|
430
|
+
const start = bulletIndices[i];
|
|
431
|
+
const end = i + 1 < bulletIndices.length ? bulletIndices[i + 1] : lines.length;
|
|
432
|
+
for (let j = start; j < end; j++) {
|
|
433
|
+
if (j === start || lines[j].startsWith(" ") || lines[j].trim() === "") {
|
|
434
|
+
removeSet.add(j);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const kept = lines.filter((_, i) => !removeSet.has(i));
|
|
439
|
+
return { body: kept.join("\n"), trimmed: excess };
|
|
440
|
+
}
|
|
441
|
+
const SNAPSHOT_DEBOUNCE_MS = 5 * 60 * 1000; // 5 minutes
|
|
442
|
+
/**
|
|
443
|
+
* Cap on the JSON body accepted by the Context PUT/PATCH endpoints.
|
|
444
|
+
*
|
|
445
|
+
* Real context files are well under this — `today.md` is typically
|
|
446
|
+
* ~10 KB at the busiest point of the day, `roadmap.md` runs ~50 KB,
|
|
447
|
+
* project pages ~50 KB, and `agent/journal.md` is bounded by the
|
|
448
|
+
* retention rollup. 1 MB leaves >10x headroom for legitimate writes
|
|
449
|
+
* while preventing a runaway-payload denial-of-service:
|
|
450
|
+
*
|
|
451
|
+
* - The agent could otherwise be tricked (prompt injection from a
|
|
452
|
+
* poisoned email or Obsidian note) into PATCHing a multi-megabyte
|
|
453
|
+
* payload, and each PATCH writes a snapshot row in
|
|
454
|
+
* `md_file_snapshots`. Snapshots are pruned at 30 days, so a
|
|
455
|
+
* burst of large writes can balloon the DB before retention
|
|
456
|
+
* catches up.
|
|
457
|
+
*
|
|
458
|
+
* - 1 MB is an order of magnitude smaller than the attachment route's
|
|
459
|
+
* 25 MB cap; context files have no legitimate need to be that big.
|
|
460
|
+
*
|
|
461
|
+
* Only PUT/PATCH against the wildcard route apply this cap. Smaller
|
|
462
|
+
* structured endpoints (lock, archive-today, repair/stub) use
|
|
463
|
+
* `readOptionalJsonBody` whose payloads are tiny by construction.
|
|
464
|
+
*/
|
|
465
|
+
const CONTEXT_BODY_MAX_BYTES = 1024 * 1024;
|
|
466
|
+
export function createContextRoutes(deps) {
|
|
467
|
+
const app = new Hono();
|
|
468
|
+
const { db, config, writeTracker } = deps;
|
|
469
|
+
// Resolve the context directory at request time rather than closing over
|
|
470
|
+
// the startup value. `/api/setup/migrate-context` mutates `config` in
|
|
471
|
+
// memory after a successful move, and the Context API must immediately
|
|
472
|
+
// follow the new primary-vault path without requiring a daemon restart.
|
|
473
|
+
//
|
|
474
|
+
// Intentionally omit `db` here: degraded mode is handled by the 503
|
|
475
|
+
// middleware below, so once a request reaches a handler we want the
|
|
476
|
+
// actual current target path, never the legacy fallback.
|
|
477
|
+
const getCurrentContextDir = () => getContextDir(config);
|
|
478
|
+
/**
|
|
479
|
+
* Management Mode degraded-mode gate (plan §5.4).
|
|
480
|
+
* When the primary vault is unreachable, refuse BOTH reads and writes
|
|
481
|
+
* with 503 so the agent does not read or write a stale fallback
|
|
482
|
+
* location. Checked per-request so lifting degraded mode in the health
|
|
483
|
+
* probe takes effect without restart. The lock endpoints under
|
|
484
|
+
* `/context/lock/*` also participate: acquiring a lock during degraded
|
|
485
|
+
* mode would leave the lock held with no way to write, so we gate them
|
|
486
|
+
* too.
|
|
487
|
+
*/
|
|
488
|
+
app.use("/context/*", async (c, next) => {
|
|
489
|
+
const state = getDegradedMode(db);
|
|
490
|
+
if (state) {
|
|
491
|
+
return c.json({
|
|
492
|
+
error: "primary_vault_unreachable",
|
|
493
|
+
reason: state.reason,
|
|
494
|
+
path: state.path,
|
|
495
|
+
since: state.since,
|
|
496
|
+
}, 503);
|
|
497
|
+
}
|
|
498
|
+
// Phase 2 — global context-write gate engaged during a
|
|
499
|
+
// /api/setup/migrate-context run. Refuses WRITES (not reads)
|
|
500
|
+
// because reads against the still-intact source are safe; the
|
|
501
|
+
// migration endpoint blocks writes so no handler races the move.
|
|
502
|
+
const writeMethods = new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
503
|
+
if (deps.contextWriteGate?.isEngaged() && writeMethods.has(c.req.method)) {
|
|
504
|
+
const gateState = deps.contextWriteGate.getState();
|
|
505
|
+
return c.json({
|
|
506
|
+
error: "migration_in_progress",
|
|
507
|
+
reason: gateState.reason,
|
|
508
|
+
since: gateState.since,
|
|
509
|
+
}, 503);
|
|
510
|
+
}
|
|
511
|
+
await next();
|
|
512
|
+
});
|
|
513
|
+
const morningRoutineLock = deps.morningRoutineLock ??
|
|
514
|
+
new InMemoryTodayWriteLockManager(getTodayWriteLockTimeoutMs(config.executeTimeoutMinutes));
|
|
515
|
+
const roadmapWriteLock = deps.roadmapWriteLock ??
|
|
516
|
+
new InMemoryRoadmapWriteLockManager(getRoadmapWriteLockTimeoutMs(config.executeTimeoutMinutes));
|
|
517
|
+
// Per-instance state (not shared across tests)
|
|
518
|
+
const lastSnapshotTimes = new Map();
|
|
519
|
+
// Mutex for serialized writes
|
|
520
|
+
let writeLock = Promise.resolve();
|
|
521
|
+
function withWriteLock(fn) {
|
|
522
|
+
const prev = writeLock;
|
|
523
|
+
let resolve;
|
|
524
|
+
writeLock = new Promise((r) => {
|
|
525
|
+
resolve = r;
|
|
526
|
+
});
|
|
527
|
+
return prev.then(() => {
|
|
528
|
+
try {
|
|
529
|
+
return fn();
|
|
530
|
+
}
|
|
531
|
+
finally {
|
|
532
|
+
resolve();
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
function saveSnapshot(filePath, content, trigger, force = false, sessionId) {
|
|
537
|
+
const now = Date.now();
|
|
538
|
+
const lastTime = lastSnapshotTimes.get(filePath) ?? 0;
|
|
539
|
+
if (!force && now - lastTime < SNAPSHOT_DEBOUNCE_MS) {
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
const result = db
|
|
543
|
+
.prepare("INSERT INTO md_file_snapshots (file_path, content, trigger, session_id) VALUES (?, ?, ?, ?)")
|
|
544
|
+
.run(filePath, content, trigger, sessionId ?? null);
|
|
545
|
+
lastSnapshotTimes.set(filePath, now);
|
|
546
|
+
return Number(result.lastInsertRowid);
|
|
547
|
+
}
|
|
548
|
+
function isRoadmapValidationDisabled(path, headerValue) {
|
|
549
|
+
return path === "roadmap" && headerValue?.toLowerCase() === "off";
|
|
550
|
+
}
|
|
551
|
+
function logRoadmapValidationBypass(c, method, path) {
|
|
552
|
+
logger.warn({
|
|
553
|
+
path,
|
|
554
|
+
method,
|
|
555
|
+
sessionId: c.req.header("X-Session-Id") ?? null,
|
|
556
|
+
caller: c.req.header("X-Caller") ??
|
|
557
|
+
c.req.header("X-Agent-Caller") ??
|
|
558
|
+
c.req.header("User-Agent") ??
|
|
559
|
+
null,
|
|
560
|
+
route: c.req.path,
|
|
561
|
+
}, "Roadmap validation bypassed by X-Roadmap-Validation: off");
|
|
562
|
+
}
|
|
563
|
+
function roadmapDefaultLongTermPlanSource(c) {
|
|
564
|
+
const caller = (c.req.header("X-Caller") ??
|
|
565
|
+
c.req.header("X-Agent-Caller") ??
|
|
566
|
+
"").toLowerCase();
|
|
567
|
+
return caller.includes("dashboard") ? "dashboard" : "manual";
|
|
568
|
+
}
|
|
569
|
+
async function readOptionalJsonBody(c) {
|
|
570
|
+
const raw = await c.req.text();
|
|
571
|
+
if (raw.trim() === "")
|
|
572
|
+
return { ok: true, body: {} };
|
|
573
|
+
try {
|
|
574
|
+
const parsed = JSON.parse(raw);
|
|
575
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
576
|
+
return {
|
|
577
|
+
ok: false,
|
|
578
|
+
response: c.json({
|
|
579
|
+
error: "validation_error",
|
|
580
|
+
message: "JSON body must be an object.",
|
|
581
|
+
}, 400),
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
return { ok: true, body: parsed };
|
|
585
|
+
}
|
|
586
|
+
catch (err) {
|
|
587
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
588
|
+
logger.warn({ path: c.req.path, method: c.req.method, detail }, "Request rejected — body is not valid JSON");
|
|
589
|
+
return {
|
|
590
|
+
ok: false,
|
|
591
|
+
response: c.json({ error: "invalid_json_body", message: detail }, 400),
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
// === Routes registered BEFORE wildcards (Hono matches in registration order) ===
|
|
596
|
+
// POST /context/lock/morning-routine — Acquire exclusive lock
|
|
597
|
+
app.post("/context/lock/morning-routine", (c) => {
|
|
598
|
+
const result = morningRoutineLock.acquire();
|
|
599
|
+
if (!result.ok) {
|
|
600
|
+
return c.json({ error: "lock_held", holder: result.holder }, 409);
|
|
601
|
+
}
|
|
602
|
+
return c.json({ status: "acquired", lockId: result.lockId });
|
|
603
|
+
});
|
|
604
|
+
// DELETE /context/lock/morning-routine — Release exclusive lock
|
|
605
|
+
app.delete("/context/lock/morning-routine", async (c) => {
|
|
606
|
+
const body = await c.req.json().catch(() => ({}));
|
|
607
|
+
const lockId = body.lockId;
|
|
608
|
+
if (lockId && morningRoutineLock.release(lockId)) {
|
|
609
|
+
return c.json({ status: "released" });
|
|
610
|
+
}
|
|
611
|
+
return c.json({ error: "lock_not_held" }, 400);
|
|
612
|
+
});
|
|
613
|
+
// POST /context/lock/roadmap — Acquire exclusive roadmap write lock
|
|
614
|
+
// Dispatcher auto-acquires this for `routine.roadmap_refresh`; other
|
|
615
|
+
// flows (DM handler via the roadmap skill, evening sweeper) may
|
|
616
|
+
// acquire it manually. See ROADMAP-REDESIGN.md §3.6.
|
|
617
|
+
app.post("/context/lock/roadmap", (c) => {
|
|
618
|
+
const result = roadmapWriteLock.acquire();
|
|
619
|
+
if (!result.ok) {
|
|
620
|
+
return c.json({ error: "roadmap_write_lock_held", holder: result.holder }, 409);
|
|
621
|
+
}
|
|
622
|
+
return c.json({ status: "acquired", lockId: result.lockId });
|
|
623
|
+
});
|
|
624
|
+
// DELETE /context/lock/roadmap — Release the roadmap write lock
|
|
625
|
+
app.delete("/context/lock/roadmap", async (c) => {
|
|
626
|
+
const body = await c.req.json().catch(() => ({}));
|
|
627
|
+
const lockId = body.lockId;
|
|
628
|
+
if (lockId && roadmapWriteLock.release(lockId)) {
|
|
629
|
+
return c.json({ status: "released" });
|
|
630
|
+
}
|
|
631
|
+
return c.json({ error: "lock_not_held" }, 400);
|
|
632
|
+
});
|
|
633
|
+
// POST /context/roadmap/id — Mint a stable daemon-owned roadmap entry id.
|
|
634
|
+
app.post("/context/roadmap/id", async (c) => {
|
|
635
|
+
if (roadmapWriteLock.getHolder()) {
|
|
636
|
+
const lockId = c.req.header("X-Lock-Id");
|
|
637
|
+
if (!roadmapWriteLock.isHeldBy(lockId)) {
|
|
638
|
+
logger.info({ path: "roadmap" }, "Roadmap id mint rejected — roadmap write lock held");
|
|
639
|
+
return c.json({ error: "roadmap_write_lock_held" }, 409);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
const parsedBody = await readOptionalJsonBody(c);
|
|
643
|
+
if (!parsedBody.ok)
|
|
644
|
+
return parsedBody.response;
|
|
645
|
+
const requestedDate = parsedBody.body.creationDate ?? parsedBody.body.sourceDate;
|
|
646
|
+
const creationDate = typeof requestedDate === "string"
|
|
647
|
+
? requestedDate
|
|
648
|
+
: localDateStr(new Date(), config.timezone || undefined);
|
|
649
|
+
if (!isValidYmd(creationDate)) {
|
|
650
|
+
return c.json({
|
|
651
|
+
error: "validation_error",
|
|
652
|
+
message: "creationDate must be YYYY-MM-DD.",
|
|
653
|
+
}, 400);
|
|
654
|
+
}
|
|
655
|
+
return withWriteLock(() => {
|
|
656
|
+
const contextDir = getCurrentContextDir();
|
|
657
|
+
const fullPath = safePath(contextDir, "roadmap");
|
|
658
|
+
if (!fullPath) {
|
|
659
|
+
return c.json({ error: "invalid_path", path: "roadmap" }, 400);
|
|
660
|
+
}
|
|
661
|
+
const content = existsSync(fullPath)
|
|
662
|
+
? readFileSync(fullPath, "utf-8")
|
|
663
|
+
: "";
|
|
664
|
+
const existingIds = extractRoadmapIds(content).map((ref) => ref.id);
|
|
665
|
+
try {
|
|
666
|
+
return c.json({
|
|
667
|
+
id: generateRoadmapId({
|
|
668
|
+
creationDate,
|
|
669
|
+
existingIds,
|
|
670
|
+
randomBytes: deps.roadmapIdRandomBytes,
|
|
671
|
+
}),
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
catch (err) {
|
|
675
|
+
if (err instanceof RoadmapIdGenerationError) {
|
|
676
|
+
return c.json({ error: "roadmap_id_generation_failed" }, 503);
|
|
677
|
+
}
|
|
678
|
+
throw err;
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
});
|
|
682
|
+
// POST /context/archive-today — B-007 §5.9 day rotation.
|
|
683
|
+
// Before Phase 1 this copied today.md to `schedule/YYYY-MM-DD.md`; that
|
|
684
|
+
// mechanical archive has been retired (the synthesized `daily/YYYY-MM-DD.md`
|
|
685
|
+
// is now written by the morning routine). The endpoint is kept as the
|
|
686
|
+
// agent-triggered rotation that renames `today.md → yesterday.md` and
|
|
687
|
+
// returns the previous date so the agent can write the new `today.md`
|
|
688
|
+
// in the same flow.
|
|
689
|
+
app.post("/context/archive-today", (c) => {
|
|
690
|
+
return withWriteLock(() => {
|
|
691
|
+
const contextDir = getCurrentContextDir();
|
|
692
|
+
const todayPath = join(contextDir, "today.md");
|
|
693
|
+
if (!existsSync(todayPath)) {
|
|
694
|
+
return c.json({ error: "not_found", path: "today" }, 404);
|
|
695
|
+
}
|
|
696
|
+
const content = readFileSync(todayPath, "utf-8");
|
|
697
|
+
const dateStr = content.match(/^#.*(\d{4}-\d{2}-\d{2})/)?.[1] ??
|
|
698
|
+
localDateStr(new Date());
|
|
699
|
+
const yesterdayPath = join(contextDir, "yesterday.md");
|
|
700
|
+
// Atomic write through O_NOFOLLOW + rename so a symlink swap at
|
|
701
|
+
// `yesterday.md` between request validation and the write cannot
|
|
702
|
+
// redirect the rotation into an attacker-controlled path. The
|
|
703
|
+
// legacy `copyFileSync` would silently follow such a symlink.
|
|
704
|
+
writeFileAtomically(yesterdayPath, content);
|
|
705
|
+
saveSnapshot("today", content, "rotate-to-yesterday", true);
|
|
706
|
+
return c.json({
|
|
707
|
+
status: "archived",
|
|
708
|
+
archivePath: "yesterday.md",
|
|
709
|
+
rotatedFrom: dateStr,
|
|
710
|
+
});
|
|
711
|
+
});
|
|
712
|
+
});
|
|
713
|
+
// POST /context/restore-snapshot/:id — restore a prior md_file_snapshots
|
|
714
|
+
// row back onto disk. The current on-disk file (if any) is snapshotted
|
|
715
|
+
// first so the restore itself is reversible from the Knowledge page.
|
|
716
|
+
app.post("/context/restore-snapshot/:id", (c) => {
|
|
717
|
+
const id = Number(c.req.param("id"));
|
|
718
|
+
if (!Number.isSafeInteger(id) || id <= 0) {
|
|
719
|
+
return c.json({ error: "invalid_id" }, 400);
|
|
720
|
+
}
|
|
721
|
+
const row = db
|
|
722
|
+
.prepare("SELECT id, file_path, content FROM md_file_snapshots WHERE id = ?")
|
|
723
|
+
.get(id);
|
|
724
|
+
if (!row) {
|
|
725
|
+
return c.json({ error: "not_found" }, 404);
|
|
726
|
+
}
|
|
727
|
+
const target = resolveContextTarget(row.file_path);
|
|
728
|
+
const path = target.base;
|
|
729
|
+
const contextDir = getCurrentContextDir();
|
|
730
|
+
const fullPath = safePath(contextDir, row.file_path);
|
|
731
|
+
if (!fullPath) {
|
|
732
|
+
return c.json({ error: "invalid_path", path }, 400);
|
|
733
|
+
}
|
|
734
|
+
if (!isWriteAllowed(path, "PUT") && !isWriteAllowed(path, "PATCH")) {
|
|
735
|
+
logger.warn({ path, method: "RESTORE" }, "Snapshot restore forbidden");
|
|
736
|
+
return c.json({ error: "forbidden", path, method: "RESTORE" }, 403);
|
|
737
|
+
}
|
|
738
|
+
if (morningRoutineLock.getHolder() && path === "today") {
|
|
739
|
+
const lockId = c.req.header("X-Lock-Id");
|
|
740
|
+
if (!morningRoutineLock.isHeldBy(lockId)) {
|
|
741
|
+
logger.info({ path }, "Snapshot restore rejected — morning routine lock held");
|
|
742
|
+
return c.json({ error: "morning_routine_lock_held" }, 409);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
if (roadmapWriteLock.getHolder() && path === "roadmap") {
|
|
746
|
+
const lockId = c.req.header("X-Lock-Id");
|
|
747
|
+
if (!roadmapWriteLock.isHeldBy(lockId)) {
|
|
748
|
+
logger.info({ path }, "Snapshot restore rejected — roadmap write lock held");
|
|
749
|
+
return c.json({ error: "roadmap_write_lock_held" }, 409);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
const contentError = validateContextContent(target, row.content, {
|
|
753
|
+
skipFrontmatterValidation: true,
|
|
754
|
+
});
|
|
755
|
+
if (contentError) {
|
|
756
|
+
return c.json({ error: "validation_error", message: contentError.message }, contentError.status);
|
|
757
|
+
}
|
|
758
|
+
return withWriteLock(() => {
|
|
759
|
+
let backupSnapshotId = null;
|
|
760
|
+
if (existsSync(fullPath)) {
|
|
761
|
+
const current = readFileSync(fullPath, "utf-8");
|
|
762
|
+
backupSnapshotId = saveSnapshot(path, current, "api_restore_snapshot", true);
|
|
763
|
+
}
|
|
764
|
+
// writeFileAtomically handles parent-dir creation, refuses to
|
|
765
|
+
// follow a symlink at the destination, and renames into place.
|
|
766
|
+
writeFileAtomically(fullPath, row.content);
|
|
767
|
+
writeTracker?.markWriting(fullPath, row.content);
|
|
768
|
+
if (shouldRefreshPromptContext(path, "PUT")) {
|
|
769
|
+
notifyPromptContextChanged(deps, path, `context_restore_snapshot:${path}`, { path, method: "RESTORE" });
|
|
770
|
+
}
|
|
771
|
+
if (path.startsWith("routines/custom/")) {
|
|
772
|
+
deps.onCustomRoutinesChanged?.();
|
|
773
|
+
}
|
|
774
|
+
const writtenStat = statSync(fullPath);
|
|
775
|
+
logger.info({
|
|
776
|
+
path,
|
|
777
|
+
method: "RESTORE",
|
|
778
|
+
restoredFromSnapshotId: id,
|
|
779
|
+
backupSnapshotId: backupSnapshotId ?? undefined,
|
|
780
|
+
}, "Context snapshot restored");
|
|
781
|
+
return c.json({
|
|
782
|
+
status: "restored",
|
|
783
|
+
path,
|
|
784
|
+
restoredFromSnapshotId: id,
|
|
785
|
+
backupSnapshotId,
|
|
786
|
+
lastModified: writtenStat.mtime.toISOString(),
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
});
|
|
790
|
+
// GET /context/list/:dir — List files in directory
|
|
791
|
+
app.get("/context/list/:dir", (c) => {
|
|
792
|
+
const dir = c.req.param("dir");
|
|
793
|
+
// B-007 §5.1 — canonical listable directories.
|
|
794
|
+
const allowedDirs = [
|
|
795
|
+
"projects",
|
|
796
|
+
"weekly",
|
|
797
|
+
"monthly",
|
|
798
|
+
"daily",
|
|
799
|
+
"user",
|
|
800
|
+
"rules",
|
|
801
|
+
"routines",
|
|
802
|
+
"dossiers",
|
|
803
|
+
"git",
|
|
804
|
+
"git-repos",
|
|
805
|
+
"inbox",
|
|
806
|
+
];
|
|
807
|
+
if (!allowedDirs.includes(dir)) {
|
|
808
|
+
return c.json({ error: "invalid_directory", allowed: allowedDirs }, 400);
|
|
809
|
+
}
|
|
810
|
+
const contextDir = getCurrentContextDir();
|
|
811
|
+
const dirPath = join(contextDir, dir);
|
|
812
|
+
if (!existsSync(dirPath)) {
|
|
813
|
+
return c.json({ files: [] });
|
|
814
|
+
}
|
|
815
|
+
const files = readdirSync(dirPath)
|
|
816
|
+
.filter((f) => CONTEXT_FILE_EXTENSIONS.some((ext) => f.endsWith(ext)))
|
|
817
|
+
.map((f) => {
|
|
818
|
+
const stat = statSync(join(dirPath, f));
|
|
819
|
+
return { name: f, lastModified: stat.mtime.toISOString() };
|
|
820
|
+
});
|
|
821
|
+
// B-007 §5.8 Q3 — surface custom routines so the dashboard routines
|
|
822
|
+
// editor sees them alongside the built-ins. `routines/custom/` is the
|
|
823
|
+
// only nested directory we need to flatten; other listable dirs are
|
|
824
|
+
// flat by design (§5.1).
|
|
825
|
+
if (dir === "routines") {
|
|
826
|
+
const customDir = join(dirPath, "custom");
|
|
827
|
+
if (existsSync(customDir)) {
|
|
828
|
+
for (const f of readdirSync(customDir)) {
|
|
829
|
+
if (!CONTEXT_FILE_EXTENSIONS.some((ext) => f.endsWith(ext)))
|
|
830
|
+
continue;
|
|
831
|
+
const stat = statSync(join(customDir, f));
|
|
832
|
+
files.push({
|
|
833
|
+
name: `custom/${f}`,
|
|
834
|
+
lastModified: stat.mtime.toISOString(),
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
// Unified repositories layout (`git/<slug>/overview.md` +
|
|
840
|
+
// `git/<slug>/journal/<YYYY-MM-DD>.md`) — surface every per-repo file
|
|
841
|
+
// under the `git` listing so the Knowledge page tree shows them.
|
|
842
|
+
// Without this the listing only contains files directly under `git/`,
|
|
843
|
+
// and the per-slug subdirectories silently drop off the dashboard.
|
|
844
|
+
// Mirrors the `routines/custom/` flatten above.
|
|
845
|
+
if (dir === "git") {
|
|
846
|
+
for (const entry of readdirSync(dirPath, { withFileTypes: true })) {
|
|
847
|
+
if (!entry.isDirectory())
|
|
848
|
+
continue;
|
|
849
|
+
const slug = entry.name;
|
|
850
|
+
const slugDir = join(dirPath, slug);
|
|
851
|
+
for (const f of readdirSync(slugDir)) {
|
|
852
|
+
if (!CONTEXT_FILE_EXTENSIONS.some((ext) => f.endsWith(ext)))
|
|
853
|
+
continue;
|
|
854
|
+
const stat = statSync(join(slugDir, f));
|
|
855
|
+
files.push({
|
|
856
|
+
name: `${slug}/${f}`,
|
|
857
|
+
lastModified: stat.mtime.toISOString(),
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
const journalDir = join(slugDir, "journal");
|
|
861
|
+
if (existsSync(journalDir)) {
|
|
862
|
+
for (const f of readdirSync(journalDir)) {
|
|
863
|
+
if (!CONTEXT_FILE_EXTENSIONS.some((ext) => f.endsWith(ext)))
|
|
864
|
+
continue;
|
|
865
|
+
const stat = statSync(join(journalDir, f));
|
|
866
|
+
files.push({
|
|
867
|
+
name: `${slug}/journal/${f}`,
|
|
868
|
+
lastModified: stat.mtime.toISOString(),
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
// MANAGEMENT-POLICY-CAPTURE-PLAN §4.4.1 step 1 — surface policy files
|
|
875
|
+
// under `rules/policies/` flattened into the `rules` listing so the
|
|
876
|
+
// `management-policy` skill can use the directory listing as its
|
|
877
|
+
// source-of-truth (the agent-maintained `_index.md` is only the
|
|
878
|
+
// convenience snapshot). Mirrors the `routines/custom/` flatten above.
|
|
879
|
+
if (dir === "rules") {
|
|
880
|
+
const policiesDir = join(dirPath, "policies");
|
|
881
|
+
if (existsSync(policiesDir)) {
|
|
882
|
+
for (const f of readdirSync(policiesDir)) {
|
|
883
|
+
if (!CONTEXT_FILE_EXTENSIONS.some((ext) => f.endsWith(ext)))
|
|
884
|
+
continue;
|
|
885
|
+
const stat = statSync(join(policiesDir, f));
|
|
886
|
+
files.push({
|
|
887
|
+
name: `policies/${f}`,
|
|
888
|
+
lastModified: stat.mtime.toISOString(),
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
return c.json({ files });
|
|
894
|
+
});
|
|
895
|
+
// GET /context/today/reconciliation — compare open Agent Plan rows with
|
|
896
|
+
// pending/running schedules for the same local day. This is intentionally
|
|
897
|
+
// diagnostic only: morning routine may write today.md and register schedules
|
|
898
|
+
// in separate API calls, so write-time hard failure would create false
|
|
899
|
+
// conflicts. The endpoint gives operators and future jobs a server-side
|
|
900
|
+
// reconciliation surface.
|
|
901
|
+
app.get("/context/today/reconciliation", (c) => {
|
|
902
|
+
const contextDir = getCurrentContextDir();
|
|
903
|
+
const fullPath = safePath(contextDir, "today");
|
|
904
|
+
if (!fullPath) {
|
|
905
|
+
return c.json({ error: "invalid_path", path: "today" }, 400);
|
|
906
|
+
}
|
|
907
|
+
if (!existsSync(fullPath)) {
|
|
908
|
+
return c.json({ error: "not_found", path: "today" }, 404);
|
|
909
|
+
}
|
|
910
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
911
|
+
const validationError = validateTodayContent(content);
|
|
912
|
+
const todayDate = extractTodayDate(content) ??
|
|
913
|
+
localDateStr(new Date(), config.timezone || undefined);
|
|
914
|
+
const openRows = extractTodayAgentPlanRows(content).rows.filter((row) => !row.checked);
|
|
915
|
+
const openRowsWithMetadata = openRows.map((row) => ({
|
|
916
|
+
row,
|
|
917
|
+
agentPlan: buildTodayAgentPlanMetadata(todayDate, row),
|
|
918
|
+
}));
|
|
919
|
+
const pendingRows = db
|
|
920
|
+
.prepare(`SELECT id, scheduled_for, task_type, task_description, task_context, status
|
|
921
|
+
FROM agent_schedule
|
|
922
|
+
WHERE status IN ('pending', 'running')`)
|
|
923
|
+
.all();
|
|
924
|
+
const schedules = pendingRows
|
|
925
|
+
.map((row) => toTodayScheduleCandidate(row, config.timezone || undefined))
|
|
926
|
+
.filter((row) => row !== null)
|
|
927
|
+
.map((row) => ({
|
|
928
|
+
...row,
|
|
929
|
+
agentPlan: readTodayAgentPlanMetadata(row.taskContext),
|
|
930
|
+
}))
|
|
931
|
+
.filter((row) => row.agentPlan !== null && row.agentPlan.date === todayDate);
|
|
932
|
+
const rowMatches = openRowsWithMetadata.map(({ row, agentPlan }) => {
|
|
933
|
+
const matches = schedules.filter((schedule) => schedule.localDate === todayDate &&
|
|
934
|
+
schedule.localTime === row.time &&
|
|
935
|
+
schedule.agentPlan.ref === agentPlan.ref &&
|
|
936
|
+
schedule.agentPlan.fingerprint === agentPlan.fingerprint &&
|
|
937
|
+
schedule.agentPlan.category === row.category &&
|
|
938
|
+
schedule.agentPlan.trigger === row.trigger);
|
|
939
|
+
return { row, agentPlan, matches };
|
|
940
|
+
});
|
|
941
|
+
const rowsWithoutSchedule = rowMatches.filter(({ matches }) => matches.length === 0);
|
|
942
|
+
const duplicateAgentPlanSchedules = rowMatches.filter(({ matches }) => matches.length > 1);
|
|
943
|
+
const matchedScheduleIds = new Set();
|
|
944
|
+
for (const { matches } of rowMatches) {
|
|
945
|
+
for (const schedule of matches)
|
|
946
|
+
matchedScheduleIds.add(schedule.id);
|
|
947
|
+
}
|
|
948
|
+
const schedulesWithoutRow = schedules.filter((row) => !matchedScheduleIds.has(row.id));
|
|
949
|
+
const mismatchCount = (rowsWithoutSchedule.length +
|
|
950
|
+
duplicateAgentPlanSchedules.length +
|
|
951
|
+
schedulesWithoutRow.length);
|
|
952
|
+
return c.json({
|
|
953
|
+
status: validationError
|
|
954
|
+
? "invalid_today"
|
|
955
|
+
: mismatchCount > 0
|
|
956
|
+
? "mismatch"
|
|
957
|
+
: "ok",
|
|
958
|
+
validationError,
|
|
959
|
+
todayDate,
|
|
960
|
+
openAgentPlanRows: openRows.length,
|
|
961
|
+
pendingSchedules: schedules.length,
|
|
962
|
+
rowsWithoutSchedule: rowsWithoutSchedule.map(({ row, agentPlan }) => ({
|
|
963
|
+
line: row.line,
|
|
964
|
+
ref: agentPlan.ref,
|
|
965
|
+
time: row.time,
|
|
966
|
+
action: row.action,
|
|
967
|
+
category: row.category,
|
|
968
|
+
trigger: row.trigger,
|
|
969
|
+
})),
|
|
970
|
+
schedulesWithoutRow: schedulesWithoutRow.map((row) => ({
|
|
971
|
+
id: row.id,
|
|
972
|
+
ref: row.agentPlan.ref,
|
|
973
|
+
localTime: row.localTime,
|
|
974
|
+
scheduledFor: row.scheduledFor,
|
|
975
|
+
taskType: row.taskType,
|
|
976
|
+
status: row.status,
|
|
977
|
+
description: row.description,
|
|
978
|
+
})),
|
|
979
|
+
duplicateAgentPlanSchedules: duplicateAgentPlanSchedules.map(({ row, agentPlan, matches }) => ({
|
|
980
|
+
line: row.line,
|
|
981
|
+
ref: agentPlan.ref,
|
|
982
|
+
time: row.time,
|
|
983
|
+
action: row.action,
|
|
984
|
+
scheduleIds: matches.map((match) => match.id),
|
|
985
|
+
})),
|
|
986
|
+
});
|
|
987
|
+
});
|
|
988
|
+
// GET /context/health — schema drift and missing-file report for the
|
|
989
|
+
// primary context vault. Registered before the wildcard read route.
|
|
990
|
+
app.get("/context/health", (c) => {
|
|
991
|
+
const contextDir = getCurrentContextDir();
|
|
992
|
+
return c.json(buildContextHealthReport(contextDir));
|
|
993
|
+
});
|
|
994
|
+
// POST /context/repair/stub — create a known missing stub from the
|
|
995
|
+
// templates tree. This is intentionally guarded to a small allow-list;
|
|
996
|
+
// it is not an arbitrary file creation endpoint.
|
|
997
|
+
app.post("/context/repair/stub", async (c) => {
|
|
998
|
+
const parsedBody = await readOptionalJsonBody(c);
|
|
999
|
+
if (!parsedBody.ok)
|
|
1000
|
+
return parsedBody.response;
|
|
1001
|
+
const rawPath = parsedBody.body.path;
|
|
1002
|
+
if (typeof rawPath !== "string") {
|
|
1003
|
+
return c.json({
|
|
1004
|
+
error: "validation_error",
|
|
1005
|
+
message: "path must be a string.",
|
|
1006
|
+
}, 400);
|
|
1007
|
+
}
|
|
1008
|
+
const normalizedPath = normalizeRepairStubPath(rawPath);
|
|
1009
|
+
if (!normalizedPath || !REPAIRABLE_STUB_TARGETS.has(normalizedPath)) {
|
|
1010
|
+
return c.json({
|
|
1011
|
+
error: "unsupported_stub_target",
|
|
1012
|
+
message: "Only known context stub targets can be repaired.",
|
|
1013
|
+
path: rawPath,
|
|
1014
|
+
}, 400);
|
|
1015
|
+
}
|
|
1016
|
+
const templatesRoot = resolveTemplatesRoot(config.workspaceDir);
|
|
1017
|
+
if (!templatesRoot) {
|
|
1018
|
+
return c.json({
|
|
1019
|
+
error: "templates_unavailable",
|
|
1020
|
+
message: "agent-assets/templates could not be located.",
|
|
1021
|
+
}, 503);
|
|
1022
|
+
}
|
|
1023
|
+
const templatePath = join(templatesRoot, normalizedPath);
|
|
1024
|
+
if (!existsSync(templatePath)) {
|
|
1025
|
+
return c.json({
|
|
1026
|
+
error: "template_not_found",
|
|
1027
|
+
message: `No template exists for ${normalizedPath}.`,
|
|
1028
|
+
path: normalizedPath,
|
|
1029
|
+
}, 404);
|
|
1030
|
+
}
|
|
1031
|
+
const contextDir = getCurrentContextDir();
|
|
1032
|
+
const fullPath = safePath(contextDir, normalizedPath);
|
|
1033
|
+
if (!fullPath) {
|
|
1034
|
+
return c.json({ error: "invalid_path", path: normalizedPath }, 400);
|
|
1035
|
+
}
|
|
1036
|
+
return withWriteLock(() => {
|
|
1037
|
+
if (existsSync(fullPath)) {
|
|
1038
|
+
const existingStat = statSync(fullPath);
|
|
1039
|
+
return c.json({
|
|
1040
|
+
status: "exists",
|
|
1041
|
+
path: normalizedPath,
|
|
1042
|
+
lastModified: existingStat.mtime.toISOString(),
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
// Read the template once and write atomically; replaces the
|
|
1046
|
+
// previous copyFileSync, which would have silently followed a
|
|
1047
|
+
// symlink planted at `fullPath` during the TOCTOU window between
|
|
1048
|
+
// safePath validation and the write.
|
|
1049
|
+
const content = readFileSync(templatePath, "utf-8");
|
|
1050
|
+
writeFileAtomically(fullPath, content);
|
|
1051
|
+
writeTracker?.markWriting(fullPath, content);
|
|
1052
|
+
const normalizedBase = normalizeContextPath(normalizedPath);
|
|
1053
|
+
if (shouldRefreshPromptContext(normalizedBase, "PUT")) {
|
|
1054
|
+
notifyPromptContextChanged(deps, normalizedBase, `context_repair_stub:${normalizedBase}`, { path: normalizedBase, method: "REPAIR" });
|
|
1055
|
+
}
|
|
1056
|
+
deps.onIndexableContextChange?.(normalizedPath);
|
|
1057
|
+
const writtenStat = statSync(fullPath);
|
|
1058
|
+
logger.info({ path: normalizedPath, templatePath }, "Context stub repaired from template");
|
|
1059
|
+
return c.json({
|
|
1060
|
+
status: "created",
|
|
1061
|
+
path: normalizedPath,
|
|
1062
|
+
lastModified: writtenStat.mtime.toISOString(),
|
|
1063
|
+
});
|
|
1064
|
+
});
|
|
1065
|
+
});
|
|
1066
|
+
// === Wildcard routes ===
|
|
1067
|
+
// GET /context/* — Read context file
|
|
1068
|
+
app.get("/context/*", (c) => {
|
|
1069
|
+
const rawPath = c.req.path.replace("/api/context/", "");
|
|
1070
|
+
if (!rawPath || rawPath === "list") {
|
|
1071
|
+
return c.json({ error: "path_required" }, 400);
|
|
1072
|
+
}
|
|
1073
|
+
const path = normalizeContextPath(rawPath);
|
|
1074
|
+
const contextDir = getCurrentContextDir();
|
|
1075
|
+
const fullPath = safePath(contextDir, rawPath);
|
|
1076
|
+
if (!fullPath) {
|
|
1077
|
+
return c.json({ error: "invalid_path", path }, 400);
|
|
1078
|
+
}
|
|
1079
|
+
if (!existsSync(fullPath)) {
|
|
1080
|
+
return c.json({ error: "not_found", path }, 404);
|
|
1081
|
+
}
|
|
1082
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
1083
|
+
const stat = statSync(fullPath);
|
|
1084
|
+
// STAGE-C-DM-FRESHNESS-PLAN §Task 4 — record reads of `today` so the
|
|
1085
|
+
// dashboard refetch-hit metric can detect when the agent invokes the
|
|
1086
|
+
// Task 3 directive on a resumed turn. Bounded to `today` reads only
|
|
1087
|
+
// so the agent_actions volume stays small. Best-effort: any logging
|
|
1088
|
+
// failure must not break the read.
|
|
1089
|
+
if (path === "today") {
|
|
1090
|
+
try {
|
|
1091
|
+
deps.db
|
|
1092
|
+
.prepare(`INSERT INTO agent_actions (action_type, trigger, result, detail, started_at, completed_at)
|
|
1093
|
+
VALUES ('context_read', 'reactive', 'success', json(?), datetime('now'), datetime('now'))`)
|
|
1094
|
+
.run(JSON.stringify({ path }));
|
|
1095
|
+
}
|
|
1096
|
+
catch (err) {
|
|
1097
|
+
logger.warn({ err, path }, "Failed to record context_read agent_actions row (Stage C metrics)");
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
return c.json({
|
|
1101
|
+
content,
|
|
1102
|
+
lastModified: stat.mtime.toISOString(),
|
|
1103
|
+
editable: isWriteAllowed(path, "PUT"),
|
|
1104
|
+
});
|
|
1105
|
+
});
|
|
1106
|
+
// PUT /context/* — Full replace
|
|
1107
|
+
app.put("/context/*", async (c) => {
|
|
1108
|
+
const rawPath = c.req.path.replace("/api/context/", "");
|
|
1109
|
+
const target = resolveContextTarget(rawPath);
|
|
1110
|
+
const path = target.base;
|
|
1111
|
+
const contextDir = getCurrentContextDir();
|
|
1112
|
+
const fullPath = safePath(contextDir, rawPath);
|
|
1113
|
+
if (!fullPath) {
|
|
1114
|
+
return c.json({ error: "invalid_path", path }, 400);
|
|
1115
|
+
}
|
|
1116
|
+
if (!isWriteAllowed(path, "PUT")) {
|
|
1117
|
+
logger.warn({ path, method: "PUT" }, "Context write forbidden");
|
|
1118
|
+
return c.json({ error: "forbidden", path, method: "PUT" }, 403);
|
|
1119
|
+
}
|
|
1120
|
+
// Morning Routine lock: reject writes to today while lock is held
|
|
1121
|
+
if (morningRoutineLock.getHolder() && path === "today") {
|
|
1122
|
+
const lockId = c.req.header("X-Lock-Id");
|
|
1123
|
+
if (!morningRoutineLock.isHeldBy(lockId)) {
|
|
1124
|
+
logger.info({ path }, "Context PUT rejected — morning routine lock held");
|
|
1125
|
+
return c.json({ error: "morning_routine_lock_held" }, 409);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
// Roadmap write lock: reject writes to roadmap while another session holds it
|
|
1129
|
+
if (roadmapWriteLock.getHolder() && path === "roadmap") {
|
|
1130
|
+
const lockId = c.req.header("X-Lock-Id");
|
|
1131
|
+
if (!roadmapWriteLock.isHeldBy(lockId)) {
|
|
1132
|
+
logger.info({ path }, "Context PUT rejected — roadmap write lock held");
|
|
1133
|
+
return c.json({ error: "roadmap_write_lock_held" }, 409);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
const parsedBody = await readJsonBody(c, { maxBytes: CONTEXT_BODY_MAX_BYTES });
|
|
1137
|
+
if (!parsedBody.ok)
|
|
1138
|
+
return parsedBody.response;
|
|
1139
|
+
const body = parsedBody.body;
|
|
1140
|
+
const parsed = contextPutSchema.safeParse(body);
|
|
1141
|
+
if (!parsed.success) {
|
|
1142
|
+
return c.json({ error: "validation_error", details: parsed.error }, 400);
|
|
1143
|
+
}
|
|
1144
|
+
const roadmapValidationOff = isRoadmapValidationDisabled(path, c.req.header("X-Roadmap-Validation"));
|
|
1145
|
+
if (roadmapValidationOff) {
|
|
1146
|
+
logRoadmapValidationBypass(c, "PUT", path);
|
|
1147
|
+
}
|
|
1148
|
+
const expectedAgentDay = path === "today"
|
|
1149
|
+
? getAgentDayDateStr(config.timezone || undefined, config.dayBoundaryHour ?? 4)
|
|
1150
|
+
: undefined;
|
|
1151
|
+
const preflight = prepareContextContentForWrite(target, parsed.data.content, {
|
|
1152
|
+
timezone: config.timezone || undefined,
|
|
1153
|
+
disableRoadmapValidation: roadmapValidationOff,
|
|
1154
|
+
defaultLongTermPlanSource: roadmapDefaultLongTermPlanSource(c),
|
|
1155
|
+
expectedAgentDay,
|
|
1156
|
+
});
|
|
1157
|
+
if (!preflight.ok) {
|
|
1158
|
+
return c.json({
|
|
1159
|
+
error: "validation_error",
|
|
1160
|
+
message: preflight.message,
|
|
1161
|
+
path: preflight.path,
|
|
1162
|
+
}, preflight.status);
|
|
1163
|
+
}
|
|
1164
|
+
const sessionId = c.req.header("X-Session-Id");
|
|
1165
|
+
return withWriteLock(() => {
|
|
1166
|
+
// Append-only files: PUT is only allowed for initial creation.
|
|
1167
|
+
// Once the file exists, all writes must go through PATCH to preserve
|
|
1168
|
+
// the append-only contract. This check MUST be inside withWriteLock
|
|
1169
|
+
// to prevent TOCTOU races where two concurrent PUTs both pass an
|
|
1170
|
+
// outer existsSync check and then sequentially overwrite.
|
|
1171
|
+
if (CREATE_ONLY_PUT.has(path) && existsSync(fullPath)) {
|
|
1172
|
+
logger.warn({ path }, "Context PUT rejected — file exists, use PATCH to append");
|
|
1173
|
+
return c.json({
|
|
1174
|
+
error: "append_only",
|
|
1175
|
+
message: `${path} already exists. Use PATCH to append new sections.`,
|
|
1176
|
+
path,
|
|
1177
|
+
}, 409);
|
|
1178
|
+
}
|
|
1179
|
+
// Optimistic concurrency check: if client supplied expectedMtime,
|
|
1180
|
+
// compare against the current file. On mismatch, return 409 with
|
|
1181
|
+
// the current state so the UI can surface a conflict dialog without
|
|
1182
|
+
// a second round-trip.
|
|
1183
|
+
let snapshotId = null;
|
|
1184
|
+
let contentToWrite = preflight.content;
|
|
1185
|
+
if (existsSync(fullPath)) {
|
|
1186
|
+
const currentStat = statSync(fullPath);
|
|
1187
|
+
const currentMtime = currentStat.mtime.toISOString();
|
|
1188
|
+
const existing = readFileSync(fullPath, "utf-8");
|
|
1189
|
+
if (parsed.data.expectedMtime !== undefined &&
|
|
1190
|
+
parsed.data.expectedMtime !== currentMtime) {
|
|
1191
|
+
logger.info({ path, expectedMtime: parsed.data.expectedMtime, currentMtime }, "Context PUT conflict");
|
|
1192
|
+
return c.json({
|
|
1193
|
+
error: "conflict",
|
|
1194
|
+
currentMtime,
|
|
1195
|
+
currentContent: existing,
|
|
1196
|
+
}, 409);
|
|
1197
|
+
}
|
|
1198
|
+
const prepared = prepareContextContentForWrite(target, parsed.data.content, {
|
|
1199
|
+
timezone: config.timezone || undefined,
|
|
1200
|
+
disableRoadmapValidation: roadmapValidationOff,
|
|
1201
|
+
previousRoadmapContent: existing,
|
|
1202
|
+
today: localDateStr(new Date(), config.timezone || undefined),
|
|
1203
|
+
defaultLongTermPlanSource: roadmapDefaultLongTermPlanSource(c),
|
|
1204
|
+
expectedAgentDay,
|
|
1205
|
+
});
|
|
1206
|
+
if (!prepared.ok) {
|
|
1207
|
+
return c.json({
|
|
1208
|
+
error: "validation_error",
|
|
1209
|
+
message: prepared.message,
|
|
1210
|
+
path: prepared.path,
|
|
1211
|
+
}, prepared.status);
|
|
1212
|
+
}
|
|
1213
|
+
contentToWrite = prepared.content;
|
|
1214
|
+
snapshotId = saveSnapshot(path, existing, "api_put", true, sessionId);
|
|
1215
|
+
}
|
|
1216
|
+
else if (parsed.data.expectedMtime !== undefined) {
|
|
1217
|
+
// Client expected a specific mtime but the file is gone
|
|
1218
|
+
return c.json({
|
|
1219
|
+
error: "conflict",
|
|
1220
|
+
currentMtime: "",
|
|
1221
|
+
currentContent: "",
|
|
1222
|
+
}, 409);
|
|
1223
|
+
}
|
|
1224
|
+
// Symlink-safe atomic write — protects against a TOCTOU swap of
|
|
1225
|
+
// `fullPath` to a symlink between safePath validation and the write.
|
|
1226
|
+
writeFileAtomically(fullPath, contentToWrite);
|
|
1227
|
+
writeTracker?.markWriting(fullPath, contentToWrite);
|
|
1228
|
+
if (shouldRefreshPromptContext(path, "PUT")) {
|
|
1229
|
+
notifyPromptContextChanged(deps, path, `context_put:${path}`, { path, method: "PUT" });
|
|
1230
|
+
}
|
|
1231
|
+
if (path.startsWith("routines/custom/")) {
|
|
1232
|
+
deps.onCustomRoutinesChanged?.();
|
|
1233
|
+
}
|
|
1234
|
+
deps.onIndexableContextChange?.(`${path}${target.ext}`);
|
|
1235
|
+
const writtenStat = statSync(fullPath);
|
|
1236
|
+
logger.info({ path, method: "PUT", bytesWritten: writtenStat.size, snapshotId: snapshotId ?? undefined }, "Context file updated");
|
|
1237
|
+
return c.json({
|
|
1238
|
+
status: "updated",
|
|
1239
|
+
snapshotId: snapshotId ?? 0,
|
|
1240
|
+
lastModified: writtenStat.mtime.toISOString(),
|
|
1241
|
+
});
|
|
1242
|
+
});
|
|
1243
|
+
});
|
|
1244
|
+
// PATCH /context/* — Section operation
|
|
1245
|
+
app.patch("/context/*", async (c) => {
|
|
1246
|
+
const rawPath = c.req.path.replace("/api/context/", "");
|
|
1247
|
+
const target = resolveContextTarget(rawPath);
|
|
1248
|
+
const path = target.base;
|
|
1249
|
+
const contextDir = getCurrentContextDir();
|
|
1250
|
+
const fullPath = safePath(contextDir, rawPath);
|
|
1251
|
+
if (!fullPath) {
|
|
1252
|
+
return c.json({ error: "invalid_path", path }, 400);
|
|
1253
|
+
}
|
|
1254
|
+
if (!isWriteAllowed(path, "PATCH")) {
|
|
1255
|
+
logger.warn({ path, method: "PATCH" }, "Context write forbidden");
|
|
1256
|
+
return c.json({ error: "forbidden", path, method: "PATCH" }, 403);
|
|
1257
|
+
}
|
|
1258
|
+
// Morning Routine lock: reject writes to today while lock is held
|
|
1259
|
+
if (morningRoutineLock.getHolder() && path === "today") {
|
|
1260
|
+
const lockId = c.req.header("X-Lock-Id");
|
|
1261
|
+
if (!morningRoutineLock.isHeldBy(lockId)) {
|
|
1262
|
+
logger.info({ path }, "Context PATCH rejected — morning routine lock held");
|
|
1263
|
+
return c.json({ error: "morning_routine_lock_held" }, 409);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
// Roadmap write lock: reject writes to roadmap while another session holds it
|
|
1267
|
+
if (roadmapWriteLock.getHolder() && path === "roadmap") {
|
|
1268
|
+
const lockId = c.req.header("X-Lock-Id");
|
|
1269
|
+
if (!roadmapWriteLock.isHeldBy(lockId)) {
|
|
1270
|
+
logger.info({ path }, "Context PATCH rejected — roadmap write lock held");
|
|
1271
|
+
return c.json({ error: "roadmap_write_lock_held" }, 409);
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
const parsedBody = await readJsonBody(c, { maxBytes: CONTEXT_BODY_MAX_BYTES });
|
|
1275
|
+
if (!parsedBody.ok)
|
|
1276
|
+
return parsedBody.response;
|
|
1277
|
+
const body = parsedBody.body;
|
|
1278
|
+
const parsed = contextPatchSchema.safeParse(body);
|
|
1279
|
+
if (!parsed.success) {
|
|
1280
|
+
return c.json({ error: "validation_error", details: parsed.error }, 400);
|
|
1281
|
+
}
|
|
1282
|
+
if (target.ext === ".base") {
|
|
1283
|
+
return c.json({
|
|
1284
|
+
error: "unsupported_operation",
|
|
1285
|
+
message: "PATCH is not supported for .base files; use PUT to replace the file.",
|
|
1286
|
+
}, 400);
|
|
1287
|
+
}
|
|
1288
|
+
const { section, mode, content: newContent, cutoff, maxEntries } = parsed.data;
|
|
1289
|
+
const sessionId = c.req.header("X-Session-Id");
|
|
1290
|
+
const roadmapValidationOff = isRoadmapValidationDisabled(path, c.req.header("X-Roadmap-Validation"));
|
|
1291
|
+
if (roadmapValidationOff) {
|
|
1292
|
+
logRoadmapValidationBypass(c, "PATCH", path);
|
|
1293
|
+
}
|
|
1294
|
+
const expectedAgentDay = path === "today"
|
|
1295
|
+
? getAgentDayDateStr(config.timezone || undefined, config.dayBoundaryHour ?? 4)
|
|
1296
|
+
: undefined;
|
|
1297
|
+
return withWriteLock(() => {
|
|
1298
|
+
if (!existsSync(fullPath)) {
|
|
1299
|
+
return c.json({ error: "not_found", path }, 404);
|
|
1300
|
+
}
|
|
1301
|
+
const fileContent = readFileSync(fullPath, "utf-8");
|
|
1302
|
+
// ── append_to_file: append content to end of file (no section lookup) ──
|
|
1303
|
+
// Designed for agent/journal.md and similar append-only files where
|
|
1304
|
+
// each write adds a new top-level ## section rather than modifying
|
|
1305
|
+
// an existing one. Avoids the hack of targeting the last section's
|
|
1306
|
+
// body and injecting H2 headers inside it.
|
|
1307
|
+
if (mode === "append_to_file") {
|
|
1308
|
+
const separator = fileContent.endsWith("\n") ? "" : "\n";
|
|
1309
|
+
const updated = fileContent + separator + (newContent ?? "") + "\n";
|
|
1310
|
+
const prepared = prepareContextContentForWrite(target, updated, {
|
|
1311
|
+
timezone: config.timezone || undefined,
|
|
1312
|
+
disableRoadmapValidation: roadmapValidationOff,
|
|
1313
|
+
previousRoadmapContent: fileContent,
|
|
1314
|
+
today: localDateStr(new Date(), config.timezone || undefined),
|
|
1315
|
+
defaultLongTermPlanSource: roadmapDefaultLongTermPlanSource(c),
|
|
1316
|
+
allowLegacyToday: path === "today" && isLegacyTodayContent(fileContent),
|
|
1317
|
+
expectedAgentDay,
|
|
1318
|
+
});
|
|
1319
|
+
if (!prepared.ok) {
|
|
1320
|
+
return c.json({
|
|
1321
|
+
error: "validation_error",
|
|
1322
|
+
message: prepared.message,
|
|
1323
|
+
path: prepared.path,
|
|
1324
|
+
}, prepared.status);
|
|
1325
|
+
}
|
|
1326
|
+
saveSnapshot(path, fileContent, "api_patch", false, sessionId);
|
|
1327
|
+
writeFileAtomically(fullPath, prepared.content);
|
|
1328
|
+
writeTracker?.markWriting(fullPath, prepared.content);
|
|
1329
|
+
if (shouldRefreshPromptContext(path, "PATCH")) {
|
|
1330
|
+
notifyPromptContextChanged(deps, path, `context_patch:${path}`, {
|
|
1331
|
+
path,
|
|
1332
|
+
method: "PATCH",
|
|
1333
|
+
mode,
|
|
1334
|
+
section,
|
|
1335
|
+
content: newContent,
|
|
1336
|
+
previousContent: fileContent,
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
if (path.startsWith("routines/custom/")) {
|
|
1340
|
+
deps.onCustomRoutinesChanged?.();
|
|
1341
|
+
}
|
|
1342
|
+
deps.onIndexableContextChange?.(`${path}${target.ext}`);
|
|
1343
|
+
logger.info({ path, method: "PATCH", mode }, "Content appended to file");
|
|
1344
|
+
return c.json({ status: "appended" });
|
|
1345
|
+
}
|
|
1346
|
+
// ── Section-based modes: require section lookup ──
|
|
1347
|
+
const sectionBounds = findSection(fileContent, section);
|
|
1348
|
+
if (!sectionBounds) {
|
|
1349
|
+
return c.json({
|
|
1350
|
+
error: "section_not_found",
|
|
1351
|
+
section,
|
|
1352
|
+
availableSections: getAvailableSections(fileContent),
|
|
1353
|
+
}, 400);
|
|
1354
|
+
}
|
|
1355
|
+
let updated;
|
|
1356
|
+
const before = fileContent.slice(0, sectionBounds.start);
|
|
1357
|
+
const after = fileContent.slice(sectionBounds.end);
|
|
1358
|
+
const currentBody = fileContent.slice(sectionBounds.start, sectionBounds.end);
|
|
1359
|
+
let removedCount;
|
|
1360
|
+
let trimmedCount;
|
|
1361
|
+
switch (mode) {
|
|
1362
|
+
case "append": {
|
|
1363
|
+
// Ensure a single newline separator without destroying existing content
|
|
1364
|
+
const separator = currentBody.endsWith("\n") ? "" : "\n";
|
|
1365
|
+
let appendedBody = currentBody + separator + (newContent ?? "") + "\n";
|
|
1366
|
+
// maxEntries: trim oldest bullet entries from the top
|
|
1367
|
+
if (maxEntries !== undefined) {
|
|
1368
|
+
const trimResult = trimBulletEntries(appendedBody, maxEntries);
|
|
1369
|
+
appendedBody = trimResult.body;
|
|
1370
|
+
trimmedCount = trimResult.trimmed;
|
|
1371
|
+
}
|
|
1372
|
+
updated = before + appendedBody + after;
|
|
1373
|
+
break;
|
|
1374
|
+
}
|
|
1375
|
+
case "replace":
|
|
1376
|
+
updated = before + (newContent ?? "") + "\n" + after;
|
|
1377
|
+
break;
|
|
1378
|
+
case "clear":
|
|
1379
|
+
updated = before + "\n" + after;
|
|
1380
|
+
break;
|
|
1381
|
+
case "clear_before": {
|
|
1382
|
+
// Schema refinements validate format, but defense-in-depth for
|
|
1383
|
+
// direct API callers that bypass schema validation.
|
|
1384
|
+
if (!cutoff || !/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(cutoff)) {
|
|
1385
|
+
return c.json({
|
|
1386
|
+
error: "cutoff_required",
|
|
1387
|
+
message: "clear_before requires cutoff in 'YYYY-MM-DD HH:MM:SS' format (zero-padded)",
|
|
1388
|
+
}, 400);
|
|
1389
|
+
}
|
|
1390
|
+
const clearResult = clearEntriesBefore(currentBody, cutoff);
|
|
1391
|
+
updated = before + clearResult.remaining + after;
|
|
1392
|
+
removedCount = clearResult.removedCount;
|
|
1393
|
+
break;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
const prepared = prepareContextContentForWrite(target, updated, {
|
|
1397
|
+
timezone: config.timezone || undefined,
|
|
1398
|
+
disableRoadmapValidation: roadmapValidationOff,
|
|
1399
|
+
previousRoadmapContent: fileContent,
|
|
1400
|
+
today: localDateStr(new Date(), config.timezone || undefined),
|
|
1401
|
+
defaultLongTermPlanSource: roadmapDefaultLongTermPlanSource(c),
|
|
1402
|
+
allowLegacyToday: path === "today" && isLegacyTodayContent(fileContent),
|
|
1403
|
+
expectedAgentDay,
|
|
1404
|
+
});
|
|
1405
|
+
if (!prepared.ok) {
|
|
1406
|
+
return c.json({
|
|
1407
|
+
error: "validation_error",
|
|
1408
|
+
message: prepared.message,
|
|
1409
|
+
path: prepared.path,
|
|
1410
|
+
}, prepared.status);
|
|
1411
|
+
}
|
|
1412
|
+
// Force snapshot on replace (bypass debounce) to ensure recovery
|
|
1413
|
+
// from accidental overwrites. Other modes use normal debounce.
|
|
1414
|
+
const forceSnapshot = mode === "replace" || mode === "clear" || mode === "clear_before";
|
|
1415
|
+
saveSnapshot(path, fileContent, "api_patch", forceSnapshot, sessionId);
|
|
1416
|
+
writeFileAtomically(fullPath, prepared.content);
|
|
1417
|
+
writeTracker?.markWriting(fullPath, prepared.content);
|
|
1418
|
+
if (shouldRefreshPromptContext(path, "PATCH")) {
|
|
1419
|
+
notifyPromptContextChanged(deps, path, `context_patch:${path}`, {
|
|
1420
|
+
path,
|
|
1421
|
+
method: "PATCH",
|
|
1422
|
+
mode,
|
|
1423
|
+
section,
|
|
1424
|
+
content: newContent,
|
|
1425
|
+
previousContent: fileContent,
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
if (path.startsWith("routines/custom/")) {
|
|
1429
|
+
deps.onCustomRoutinesChanged?.();
|
|
1430
|
+
}
|
|
1431
|
+
deps.onIndexableContextChange?.(`${path}${target.ext}`);
|
|
1432
|
+
const resultStatus = mode === "append" ? "appended" : mode === "replace" ? "replaced" : "cleared";
|
|
1433
|
+
logger.info({ path, method: "PATCH", section, mode, removedCount, trimmedCount }, "Context section " + resultStatus);
|
|
1434
|
+
return c.json({ status: resultStatus, removedCount, trimmedCount });
|
|
1435
|
+
});
|
|
1436
|
+
});
|
|
1437
|
+
// DELETE /context/* — File delete (currently limited to `routines/custom/*`
|
|
1438
|
+
// via the write-permission whitelist). B-007 §5.8 Q3: the agent retires a
|
|
1439
|
+
// custom routine after the user confirms. The scheduler listens via
|
|
1440
|
+
// `onCustomRoutinesChanged` and unregisters the cron job on reload.
|
|
1441
|
+
app.delete("/context/*", (c) => {
|
|
1442
|
+
const path = normalizeContextPath(c.req.path.replace("/api/context/", ""));
|
|
1443
|
+
const contextDir = getCurrentContextDir();
|
|
1444
|
+
const fullPath = safePath(contextDir, path);
|
|
1445
|
+
if (!fullPath) {
|
|
1446
|
+
return c.json({ error: "invalid_path", path }, 400);
|
|
1447
|
+
}
|
|
1448
|
+
if (!isWriteAllowed(path, "DELETE")) {
|
|
1449
|
+
logger.warn({ path, method: "DELETE" }, "Context delete forbidden");
|
|
1450
|
+
return c.json({ error: "forbidden", path, method: "DELETE" }, 403);
|
|
1451
|
+
}
|
|
1452
|
+
return withWriteLock(() => {
|
|
1453
|
+
if (!existsSync(fullPath)) {
|
|
1454
|
+
return c.json({ error: "not_found", path }, 404);
|
|
1455
|
+
}
|
|
1456
|
+
const existing = readFileSync(fullPath, "utf-8");
|
|
1457
|
+
const snapshotId = saveSnapshot(path, existing, "api_delete", true);
|
|
1458
|
+
unlinkSync(fullPath);
|
|
1459
|
+
if (path.startsWith("routines/custom/")) {
|
|
1460
|
+
deps.onCustomRoutinesChanged?.();
|
|
1461
|
+
}
|
|
1462
|
+
deps.onIndexableContextChange?.(path);
|
|
1463
|
+
logger.info({ path, method: "DELETE", snapshotId: snapshotId ?? undefined }, "Context file deleted");
|
|
1464
|
+
return c.json({ status: "deleted", snapshotId: snapshotId ?? 0 });
|
|
1465
|
+
});
|
|
1466
|
+
});
|
|
1467
|
+
return app;
|
|
1468
|
+
}
|
|
1469
|
+
function validateContextContent(target, content, options) {
|
|
1470
|
+
if (target.base === "today") {
|
|
1471
|
+
const message = validateTodayContent(content, {
|
|
1472
|
+
allowLegacyToday: options?.allowLegacyToday ?? false,
|
|
1473
|
+
expectedAgentDay: options?.expectedAgentDay,
|
|
1474
|
+
});
|
|
1475
|
+
return message ? { message, status: 400 } : null;
|
|
1476
|
+
}
|
|
1477
|
+
if (target.base === "roadmap") {
|
|
1478
|
+
const result = validateRoadmap(content);
|
|
1479
|
+
if (!result.ok && result.error) {
|
|
1480
|
+
return {
|
|
1481
|
+
message: formatRoadmapValidationError(result.error),
|
|
1482
|
+
status: 400,
|
|
1483
|
+
path: result.error.path,
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
return null;
|
|
1487
|
+
}
|
|
1488
|
+
if (target.base.startsWith("routines/custom/")) {
|
|
1489
|
+
const slug = target.base.slice("routines/custom/".length);
|
|
1490
|
+
const result = parseCustomRoutineSpec(slug, content);
|
|
1491
|
+
if (!result.ok) {
|
|
1492
|
+
return {
|
|
1493
|
+
message: explainCustomRoutineValidationError(result.error),
|
|
1494
|
+
status: 400,
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
return null;
|
|
1498
|
+
}
|
|
1499
|
+
if (target.base.startsWith("routines/") && target.base !== "routines/_index") {
|
|
1500
|
+
const message = validateBuiltInRoutineRulebook(target.base, content);
|
|
1501
|
+
return message ? { message, status: 400 } : null;
|
|
1502
|
+
}
|
|
1503
|
+
const relativePath = `${target.base}${target.ext}`;
|
|
1504
|
+
if (!options?.skipFrontmatterValidation) {
|
|
1505
|
+
const frontmatterError = validateContextFileFrontmatter(content, relativePath);
|
|
1506
|
+
if (frontmatterError) {
|
|
1507
|
+
return { message: frontmatterError.message, status: 422 };
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
if (target.ext !== ".base")
|
|
1511
|
+
return null;
|
|
1512
|
+
const message = validateBaseYamlSyntax(content);
|
|
1513
|
+
return message ? { message, status: 400 } : null;
|
|
1514
|
+
}
|
|
1515
|
+
const TODAY_REQUIRED_SECTIONS = [
|
|
1516
|
+
"User Schedule",
|
|
1517
|
+
"User Tasks",
|
|
1518
|
+
"Agent Plan",
|
|
1519
|
+
"Agent Notes",
|
|
1520
|
+
"Agent Log",
|
|
1521
|
+
"Handoff",
|
|
1522
|
+
];
|
|
1523
|
+
const TODAY_H1_RE = /^# \d{4}-\d{2}-\d{2}(?: \([^)]+\))?$/;
|
|
1524
|
+
const TODAY_DAY_TYPE_RE = /^> Day type: (Weekday|Weekend) \| Work focus: (on|off) \| Study focus: (on|off) \| Personal focus: (on|off)$/;
|
|
1525
|
+
function isLegacyTodayContent(content) {
|
|
1526
|
+
const lines = content.split(/\r?\n/);
|
|
1527
|
+
return (lines[0] ?? "").trim() === "# Today";
|
|
1528
|
+
}
|
|
1529
|
+
function validateTodayContent(content, options = {}) {
|
|
1530
|
+
if (options.allowLegacyToday && isLegacyTodayContent(content))
|
|
1531
|
+
return null;
|
|
1532
|
+
const lines = content.split(/\r?\n/);
|
|
1533
|
+
const firstLine = (lines[0] ?? "").trim();
|
|
1534
|
+
if (!TODAY_H1_RE.test(firstLine)) {
|
|
1535
|
+
return "today.md line 1 must be `# YYYY-MM-DD (day-of-week)`.";
|
|
1536
|
+
}
|
|
1537
|
+
if (!TODAY_DAY_TYPE_RE.test((lines[1] ?? "").trim())) {
|
|
1538
|
+
return "today.md line 2 must be `> Day type: Weekday|Weekend | Work focus: on|off | Study focus: on|off | Personal focus: on|off`.";
|
|
1539
|
+
}
|
|
1540
|
+
// Agent-day-date check — rejects wrong-date H1 with a clear error echoing
|
|
1541
|
+
// both values. Without this, a wrong-date PUT silently succeeds (regex
|
|
1542
|
+
// passes) and the dispatcher's post-run hasCurrentAgentDayTodayMd() check
|
|
1543
|
+
// schedules a retry while the same session still has the prompt context
|
|
1544
|
+
// loaded, wasting a heavy-tier turn cycle. With this guard the agent gets
|
|
1545
|
+
// immediate feedback and corrects in-session.
|
|
1546
|
+
if (options.expectedAgentDay) {
|
|
1547
|
+
// TODAY_H1_RE already matched, so the YYYY-MM-DD capture is guaranteed.
|
|
1548
|
+
// No optional-chain — the regex precondition guarantees `[1]` is set.
|
|
1549
|
+
const writtenDate = firstLine.match(/^# (\d{4}-\d{2}-\d{2})/)[1];
|
|
1550
|
+
if (writtenDate !== options.expectedAgentDay) {
|
|
1551
|
+
return (`today.md line 1 date '${writtenDate}' does not match the current ` +
|
|
1552
|
+
`agent-day date '${options.expectedAgentDay}'. ` +
|
|
1553
|
+
`Use the date from <current_agent_day date="..."> in your prompt context — ` +
|
|
1554
|
+
`the agent-day differs from calendar today before the day-boundary hour.`);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
let previousSectionIndex = 1;
|
|
1558
|
+
for (const section of TODAY_REQUIRED_SECTIONS) {
|
|
1559
|
+
const index = lines.findIndex((line, lineIndex) => lineIndex > previousSectionIndex && line.trim() === `## ${section}`);
|
|
1560
|
+
if (index < 0) {
|
|
1561
|
+
return `today.md requires \`## ${section}\` in canonical order.`;
|
|
1562
|
+
}
|
|
1563
|
+
previousSectionIndex = index;
|
|
1564
|
+
}
|
|
1565
|
+
const parsed = extractTodayAgentPlanRows(content);
|
|
1566
|
+
if (parsed.invalidRows.length > 0) {
|
|
1567
|
+
const first = parsed.invalidRows[0];
|
|
1568
|
+
return (`today.md Agent Plan line ${first.line} must match ` +
|
|
1569
|
+
`\`- [ ] HH:MM <action> [work|study|personal|home] →DM|→notify|→check-in|→wake\`. ` +
|
|
1570
|
+
`Got: ${JSON.stringify(first.raw)}`);
|
|
1571
|
+
}
|
|
1572
|
+
return null;
|
|
1573
|
+
}
|
|
1574
|
+
function toTodayScheduleCandidate(row, timezone) {
|
|
1575
|
+
const scheduledAt = parseScheduleDate(row.scheduled_for);
|
|
1576
|
+
if (Number.isNaN(scheduledAt.getTime()))
|
|
1577
|
+
return null;
|
|
1578
|
+
const local = nowInTimezone(timezone, scheduledAt);
|
|
1579
|
+
const localDate = `${local.year}-${String(local.month).padStart(2, "0")}-${String(local.day).padStart(2, "0")}`;
|
|
1580
|
+
const localTime = `${String(local.hours).padStart(2, "0")}:${String(local.minutes).padStart(2, "0")}`;
|
|
1581
|
+
return {
|
|
1582
|
+
id: row.id,
|
|
1583
|
+
scheduledFor: row.scheduled_for,
|
|
1584
|
+
localDate,
|
|
1585
|
+
localTime,
|
|
1586
|
+
taskType: row.task_type,
|
|
1587
|
+
status: row.status,
|
|
1588
|
+
description: row.task_description,
|
|
1589
|
+
taskContext: parseJsonObject(row.task_context),
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
function parseScheduleDate(value) {
|
|
1593
|
+
return new Date(value.includes("T") ? value : value.replace(" ", "T") + "Z");
|
|
1594
|
+
}
|
|
1595
|
+
function parseJsonObject(raw) {
|
|
1596
|
+
if (!raw)
|
|
1597
|
+
return {};
|
|
1598
|
+
try {
|
|
1599
|
+
const parsed = JSON.parse(raw);
|
|
1600
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1601
|
+
return parsed;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
catch {
|
|
1605
|
+
// Ignore corrupt metadata for reconciliation diagnostics.
|
|
1606
|
+
}
|
|
1607
|
+
return {};
|
|
1608
|
+
}
|
|
1609
|
+
function prepareContextContentForWrite(target, content, options) {
|
|
1610
|
+
if (target.base !== "roadmap") {
|
|
1611
|
+
const contentError = validateContextContent(target, content, {
|
|
1612
|
+
allowLegacyToday: options?.allowLegacyToday,
|
|
1613
|
+
expectedAgentDay: options?.expectedAgentDay,
|
|
1614
|
+
});
|
|
1615
|
+
if (contentError) {
|
|
1616
|
+
return {
|
|
1617
|
+
ok: false,
|
|
1618
|
+
message: contentError.message,
|
|
1619
|
+
status: contentError.status,
|
|
1620
|
+
path: contentError.path,
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
return { ok: true, content };
|
|
1624
|
+
}
|
|
1625
|
+
if (options?.disableRoadmapValidation) {
|
|
1626
|
+
return { ok: true, content };
|
|
1627
|
+
}
|
|
1628
|
+
const normalized = normalizeRoadmapForWrite(content, {
|
|
1629
|
+
timezone: options?.timezone,
|
|
1630
|
+
defaultLongTermPlanSource: options?.defaultLongTermPlanSource ?? "manual",
|
|
1631
|
+
});
|
|
1632
|
+
const result = validateRoadmap(normalized.content);
|
|
1633
|
+
if (!result.ok && result.error) {
|
|
1634
|
+
return {
|
|
1635
|
+
ok: false,
|
|
1636
|
+
message: formatRoadmapValidationError(result.error),
|
|
1637
|
+
status: 400,
|
|
1638
|
+
path: result.error.path,
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
if (options?.previousRoadmapContent !== undefined) {
|
|
1642
|
+
const transition = validateRoadmapTransition(options.previousRoadmapContent, normalized.content, {
|
|
1643
|
+
today: options.today,
|
|
1644
|
+
timezone: options.timezone,
|
|
1645
|
+
});
|
|
1646
|
+
if (!transition.ok && transition.error) {
|
|
1647
|
+
return {
|
|
1648
|
+
ok: false,
|
|
1649
|
+
message: formatRoadmapValidationError(transition.error),
|
|
1650
|
+
status: 400,
|
|
1651
|
+
path: transition.error.path,
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
return { ok: true, content: normalized.content };
|
|
1656
|
+
}
|
|
1657
|
+
function formatRoadmapValidationError(error) {
|
|
1658
|
+
const line = error.line ? `line ${error.line}: ` : "";
|
|
1659
|
+
return `${line}${error.message}`;
|
|
1660
|
+
}
|
|
1661
|
+
function validateBuiltInRoutineRulebook(path, content) {
|
|
1662
|
+
const frontmatter = extractRoutineFrontmatter(content);
|
|
1663
|
+
if (frontmatter === null) {
|
|
1664
|
+
return "Routine rulebooks require YAML frontmatter.";
|
|
1665
|
+
}
|
|
1666
|
+
const expectedSlug = path.slice("routines/".length);
|
|
1667
|
+
const typeRaw = readRoutineFrontmatterScalar(frontmatter, "type");
|
|
1668
|
+
if (!typeRaw) {
|
|
1669
|
+
return "Routine rulebooks require `type: rule` in frontmatter.";
|
|
1670
|
+
}
|
|
1671
|
+
if (typeRaw !== "rule") {
|
|
1672
|
+
return "Routine rulebooks must declare `type: rule`.";
|
|
1673
|
+
}
|
|
1674
|
+
const slugRaw = readRoutineFrontmatterScalar(frontmatter, "slug");
|
|
1675
|
+
if (!slugRaw) {
|
|
1676
|
+
return "Routine rulebooks require a `slug` frontmatter field.";
|
|
1677
|
+
}
|
|
1678
|
+
if (slugRaw !== expectedSlug) {
|
|
1679
|
+
return `Routine rulebook slug must match the filename (${expectedSlug}).`;
|
|
1680
|
+
}
|
|
1681
|
+
if (!/^##\s+Checks\s*$/m.test(content)) {
|
|
1682
|
+
return "Routine rulebooks require a `## Checks` section.";
|
|
1683
|
+
}
|
|
1684
|
+
return null;
|
|
1685
|
+
}
|
|
1686
|
+
function explainCustomRoutineValidationError(error) {
|
|
1687
|
+
switch (error.kind) {
|
|
1688
|
+
case "missing_field":
|
|
1689
|
+
return `Custom routine files require \`${error.field}\` in frontmatter.`;
|
|
1690
|
+
case "invalid_cron":
|
|
1691
|
+
return `Invalid cron expression: \`${error.value}\`.`;
|
|
1692
|
+
case "invalid_slug":
|
|
1693
|
+
return `Custom routine slug is invalid or does not match the filename: \`${error.value}\`.`;
|
|
1694
|
+
case "invalid_type":
|
|
1695
|
+
return `Custom routines must declare \`type: rule\`, got \`${error.value}\`.`;
|
|
1696
|
+
case "invalid_process_key":
|
|
1697
|
+
return `Custom routine \`process_key\` must match the filename-derived key, got \`${error.value}\`.`;
|
|
1698
|
+
case "invalid_enabled":
|
|
1699
|
+
return `Custom routine \`enabled\` must be \`true\` or \`false\`, got \`${error.value}\`.`;
|
|
1700
|
+
case "invalid_tier":
|
|
1701
|
+
return `Custom routine \`backend_tier\` must be \`light\` or \`heavy\`, got \`${error.value}\`.`;
|
|
1702
|
+
case "invalid_budget":
|
|
1703
|
+
return `Custom routine \`max_budget_usd\` must be a positive number, got \`${error.value}\`.`;
|
|
1704
|
+
case "missing_checks_section":
|
|
1705
|
+
return "Custom routines require a `## Checks` section.";
|
|
1706
|
+
case "no_frontmatter":
|
|
1707
|
+
return "Custom routines require YAML frontmatter.";
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
function extractRoutineFrontmatter(content) {
|
|
1711
|
+
if (!content.startsWith("---\n") && !content.startsWith("---\r\n")) {
|
|
1712
|
+
return null;
|
|
1713
|
+
}
|
|
1714
|
+
const afterOpen = content.startsWith("---\r\n") ? 5 : 4;
|
|
1715
|
+
const endIdx = content.indexOf("\n---", afterOpen - 1);
|
|
1716
|
+
if (endIdx < 0)
|
|
1717
|
+
return null;
|
|
1718
|
+
return content.slice(afterOpen, endIdx);
|
|
1719
|
+
}
|
|
1720
|
+
function readRoutineFrontmatterScalar(frontmatter, field) {
|
|
1721
|
+
const re = new RegExp(`^${field}\\s*:\\s*(.+?)\\s*$`, "m");
|
|
1722
|
+
const match = frontmatter.match(re);
|
|
1723
|
+
if (!match)
|
|
1724
|
+
return null;
|
|
1725
|
+
let value = match[1].trim();
|
|
1726
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
1727
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
1728
|
+
value = value.slice(1, -1);
|
|
1729
|
+
}
|
|
1730
|
+
return value;
|
|
1731
|
+
}
|
|
1732
|
+
function validateBaseYamlSyntax(content) {
|
|
1733
|
+
if (content.trim().length === 0) {
|
|
1734
|
+
return ".base files must not be empty.";
|
|
1735
|
+
}
|
|
1736
|
+
const lines = content.split("\n");
|
|
1737
|
+
let sawMeaningfulLine = false;
|
|
1738
|
+
for (let index = 0; index < lines.length; index++) {
|
|
1739
|
+
const raw = lines[index];
|
|
1740
|
+
const lineNo = index + 1;
|
|
1741
|
+
if (raw.includes("\t")) {
|
|
1742
|
+
return `.base YAML may not contain tab indentation (line ${lineNo}).`;
|
|
1743
|
+
}
|
|
1744
|
+
const trimmed = raw.trim();
|
|
1745
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
1746
|
+
continue;
|
|
1747
|
+
sawMeaningfulLine = true;
|
|
1748
|
+
const indent = raw.length - raw.trimStart().length;
|
|
1749
|
+
if (indent % 2 !== 0) {
|
|
1750
|
+
return `.base YAML uses 2-space indentation (line ${lineNo}).`;
|
|
1751
|
+
}
|
|
1752
|
+
const isListItem = /^-\s+\S/.test(trimmed);
|
|
1753
|
+
const isMapping = /^[^:#][^:]*:\s*(?:.*)?$/.test(trimmed);
|
|
1754
|
+
if (!isListItem && !isMapping) {
|
|
1755
|
+
return `Invalid .base YAML structure on line ${lineNo}.`;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
if (!sawMeaningfulLine) {
|
|
1759
|
+
return ".base files must contain at least one mapping entry.";
|
|
1760
|
+
}
|
|
1761
|
+
return null;
|
|
1762
|
+
}
|
|
1763
|
+
// Export for testing
|
|
1764
|
+
export { normalizeSection, findSection, isWriteAllowed, safePath, resolveContextTarget, validateBaseYamlSyntax, validateTodayContent, clearEntriesBefore, trimBulletEntries, parseEntryTimestamp, };
|
|
1765
|
+
//# sourceMappingURL=context.js.map
|