@aitne/daemon 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/adapter-watchdog.d.ts +70 -0
- package/dist/adapters/adapter-watchdog.js +115 -0
- package/dist/adapters/discord.d.ts +17 -1
- package/dist/adapters/discord.js +33 -0
- package/dist/adapters/notification-manager.d.ts +27 -1
- package/dist/adapters/notification-manager.js +54 -39
- package/dist/adapters/slack-adapter.d.ts +26 -1
- package/dist/adapters/slack-adapter.js +41 -0
- package/dist/adapters/telegram-adapter.d.ts +18 -1
- package/dist/adapters/telegram-adapter.js +41 -2
- package/dist/adapters/types.d.ts +20 -0
- package/dist/adapters/whatsapp-adapter.d.ts +26 -7
- package/dist/adapters/whatsapp-adapter.js +74 -21
- package/dist/api/env-writer.js +8 -5
- package/dist/api/helpers/agent-errors-registry.d.ts +5 -5
- package/dist/api/helpers/agent-errors-registry.js +5 -5
- package/dist/api/routes/agent.js +33 -12
- package/dist/api/routes/agents/index.js +75 -16
- package/dist/api/routes/agents/views.d.ts +37 -2
- package/dist/api/routes/agents/views.js +64 -2
- package/dist/api/routes/background-task.d.ts +22 -0
- package/dist/api/routes/background-task.js +338 -0
- package/dist/api/routes/browser-history.js +9 -1
- package/dist/api/routes/context/permissions.js +3 -2
- package/dist/api/routes/context/snapshots.js +0 -3
- package/dist/api/routes/context/write.js +3 -17
- package/dist/api/routes/dashboard/config.js +48 -12
- package/dist/api/routes/dashboard/cost-approvals.js +66 -0
- package/dist/api/routes/dashboard/notifications.js +9 -9
- package/dist/api/routes/integrations/crud-patch.js +5 -1
- package/dist/api/routes/integrations-reconcile.js +2 -2
- package/dist/api/routes/notion.d.ts +1 -1
- package/dist/api/routes/observations.js +7 -7
- package/dist/api/routes/obsidian.d.ts +1 -1
- package/dist/api/routes/receipts.js +5 -1
- package/dist/api/routes/setup-migrate.js +1 -1
- package/dist/api/routes/setup.js +1 -1
- package/dist/api/routes/task-flows.d.ts +1 -1
- package/dist/api/routes/task-flows.js +1 -1
- package/dist/api/routes/tuning.d.ts +29 -0
- package/dist/api/routes/tuning.js +304 -0
- package/dist/api/server.d.ts +44 -16
- package/dist/api/server.js +9 -0
- package/dist/bootstrap/adapters.d.ts +19 -0
- package/dist/bootstrap/adapters.js +61 -0
- package/dist/bootstrap/api.d.ts +5 -3
- package/dist/bootstrap/api.js +45 -13
- package/dist/bootstrap/catchup.d.ts +1 -1
- package/dist/bootstrap/catchup.js +11 -11
- package/dist/bootstrap/event-pipeline.d.ts +11 -0
- package/dist/bootstrap/event-pipeline.js +245 -7
- package/dist/bootstrap/observers.js +9 -6
- package/dist/bootstrap/schedule-helpers.d.ts +104 -6
- package/dist/bootstrap/schedule-helpers.js +172 -19
- package/dist/config.js +26 -12
- package/dist/core/agent-core.d.ts +33 -1
- package/dist/core/agent-core.js +36 -1
- package/dist/core/agents/activity-scan-cadence.d.ts +103 -0
- package/dist/core/agents/activity-scan-cadence.js +127 -0
- package/dist/core/agents/agent-route-override.d.ts +53 -0
- package/dist/core/agents/agent-route-override.js +69 -0
- package/dist/core/agents/builtin-registry.d.ts +51 -14
- package/dist/core/agents/builtin-registry.js +92 -15
- package/dist/core/agents/config-gate-reconcile.d.ts +38 -0
- package/dist/core/agents/config-gate-reconcile.js +51 -0
- package/dist/core/agents/cron-substitute.d.ts +1 -1
- package/dist/core/agents/cron-substitute.js +1 -1
- package/dist/core/agents/custom-routine-migration.d.ts +60 -0
- package/dist/core/agents/custom-routine-migration.js +149 -0
- package/dist/core/agents/firing-blocked.d.ts +1 -1
- package/dist/core/agents/hourly-cadence.d.ts +102 -0
- package/dist/core/agents/hourly-cadence.js +126 -0
- package/dist/core/agents/loader-boot.js +23 -0
- package/dist/core/agents/loader.d.ts +19 -0
- package/dist/core/agents/loader.js +34 -2
- package/dist/core/agents/override-merge.d.ts +1 -1
- package/dist/core/agents/override-merge.js +9 -1
- package/dist/core/agents/recurrence-convert.d.ts +1 -1
- package/dist/core/agents/recurrence-convert.js +1 -1
- package/dist/core/agents/recurring-schedule-adapter.js +8 -0
- package/dist/core/alerts.js +6 -6
- package/dist/core/backends/auth-health-monitor.d.ts +2 -2
- package/dist/core/backends/auth-health-monitor.js +1 -1
- package/dist/core/backends/backend-router.d.ts +27 -1
- package/dist/core/backends/backend-router.js +165 -1
- package/dist/core/backends/claude-code-core.d.ts +71 -31
- package/dist/core/backends/claude-code-core.js +282 -54
- package/dist/core/backends/cli-quota-guards.d.ts +29 -1
- package/dist/core/backends/cli-quota-guards.js +40 -5
- package/dist/core/backends/codex-core.d.ts +6 -0
- package/dist/core/backends/codex-core.js +22 -6
- package/dist/core/backends/failure-spend.d.ts +58 -0
- package/dist/core/backends/failure-spend.js +137 -0
- package/dist/core/backends/gemini-cli-core.d.ts +6 -0
- package/dist/core/backends/gemini-cli-core.js +25 -6
- package/dist/core/backends/model-registry.d.ts +1 -1
- package/dist/core/backends/model-registry.js +4 -4
- package/dist/core/backends/opencode-core.d.ts +1 -1
- package/dist/core/backends/opencode-core.js +5 -5
- package/dist/core/backends/plan-presets.js +39 -15
- package/dist/core/bang-commands/commands-cost.js +3 -1
- package/dist/core/bang-commands/commands-report.js +4 -3
- package/dist/core/bang-commands/commands-research.js +4 -1
- package/dist/core/bang-commands/commands-revert-tuning.d.ts +18 -0
- package/dist/core/bang-commands/commands-revert-tuning.js +63 -0
- package/dist/core/bang-commands/commands-stop-start.js +3 -3
- package/dist/core/bang-commands/commands-task-control.d.ts +19 -0
- package/dist/core/bang-commands/commands-task-control.js +147 -0
- package/dist/core/bang-commands/commands-wiki.js +5 -5
- package/dist/core/bang-commands/index.d.ts +2 -0
- package/dist/core/bang-commands/index.js +12 -0
- package/dist/core/bang-commands/registry.d.ts +12 -0
- package/dist/core/browser-history/research-cluster-fanout.d.ts +28 -14
- package/dist/core/browser-history/research-cluster-fanout.js +39 -16
- package/dist/core/channel-timeline.d.ts +5 -1
- package/dist/core/channel-timeline.js +13 -0
- package/dist/core/context/index-reconciler.js +5 -2
- package/dist/core/context/policy-index-reconciler.d.ts +6 -4
- package/dist/core/context/policy-index-runner.js +25 -6
- package/dist/core/context-builder-calendar.js +10 -2
- package/dist/core/context-builder-conversation.d.ts +8 -1
- package/dist/core/context-builder-conversation.js +41 -7
- package/dist/core/context-builder-yesterday.js +4 -3
- package/dist/core/context-builder.d.ts +7 -2
- package/dist/core/context-builder.js +62 -20
- package/dist/core/context-file-serializer.d.ts +1 -1
- package/dist/core/context-file-serializer.js +1 -1
- package/dist/core/context-health.js +2 -2
- package/dist/core/context-paths.d.ts +1 -1
- package/dist/core/context-paths.js +1 -1
- package/dist/core/context-validation/prepare-write.js +1 -1
- package/dist/core/context-validation/routine-rulebook.d.ts +1 -1
- package/dist/core/context-vault-aliases.d.ts +0 -13
- package/dist/core/context-vault-aliases.js +37 -0
- package/dist/core/custom-routines.d.ts +99 -0
- package/dist/core/custom-routines.js +187 -0
- package/dist/core/daemon-api-cli.js +49 -0
- package/dist/core/day-boundary.d.ts +46 -0
- package/dist/core/day-boundary.js +40 -0
- package/dist/core/dispatcher-activity-scan.d.ts +221 -0
- package/dist/core/dispatcher-activity-scan.js +775 -0
- package/dist/core/dispatcher-error-handling.d.ts +6 -11
- package/dist/core/dispatcher-error-handling.js +38 -62
- package/dist/core/dispatcher-hourly-check.js +6 -1
- package/dist/core/dispatcher-message-handler.d.ts +10 -0
- package/dist/core/dispatcher-message-handler.js +17 -0
- package/dist/core/dispatcher-morning-routine.d.ts +6 -6
- package/dist/core/dispatcher-morning-routine.js +13 -13
- package/dist/core/dispatcher-result-processor.d.ts +33 -0
- package/dist/core/dispatcher-result-processor.js +167 -11
- package/dist/core/dispatcher-scheduled-background-task.d.ts +42 -0
- package/dist/core/dispatcher-scheduled-background-task.js +89 -0
- package/dist/core/dispatcher-scheduled-tasks.d.ts +63 -1
- package/dist/core/dispatcher-scheduled-tasks.js +213 -6
- package/dist/core/dispatcher-task-delivery.d.ts +105 -0
- package/dist/core/dispatcher-task-delivery.js +555 -0
- package/dist/core/dispatcher-types.d.ts +48 -9
- package/dist/core/dispatcher-types.js +3 -3
- package/dist/core/dispatcher.d.ts +112 -31
- package/dist/core/dispatcher.js +284 -59
- package/dist/core/dm-freshness-metrics.d.ts +1 -1
- package/dist/core/drift-effects.js +2 -2
- package/dist/core/feedback/consolidation-prep.js +17 -5
- package/dist/core/feedback/eviction-scorer.js +6 -2
- package/dist/core/feedback/lesson-format.js +9 -4
- package/dist/core/feedback/lesson-injection.d.ts +1 -1
- package/dist/core/feedback/lesson-injection.js +17 -2
- package/dist/core/feedback/lesson-store-overview.d.ts +8 -4
- package/dist/core/feedback/lesson-store-overview.js +8 -4
- package/dist/core/feedback/regeneralization-prep.js +29 -16
- package/dist/core/feedback/self-performance-prep.d.ts +186 -0
- package/dist/core/feedback/self-performance-prep.js +541 -0
- package/dist/core/feedback/tuning-actuator.d.ts +198 -0
- package/dist/core/feedback/tuning-actuator.js +432 -0
- package/dist/core/feedback/tuning-recommender.d.ts +247 -0
- package/dist/core/feedback/tuning-recommender.js +580 -0
- package/dist/core/feedback/tuning-revert-monitor.d.ts +90 -0
- package/dist/core/feedback/tuning-revert-monitor.js +213 -0
- package/dist/core/health-monitor.d.ts +6 -0
- package/dist/core/health-monitor.js +1 -1
- package/dist/core/injection-policy.d.ts +4 -4
- package/dist/core/injection-policy.js +4 -4
- package/dist/core/integration-main-backend.js +4 -0
- package/dist/core/management-md.d.ts +2 -2
- package/dist/core/management-md.js +51 -13
- package/dist/core/morning/orchestrator.d.ts +2 -2
- package/dist/core/morning/orchestrator.js +2 -2
- package/dist/core/notification-gate.d.ts +64 -0
- package/dist/core/notification-gate.js +51 -0
- package/dist/core/notification-rate-limit.d.ts +40 -0
- package/dist/core/notification-rate-limit.js +50 -0
- package/dist/core/policy-files.d.ts +1 -1
- package/dist/core/policy-files.js +2 -2
- package/dist/core/pre-pass-freshness.d.ts +4 -4
- package/dist/core/retention.d.ts +5 -0
- package/dist/core/retention.js +20 -4
- package/dist/core/review-context.d.ts +1 -1
- package/dist/core/review-context.js +10 -5
- package/dist/core/roadmap-write-lock.d.ts +2 -1
- package/dist/core/roadmap-write-lock.js +15 -10
- package/dist/core/routine-acquisition-plan.d.ts +47 -1
- package/dist/core/routine-acquisition-plan.js +78 -20
- package/dist/core/routine-fetch-window-retry.js +7 -4
- package/dist/core/routine-fetch-window-runner.d.ts +39 -3
- package/dist/core/routine-fetch-window-runner.js +264 -13
- package/dist/core/routine-windows.d.ts +2 -2
- package/dist/core/routine-windows.js +8 -5
- package/dist/core/scheduler.d.ts +175 -16
- package/dist/core/scheduler.js +559 -102
- package/dist/core/signal-detector.d.ts +12 -0
- package/dist/core/signal-detector.js +53 -9
- package/dist/core/skills-compiler-denied-tools.js +2 -2
- package/dist/core/skills-compiler-skill-index.d.ts +2 -2
- package/dist/core/skills-compiler-skill-index.js +2 -2
- package/dist/core/skills-compiler-variants.d.ts +1 -1
- package/dist/core/skills-compiler-variants.js +8 -0
- package/dist/core/skills-compiler.d.ts +29 -26
- package/dist/core/skills-compiler.js +117 -81
- package/dist/core/skills-manifest.d.ts +37 -0
- package/dist/core/skills-manifest.js +73 -2
- package/dist/core/sleep-inhibitor.d.ts +79 -0
- package/dist/core/sleep-inhibitor.js +132 -0
- package/dist/core/slim-system-prompt-loader.d.ts +77 -0
- package/dist/core/slim-system-prompt-loader.js +141 -0
- package/dist/core/spawn-gates.d.ts +126 -0
- package/dist/core/spawn-gates.js +180 -0
- package/dist/core/today-direct-writer.d.ts +2 -2
- package/dist/core/today-direct-writer.js +1 -1
- package/dist/core/today-write-lock.d.ts +4 -2
- package/dist/core/today-write-lock.js +30 -20
- package/dist/core/wake-detector.d.ts +55 -0
- package/dist/core/wake-detector.js +80 -0
- package/dist/core/wiki/compile-lock.d.ts +1 -1
- package/dist/core/wiki/compile-lock.js +1 -1
- package/dist/core/workdir.js +15 -6
- package/dist/db/activity-scan-signals.d.ts +77 -0
- package/dist/db/activity-scan-signals.js +378 -0
- package/dist/db/agents-store.d.ts +28 -0
- package/dist/db/agents-store.js +62 -0
- package/dist/db/background-task-clarifications-store.d.ts +81 -0
- package/dist/db/background-task-clarifications-store.js +152 -0
- package/dist/db/background-task-store.d.ts +207 -0
- package/dist/db/background-task-store.js +380 -0
- package/dist/db/browser-history-store.d.ts +39 -6
- package/dist/db/browser-history-store.js +51 -7
- package/dist/db/browser-task-clarifications-store.d.ts +12 -0
- package/dist/db/browser-task-clarifications-store.js +35 -5
- package/dist/db/browser-task-store.d.ts +3 -0
- package/dist/db/browser-task-store.js +29 -4
- package/dist/db/deferred-dm.d.ts +86 -0
- package/dist/db/deferred-dm.js +199 -0
- package/dist/db/migrations.js +330 -0
- package/dist/db/observations.d.ts +2 -2
- package/dist/db/observations.js +3 -3
- package/dist/db/schema.js +217 -16
- package/dist/db/voice-transcripts-store.d.ts +1 -1
- package/dist/index.js +86 -29
- package/dist/messaging/browser-task-mcp-notifier.d.ts +12 -70
- package/dist/messaging/browser-task-mcp-notifier.js +30 -151
- package/dist/messaging/browser-task-screenshot-attachment.d.ts +15 -0
- package/dist/messaging/browser-task-screenshot-attachment.js +63 -0
- package/dist/observers/delegated-sync-worker.d.ts +6 -6
- package/dist/observers/delegated-sync-worker.js +10 -10
- package/dist/observers/git-delegated-cron.d.ts +1 -1
- package/dist/observers/git-delegated-cron.js +2 -2
- package/dist/observers/github-poller-classifier.d.ts +3 -3
- package/dist/observers/github-poller-classifier.js +3 -3
- package/dist/observers/imminent-event-scheduler.d.ts +1 -1
- package/dist/observers/imminent-event-scheduler.js +1 -1
- package/dist/observers/mail-poller.d.ts +1 -0
- package/dist/observers/mail-poller.js +42 -3
- package/dist/observers/observation-summarizer/summarizer-client.d.ts +2 -2
- package/dist/observers/observation-summarizer/summarizer-client.js +2 -2
- package/dist/observers/observation-summarizer/worker.d.ts +2 -2
- package/dist/observers/observation-summarizer/worker.js +4 -4
- package/dist/observers/obsidian-watcher.d.ts +1 -1
- package/dist/observers/obsidian-watcher.js +1 -1
- package/dist/safety/agent-write-tracker.d.ts +4 -4
- package/dist/safety/agent-write-tracker.js +4 -4
- package/dist/safety/audit.d.ts +43 -5
- package/dist/safety/audit.js +86 -18
- package/dist/safety/risk-classifier.d.ts +6 -0
- package/dist/safety/risk-classifier.js +75 -11
- package/dist/scheduler/activity-scan-gate.d.ts +86 -0
- package/dist/scheduler/activity-scan-gate.js +132 -0
- package/dist/services/background-task/background-task-budget.d.ts +80 -0
- package/dist/services/background-task/background-task-budget.js +91 -0
- package/dist/services/background-task/background-task-driver.d.ts +105 -0
- package/dist/services/background-task/background-task-driver.js +416 -0
- package/dist/services/background-task/background-task-runner.d.ts +96 -0
- package/dist/services/background-task/background-task-runner.js +673 -0
- package/dist/services/background-task/background-task-tools.d.ts +84 -0
- package/dist/services/background-task/background-task-tools.js +247 -0
- package/dist/services/background-task/background-task-transition-events.d.ts +43 -0
- package/dist/services/background-task/background-task-transition-events.js +54 -0
- package/dist/services/browser-history/automation/egress-denylist.d.ts +1 -1
- package/dist/services/browser-history/automation/egress-denylist.js +16 -6
- package/dist/services/browser-history/managed-chromium/sandbox-launcher.js +0 -1
- package/dist/services/browser-task/browser-task-runner.js +53 -8
- package/dist/services/observations-batch.d.ts +1 -1
- package/dist/services/observations-batch.js +2 -2
- package/dist/settings/runtime-settings.d.ts +38 -11
- package/dist/settings/runtime-settings.js +203 -40
- package/dist/settings/settings-store.js +11 -3
- package/package.json +4 -4
|
@@ -89,6 +89,8 @@ import { EventPriority } from "@aitne/shared";
|
|
|
89
89
|
import { createLogger } from "../logging.js";
|
|
90
90
|
import { markContextChanged } from "../core/dashboard-session-controls.js";
|
|
91
91
|
import { EventDispatcher } from "../core/dispatcher.js";
|
|
92
|
+
import { SessionGateRegistry } from "../core/session-gate.js";
|
|
93
|
+
import { enqueueUndeliveredBrowserTaskDeliveries } from "../core/dispatcher-task-delivery.js";
|
|
92
94
|
import { SignalDetector } from "../core/signal-detector.js";
|
|
93
95
|
import { ContextBuilder } from "../core/context-builder.js";
|
|
94
96
|
import { getTaskFlow, initTaskFlows } from "../core/prompts.js";
|
|
@@ -111,6 +113,7 @@ import { AuthRecovery } from "../core/backends/auth-recovery.js";
|
|
|
111
113
|
// Workdir / skills
|
|
112
114
|
import { ensureBackendMaterialized, syncAllUserSkills, buildConfiguredServices, refreshDmSessionWorkdirs, validateDelegatedStartup, } from "../core/workdir.js";
|
|
113
115
|
import { validateBuiltinSkillSourceTree } from "../core/skills-compiler-variants.js";
|
|
116
|
+
import { eventTypeAcceptsUserSkills } from "../core/skills-manifest.js";
|
|
114
117
|
// Audit / safety / messaging
|
|
115
118
|
import { AuditLogger } from "../safety/audit.js";
|
|
116
119
|
import { AgentExecutionRecorder } from "../core/agent-execution-recorder.js";
|
|
@@ -182,7 +185,29 @@ export async function createEventPipeline(deps) {
|
|
|
182
185
|
// row whose flush timer didn't fire (process killed) would otherwise
|
|
183
186
|
// linger forever and confuse the dashboard's notification feed.
|
|
184
187
|
NotificationManager.closeStaleBatchedRows(db);
|
|
185
|
-
|
|
188
|
+
// BACKGROUND_TASK_RUNNER_DESIGN.md §2.3 / §13 Decision 4 (Phase 4, opt-in)
|
|
189
|
+
// — router that hands an ACTIVE-owner proactive forward to the
|
|
190
|
+
// task-delivery gate so the real DM agent weaves it into the live thread.
|
|
191
|
+
// Only invoked by `deliverProactive` when the owner is active AND
|
|
192
|
+
// `autonomousForwardNaturalDelivery` is on (default off). Resolves the
|
|
193
|
+
// owner's default DM channel as the weave target; no channel ⇒ returns
|
|
194
|
+
// false and the verbatim path runs unchanged.
|
|
195
|
+
const { createAutonomousForwardDeliveryEvent: makeAutonomousForwardEvent } = await import("../core/dispatcher-task-delivery.js");
|
|
196
|
+
const { selectDefaultOwnerChannel: resolveOwnerDmChannel } = await import("../messaging/owner-channels.js");
|
|
197
|
+
const { channelRef: ownerChannelRef } = await import("../db/browser-automation-purchase-primary-channels-store.js");
|
|
198
|
+
const notificationManager = new NotificationManager(messageHub, db, config, {
|
|
199
|
+
routeAutonomousForwardNaturally: async ({ content, event }) => {
|
|
200
|
+
const owner = resolveOwnerDmChannel(db);
|
|
201
|
+
if (!owner)
|
|
202
|
+
return false;
|
|
203
|
+
await eventBus.put(makeAutonomousForwardEvent({
|
|
204
|
+
content,
|
|
205
|
+
originatingChannel: ownerChannelRef(owner.platform, owner.channelId),
|
|
206
|
+
correlationId: event.correlationId ?? null,
|
|
207
|
+
}));
|
|
208
|
+
return true;
|
|
209
|
+
},
|
|
210
|
+
});
|
|
186
211
|
const authTelemetry = new AuthTelemetry(db);
|
|
187
212
|
const makeAuthNotifier = (source) => ({
|
|
188
213
|
send: async (message, options) => {
|
|
@@ -222,7 +247,13 @@ export async function createEventPipeline(deps) {
|
|
|
222
247
|
});
|
|
223
248
|
const mailAccounts = services.mail?.listActiveAccounts() ?? [];
|
|
224
249
|
ensureBackendMaterialized(config.workspaceDir, sessionDir, backendId, eventType, processKey, cfgServices, mailAccounts, readIntegrations(db), config.character, wikiWorkspaceName, getContextDir(config, db), db, messageText ?? null);
|
|
225
|
-
|
|
250
|
+
// Narrow-persona keys (wiki.* / routine.research_*) run a tight
|
|
251
|
+
// built-in manifest and never call a user skill — skip the owner's
|
|
252
|
+
// library on the fallback re-materialise too, matching the primary
|
|
253
|
+
// workdir path. See `eventTypeAcceptsUserSkills`.
|
|
254
|
+
if (eventTypeAcceptsUserSkills(processKey ?? eventType)) {
|
|
255
|
+
syncAllUserSkills(sessionDir, resolveUserSkillsRoot(config));
|
|
256
|
+
}
|
|
226
257
|
});
|
|
227
258
|
// docs/design/appendices/skills-unification.md Phase 1 §R5 / item 6 — refuse to boot on a
|
|
228
259
|
// malformed source tree. Throws on slug-pattern violations and
|
|
@@ -319,7 +350,8 @@ export async function createEventPipeline(deps) {
|
|
|
319
350
|
initTaskFlows(config.workspaceDir, config.dataDir);
|
|
320
351
|
// ── Signal detector + dispatcher ──────────────────────────────────────
|
|
321
352
|
const signalDetector = new SignalDetector(config, { db });
|
|
322
|
-
const
|
|
353
|
+
const sessionGates = new SessionGateRegistry();
|
|
354
|
+
const dispatcher = new EventDispatcher(eventBus, agentRouter, contextBuilder, getTaskFlow, notificationManager, sessionManager, messageRecorder, auditLogger, db, config, morningRoutineLock, services, roadmapWriteLock, writeTracker, sessionGates);
|
|
323
355
|
notificationManager.setSignalDetector(signalDetector);
|
|
324
356
|
// Wire the scoped read-token manager into every backend so daemon-API
|
|
325
357
|
// calls from `<sessionDir>` workdirs carry a per-session token, not the
|
|
@@ -453,7 +485,7 @@ export async function createEventPipeline(deps) {
|
|
|
453
485
|
// re-registration when an integration mode flips. When no delegated
|
|
454
486
|
// integration is present, the worker is null and the call is a no-op.
|
|
455
487
|
dispatcher.setDelegatedSyncRefresh(async () => {
|
|
456
|
-
await delegatedSyncWorker?.
|
|
488
|
+
await delegatedSyncWorker?.runDisabledCadencesForActivityScan();
|
|
457
489
|
});
|
|
458
490
|
// ── Delegated probe observer (DELEGATED-MODE-V2 §7.1) ────────────────
|
|
459
491
|
// Hourly re-probe of delegated integrations' connector tools so the
|
|
@@ -502,6 +534,40 @@ export async function createEventPipeline(deps) {
|
|
|
502
534
|
return null;
|
|
503
535
|
}
|
|
504
536
|
};
|
|
537
|
+
// BACKGROUND_TASK_RUNNER_DESIGN.md Phase 1 (delivery assets) — the
|
|
538
|
+
// `task.delivery` idle + active branches attach a task's deliverable
|
|
539
|
+
// files inline: browser-task trace screenshots (resolved by key) and
|
|
540
|
+
// worker-produced output files like PDF / PPTX / PNG (resolved by path).
|
|
541
|
+
// The dispatcher owns delivery but has no messageHub / trace-store
|
|
542
|
+
// access, so we inject this resolver → outbound attachment refs (native
|
|
543
|
+
// file for messaging adapters, ingested store ref for the dashboard).
|
|
544
|
+
// Best-effort — unresolvable assets (retention drop, missing file,
|
|
545
|
+
// unknown type) are dropped; the text draft still sends.
|
|
546
|
+
{
|
|
547
|
+
const { resolveScreenshotAttachment, buildPathAttachment } = await import("../messaging/browser-task-screenshot-attachment.js");
|
|
548
|
+
dispatcher.setTaskDeliveryAssetResolver(async (platform, assets) => {
|
|
549
|
+
const resolved = await Promise.all(assets.map((asset) => {
|
|
550
|
+
if (asset.screenshotKey) {
|
|
551
|
+
return resolveScreenshotAttachment({
|
|
552
|
+
platform,
|
|
553
|
+
key: asset.screenshotKey,
|
|
554
|
+
paDataDir: config.dataDir,
|
|
555
|
+
ingestOutboundImage: ingestBrowserTaskScreenshot,
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
if (asset.path) {
|
|
559
|
+
return buildPathAttachment({
|
|
560
|
+
platform,
|
|
561
|
+
absPath: asset.path,
|
|
562
|
+
filename: asset.filename,
|
|
563
|
+
ingestOutboundImage: ingestBrowserTaskScreenshot,
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
return Promise.resolve(null);
|
|
567
|
+
}));
|
|
568
|
+
return resolved.filter((a) => a !== null);
|
|
569
|
+
});
|
|
570
|
+
}
|
|
505
571
|
// ── Phase B-4 purchase handler ────────────────────────────────────────
|
|
506
572
|
// MANAGED_CHROMIUM_IMPLEMENTATION_PLAN.md §17.3 / §13 step 50.
|
|
507
573
|
//
|
|
@@ -646,9 +712,8 @@ export async function createEventPipeline(deps) {
|
|
|
646
712
|
const { createBrowserTaskMcpNotifier } = await import("../messaging/browser-task-mcp-notifier.js");
|
|
647
713
|
const browserTaskSlotStateRef = createSlotStateRef(config.browserTaskMaxConcurrent);
|
|
648
714
|
const browserTaskMcpNotifier = createBrowserTaskMcpNotifier({
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
ingestOutboundImage: ingestBrowserTaskScreenshot,
|
|
715
|
+
eventBus,
|
|
716
|
+
db,
|
|
652
717
|
});
|
|
653
718
|
const browserTaskHostProfile = createBrowserTaskHostProfile();
|
|
654
719
|
// Hoisted out of the `createBrowserTaskRunner({ notifier: ... })` arg
|
|
@@ -739,6 +804,41 @@ export async function createEventPipeline(deps) {
|
|
|
739
804
|
// a user-scheduled task can silently fail at fire time hours/days
|
|
740
805
|
// after the user issued it.
|
|
741
806
|
dispatcher.setBrowserTaskTerminalNotifier(browserTaskTerminalNotifier);
|
|
807
|
+
// ── Background-task runner (BACKGROUND_TASK_RUNNER_DESIGN.md §4) ───────
|
|
808
|
+
// Generic detached-task worker. Shares the proven slot manager (via a
|
|
809
|
+
// synthetic per-task key so tasks contend only on the global cap) and
|
|
810
|
+
// the gated `task.delivery` boundary. The worker is a plain SDK session
|
|
811
|
+
// (no Playwright). The delivery enqueuer wraps the `task.delivery` event
|
|
812
|
+
// factories + the event bus so the runner stays free of any core import.
|
|
813
|
+
const { createBackgroundTaskRunner, createBackgroundTaskSlotStateRef, } = await import("../services/background-task/background-task-runner.js");
|
|
814
|
+
const { createBackgroundTaskTransitionEmitter: createBackgroundTaskTransitionEmitterAtBoot, } = await import("../services/background-task/background-task-transition-events.js");
|
|
815
|
+
const { createBackgroundTaskResultDeliveryEvent, createBackgroundTaskClarificationDeliveryEvent, enqueueUndeliveredBackgroundTaskDeliveries, } = await import("../core/dispatcher-task-delivery.js");
|
|
816
|
+
const backgroundTaskSlotStateRef = createBackgroundTaskSlotStateRef(config.backgroundTaskMaxConcurrent);
|
|
817
|
+
const backgroundTaskTransitionEmitter = createBackgroundTaskTransitionEmitterAtBoot(eventBroadcaster);
|
|
818
|
+
const backgroundTaskDeliveryEnqueuer = {
|
|
819
|
+
async enqueueResult(input) {
|
|
820
|
+
await eventBus.put(createBackgroundTaskResultDeliveryEvent(input));
|
|
821
|
+
},
|
|
822
|
+
async enqueueClarification(input) {
|
|
823
|
+
await eventBus.put(createBackgroundTaskClarificationDeliveryEvent(input));
|
|
824
|
+
},
|
|
825
|
+
};
|
|
826
|
+
const backgroundTaskRunner = createBackgroundTaskRunner({
|
|
827
|
+
db,
|
|
828
|
+
slotStateRef: backgroundTaskSlotStateRef,
|
|
829
|
+
transitionEmitter: backgroundTaskTransitionEmitter,
|
|
830
|
+
deliveryEnqueuer: backgroundTaskDeliveryEnqueuer,
|
|
831
|
+
resumeAcrossRestart: config.backgroundTaskResumeAcrossRestart,
|
|
832
|
+
driver: {
|
|
833
|
+
db,
|
|
834
|
+
paDataDir: config.dataDir,
|
|
835
|
+
workspaceDir: config.workspaceDir,
|
|
836
|
+
contextDir: getContextDir(config),
|
|
837
|
+
clarificationTtlMs: config.backgroundTaskClarificationTtlMinutes * 60_000,
|
|
838
|
+
transitionEmitter: backgroundTaskTransitionEmitter,
|
|
839
|
+
},
|
|
840
|
+
});
|
|
841
|
+
dispatcher.setBackgroundTaskRunner(backgroundTaskRunner);
|
|
742
842
|
// ── Browser-task deadline scanner tick ────────────────────────────────
|
|
743
843
|
// BROWSER_TASK_REDESIGN_PLAN.md §5 ask_user "Deadline enforcement" +
|
|
744
844
|
// §5.1 pending-queue timeout safety valve. Single 30 s tick handles
|
|
@@ -786,6 +886,7 @@ export async function createEventPipeline(deps) {
|
|
|
786
886
|
expiredPending: sweep.expired,
|
|
787
887
|
nowMs: now,
|
|
788
888
|
});
|
|
889
|
+
await sweepDeliveryRecovery(now);
|
|
789
890
|
if (actions.length === 0)
|
|
790
891
|
return;
|
|
791
892
|
for (const action of actions) {
|
|
@@ -859,6 +960,16 @@ export async function createEventPipeline(deps) {
|
|
|
859
960
|
logger.warn({ err }, "browser-task deadline tick failed (continuing)");
|
|
860
961
|
}
|
|
861
962
|
}
|
|
963
|
+
async function sweepDeliveryRecovery(nowMs) {
|
|
964
|
+
const count = await enqueueUndeliveredBrowserTaskDeliveries({
|
|
965
|
+
db,
|
|
966
|
+
eventBus,
|
|
967
|
+
nowMs,
|
|
968
|
+
});
|
|
969
|
+
if (count > 0) {
|
|
970
|
+
logger.debug({ count }, "browser-task delivery recovery enqueued task.delivery events");
|
|
971
|
+
}
|
|
972
|
+
}
|
|
862
973
|
async function sendDeadlineDm(ref, text) {
|
|
863
974
|
if (!ref)
|
|
864
975
|
return;
|
|
@@ -884,8 +995,132 @@ export async function createEventPipeline(deps) {
|
|
|
884
995
|
// a 30 s tick is housekeeping, not load-bearing for liveness.
|
|
885
996
|
if (typeof timer.unref === "function")
|
|
886
997
|
timer.unref();
|
|
998
|
+
void tick();
|
|
887
999
|
return timer;
|
|
888
1000
|
})();
|
|
1001
|
+
// ── Background-task housekeeping tick ──────────────────────────────────
|
|
1002
|
+
// BACKGROUND_TASK_RUNNER_DESIGN.md §6 / §10.2 — one 30 s tick that:
|
|
1003
|
+
// 1. transitions overdue clarifications (resolved=0 AND deadline_at <
|
|
1004
|
+
// now) to `timeout` via the runner (releases the slot + synthesizes
|
|
1005
|
+
// a fail-loud artifact + enqueues delivery);
|
|
1006
|
+
// 2. sweeps pending-queue timeouts (a task that sat behind the
|
|
1007
|
+
// concurrency cap too long);
|
|
1008
|
+
// 3. runs the delivery recovery sweep (re-enqueue `task.delivery` for
|
|
1009
|
+
// completed notify=true artifacts whose DM was lost, + undelivered
|
|
1010
|
+
// open clarifications).
|
|
1011
|
+
// Best-effort + idempotent: per-row failures log and continue; the
|
|
1012
|
+
// runner's `expireForDeadline` is a no-op on already-terminal rows.
|
|
1013
|
+
const backgroundTaskHousekeepingTimer = await (async () => {
|
|
1014
|
+
const { listOverdueClarifications, expireClarification, } = await import("../db/background-task-clarifications-store.js");
|
|
1015
|
+
const { sweepPendingTimeouts } = await import("../services/browser-task/browser-task-slots.js");
|
|
1016
|
+
const TICK_MS = 30_000;
|
|
1017
|
+
async function tick() {
|
|
1018
|
+
try {
|
|
1019
|
+
const nowMs = Date.now();
|
|
1020
|
+
// (1) clarification deadlines
|
|
1021
|
+
for (const clar of listOverdueClarifications(db, nowMs)) {
|
|
1022
|
+
try {
|
|
1023
|
+
expireClarification(db, clar.id, nowMs);
|
|
1024
|
+
await backgroundTaskRunner.expireForDeadline(clar.taskId, "clarification_deadline");
|
|
1025
|
+
}
|
|
1026
|
+
catch (err) {
|
|
1027
|
+
logger.warn({ err, taskId: clar.taskId }, "background-task clarification-deadline action failed (continuing)");
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
// (2) pending-queue timeouts
|
|
1031
|
+
const sweep = sweepPendingTimeouts(backgroundTaskSlotStateRef.state, nowMs, config.backgroundTaskPendingQueueTimeoutMinutes);
|
|
1032
|
+
backgroundTaskSlotStateRef.state = sweep.state;
|
|
1033
|
+
for (const expired of sweep.expired) {
|
|
1034
|
+
try {
|
|
1035
|
+
await backgroundTaskRunner.expireForDeadline(expired.taskId, "queue_timeout", expired.waitedMs);
|
|
1036
|
+
}
|
|
1037
|
+
catch (err) {
|
|
1038
|
+
logger.warn({ err, taskId: expired.taskId }, "background-task queue-timeout action failed (continuing)");
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
// (3) delivery recovery
|
|
1042
|
+
const count = await enqueueUndeliveredBackgroundTaskDeliveries({
|
|
1043
|
+
db,
|
|
1044
|
+
eventBus,
|
|
1045
|
+
nowMs,
|
|
1046
|
+
});
|
|
1047
|
+
if (count > 0) {
|
|
1048
|
+
logger.debug({ count }, "background-task delivery recovery enqueued task.delivery events");
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
catch (err) {
|
|
1052
|
+
logger.warn({ err }, "background-task housekeeping tick failed (continuing)");
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
const timer = setInterval(() => {
|
|
1056
|
+
void tick();
|
|
1057
|
+
}, TICK_MS);
|
|
1058
|
+
if (typeof timer.unref === "function")
|
|
1059
|
+
timer.unref();
|
|
1060
|
+
void tick();
|
|
1061
|
+
return timer;
|
|
1062
|
+
})();
|
|
1063
|
+
// ── Background-task boot recovery (resume / re-dispatch) ──────────────
|
|
1064
|
+
// BACKGROUND_TASK_RUNNER_DESIGN.md §10.2 — unlike browser_task (whose
|
|
1065
|
+
// in-memory session is unrecoverable, so its rows are force-failed),
|
|
1066
|
+
// background tasks survive a restart: their brief is self-contained AND
|
|
1067
|
+
// (Phase 4) their SDK session id is persisted.
|
|
1068
|
+
//
|
|
1069
|
+
// With `backgroundTaskResumeAcrossRestart` ON (default):
|
|
1070
|
+
// - `running` rows that captured a session id → RESUME the warm SDK
|
|
1071
|
+
// session (`resumeFromBoot`), falling back to re-dispatch on any
|
|
1072
|
+
// "couldn't load the session" signal.
|
|
1073
|
+
// - `awaiting_user` rows that captured a session id → LEFT as-is, so a
|
|
1074
|
+
// later `/clarify` reconstructs the handle and resumes (the delivery
|
|
1075
|
+
// recovery sweep re-sends the question if it never reached the owner).
|
|
1076
|
+
// - everything else (no session id, `pending`, or never-inited)
|
|
1077
|
+
// → re-dispatch from brief.
|
|
1078
|
+
// With the toggle OFF: the v1 behaviour — every non-terminal row is
|
|
1079
|
+
// re-dispatched from brief.
|
|
1080
|
+
//
|
|
1081
|
+
// Best-effort — failures log but do not abort startup.
|
|
1082
|
+
void (async () => {
|
|
1083
|
+
try {
|
|
1084
|
+
const { resetNonTerminalForBootRedispatch, listNonTerminalBackgroundTasks, } = await import("../db/background-task-store.js");
|
|
1085
|
+
if (!config.backgroundTaskResumeAcrossRestart) {
|
|
1086
|
+
const reset = resetNonTerminalForBootRedispatch(db);
|
|
1087
|
+
if (reset.length === 0)
|
|
1088
|
+
return;
|
|
1089
|
+
logger.warn({ count: reset.length }, "background-task boot recovery — re-dispatching non-terminal tasks from brief (resume disabled)");
|
|
1090
|
+
for (const { id } of reset) {
|
|
1091
|
+
void backgroundTaskRunner.runFromPost(id).catch((err) => {
|
|
1092
|
+
logger.error({ err, taskId: id }, "background-task boot re-dispatch threw (continuing)");
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
const rows = listNonTerminalBackgroundTasks(db);
|
|
1098
|
+
if (rows.length === 0)
|
|
1099
|
+
return;
|
|
1100
|
+
const resumeRunning = rows.filter((r) => r.state === "running" && r.backendSessionId);
|
|
1101
|
+
const leaveParked = rows.filter((r) => r.state === "awaiting_user" && r.backendSessionId);
|
|
1102
|
+
// Everything not resumed and not left parked is re-dispatched: the
|
|
1103
|
+
// runner's `resumeFromBoot` resets+re-runs each one (a `running` row
|
|
1104
|
+
// without a session id, a `pending` row, etc.).
|
|
1105
|
+
const redispatchIds = rows
|
|
1106
|
+
.filter((r) => !(r.state === "running" && r.backendSessionId)
|
|
1107
|
+
&& !(r.state === "awaiting_user" && r.backendSessionId))
|
|
1108
|
+
.map((r) => r.id);
|
|
1109
|
+
logger.warn({
|
|
1110
|
+
resume: resumeRunning.length,
|
|
1111
|
+
leftParked: leaveParked.length,
|
|
1112
|
+
redispatch: redispatchIds.length,
|
|
1113
|
+
}, "background-task boot recovery — resuming / re-dispatching non-terminal tasks");
|
|
1114
|
+
for (const { id } of [...resumeRunning, ...redispatchIds.map((id) => ({ id }))]) {
|
|
1115
|
+
void backgroundTaskRunner.resumeFromBoot(id).catch((err) => {
|
|
1116
|
+
logger.error({ err, taskId: id }, "background-task boot resume/re-dispatch threw (continuing)");
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
catch (err) {
|
|
1121
|
+
logger.warn({ err }, "background-task boot recovery failed (continuing; rows stay non-terminal for next boot)");
|
|
1122
|
+
}
|
|
1123
|
+
})();
|
|
889
1124
|
// ── Browser-task boot-recovery DM fan-out ─────────────────────────────
|
|
890
1125
|
// BROWSER_TASK_REDESIGN_PLAN.md §6.5 — `initDatabase` flipped every
|
|
891
1126
|
// non-terminal `browser_task` row to `failed (daemon_restarted)` and
|
|
@@ -1024,6 +1259,9 @@ export async function createEventPipeline(deps) {
|
|
|
1024
1259
|
browserTaskDeadlineTimer,
|
|
1025
1260
|
browserTaskSlotStateRef,
|
|
1026
1261
|
browserTaskRunner,
|
|
1262
|
+
backgroundTaskSlotStateRef,
|
|
1263
|
+
backgroundTaskRunner,
|
|
1264
|
+
backgroundTaskHousekeepingTimer,
|
|
1027
1265
|
};
|
|
1028
1266
|
}
|
|
1029
1267
|
/**
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
*/
|
|
59
59
|
import { join } from "node:path";
|
|
60
60
|
import { getContextDir } from "../config.js";
|
|
61
|
+
import { getAgentEnabled } from "../db/agents-store.js";
|
|
61
62
|
import { isSetupCompleted, isDegraded as readDegradedMode, } from "../db/runtime-state.js";
|
|
62
63
|
import { getRepositoryByGithub, getRepositoryByLocalPath, listRepositories, selectGithubRepoSlugs, selectGitWatchedRepos, } from "../db/repositories-store.js";
|
|
63
64
|
import { dispatchMatchingTriggers } from "../core/trigger-dispatch.js";
|
|
@@ -191,7 +192,7 @@ export async function createObservers(deps) {
|
|
|
191
192
|
eventBus,
|
|
192
193
|
// Threaded through so observations of agent-originated commits
|
|
193
194
|
// flip to `actor='agent'` (C1). Without this, daemon-side
|
|
194
|
-
// commits would feed the
|
|
195
|
+
// commits would feed the activity_scan pending floor as user
|
|
195
196
|
// activity and re-invoke the agent in a loop.
|
|
196
197
|
writeTracker,
|
|
197
198
|
pushOverdueMinutes: config.gitPushOverdueMinutes,
|
|
@@ -307,8 +308,8 @@ export async function createObservers(deps) {
|
|
|
307
308
|
}
|
|
308
309
|
// Each call returns a fresh observer so the integration-lifecycle
|
|
309
310
|
// helper re-registers a new instance after a mode flip — picking up
|
|
310
|
-
// any gitPollIntervalSeconds / gitPushOverdueMinutes
|
|
311
|
-
//
|
|
311
|
+
// any gitPollIntervalSeconds / gitPushOverdueMinutes PATCH (or an
|
|
312
|
+
// activity-scan agent toggle) that landed while the cron was idle.
|
|
312
313
|
const buildGitDelegatedCronObserver = () => new GitDelegatedCronObserver({
|
|
313
314
|
db,
|
|
314
315
|
eventBus,
|
|
@@ -316,7 +317,9 @@ export async function createObservers(deps) {
|
|
|
316
317
|
githubRepos: selectGithubRepoSlugs(db),
|
|
317
318
|
cadenceSeconds: config.gitPollIntervalSeconds,
|
|
318
319
|
pushOverdueMinutes: config.gitPushOverdueMinutes,
|
|
319
|
-
|
|
320
|
+
// Collision-avoidance hint only: the activity-scan agent row's enabled
|
|
321
|
+
// flag is the single switch (AGENTS_HUB_REDESIGN_PLAN.md §2).
|
|
322
|
+
activityScanEnabled: getAgentEnabled(db, "activity-scan", true),
|
|
320
323
|
});
|
|
321
324
|
if (hasActiveDelegatedGitLifecycleIntegration(db)) {
|
|
322
325
|
observerManager.register(buildGitDelegatedCronObserver());
|
|
@@ -509,7 +512,7 @@ export async function createObservers(deps) {
|
|
|
509
512
|
// ── 7.2 Observation summarizer (cost-reduction-structural §A) ──
|
|
510
513
|
// Drains pending observation rows asynchronously: pre-filter →
|
|
511
514
|
// per-source LLM call → `summary_text` + `novelty_score` written
|
|
512
|
-
// back to the row. The
|
|
515
|
+
// back to the row. The activity_scan skill consumes summaries instead
|
|
513
516
|
// of re-fetching raw content. Disabled cleanly via
|
|
514
517
|
// `observationSummarizerEnabled` — when off, observations stay
|
|
515
518
|
// pending and the skill drops to legacy fetch-on-doubt.
|
|
@@ -545,7 +548,7 @@ export async function createObservers(deps) {
|
|
|
545
548
|
}
|
|
546
549
|
// Codex / Gemini summarizer support is not yet implemented; the
|
|
547
550
|
// worker translates `unsupported_backend` into a 'skipped' row so
|
|
548
|
-
// the
|
|
551
|
+
// the activity_scan skill drops to its legacy fetch path.
|
|
549
552
|
return new UnsupportedSummarizerClient(fallbackBackend, fallbackModel);
|
|
550
553
|
})();
|
|
551
554
|
observerManager.register(new ObservationSummarizerWorker({
|
|
@@ -25,11 +25,11 @@ export declare const WEEKLY_REVIEW_CATCHUP_DAYS_OF_WEEK: Set<number>;
|
|
|
25
25
|
export declare function getDueCatchupRoutines(db: Database.Database, config: AgentConfig, agentDayStartUtc: string, agentDayEndUtc: string, now: Date): string[];
|
|
26
26
|
/**
|
|
27
27
|
* Decide whether the boot sequence should immediately fire one
|
|
28
|
-
* catch-up `routine.
|
|
28
|
+
* catch-up `routine.activity_scan` (because the cron callback never ran
|
|
29
29
|
* for the current slot — typically because the host was asleep / the
|
|
30
30
|
* daemon was stopped during the slot window).
|
|
31
31
|
*
|
|
32
|
-
* Slot math mirrors `
|
|
32
|
+
* Slot math mirrors `shouldFireActivityScanTickAt` in `scheduler.ts` so the
|
|
33
33
|
* catch-up always lands on the same slot the cron would have fired at.
|
|
34
34
|
*
|
|
35
35
|
* **Wrap-around active hours are NOT supported.** The active-hours
|
|
@@ -49,12 +49,12 @@ export declare function getDueCatchupRoutines(db: Database.Database, config: Age
|
|
|
49
49
|
* config-write time, or (b) split the window into two non-wrap
|
|
50
50
|
* ranges in the same call site that consumes them.
|
|
51
51
|
*/
|
|
52
|
-
export declare function
|
|
52
|
+
export declare function shouldCatchUpActivityScan(db: Database.Database, config: AgentConfig, now: Date): boolean;
|
|
53
53
|
export declare function getProgressMinutesForHour(hour: number, dayBoundaryHour: number): number;
|
|
54
54
|
export declare function hasFreshAgentDayTodayMd(todayMdPath: string, timezone: string | undefined, dayBoundaryHour: number, now?: Date): boolean;
|
|
55
55
|
/**
|
|
56
56
|
* Did `routine.morning_routine` complete successfully within the current
|
|
57
|
-
* agent-day window? Used by the pre-routine gate that fronts
|
|
57
|
+
* agent-day window? Used by the pre-routine gate that fronts activity_scan
|
|
58
58
|
* and the review routines (evening / weekly / monthly) so they refuse to
|
|
59
59
|
* run before the day has been properly opened.
|
|
60
60
|
*
|
|
@@ -117,10 +117,10 @@ export interface StalledMorningRoutineWake {
|
|
|
117
117
|
* without producing a successful `agent_actions` row. Returns the
|
|
118
118
|
* offending row's metadata if stalled, null when the system is healthy.
|
|
119
119
|
*
|
|
120
|
-
* Pairs with `queueMorningRoutineWake` + the
|
|
120
|
+
* Pairs with `queueMorningRoutineWake` + the activity-scan pre-routine
|
|
121
121
|
* gate. The dedup that keeps `queueMorningRoutineWake` from re-inserting
|
|
122
122
|
* means a stuck wake row leaves the system in a silent freeze — the gate
|
|
123
|
-
* skips `routine.
|
|
123
|
+
* skips `routine.activity_scan`, `routine.evening_review`, etc. forever
|
|
124
124
|
* without surfacing to the user. This helper is the externally visible
|
|
125
125
|
* signal the watchdog uses to break the silence.
|
|
126
126
|
*
|
|
@@ -136,4 +136,102 @@ export declare function getStalledMorningRoutineWake(db: Database.Database, agen
|
|
|
136
136
|
timezone?: string;
|
|
137
137
|
dayBoundaryHour: number;
|
|
138
138
|
}, thresholdMinutes: number, now?: Date): StalledMorningRoutineWake | null;
|
|
139
|
+
/**
|
|
140
|
+
* Audit-row action types that count as "a morning-routine attempt started"
|
|
141
|
+
* for the missed-fire predicate below. The parent row
|
|
142
|
+
* (`routine.morning_routine`) is written when the pipeline finishes
|
|
143
|
+
* (success or failure); the Stage A row
|
|
144
|
+
* (`routine.morning_routine_today`) is written `in_progress` the moment
|
|
145
|
+
* the agent execution starts, so a hung Stage A is still visible as an
|
|
146
|
+
* attempt. The fetch-window pre-pass is deliberately NOT included — it
|
|
147
|
+
* also runs for hourly/scheduled flows, and counting it would let an
|
|
148
|
+
* unrelated pre-pass mask a dead morning pipeline.
|
|
149
|
+
*/
|
|
150
|
+
export declare const MORNING_ROUTINE_ATTEMPT_ACTION_TYPES: readonly ["routine.morning_routine", "routine.morning_routine_today"];
|
|
151
|
+
/**
|
|
152
|
+
* Grace period after the agent-day boundary before the missed-fire
|
|
153
|
+
* self-heal may conclude the 04:00 cron tick was swallowed. Wide enough
|
|
154
|
+
* that the normal cron → queueMorningRoutineWake → ScheduleWatcher claim
|
|
155
|
+
* → Stage A start chain has long since produced either a wake row or an
|
|
156
|
+
* attempt row; short enough that a swallowed tick costs at most ~25 min
|
|
157
|
+
* (grace + one self-heal interval) once the machine is awake.
|
|
158
|
+
*/
|
|
159
|
+
export declare const MORNING_MISSED_FIRE_GRACE_MINUTES = 15;
|
|
160
|
+
/**
|
|
161
|
+
* Epoch ms of the most recent morning-routine attempt (any result,
|
|
162
|
+
* including `in_progress`) started within the current agent-day, or null
|
|
163
|
+
* when nothing has been attempted yet. Pure read.
|
|
164
|
+
*/
|
|
165
|
+
export declare function getLatestMorningAttemptStartMs(db: Database.Database, agentDayConfig: {
|
|
166
|
+
timezone?: string;
|
|
167
|
+
dayBoundaryHour: number;
|
|
168
|
+
}, now?: Date): number | null;
|
|
169
|
+
export interface RecoverableStalledMorningWake {
|
|
170
|
+
/** agent_schedule.id of the `running` wake row to flip back to pending. */
|
|
171
|
+
id: number;
|
|
172
|
+
/** Minutes since the ScheduleWatcher claimed the row. */
|
|
173
|
+
claimedAgeMinutes: number;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Detect the hung-execution variant of the morning-routine silent stall:
|
|
177
|
+
* a wake row claimed to `running` at least `thresholdMinutes` ago with
|
|
178
|
+
* still no `routine.morning_routine` success for the current agent-day
|
|
179
|
+
* (machine slept mid-run and the backend stream died on the network
|
|
180
|
+
* change, the SDK call wedged, or the dispatch event was lost).
|
|
181
|
+
*
|
|
182
|
+
* `queueMorningRoutineWake`'s dedup treats a `running` row as "already
|
|
183
|
+
* in flight" and merges into it forever, so without recovery the day
|
|
184
|
+
* stays frozen until a daemon restart. The caller (scheduler self-heal
|
|
185
|
+
* tick) flips the returned row back to `pending` so the ScheduleWatcher
|
|
186
|
+
* re-claims it; the today-write-lock's wall-clock TTL guarantees a hung
|
|
187
|
+
* original cannot hold the lock against the re-run indefinitely.
|
|
188
|
+
*
|
|
189
|
+
* Staleness is measured from `task_context.claimedAt`, stamped by the
|
|
190
|
+
* ScheduleWatcher at claim time. That is the only signal that survives
|
|
191
|
+
* every confounder: `created_at` predates sleeps that delay the claim,
|
|
192
|
+
* `scheduled_for` is bumped by dedup merges, and attempt audit rows are
|
|
193
|
+
* windowed to the current agent-day (a run that started before the
|
|
194
|
+
* 04:00 boundary and hung across it has no attempt row "today").
|
|
195
|
+
* Invariants this leans on:
|
|
196
|
+
* - boot recovery (`recoverOrphanedRunningSchedules`) clears every
|
|
197
|
+
* `running` row at daemon start, so a live `running` row was always
|
|
198
|
+
* claimed by the current process — which always stamps;
|
|
199
|
+
* - `queueMorningRoutineWake`'s dedup-merge preserves unknown
|
|
200
|
+
* task_context keys, so a 04:00 cron merge cannot strip the stamp.
|
|
201
|
+
* A row without a readable stamp (stamp UPDATE failed, malformed JSON)
|
|
202
|
+
* is left to the alert-only watchdog rather than guessed at.
|
|
203
|
+
*
|
|
204
|
+
* Pure read — the caller owns the UPDATE.
|
|
205
|
+
*/
|
|
206
|
+
export declare function getRecoverableStalledMorningWake(db: Database.Database, agentDayConfig: {
|
|
207
|
+
timezone?: string;
|
|
208
|
+
dayBoundaryHour: number;
|
|
209
|
+
}, thresholdMinutes: number, now?: Date): RecoverableStalledMorningWake | null;
|
|
210
|
+
/**
|
|
211
|
+
* Detect the missed-fire variant of the morning-routine silent stall:
|
|
212
|
+
* the machine was asleep at the day-boundary minute, node-cron silently
|
|
213
|
+
* dropped the tick (it never replays missed firings), and nothing since
|
|
214
|
+
* has re-queued the routine. Observable signature, all three at once:
|
|
215
|
+
*
|
|
216
|
+
* 1. no morning-routine attempt has *started* this agent-day (any
|
|
217
|
+
* result — a failed/exhausted retry chain counts as attempted, so
|
|
218
|
+
* this self-heal never resurrects a chain that
|
|
219
|
+
* `scheduleMorningRetry` deliberately stopped after MAX_RETRIES);
|
|
220
|
+
* 2. no `pending`/`running` morning wake row exists (the cron, the
|
|
221
|
+
* wake catch-up, and the retry chain all leave one when they are
|
|
222
|
+
* mid-flight);
|
|
223
|
+
* 3. the agent-day is at least `graceMinutes` old, so a healthy cron
|
|
224
|
+
* fire has had ample time to produce 1 or 2.
|
|
225
|
+
*
|
|
226
|
+
* Complements the WakeDetector: gaps shorter than its 5-min threshold
|
|
227
|
+
* that straddle the boundary minute (lid closed 03:59–04:02), or a
|
|
228
|
+
* detector failure, still converge here within one self-heal interval.
|
|
229
|
+
*
|
|
230
|
+
* Pure read — the caller routes through `queueMorningRoutineWake`,
|
|
231
|
+
* whose DB-backed dedup makes double-queueing impossible.
|
|
232
|
+
*/
|
|
233
|
+
export declare function shouldQueueMissedMorningFire(db: Database.Database, agentDayConfig: {
|
|
234
|
+
timezone?: string;
|
|
235
|
+
dayBoundaryHour: number;
|
|
236
|
+
}, graceMinutes: number, now?: Date): boolean;
|
|
139
237
|
export declare function readSkillCurationCadence(db: Database.Database): "daily" | "weekly" | "monthly";
|