@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.
Files changed (305) hide show
  1. package/dist/adapters/adapter-watchdog.d.ts +70 -0
  2. package/dist/adapters/adapter-watchdog.js +115 -0
  3. package/dist/adapters/discord.d.ts +17 -1
  4. package/dist/adapters/discord.js +33 -0
  5. package/dist/adapters/notification-manager.d.ts +27 -1
  6. package/dist/adapters/notification-manager.js +54 -39
  7. package/dist/adapters/slack-adapter.d.ts +26 -1
  8. package/dist/adapters/slack-adapter.js +41 -0
  9. package/dist/adapters/telegram-adapter.d.ts +18 -1
  10. package/dist/adapters/telegram-adapter.js +41 -2
  11. package/dist/adapters/types.d.ts +20 -0
  12. package/dist/adapters/whatsapp-adapter.d.ts +26 -7
  13. package/dist/adapters/whatsapp-adapter.js +74 -21
  14. package/dist/api/env-writer.js +8 -5
  15. package/dist/api/helpers/agent-errors-registry.d.ts +5 -5
  16. package/dist/api/helpers/agent-errors-registry.js +5 -5
  17. package/dist/api/routes/agent.js +33 -12
  18. package/dist/api/routes/agents/index.js +75 -16
  19. package/dist/api/routes/agents/views.d.ts +37 -2
  20. package/dist/api/routes/agents/views.js +64 -2
  21. package/dist/api/routes/background-task.d.ts +22 -0
  22. package/dist/api/routes/background-task.js +338 -0
  23. package/dist/api/routes/browser-history.js +9 -1
  24. package/dist/api/routes/context/permissions.js +3 -2
  25. package/dist/api/routes/context/snapshots.js +0 -3
  26. package/dist/api/routes/context/write.js +3 -17
  27. package/dist/api/routes/dashboard/config.js +48 -12
  28. package/dist/api/routes/dashboard/cost-approvals.js +66 -0
  29. package/dist/api/routes/dashboard/notifications.js +9 -9
  30. package/dist/api/routes/integrations/crud-patch.js +5 -1
  31. package/dist/api/routes/integrations-reconcile.js +2 -2
  32. package/dist/api/routes/notion.d.ts +1 -1
  33. package/dist/api/routes/observations.js +7 -7
  34. package/dist/api/routes/obsidian.d.ts +1 -1
  35. package/dist/api/routes/receipts.js +5 -1
  36. package/dist/api/routes/setup-migrate.js +1 -1
  37. package/dist/api/routes/setup.js +1 -1
  38. package/dist/api/routes/task-flows.d.ts +1 -1
  39. package/dist/api/routes/task-flows.js +1 -1
  40. package/dist/api/routes/tuning.d.ts +29 -0
  41. package/dist/api/routes/tuning.js +304 -0
  42. package/dist/api/server.d.ts +44 -16
  43. package/dist/api/server.js +9 -0
  44. package/dist/bootstrap/adapters.d.ts +19 -0
  45. package/dist/bootstrap/adapters.js +61 -0
  46. package/dist/bootstrap/api.d.ts +5 -3
  47. package/dist/bootstrap/api.js +45 -13
  48. package/dist/bootstrap/catchup.d.ts +1 -1
  49. package/dist/bootstrap/catchup.js +11 -11
  50. package/dist/bootstrap/event-pipeline.d.ts +11 -0
  51. package/dist/bootstrap/event-pipeline.js +245 -7
  52. package/dist/bootstrap/observers.js +9 -6
  53. package/dist/bootstrap/schedule-helpers.d.ts +104 -6
  54. package/dist/bootstrap/schedule-helpers.js +172 -19
  55. package/dist/config.js +26 -12
  56. package/dist/core/agent-core.d.ts +33 -1
  57. package/dist/core/agent-core.js +36 -1
  58. package/dist/core/agents/activity-scan-cadence.d.ts +103 -0
  59. package/dist/core/agents/activity-scan-cadence.js +127 -0
  60. package/dist/core/agents/agent-route-override.d.ts +53 -0
  61. package/dist/core/agents/agent-route-override.js +69 -0
  62. package/dist/core/agents/builtin-registry.d.ts +51 -14
  63. package/dist/core/agents/builtin-registry.js +92 -15
  64. package/dist/core/agents/config-gate-reconcile.d.ts +38 -0
  65. package/dist/core/agents/config-gate-reconcile.js +51 -0
  66. package/dist/core/agents/cron-substitute.d.ts +1 -1
  67. package/dist/core/agents/cron-substitute.js +1 -1
  68. package/dist/core/agents/custom-routine-migration.d.ts +60 -0
  69. package/dist/core/agents/custom-routine-migration.js +149 -0
  70. package/dist/core/agents/firing-blocked.d.ts +1 -1
  71. package/dist/core/agents/hourly-cadence.d.ts +102 -0
  72. package/dist/core/agents/hourly-cadence.js +126 -0
  73. package/dist/core/agents/loader-boot.js +23 -0
  74. package/dist/core/agents/loader.d.ts +19 -0
  75. package/dist/core/agents/loader.js +34 -2
  76. package/dist/core/agents/override-merge.d.ts +1 -1
  77. package/dist/core/agents/override-merge.js +9 -1
  78. package/dist/core/agents/recurrence-convert.d.ts +1 -1
  79. package/dist/core/agents/recurrence-convert.js +1 -1
  80. package/dist/core/agents/recurring-schedule-adapter.js +8 -0
  81. package/dist/core/alerts.js +6 -6
  82. package/dist/core/backends/auth-health-monitor.d.ts +2 -2
  83. package/dist/core/backends/auth-health-monitor.js +1 -1
  84. package/dist/core/backends/backend-router.d.ts +27 -1
  85. package/dist/core/backends/backend-router.js +165 -1
  86. package/dist/core/backends/claude-code-core.d.ts +71 -31
  87. package/dist/core/backends/claude-code-core.js +282 -54
  88. package/dist/core/backends/cli-quota-guards.d.ts +29 -1
  89. package/dist/core/backends/cli-quota-guards.js +40 -5
  90. package/dist/core/backends/codex-core.d.ts +6 -0
  91. package/dist/core/backends/codex-core.js +22 -6
  92. package/dist/core/backends/failure-spend.d.ts +58 -0
  93. package/dist/core/backends/failure-spend.js +137 -0
  94. package/dist/core/backends/gemini-cli-core.d.ts +6 -0
  95. package/dist/core/backends/gemini-cli-core.js +25 -6
  96. package/dist/core/backends/model-registry.d.ts +1 -1
  97. package/dist/core/backends/model-registry.js +4 -4
  98. package/dist/core/backends/opencode-core.d.ts +1 -1
  99. package/dist/core/backends/opencode-core.js +5 -5
  100. package/dist/core/backends/plan-presets.js +39 -15
  101. package/dist/core/bang-commands/commands-cost.js +3 -1
  102. package/dist/core/bang-commands/commands-report.js +4 -3
  103. package/dist/core/bang-commands/commands-research.js +4 -1
  104. package/dist/core/bang-commands/commands-revert-tuning.d.ts +18 -0
  105. package/dist/core/bang-commands/commands-revert-tuning.js +63 -0
  106. package/dist/core/bang-commands/commands-stop-start.js +3 -3
  107. package/dist/core/bang-commands/commands-task-control.d.ts +19 -0
  108. package/dist/core/bang-commands/commands-task-control.js +147 -0
  109. package/dist/core/bang-commands/commands-wiki.js +5 -5
  110. package/dist/core/bang-commands/index.d.ts +2 -0
  111. package/dist/core/bang-commands/index.js +12 -0
  112. package/dist/core/bang-commands/registry.d.ts +12 -0
  113. package/dist/core/browser-history/research-cluster-fanout.d.ts +28 -14
  114. package/dist/core/browser-history/research-cluster-fanout.js +39 -16
  115. package/dist/core/channel-timeline.d.ts +5 -1
  116. package/dist/core/channel-timeline.js +13 -0
  117. package/dist/core/context/index-reconciler.js +5 -2
  118. package/dist/core/context/policy-index-reconciler.d.ts +6 -4
  119. package/dist/core/context/policy-index-runner.js +25 -6
  120. package/dist/core/context-builder-calendar.js +10 -2
  121. package/dist/core/context-builder-conversation.d.ts +8 -1
  122. package/dist/core/context-builder-conversation.js +41 -7
  123. package/dist/core/context-builder-yesterday.js +4 -3
  124. package/dist/core/context-builder.d.ts +7 -2
  125. package/dist/core/context-builder.js +62 -20
  126. package/dist/core/context-file-serializer.d.ts +1 -1
  127. package/dist/core/context-file-serializer.js +1 -1
  128. package/dist/core/context-health.js +2 -2
  129. package/dist/core/context-paths.d.ts +1 -1
  130. package/dist/core/context-paths.js +1 -1
  131. package/dist/core/context-validation/prepare-write.js +1 -1
  132. package/dist/core/context-validation/routine-rulebook.d.ts +1 -1
  133. package/dist/core/context-vault-aliases.d.ts +0 -13
  134. package/dist/core/context-vault-aliases.js +37 -0
  135. package/dist/core/custom-routines.d.ts +99 -0
  136. package/dist/core/custom-routines.js +187 -0
  137. package/dist/core/daemon-api-cli.js +49 -0
  138. package/dist/core/day-boundary.d.ts +46 -0
  139. package/dist/core/day-boundary.js +40 -0
  140. package/dist/core/dispatcher-activity-scan.d.ts +221 -0
  141. package/dist/core/dispatcher-activity-scan.js +775 -0
  142. package/dist/core/dispatcher-error-handling.d.ts +6 -11
  143. package/dist/core/dispatcher-error-handling.js +38 -62
  144. package/dist/core/dispatcher-hourly-check.js +6 -1
  145. package/dist/core/dispatcher-message-handler.d.ts +10 -0
  146. package/dist/core/dispatcher-message-handler.js +17 -0
  147. package/dist/core/dispatcher-morning-routine.d.ts +6 -6
  148. package/dist/core/dispatcher-morning-routine.js +13 -13
  149. package/dist/core/dispatcher-result-processor.d.ts +33 -0
  150. package/dist/core/dispatcher-result-processor.js +167 -11
  151. package/dist/core/dispatcher-scheduled-background-task.d.ts +42 -0
  152. package/dist/core/dispatcher-scheduled-background-task.js +89 -0
  153. package/dist/core/dispatcher-scheduled-tasks.d.ts +63 -1
  154. package/dist/core/dispatcher-scheduled-tasks.js +213 -6
  155. package/dist/core/dispatcher-task-delivery.d.ts +105 -0
  156. package/dist/core/dispatcher-task-delivery.js +555 -0
  157. package/dist/core/dispatcher-types.d.ts +48 -9
  158. package/dist/core/dispatcher-types.js +3 -3
  159. package/dist/core/dispatcher.d.ts +112 -31
  160. package/dist/core/dispatcher.js +284 -59
  161. package/dist/core/dm-freshness-metrics.d.ts +1 -1
  162. package/dist/core/drift-effects.js +2 -2
  163. package/dist/core/feedback/consolidation-prep.js +17 -5
  164. package/dist/core/feedback/eviction-scorer.js +6 -2
  165. package/dist/core/feedback/lesson-format.js +9 -4
  166. package/dist/core/feedback/lesson-injection.d.ts +1 -1
  167. package/dist/core/feedback/lesson-injection.js +17 -2
  168. package/dist/core/feedback/lesson-store-overview.d.ts +8 -4
  169. package/dist/core/feedback/lesson-store-overview.js +8 -4
  170. package/dist/core/feedback/regeneralization-prep.js +29 -16
  171. package/dist/core/feedback/self-performance-prep.d.ts +186 -0
  172. package/dist/core/feedback/self-performance-prep.js +541 -0
  173. package/dist/core/feedback/tuning-actuator.d.ts +198 -0
  174. package/dist/core/feedback/tuning-actuator.js +432 -0
  175. package/dist/core/feedback/tuning-recommender.d.ts +247 -0
  176. package/dist/core/feedback/tuning-recommender.js +580 -0
  177. package/dist/core/feedback/tuning-revert-monitor.d.ts +90 -0
  178. package/dist/core/feedback/tuning-revert-monitor.js +213 -0
  179. package/dist/core/health-monitor.d.ts +6 -0
  180. package/dist/core/health-monitor.js +1 -1
  181. package/dist/core/injection-policy.d.ts +4 -4
  182. package/dist/core/injection-policy.js +4 -4
  183. package/dist/core/integration-main-backend.js +4 -0
  184. package/dist/core/management-md.d.ts +2 -2
  185. package/dist/core/management-md.js +51 -13
  186. package/dist/core/morning/orchestrator.d.ts +2 -2
  187. package/dist/core/morning/orchestrator.js +2 -2
  188. package/dist/core/notification-gate.d.ts +64 -0
  189. package/dist/core/notification-gate.js +51 -0
  190. package/dist/core/notification-rate-limit.d.ts +40 -0
  191. package/dist/core/notification-rate-limit.js +50 -0
  192. package/dist/core/policy-files.d.ts +1 -1
  193. package/dist/core/policy-files.js +2 -2
  194. package/dist/core/pre-pass-freshness.d.ts +4 -4
  195. package/dist/core/retention.d.ts +5 -0
  196. package/dist/core/retention.js +20 -4
  197. package/dist/core/review-context.d.ts +1 -1
  198. package/dist/core/review-context.js +10 -5
  199. package/dist/core/roadmap-write-lock.d.ts +2 -1
  200. package/dist/core/roadmap-write-lock.js +15 -10
  201. package/dist/core/routine-acquisition-plan.d.ts +47 -1
  202. package/dist/core/routine-acquisition-plan.js +78 -20
  203. package/dist/core/routine-fetch-window-retry.js +7 -4
  204. package/dist/core/routine-fetch-window-runner.d.ts +39 -3
  205. package/dist/core/routine-fetch-window-runner.js +264 -13
  206. package/dist/core/routine-windows.d.ts +2 -2
  207. package/dist/core/routine-windows.js +8 -5
  208. package/dist/core/scheduler.d.ts +175 -16
  209. package/dist/core/scheduler.js +559 -102
  210. package/dist/core/signal-detector.d.ts +12 -0
  211. package/dist/core/signal-detector.js +53 -9
  212. package/dist/core/skills-compiler-denied-tools.js +2 -2
  213. package/dist/core/skills-compiler-skill-index.d.ts +2 -2
  214. package/dist/core/skills-compiler-skill-index.js +2 -2
  215. package/dist/core/skills-compiler-variants.d.ts +1 -1
  216. package/dist/core/skills-compiler-variants.js +8 -0
  217. package/dist/core/skills-compiler.d.ts +29 -26
  218. package/dist/core/skills-compiler.js +117 -81
  219. package/dist/core/skills-manifest.d.ts +37 -0
  220. package/dist/core/skills-manifest.js +73 -2
  221. package/dist/core/sleep-inhibitor.d.ts +79 -0
  222. package/dist/core/sleep-inhibitor.js +132 -0
  223. package/dist/core/slim-system-prompt-loader.d.ts +77 -0
  224. package/dist/core/slim-system-prompt-loader.js +141 -0
  225. package/dist/core/spawn-gates.d.ts +126 -0
  226. package/dist/core/spawn-gates.js +180 -0
  227. package/dist/core/today-direct-writer.d.ts +2 -2
  228. package/dist/core/today-direct-writer.js +1 -1
  229. package/dist/core/today-write-lock.d.ts +4 -2
  230. package/dist/core/today-write-lock.js +30 -20
  231. package/dist/core/wake-detector.d.ts +55 -0
  232. package/dist/core/wake-detector.js +80 -0
  233. package/dist/core/wiki/compile-lock.d.ts +1 -1
  234. package/dist/core/wiki/compile-lock.js +1 -1
  235. package/dist/core/workdir.js +15 -6
  236. package/dist/db/activity-scan-signals.d.ts +77 -0
  237. package/dist/db/activity-scan-signals.js +378 -0
  238. package/dist/db/agents-store.d.ts +28 -0
  239. package/dist/db/agents-store.js +62 -0
  240. package/dist/db/background-task-clarifications-store.d.ts +81 -0
  241. package/dist/db/background-task-clarifications-store.js +152 -0
  242. package/dist/db/background-task-store.d.ts +207 -0
  243. package/dist/db/background-task-store.js +380 -0
  244. package/dist/db/browser-history-store.d.ts +39 -6
  245. package/dist/db/browser-history-store.js +51 -7
  246. package/dist/db/browser-task-clarifications-store.d.ts +12 -0
  247. package/dist/db/browser-task-clarifications-store.js +35 -5
  248. package/dist/db/browser-task-store.d.ts +3 -0
  249. package/dist/db/browser-task-store.js +29 -4
  250. package/dist/db/deferred-dm.d.ts +86 -0
  251. package/dist/db/deferred-dm.js +199 -0
  252. package/dist/db/migrations.js +330 -0
  253. package/dist/db/observations.d.ts +2 -2
  254. package/dist/db/observations.js +3 -3
  255. package/dist/db/schema.js +217 -16
  256. package/dist/db/voice-transcripts-store.d.ts +1 -1
  257. package/dist/index.js +86 -29
  258. package/dist/messaging/browser-task-mcp-notifier.d.ts +12 -70
  259. package/dist/messaging/browser-task-mcp-notifier.js +30 -151
  260. package/dist/messaging/browser-task-screenshot-attachment.d.ts +15 -0
  261. package/dist/messaging/browser-task-screenshot-attachment.js +63 -0
  262. package/dist/observers/delegated-sync-worker.d.ts +6 -6
  263. package/dist/observers/delegated-sync-worker.js +10 -10
  264. package/dist/observers/git-delegated-cron.d.ts +1 -1
  265. package/dist/observers/git-delegated-cron.js +2 -2
  266. package/dist/observers/github-poller-classifier.d.ts +3 -3
  267. package/dist/observers/github-poller-classifier.js +3 -3
  268. package/dist/observers/imminent-event-scheduler.d.ts +1 -1
  269. package/dist/observers/imminent-event-scheduler.js +1 -1
  270. package/dist/observers/mail-poller.d.ts +1 -0
  271. package/dist/observers/mail-poller.js +42 -3
  272. package/dist/observers/observation-summarizer/summarizer-client.d.ts +2 -2
  273. package/dist/observers/observation-summarizer/summarizer-client.js +2 -2
  274. package/dist/observers/observation-summarizer/worker.d.ts +2 -2
  275. package/dist/observers/observation-summarizer/worker.js +4 -4
  276. package/dist/observers/obsidian-watcher.d.ts +1 -1
  277. package/dist/observers/obsidian-watcher.js +1 -1
  278. package/dist/safety/agent-write-tracker.d.ts +4 -4
  279. package/dist/safety/agent-write-tracker.js +4 -4
  280. package/dist/safety/audit.d.ts +43 -5
  281. package/dist/safety/audit.js +86 -18
  282. package/dist/safety/risk-classifier.d.ts +6 -0
  283. package/dist/safety/risk-classifier.js +75 -11
  284. package/dist/scheduler/activity-scan-gate.d.ts +86 -0
  285. package/dist/scheduler/activity-scan-gate.js +132 -0
  286. package/dist/services/background-task/background-task-budget.d.ts +80 -0
  287. package/dist/services/background-task/background-task-budget.js +91 -0
  288. package/dist/services/background-task/background-task-driver.d.ts +105 -0
  289. package/dist/services/background-task/background-task-driver.js +416 -0
  290. package/dist/services/background-task/background-task-runner.d.ts +96 -0
  291. package/dist/services/background-task/background-task-runner.js +673 -0
  292. package/dist/services/background-task/background-task-tools.d.ts +84 -0
  293. package/dist/services/background-task/background-task-tools.js +247 -0
  294. package/dist/services/background-task/background-task-transition-events.d.ts +43 -0
  295. package/dist/services/background-task/background-task-transition-events.js +54 -0
  296. package/dist/services/browser-history/automation/egress-denylist.d.ts +1 -1
  297. package/dist/services/browser-history/automation/egress-denylist.js +16 -6
  298. package/dist/services/browser-history/managed-chromium/sandbox-launcher.js +0 -1
  299. package/dist/services/browser-task/browser-task-runner.js +53 -8
  300. package/dist/services/observations-batch.d.ts +1 -1
  301. package/dist/services/observations-batch.js +2 -2
  302. package/dist/settings/runtime-settings.d.ts +38 -11
  303. package/dist/settings/runtime-settings.js +203 -40
  304. package/dist/settings/settings-store.js +11 -3
  305. package/package.json +4 -4
@@ -1,3 +1,5 @@
1
+ import { existsSync, renameSync } from "node:fs";
2
+ import { join } from "node:path";
1
3
  import { createLogger } from "../logging.js";
2
4
  import { MIGRATION_ID as CONTEXT_VAULT_MIGRATION_ID, runContextVaultRestructure, } from "./migrations/context-vault-restructure.js";
3
5
  const logger = createLogger("migrations");
@@ -429,6 +431,334 @@ export const MIGRATIONS = [
429
431
  )`).run();
430
432
  },
431
433
  },
434
+ {
435
+ id: "0010-hourly-check-to-activity-scan",
436
+ description: "(v0.1.10→next) — the 'Hourly Check' built-in is renamed 'Activity "
437
+ + "Scan' (slug hourly-check→activity-scan, process key "
438
+ + "routine.hourly_check→routine.activity_scan, settings keys "
439
+ + "hourlyCheck*→activityScan*). Carries the persisted identity across: "
440
+ + "(1) agents row id rename preserving enabled / enabled_overridden_at / "
441
+ + "metadata_json.runtime_window, moving child agent_executions rows "
442
+ + "first (the FK has no ON UPDATE CASCADE); (2) process_backend_config "
443
+ + "key rename for the routine + its .triage delegate — the fresh "
444
+ + "new-key preset row that applySchema seeds moments before this body "
445
+ + "runs is deleted so the operator's old row (model overrides, budget) "
446
+ + "wins; (3) settings-table key renames (canonical row wins if both "
447
+ + "exist); (4) runtime_state self-tuning ledger key renames for the two "
448
+ + "activity-scan knobs; (5) on-disk vault file renames "
449
+ + "policies/routines/hourly.md→activity-scan.md and "
450
+ + "knowledge/dossiers/hourly.md→activity-scan.md — including the "
451
+ + "pre-restructure root spellings routines/hourly.md and "
452
+ + "dossiers/hourly.md for Obsidian vaults whose 0004 consent is still "
453
+ + "pending (+ md_file_snapshots file_path rewrite so restore points "
454
+ + "follow the file). When agents holds BOTH slugs (mixed-version "
455
+ + "backup restore) the stale old row is dropped after re-homing its "
456
+ + "executions — the registry no longer carries it, so nothing else "
457
+ + "would ever clean it up. Historical "
458
+ + "agent_actions rows keep their old action_type / agent_id — readers "
459
+ + "union the legacy values (see db/activity-scan-signals.ts). Each step "
460
+ + "is independently gated, so a fresh DB (schema.ts already seeds the "
461
+ + "new names) is a recorded no-op and a re-run finds nothing to do.",
462
+ up(db, ctx) {
463
+ // (1) agents row — INSERT-copy → move children → DELETE old. This
464
+ // order is FK-safe whether or not foreign_keys is ON: the new parent
465
+ // exists before children point at it, and the old parent has no
466
+ // children left when it is deleted (its ON DELETE CASCADE finds
467
+ // nothing).
468
+ if (tableExists(db, "agents")) {
469
+ const oldRow = db
470
+ .prepare("SELECT 1 FROM agents WHERE id = 'hourly-check'")
471
+ .get();
472
+ const newRow = db
473
+ .prepare("SELECT 1 FROM agents WHERE id = 'activity-scan'")
474
+ .get();
475
+ if (oldRow && !newRow) {
476
+ db.prepare(`INSERT INTO agents (
477
+ id, name, description, source, definition_path,
478
+ definition_hash, enabled, enabled_overridden_at, process_key,
479
+ schedule_kind, schedule_expression, schedule_timezone,
480
+ tags_json, stop_warning_json, recurring_schedule_id,
481
+ last_execution_id, metadata_json, created_at, updated_at
482
+ )
483
+ SELECT
484
+ 'activity-scan', 'Activity Scan', description, source,
485
+ replace(definition_path, 'hourly-check', 'activity-scan'),
486
+ definition_hash, enabled, enabled_overridden_at,
487
+ 'routine.activity_scan',
488
+ schedule_kind, schedule_expression, schedule_timezone,
489
+ tags_json, stop_warning_json, recurring_schedule_id,
490
+ last_execution_id, metadata_json, created_at, updated_at
491
+ FROM agents WHERE id = 'hourly-check'`).run();
492
+ if (tableExists(db, "agent_executions")) {
493
+ db.prepare("UPDATE agent_executions SET agent_id = 'activity-scan' WHERE agent_id = 'hourly-check'").run();
494
+ }
495
+ db.prepare("DELETE FROM agents WHERE id = 'hourly-check'").run();
496
+ }
497
+ else if (oldRow && newRow) {
498
+ // Both rows exist — a DB restored from a mixed-version backup
499
+ // (or one that briefly ran a post-rename loader before this
500
+ // migration was recorded). The new row is the live identity the
501
+ // loader maintains; the old row is stale. Re-home its execution
502
+ // history, then drop it — the registry no longer carries
503
+ // 'hourly-check', so nothing would ever clean it up otherwise.
504
+ if (tableExists(db, "agent_executions")) {
505
+ db.prepare("UPDATE agent_executions SET agent_id = 'activity-scan' WHERE agent_id = 'hourly-check'").run();
506
+ }
507
+ db.prepare("DELETE FROM agents WHERE id = 'hourly-check'").run();
508
+ }
509
+ }
510
+ // (2) process_backend_config — the operator's old-key row carries any
511
+ // model/budget overrides; the new-key row at this point can only be
512
+ // the preset applySchema seeded microseconds earlier on this same
513
+ // boot, so deleting it in favour of the renamed old row is lossless.
514
+ if (tableExists(db, "process_backend_config")) {
515
+ const keyPairs = [
516
+ ["routine.hourly_check", "routine.activity_scan"],
517
+ ["routine.hourly_check.triage", "routine.activity_scan.triage"],
518
+ ];
519
+ for (const [oldKey, newKey] of keyPairs) {
520
+ const exists = db
521
+ .prepare("SELECT 1 FROM process_backend_config WHERE process_key = ?")
522
+ .get(oldKey);
523
+ if (!exists)
524
+ continue;
525
+ db.prepare("DELETE FROM process_backend_config WHERE process_key = ?").run(newKey);
526
+ db.prepare("UPDATE process_backend_config SET process_key = ? WHERE process_key = ?").run(newKey, oldKey);
527
+ }
528
+ }
529
+ // (3) settings rows. Literal pairs (a migration is a point-in-time
530
+ // snapshot — do not import the live alias map). Canonical row wins
531
+ // when both exist (the operator already wrote the new key via a
532
+ // post-upgrade PATCH before this migration ran — possible only on
533
+ // DBs restored from mixed-version backups).
534
+ if (tableExists(db, "settings")) {
535
+ const settingPairs = [
536
+ ["hourlyCheckEnabled", "activityScanEnabled"],
537
+ ["hourlyCheckIntervalMinutes", "activityScanIntervalMinutes"],
538
+ ["hourlyCheckActiveStartHour", "activityScanActiveStartHour"],
539
+ ["hourlyCheckActiveEndHour", "activityScanActiveEndHour"],
540
+ ["hourlyCheckMinObservations", "activityScanMinObservations"],
541
+ ["hourlyCheckStage2Enabled", "activityScanStage2Enabled"],
542
+ ["hourlyCheckHeartbeatHours", "activityScanHeartbeatHours"],
543
+ [
544
+ "hourlyCheckLowSignalPendingCeiling",
545
+ "activityScanLowSignalPendingCeiling",
546
+ ],
547
+ [
548
+ "hourlyCheckPrePassFreshnessMinutes",
549
+ "activityScanPrePassFreshnessMinutes",
550
+ ],
551
+ ["hourlyObservationCharBudget", "activityScanObservationCharBudget"],
552
+ ];
553
+ for (const [oldKey, newKey] of settingPairs) {
554
+ const oldExists = db
555
+ .prepare("SELECT 1 FROM settings WHERE key = ?")
556
+ .get(oldKey);
557
+ if (!oldExists)
558
+ continue;
559
+ const newExists = db
560
+ .prepare("SELECT 1 FROM settings WHERE key = ?")
561
+ .get(newKey);
562
+ if (newExists) {
563
+ db.prepare("DELETE FROM settings WHERE key = ?").run(oldKey);
564
+ }
565
+ else {
566
+ db.prepare("UPDATE settings SET key = ? WHERE key = ?").run(newKey, oldKey);
567
+ }
568
+ }
569
+ }
570
+ // (4) self-tuning ledger keys (SELF_TUNING_REVIEW_CYCLE_DESIGN.md §3.4).
571
+ if (tableExists(db, "runtime_state")) {
572
+ const ledgerPairs = [
573
+ [
574
+ "self_tuning:hourlyCheckPrePassFreshnessMinutes",
575
+ "self_tuning:activityScanPrePassFreshnessMinutes",
576
+ ],
577
+ [
578
+ "self_tuning:hourlyCheckLowSignalPendingCeiling",
579
+ "self_tuning:activityScanLowSignalPendingCeiling",
580
+ ],
581
+ ];
582
+ for (const [oldKey, newKey] of ledgerPairs) {
583
+ const oldExists = db
584
+ .prepare("SELECT 1 FROM runtime_state WHERE key = ?")
585
+ .get(oldKey);
586
+ if (!oldExists)
587
+ continue;
588
+ const newExists = db
589
+ .prepare("SELECT 1 FROM runtime_state WHERE key = ?")
590
+ .get(newKey);
591
+ if (newExists) {
592
+ db.prepare("DELETE FROM runtime_state WHERE key = ?").run(oldKey);
593
+ }
594
+ else {
595
+ db.prepare("UPDATE runtime_state SET key = ? WHERE key = ?").run(newKey, oldKey);
596
+ }
597
+ }
598
+ }
599
+ // (5) vault files. Gated per file (old exists, new absent); a vault
600
+ // that never materialized either file is a no-op. Snapshot paths are
601
+ // rewritten so `POST /api/context/snapshots/restore` finds the
602
+ // file's history under its new name.
603
+ //
604
+ // The PRE-RESTRUCTURE spellings (`routines/`, `dossiers/` at the
605
+ // vault root) matter on Obsidian vaults whose 0004 consent is still
606
+ // pending: `resolveVaultRestructureConsent` filters 0004 out of the
607
+ // run list but this migration still runs and records. Renaming the
608
+ // legacy-located files here keeps them aligned, and 0004's
609
+ // `dir-rename` manifest entries (`routines → policies/routines`,
610
+ // `dossiers → knowledge/dossiers`) move the renamed files to their
611
+ // canonical homes when the user eventually consents. Without this,
612
+ // a deferred-consent vault would keep `routines/hourly.md` forever —
613
+ // this migration never re-runs once recorded.
614
+ if (!ctx) {
615
+ throw new Error("Migration 0010-hourly-check-to-activity-scan requires MigrationContext (contextDir); caller passed only db.");
616
+ }
617
+ const fileRenames = [
618
+ ["policies/routines/hourly.md", "policies/routines/activity-scan.md"],
619
+ ["knowledge/dossiers/hourly.md", "knowledge/dossiers/activity-scan.md"],
620
+ ["routines/hourly.md", "routines/activity-scan.md"],
621
+ ["dossiers/hourly.md", "dossiers/activity-scan.md"],
622
+ ];
623
+ for (const [oldRel, newRel] of fileRenames) {
624
+ const oldAbs = join(ctx.contextDir, oldRel);
625
+ const newAbs = join(ctx.contextDir, newRel);
626
+ if (existsSync(oldAbs) && !existsSync(newAbs)) {
627
+ renameSync(oldAbs, newAbs);
628
+ }
629
+ if (tableExists(db, "md_file_snapshots")) {
630
+ db.prepare("UPDATE md_file_snapshots SET file_path = ? WHERE file_path = ?").run(newRel, oldRel);
631
+ }
632
+ }
633
+ },
634
+ },
635
+ {
636
+ id: "0011-research-clusters-journal-enqueue-stamp",
637
+ description: "RESEARCH_CLUSTER_COST_FIX_PLAN.md F1 (v0.1.10→next) — add the "
638
+ + "nullable `journal_update_enqueued_on` column (TEXT, local "
639
+ + "agent-day 'YYYY-MM-DD') to `browser_research_clusters`. The "
640
+ + "day-boundary fan-out stamps it BEFORE enqueueing "
641
+ + "`routine.research_cluster_update`, so a replayed day-boundary "
642
+ + "callback (wake catch-up fires on every detected sleep gap >= 5 "
643
+ + "min — every macOS maintenance DarkWake) can no longer re-enqueue "
644
+ + "the same cluster within one agent day (the 2026-06-11 incident "
645
+ + "fired ~25 runs in ~5h for one cluster). Fresh installs get the "
646
+ + "column from the schema.ts CREATE; this ALTER covers pre-existing "
647
+ + "tables and is gated on columnExists so a fresh DB is a recorded "
648
+ + "no-op.",
649
+ up(db) {
650
+ // Empty-DB safety: columnExists returns false for a missing table,
651
+ // so without this short-circuit a bare :memory: test DB would
652
+ // attempt the ALTER and throw. The runner still records the id.
653
+ if (!tableExists(db, "browser_research_clusters"))
654
+ return;
655
+ if (!columnExists(db, "browser_research_clusters", "journal_update_enqueued_on")) {
656
+ db.exec("ALTER TABLE browser_research_clusters ADD COLUMN journal_update_enqueued_on TEXT");
657
+ }
658
+ },
659
+ },
660
+ {
661
+ id: "0012-research-budget-bump",
662
+ description: "RESEARCH_CLUSTER_COST_FIX_PLAN.md F3 (v0.1.10→next) — raise the "
663
+ + "per-turn budget ceilings for `routine.research_cluster_update` "
664
+ + "($0.05→$0.50) and `routine.research_offer_dm` ($0.02→$0.15) for "
665
+ + "upgrading installs still on the seeded defaults. The SDK budget "
666
+ + "check only fires between turns, and a cold-prompt-cache run "
667
+ + "writes the full session prefix (~$0.13-0.30 observed on Haiku) "
668
+ + "before the check can abort — the old caps killed every cold run "
669
+ + "AFTER the money was spent, so the cluster journal was never "
670
+ + "written (46 runs, zero context writes). Must ship with the F1 "
671
+ + "enqueue stamp (migration 0011): with dedup alone the once-"
672
+ + "nightly run is always cold → always over the old cap → the "
673
+ + "feature stays dead. Backend-aware: applyDefaultPresets stores "
674
+ + "post-hoc-scaled budgets and the lite factor for codex/gemini is "
675
+ + "2.5, so the OLD defaults are $0.05/$0.13 (cluster_update) and "
676
+ + "$0.02/$0.05 (offer_dm) and the NEW values are the bases scaled "
677
+ + "the same way → $0.50/$1.25 and $0.15/$0.38. Fresh installs get "
678
+ + "the new values from the schema seed (cluster_update) + the "
679
+ + "envelope-overrides map (offer_dm has no seed row). Gated so it "
680
+ + "ONLY moves preset rows still in the OLD per-backend band — "
681
+ + "operator-pinned rows (updated_by='user') and rows already at a "
682
+ + "custom value are left untouched. Idempotent: after the bump no "
683
+ + "row sits in the old band, and the recorded id short-circuits a "
684
+ + "re-run anyway.",
685
+ up(db) {
686
+ // Empty-DB safety (e.g. the runner's own unit tests run on a bare
687
+ // :memory: db): if applySchema never ran, the table is absent — the
688
+ // runner still records the id so a later boot does not re-evaluate.
689
+ if (!tableExists(db, "process_backend_config"))
690
+ return;
691
+ // Literals are point-in-time snapshots of base x lite factor
692
+ // (2.5 for codex/gemini, 1 for claude/opencode), mirroring the
693
+ // 0006/0009 template: 0.05 x 2.5 = 0.13 (2-decimal rounded),
694
+ // 0.50 x 2.5 = 1.25, 0.02 x 2.5 = 0.05, 0.15 x 2.5 = 0.38. The
695
+ // ±0.01 bands tolerate float dust without clobbering a row
696
+ // already moved to a custom value.
697
+ db.prepare(`UPDATE process_backend_config
698
+ SET max_budget_usd = CASE
699
+ WHEN main_backend IN ('codex', 'gemini') THEN 1.25
700
+ ELSE 0.5
701
+ END
702
+ WHERE process_key = 'routine.research_cluster_update'
703
+ AND updated_by = 'preset'
704
+ AND (
705
+ (main_backend IN ('codex', 'gemini')
706
+ AND max_budget_usd >= 0.12 AND max_budget_usd <= 0.14)
707
+ OR (main_backend NOT IN ('codex', 'gemini')
708
+ AND max_budget_usd >= 0.04 AND max_budget_usd <= 0.06)
709
+ )`).run();
710
+ db.prepare(`UPDATE process_backend_config
711
+ SET max_budget_usd = CASE
712
+ WHEN main_backend IN ('codex', 'gemini') THEN 0.38
713
+ ELSE 0.15
714
+ END
715
+ WHERE process_key = 'routine.research_offer_dm'
716
+ AND updated_by = 'preset'
717
+ AND (
718
+ (main_backend IN ('codex', 'gemini')
719
+ AND max_budget_usd >= 0.04 AND max_budget_usd <= 0.06)
720
+ OR (main_backend NOT IN ('codex', 'gemini')
721
+ AND max_budget_usd >= 0.01 AND max_budget_usd <= 0.03)
722
+ )`).run();
723
+ },
724
+ },
725
+ {
726
+ id: "0013-browser-task-delivery-timestamps",
727
+ description: "BACKGROUND_TASK_RUNNER_DESIGN.md Phase 1 — add delivered_at recovery "
728
+ + "keys for browser_task reports and browser_task_clarifications so "
729
+ + "task.delivery can recover without double-sending.",
730
+ up(db) {
731
+ if (tableExists(db, "browser_task")
732
+ && !columnExists(db, "browser_task", "delivered_at")) {
733
+ db.exec("ALTER TABLE browser_task ADD COLUMN delivered_at INTEGER");
734
+ }
735
+ if (tableExists(db, "browser_task_clarifications")
736
+ && !columnExists(db, "browser_task_clarifications", "delivered_at")) {
737
+ db.exec("ALTER TABLE browser_task_clarifications ADD COLUMN delivered_at INTEGER");
738
+ }
739
+ },
740
+ },
741
+ {
742
+ id: "0014-background-task-significance-criteria",
743
+ description: "BACKGROUND_TASK_RUNNER_DESIGN.md Phase 4 — add the nullable "
744
+ + "`significance_criteria` column (TEXT, JSON array of concrete "
745
+ + "conditions) to `background_task` for the if_significant criteria "
746
+ + "DSL (§4.3). The DM agent writes structured criteria at spawn; the "
747
+ + "worker checks each against its result and sets notify accordingly. "
748
+ + "Fresh installs get the column from the schema.ts CREATE body; this "
749
+ + "ALTER covers pre-existing tables and is gated on columnExists so a "
750
+ + "fresh DB (and a re-boot) is a recorded no-op.",
751
+ up(db) {
752
+ // Empty-DB safety: columnExists returns false for a missing table,
753
+ // so without this short-circuit a bare :memory: test DB would
754
+ // attempt the ALTER and throw. The runner still records the id.
755
+ if (!tableExists(db, "background_task"))
756
+ return;
757
+ if (!columnExists(db, "background_task", "significance_criteria")) {
758
+ db.exec("ALTER TABLE background_task ADD COLUMN significance_criteria TEXT");
759
+ }
760
+ },
761
+ },
432
762
  ];
433
763
  /**
434
764
  * Ensure the `schema_migrations` bookkeeping table exists, then apply every
@@ -140,7 +140,7 @@ export declare function getSummaryStatusCounts(db: Database.Database): Record<Su
140
140
  /**
141
141
  * Distribution of `novelty_score` values across pending observations
142
142
  * with `summary_status='done'`. Drives the dashboard novelty-histogram
143
- * card and the hourly_check fetch-rate evaluation.
143
+ * card and the activity_scan fetch-rate evaluation.
144
144
  */
145
145
  export declare function getNoveltyDistribution(db: Database.Database): {
146
146
  score: 0 | 1 | 2 | 3;
@@ -170,7 +170,7 @@ export declare function updateObservationSummary(db: Database.Database, params:
170
170
  /**
171
171
  * Count pending observations that are older than `olderThanDays`.
172
172
  *
173
- * Pending observations are intentionally never auto-deleted (the hourly_check
173
+ * Pending observations are intentionally never auto-deleted (the activity_scan
174
174
  * dispatcher is the only consumer; silently dropping them would hide
175
175
  * operational bugs). However, if a row stays pending for many days it usually
176
176
  * indicates that the dispatcher is consistently below threshold or otherwise
@@ -71,7 +71,7 @@ export function recordObservation(db, params) {
71
71
  // excluded.change_type` actually corrects the stored row. Otherwise
72
72
  // a daemon write first recorded as actor='user'/'unknown' (before
73
73
  // AgentWriteTracker/isMarked flipped it) would stay mis-attributed
74
- // and hourly_check would count it as user activity.
74
+ // and activity_scan would count it as user activity.
75
75
  if (existingHash === incomingHash &&
76
76
  existing.actor === actor &&
77
77
  existing.change_type === params.changeType) {
@@ -321,7 +321,7 @@ export function getSummaryStatusCounts(db) {
321
321
  /**
322
322
  * Distribution of `novelty_score` values across pending observations
323
323
  * with `summary_status='done'`. Drives the dashboard novelty-histogram
324
- * card and the hourly_check fetch-rate evaluation.
324
+ * card and the activity_scan fetch-rate evaluation.
325
325
  */
326
326
  export function getNoveltyDistribution(db) {
327
327
  const rows = db.prepare(`SELECT novelty_score AS score, COUNT(*) AS count
@@ -369,7 +369,7 @@ export function updateObservationSummary(db, params) {
369
369
  /**
370
370
  * Count pending observations that are older than `olderThanDays`.
371
371
  *
372
- * Pending observations are intentionally never auto-deleted (the hourly_check
372
+ * Pending observations are intentionally never auto-deleted (the activity_scan
373
373
  * dispatcher is the only consumer; silently dropping them would hide
374
374
  * operational bugs). However, if a row stays pending for many days it usually
375
375
  * indicates that the dispatcher is consistently below threshold or otherwise