@aitne/daemon 0.1.9 → 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 (333) 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.d.ts +1 -0
  15. package/dist/api/env-writer.js +17 -7
  16. package/dist/api/helpers/agent-errors-registry.d.ts +5 -5
  17. package/dist/api/helpers/agent-errors-registry.js +5 -5
  18. package/dist/api/routes/agent-schedule.js +5 -1
  19. package/dist/api/routes/agent.js +33 -12
  20. package/dist/api/routes/agents/index.js +75 -16
  21. package/dist/api/routes/agents/views.d.ts +37 -2
  22. package/dist/api/routes/agents/views.js +64 -2
  23. package/dist/api/routes/apple-calendar.js +4 -1
  24. package/dist/api/routes/background-task.d.ts +22 -0
  25. package/dist/api/routes/background-task.js +338 -0
  26. package/dist/api/routes/browser-history.js +9 -1
  27. package/dist/api/routes/calendar.js +12 -2
  28. package/dist/api/routes/context/path-resolve.js +6 -1
  29. package/dist/api/routes/context/permissions.js +12 -2
  30. package/dist/api/routes/context/snapshots.js +0 -3
  31. package/dist/api/routes/context/write.js +3 -17
  32. package/dist/api/routes/dashboard/config.js +58 -12
  33. package/dist/api/routes/dashboard/cost-approvals.js +66 -0
  34. package/dist/api/routes/dashboard/notifications.js +9 -9
  35. package/dist/api/routes/dashboard/oauth-google.js +5 -3
  36. package/dist/api/routes/feedback.d.ts +3 -0
  37. package/dist/api/routes/feedback.js +349 -0
  38. package/dist/api/routes/git.js +10 -3
  39. package/dist/api/routes/github.js +5 -1
  40. package/dist/api/routes/integrations/crud-patch.js +5 -1
  41. package/dist/api/routes/integrations-reconcile.js +2 -2
  42. package/dist/api/routes/mcp.js +65 -13
  43. package/dist/api/routes/notion.d.ts +1 -1
  44. package/dist/api/routes/observations.js +7 -7
  45. package/dist/api/routes/obsidian.d.ts +1 -1
  46. package/dist/api/routes/receipts.js +5 -1
  47. package/dist/api/routes/setup-migrate.js +1 -1
  48. package/dist/api/routes/setup.js +1 -1
  49. package/dist/api/routes/task-flows.d.ts +1 -1
  50. package/dist/api/routes/task-flows.js +1 -1
  51. package/dist/api/routes/tuning.d.ts +29 -0
  52. package/dist/api/routes/tuning.js +304 -0
  53. package/dist/api/server.d.ts +44 -16
  54. package/dist/api/server.js +12 -0
  55. package/dist/bootstrap/adapters.d.ts +19 -0
  56. package/dist/bootstrap/adapters.js +61 -0
  57. package/dist/bootstrap/api.d.ts +5 -3
  58. package/dist/bootstrap/api.js +45 -13
  59. package/dist/bootstrap/catchup.d.ts +1 -1
  60. package/dist/bootstrap/catchup.js +11 -11
  61. package/dist/bootstrap/event-pipeline.d.ts +11 -0
  62. package/dist/bootstrap/event-pipeline.js +246 -8
  63. package/dist/bootstrap/observers.js +9 -6
  64. package/dist/bootstrap/schedule-helpers.d.ts +104 -6
  65. package/dist/bootstrap/schedule-helpers.js +172 -19
  66. package/dist/config.js +32 -12
  67. package/dist/core/agent-core.d.ts +33 -1
  68. package/dist/core/agent-core.js +36 -1
  69. package/dist/core/agents/activity-scan-cadence.d.ts +103 -0
  70. package/dist/core/agents/activity-scan-cadence.js +127 -0
  71. package/dist/core/agents/agent-route-override.d.ts +53 -0
  72. package/dist/core/agents/agent-route-override.js +69 -0
  73. package/dist/core/agents/builtin-registry.d.ts +51 -14
  74. package/dist/core/agents/builtin-registry.js +92 -15
  75. package/dist/core/agents/config-gate-reconcile.d.ts +38 -0
  76. package/dist/core/agents/config-gate-reconcile.js +51 -0
  77. package/dist/core/agents/cron-substitute.d.ts +1 -1
  78. package/dist/core/agents/cron-substitute.js +1 -1
  79. package/dist/core/agents/custom-routine-migration.d.ts +60 -0
  80. package/dist/core/agents/custom-routine-migration.js +149 -0
  81. package/dist/core/agents/firing-blocked.d.ts +1 -1
  82. package/dist/core/agents/hourly-cadence.d.ts +102 -0
  83. package/dist/core/agents/hourly-cadence.js +126 -0
  84. package/dist/core/agents/loader-boot.js +23 -0
  85. package/dist/core/agents/loader.d.ts +19 -0
  86. package/dist/core/agents/loader.js +34 -2
  87. package/dist/core/agents/override-merge.d.ts +1 -1
  88. package/dist/core/agents/override-merge.js +9 -1
  89. package/dist/core/agents/recurrence-convert.d.ts +1 -1
  90. package/dist/core/agents/recurrence-convert.js +1 -1
  91. package/dist/core/agents/recurring-schedule-adapter.js +8 -0
  92. package/dist/core/alerts.js +6 -6
  93. package/dist/core/backends/auth-health-monitor.d.ts +2 -2
  94. package/dist/core/backends/auth-health-monitor.js +1 -1
  95. package/dist/core/backends/backend-router.d.ts +27 -1
  96. package/dist/core/backends/backend-router.js +165 -1
  97. package/dist/core/backends/claude-code-core.d.ts +71 -31
  98. package/dist/core/backends/claude-code-core.js +282 -54
  99. package/dist/core/backends/cli-quota-guards.d.ts +29 -1
  100. package/dist/core/backends/cli-quota-guards.js +40 -5
  101. package/dist/core/backends/codex-core.d.ts +6 -0
  102. package/dist/core/backends/codex-core.js +22 -6
  103. package/dist/core/backends/failure-spend.d.ts +58 -0
  104. package/dist/core/backends/failure-spend.js +137 -0
  105. package/dist/core/backends/gemini-cli-core.d.ts +6 -0
  106. package/dist/core/backends/gemini-cli-core.js +38 -6
  107. package/dist/core/backends/model-registry.d.ts +1 -1
  108. package/dist/core/backends/model-registry.js +4 -4
  109. package/dist/core/backends/opencode-core.d.ts +1 -1
  110. package/dist/core/backends/opencode-core.js +5 -5
  111. package/dist/core/backends/plan-presets.js +47 -18
  112. package/dist/core/bang-commands/commands-cost.js +3 -1
  113. package/dist/core/bang-commands/commands-report.js +4 -3
  114. package/dist/core/bang-commands/commands-research.js +4 -1
  115. package/dist/core/bang-commands/commands-revert-tuning.d.ts +18 -0
  116. package/dist/core/bang-commands/commands-revert-tuning.js +63 -0
  117. package/dist/core/bang-commands/commands-stop-start.js +3 -3
  118. package/dist/core/bang-commands/commands-task-control.d.ts +19 -0
  119. package/dist/core/bang-commands/commands-task-control.js +147 -0
  120. package/dist/core/bang-commands/commands-wiki.js +5 -5
  121. package/dist/core/bang-commands/index.d.ts +2 -0
  122. package/dist/core/bang-commands/index.js +12 -0
  123. package/dist/core/bang-commands/registry.d.ts +12 -0
  124. package/dist/core/browser-history/research-cluster-fanout.d.ts +28 -14
  125. package/dist/core/browser-history/research-cluster-fanout.js +39 -16
  126. package/dist/core/channel-timeline.d.ts +5 -1
  127. package/dist/core/channel-timeline.js +13 -0
  128. package/dist/core/context/index-reconciler.js +5 -2
  129. package/dist/core/context/policy-index-reconciler.d.ts +6 -4
  130. package/dist/core/context/policy-index-runner.js +25 -6
  131. package/dist/core/context-builder-calendar.js +10 -2
  132. package/dist/core/context-builder-conversation.d.ts +8 -1
  133. package/dist/core/context-builder-conversation.js +41 -7
  134. package/dist/core/context-builder-yesterday.js +4 -3
  135. package/dist/core/context-builder.d.ts +7 -2
  136. package/dist/core/context-builder.js +193 -5
  137. package/dist/core/context-file-serializer.d.ts +1 -1
  138. package/dist/core/context-file-serializer.js +1 -1
  139. package/dist/core/context-health.js +2 -2
  140. package/dist/core/context-paths.d.ts +11 -1
  141. package/dist/core/context-paths.js +17 -1
  142. package/dist/core/context-validation/prepare-write.js +1 -1
  143. package/dist/core/context-validation/routine-rulebook.d.ts +1 -1
  144. package/dist/core/context-vault-aliases.d.ts +0 -13
  145. package/dist/core/context-vault-aliases.js +37 -0
  146. package/dist/core/custom-routines.d.ts +99 -0
  147. package/dist/core/custom-routines.js +187 -0
  148. package/dist/core/daemon-api-cli.js +50 -1
  149. package/dist/core/day-boundary.d.ts +46 -0
  150. package/dist/core/day-boundary.js +40 -0
  151. package/dist/core/dispatcher-activity-scan.d.ts +221 -0
  152. package/dist/core/dispatcher-activity-scan.js +775 -0
  153. package/dist/core/dispatcher-error-handling.d.ts +6 -11
  154. package/dist/core/dispatcher-error-handling.js +38 -62
  155. package/dist/core/dispatcher-hourly-check.js +6 -1
  156. package/dist/core/dispatcher-message-handler.d.ts +10 -0
  157. package/dist/core/dispatcher-message-handler.js +24 -0
  158. package/dist/core/dispatcher-morning-routine.d.ts +6 -6
  159. package/dist/core/dispatcher-morning-routine.js +13 -13
  160. package/dist/core/dispatcher-result-processor.d.ts +33 -0
  161. package/dist/core/dispatcher-result-processor.js +167 -11
  162. package/dist/core/dispatcher-scheduled-background-task.d.ts +42 -0
  163. package/dist/core/dispatcher-scheduled-background-task.js +89 -0
  164. package/dist/core/dispatcher-scheduled-tasks.d.ts +104 -1
  165. package/dist/core/dispatcher-scheduled-tasks.js +480 -8
  166. package/dist/core/dispatcher-task-delivery.d.ts +105 -0
  167. package/dist/core/dispatcher-task-delivery.js +555 -0
  168. package/dist/core/dispatcher-types.d.ts +48 -9
  169. package/dist/core/dispatcher-types.js +3 -3
  170. package/dist/core/dispatcher.d.ts +112 -31
  171. package/dist/core/dispatcher.js +297 -60
  172. package/dist/core/dm-freshness-metrics.d.ts +1 -1
  173. package/dist/core/drift-effects.js +2 -2
  174. package/dist/core/feedback/consolidation-prep.d.ts +94 -0
  175. package/dist/core/feedback/consolidation-prep.js +254 -0
  176. package/dist/core/feedback/eviction-scorer.d.ts +81 -0
  177. package/dist/core/feedback/eviction-scorer.js +136 -0
  178. package/dist/core/feedback/lesson-format.d.ts +79 -0
  179. package/dist/core/feedback/lesson-format.js +199 -0
  180. package/dist/core/feedback/lesson-injection.d.ts +98 -0
  181. package/dist/core/feedback/lesson-injection.js +174 -0
  182. package/dist/core/feedback/lesson-merge.d.ts +51 -0
  183. package/dist/core/feedback/lesson-merge.js +88 -0
  184. package/dist/core/feedback/lesson-store-overview.d.ts +46 -0
  185. package/dist/core/feedback/lesson-store-overview.js +42 -0
  186. package/dist/core/feedback/promotion-gate.d.ts +69 -0
  187. package/dist/core/feedback/promotion-gate.js +117 -0
  188. package/dist/core/feedback/regeneralization-prep.d.ts +87 -0
  189. package/dist/core/feedback/regeneralization-prep.js +152 -0
  190. package/dist/core/feedback/scope-parser.d.ts +86 -0
  191. package/dist/core/feedback/scope-parser.js +141 -0
  192. package/dist/core/feedback/self-performance-prep.d.ts +186 -0
  193. package/dist/core/feedback/self-performance-prep.js +541 -0
  194. package/dist/core/feedback/tuning-actuator.d.ts +198 -0
  195. package/dist/core/feedback/tuning-actuator.js +432 -0
  196. package/dist/core/feedback/tuning-recommender.d.ts +247 -0
  197. package/dist/core/feedback/tuning-recommender.js +580 -0
  198. package/dist/core/feedback/tuning-revert-monitor.d.ts +90 -0
  199. package/dist/core/feedback/tuning-revert-monitor.js +213 -0
  200. package/dist/core/health-monitor.d.ts +6 -0
  201. package/dist/core/health-monitor.js +1 -1
  202. package/dist/core/injection-policy.d.ts +83 -1
  203. package/dist/core/injection-policy.js +61 -3
  204. package/dist/core/integration-main-backend.js +4 -0
  205. package/dist/core/management-md.d.ts +2 -2
  206. package/dist/core/management-md.js +51 -13
  207. package/dist/core/morning/orchestrator.d.ts +2 -2
  208. package/dist/core/morning/orchestrator.js +2 -2
  209. package/dist/core/notification-gate.d.ts +64 -0
  210. package/dist/core/notification-gate.js +51 -0
  211. package/dist/core/notification-rate-limit.d.ts +40 -0
  212. package/dist/core/notification-rate-limit.js +50 -0
  213. package/dist/core/policy-files.d.ts +1 -1
  214. package/dist/core/policy-files.js +2 -2
  215. package/dist/core/pre-pass-freshness.d.ts +4 -4
  216. package/dist/core/retention.d.ts +5 -0
  217. package/dist/core/retention.js +20 -4
  218. package/dist/core/review-context.d.ts +1 -1
  219. package/dist/core/review-context.js +10 -5
  220. package/dist/core/roadmap-write-lock.d.ts +2 -1
  221. package/dist/core/roadmap-write-lock.js +15 -10
  222. package/dist/core/routine-acquisition-plan.d.ts +47 -1
  223. package/dist/core/routine-acquisition-plan.js +78 -20
  224. package/dist/core/routine-fetch-window-retry.js +7 -4
  225. package/dist/core/routine-fetch-window-runner.d.ts +39 -3
  226. package/dist/core/routine-fetch-window-runner.js +264 -13
  227. package/dist/core/routine-windows.d.ts +2 -2
  228. package/dist/core/routine-windows.js +8 -5
  229. package/dist/core/scheduler.d.ts +175 -16
  230. package/dist/core/scheduler.js +559 -102
  231. package/dist/core/signal-detector.d.ts +51 -1
  232. package/dist/core/signal-detector.js +321 -24
  233. package/dist/core/skills-compiler-denied-tools.js +2 -2
  234. package/dist/core/skills-compiler-skill-index.d.ts +2 -2
  235. package/dist/core/skills-compiler-skill-index.js +2 -2
  236. package/dist/core/skills-compiler-variants.d.ts +1 -1
  237. package/dist/core/skills-compiler-variants.js +8 -0
  238. package/dist/core/skills-compiler.d.ts +29 -26
  239. package/dist/core/skills-compiler.js +117 -81
  240. package/dist/core/skills-manifest.d.ts +37 -0
  241. package/dist/core/skills-manifest.js +73 -2
  242. package/dist/core/sleep-inhibitor.d.ts +79 -0
  243. package/dist/core/sleep-inhibitor.js +132 -0
  244. package/dist/core/slim-system-prompt-loader.d.ts +77 -0
  245. package/dist/core/slim-system-prompt-loader.js +141 -0
  246. package/dist/core/spawn-gates.d.ts +126 -0
  247. package/dist/core/spawn-gates.js +180 -0
  248. package/dist/core/today-direct-writer.d.ts +60 -14
  249. package/dist/core/today-direct-writer.js +90 -13
  250. package/dist/core/today-write-lock.d.ts +4 -2
  251. package/dist/core/today-write-lock.js +30 -20
  252. package/dist/core/wake-detector.d.ts +55 -0
  253. package/dist/core/wake-detector.js +80 -0
  254. package/dist/core/wiki/compile-lock.d.ts +1 -1
  255. package/dist/core/wiki/compile-lock.js +1 -1
  256. package/dist/core/wiki/wiki-fts.js +13 -6
  257. package/dist/core/workdir.js +15 -6
  258. package/dist/db/activity-scan-signals.d.ts +77 -0
  259. package/dist/db/activity-scan-signals.js +378 -0
  260. package/dist/db/agents-store.d.ts +28 -0
  261. package/dist/db/agents-store.js +62 -0
  262. package/dist/db/background-task-clarifications-store.d.ts +81 -0
  263. package/dist/db/background-task-clarifications-store.js +152 -0
  264. package/dist/db/background-task-store.d.ts +207 -0
  265. package/dist/db/background-task-store.js +380 -0
  266. package/dist/db/browser-history-store.d.ts +39 -6
  267. package/dist/db/browser-history-store.js +51 -7
  268. package/dist/db/browser-task-clarifications-store.d.ts +12 -0
  269. package/dist/db/browser-task-clarifications-store.js +35 -5
  270. package/dist/db/browser-task-store.d.ts +3 -0
  271. package/dist/db/browser-task-store.js +29 -4
  272. package/dist/db/deferred-dm.d.ts +86 -0
  273. package/dist/db/deferred-dm.js +199 -0
  274. package/dist/db/feedback-signals-store.d.ts +77 -0
  275. package/dist/db/feedback-signals-store.js +144 -0
  276. package/dist/db/migrations.js +380 -0
  277. package/dist/db/observations.d.ts +2 -2
  278. package/dist/db/observations.js +3 -3
  279. package/dist/db/schema.js +260 -22
  280. package/dist/db/voice-transcripts-store.d.ts +1 -1
  281. package/dist/index.js +86 -29
  282. package/dist/messaging/browser-task-mcp-notifier.d.ts +12 -70
  283. package/dist/messaging/browser-task-mcp-notifier.js +30 -151
  284. package/dist/messaging/browser-task-screenshot-attachment.d.ts +15 -0
  285. package/dist/messaging/browser-task-screenshot-attachment.js +63 -0
  286. package/dist/observers/delegated-sync-worker.d.ts +6 -6
  287. package/dist/observers/delegated-sync-worker.js +10 -10
  288. package/dist/observers/git-delegated-cron.d.ts +1 -1
  289. package/dist/observers/git-delegated-cron.js +2 -2
  290. package/dist/observers/github-poller-classifier.d.ts +3 -3
  291. package/dist/observers/github-poller-classifier.js +3 -3
  292. package/dist/observers/imminent-event-scheduler.d.ts +1 -1
  293. package/dist/observers/imminent-event-scheduler.js +1 -1
  294. package/dist/observers/mail-poller.d.ts +1 -0
  295. package/dist/observers/mail-poller.js +42 -3
  296. package/dist/observers/observation-summarizer/summarizer-client.d.ts +2 -2
  297. package/dist/observers/observation-summarizer/summarizer-client.js +2 -2
  298. package/dist/observers/observation-summarizer/worker.d.ts +2 -2
  299. package/dist/observers/observation-summarizer/worker.js +4 -4
  300. package/dist/observers/obsidian-watcher.d.ts +1 -1
  301. package/dist/observers/obsidian-watcher.js +1 -1
  302. package/dist/safety/agent-write-tracker.d.ts +4 -4
  303. package/dist/safety/agent-write-tracker.js +4 -4
  304. package/dist/safety/always-disallowed.d.ts +1 -1
  305. package/dist/safety/always-disallowed.js +39 -0
  306. package/dist/safety/audit.d.ts +43 -5
  307. package/dist/safety/audit.js +86 -18
  308. package/dist/safety/risk-classifier.d.ts +6 -0
  309. package/dist/safety/risk-classifier.js +97 -18
  310. package/dist/scheduler/activity-scan-gate.d.ts +86 -0
  311. package/dist/scheduler/activity-scan-gate.js +132 -0
  312. package/dist/services/background-task/background-task-budget.d.ts +80 -0
  313. package/dist/services/background-task/background-task-budget.js +91 -0
  314. package/dist/services/background-task/background-task-driver.d.ts +105 -0
  315. package/dist/services/background-task/background-task-driver.js +416 -0
  316. package/dist/services/background-task/background-task-runner.d.ts +96 -0
  317. package/dist/services/background-task/background-task-runner.js +673 -0
  318. package/dist/services/background-task/background-task-tools.d.ts +84 -0
  319. package/dist/services/background-task/background-task-tools.js +247 -0
  320. package/dist/services/background-task/background-task-transition-events.d.ts +43 -0
  321. package/dist/services/background-task/background-task-transition-events.js +54 -0
  322. package/dist/services/browser-history/automation/egress-denylist.d.ts +1 -1
  323. package/dist/services/browser-history/automation/egress-denylist.js +34 -8
  324. package/dist/services/browser-history/lifecycle/platform.js +44 -2
  325. package/dist/services/browser-history/managed-chromium/sandbox-launcher.js +0 -1
  326. package/dist/services/browser-task/browser-task-runner.js +53 -8
  327. package/dist/services/mcp/probe.js +30 -8
  328. package/dist/services/observations-batch.d.ts +1 -1
  329. package/dist/services/observations-batch.js +2 -2
  330. package/dist/settings/runtime-settings.d.ts +45 -12
  331. package/dist/settings/runtime-settings.js +215 -40
  332. package/dist/settings/settings-store.js +11 -3
  333. package/package.json +4 -4
@@ -42,10 +42,13 @@ import { isAgentTaskEvent, isDocsQAMessage, isMessageEvent, isRoutineEvent, isSc
42
42
  import { getContextDir } from "../config.js";
43
43
  import { finalizeRetemplate } from "./template-store.js";
44
44
  import { recordManagementInitDone, recordManagementScan, } from "../db/repositories-store.js";
45
- import { formatForwardSuffix, getProactiveForwardType, isProactiveForwardMetadata, parseMessageMetadata, recordProactiveForwardDeliveries, } from "./channel-timeline.js";
45
+ import { formatForwardSuffix, isProactiveForwardMetadata, parseMessageMetadata, recordProactiveForwardDeliveries, } from "./channel-timeline.js";
46
46
  import { randomUUID } from "node:crypto";
47
+ import { statSync } from "node:fs";
48
+ import { join } from "node:path";
47
49
  import { OWNER_DM_SCOPE, OWNER_SCOPE_KEY, DASHBOARD_CHAT_SCOPE, DASHBOARD_SCOPE_KEY, getConversationScope, } from "../messaging/constants.js";
48
50
  import { readEventReplyTarget } from "./wiki/dispatcher.js";
51
+ import { TASK_DELIVERY_ATTACHMENTS_KEY } from "./dispatcher-task-delivery.js";
49
52
  import { createLogger } from "../logging.js";
50
53
  import { assertOutboundAllowedForAgent, OutboundPurchaseTemplateError, } from "../safety/outbound-purchase-guard.js";
51
54
  const logger = createLogger("dispatcher-result");
@@ -138,6 +141,16 @@ export class ResultProcessor {
138
141
  threadId: explicitReply.threadId ?? null,
139
142
  };
140
143
  }
144
+ // BACKGROUND_TASK_RUNNER_DESIGN.md Phase 1 (delivery assets) — the
145
+ // task.delivery active turn is a no-tool DM turn, so the daemon (not
146
+ // the agent) attaches any deliverable files the task produced. The
147
+ // delivery handler resolved them and stashed the refs on the
148
+ // synthetic event; carry them onto the woven reply send. Only ever
149
+ // populated for the synthetic scheduled.dm delivery event.
150
+ const deliveryAttachments = readTaskDeliveryAttachments(event);
151
+ if (deliveryAttachments.length > 0 && explicitReply) {
152
+ sendOptions.attachments = deliveryAttachments;
153
+ }
141
154
  // MANAGED_CHROMIUM_IMPLEMENTATION_PLAN.md §17.7 structural-anti-
142
155
  // spoofing layer. The LLM's outbound text reaches the messaging
143
156
  // adapter via this notificationMgr.send chokepoint; refuse any
@@ -189,6 +202,7 @@ export class ResultProcessor {
189
202
  // the send itself, so wrap in try/catch.
190
203
  if (explicitReply && output.length > 0) {
191
204
  try {
205
+ const taskDeliveryRecord = readTaskDeliveryRecord(event);
192
206
  recordProactiveForwardDeliveries({
193
207
  db: this.db,
194
208
  config: this.config,
@@ -203,7 +217,10 @@ export class ResultProcessor {
203
217
  ...(options.originSessionId !== undefined
204
218
  ? { originSessionIds: [options.originSessionId] }
205
219
  : {}),
206
- notificationType: "proactive_forward",
220
+ notificationType: taskDeliveryRecord?.notificationType ?? "proactive_forward",
221
+ ...(taskDeliveryRecord
222
+ ? { extraMetadata: taskDeliveryRecord.metadata }
223
+ : {}),
207
224
  });
208
225
  }
209
226
  catch (err) {
@@ -213,6 +230,24 @@ export class ResultProcessor {
213
230
  }
214
231
  }
215
232
  }
233
+ // RESEARCH_CLUSTER_COST_FIX_PLAN F5 — outcome verification. The
234
+ // routine.research_cluster_update flow's ONLY deliverable is the
235
+ // per-cluster journal at context/research/<slug>.md. The 2026-06-11
236
+ // incident showed the flow ending "successfully" (no backend error,
237
+ // num_turns=1) while never writing the file — every "success" was a
238
+ // text-only narration. Upgrade "success" from "the session ended
239
+ // without a backend error" to "...AND the journal was written this
240
+ // run": a clean-but-unwritten run is recorded as `partial` /
241
+ // `journal_write_missing` (surfaced in the dashboard activity feed,
242
+ // `!report`, and `aitne audit --result partial`) rather than a
243
+ // misleading success. Gated to clean runs — a hard error already took
244
+ // the logError path with a more informative message.
245
+ const outcomeOverride = isRoutineEvent(event)
246
+ && event.routine === "research_cluster_update"
247
+ && !result.isError
248
+ && !this.researchClusterJournalWritten(event, result)
249
+ ? { result: "partial", error: "journal_write_missing" }
250
+ : undefined;
216
251
  this.audit.logAction({
217
252
  event,
218
253
  model: result.model,
@@ -226,6 +261,7 @@ export class ResultProcessor {
226
261
  costSource: result.costSource,
227
262
  contextUpdated: result.contextUpdated,
228
263
  advisorCallCount: result.advisorCallCount,
264
+ ...(outcomeOverride ?? {}),
229
265
  ...(options.dmFreshness ? { dmFreshness: options.dmFreshness } : {}),
230
266
  ...(options.dailyWrite ? { dailyWrite: options.dailyWrite } : {}),
231
267
  });
@@ -249,7 +285,7 @@ export class ResultProcessor {
249
285
  // - github.* (GitHub poller high-priority events)
250
286
  // - git.* (git watcher batched events)
251
287
  // - notion.* (notion poller)
252
- // - routine.hourly_check (Phase-9 polling sink for obsidian/git/notion)
288
+ // - routine.activity_scan (Phase-9 polling sink for obsidian/git/notion)
253
289
  if (this.isObserverEvent(event)) {
254
290
  logger.info({
255
291
  eventType: event.type,
@@ -450,13 +486,9 @@ export class ResultProcessor {
450
486
  if (message.role !== "assistant")
451
487
  return message.role;
452
488
  const metadata = parseMessageMetadata(message.metadata);
453
- const type = getProactiveForwardType(metadata);
454
- if (type === "scheduled_dm") {
455
- return "assistant (scheduled DM dispatched)";
456
- }
457
- if (type !== null) {
458
- return "assistant (forwarded from autonomous run)";
459
- }
489
+ const suffix = formatForwardSuffix(metadata);
490
+ if (suffix.length > 0)
491
+ return `assistant${suffix}`;
460
492
  return message.role;
461
493
  }
462
494
  buildCrossSessionConversationHistory(event) {
@@ -546,13 +578,91 @@ export class ResultProcessor {
546
578
  * contextUpdated observability log in processResult.
547
579
  */
548
580
  isObserverEvent(event) {
549
- return ((isRoutineEvent(event) && event.routine === "hourly_check") ||
581
+ return ((isRoutineEvent(event) && event.routine === "activity_scan") ||
550
582
  event.type.startsWith("calendar.") ||
551
583
  event.type === "schedule.approaching" ||
552
584
  event.type.startsWith("notion.") ||
553
585
  event.type.startsWith("github.") ||
554
586
  event.type.startsWith("git."));
555
587
  }
588
+ /**
589
+ * RESEARCH_CLUSTER_COST_FIX_PLAN F5 — was the cluster journal actually
590
+ * written during this `routine.research_cluster_update` run?
591
+ *
592
+ * Detection is the on-disk journal file itself — the authoritative,
593
+ * path-specific, backend-agnostic signal. The daemon writes the journal
594
+ * via the context-API chokepoint (`writeFileAtomically`), so the file's
595
+ * mtime reflects the real write time; a write that landed inside the run
596
+ * window (`[min(event enqueue, now − durationMs) − buffer, now]`) proves
597
+ * the agent executed the append rather than narrating success.
598
+ *
599
+ * Why not the `context_write` audit row (the plan's first idea): that
600
+ * row is emitted only inside `notifyPromptContextChanged`, which fires
601
+ * solely for prompt-refreshing paths (`shouldRefreshPromptContext`).
602
+ * `research/*` is intentionally a *quiet* namespace — it never triggers
603
+ * a refresh — so a research write records **no** `context_write` row.
604
+ * (The plan's §1 "zero context_write rows ⇒ zero writes" inference was
605
+ * therefore unsound for this namespace; the on-disk check has none of
606
+ * that coupling.) F1 guarantees ≤ 1 cluster_update run/cluster/day, so
607
+ * the run window cannot collide with another run writing the same file;
608
+ * the sibling research flows write *different* files
609
+ * (`<slug>-assistance-<date>.md`, `<slug>-wiki.md`), never `<slug>.md`.
610
+ *
611
+ * Returns `true` (treat as written — do NOT downgrade) when the slug is
612
+ * absent/invalid or the stat fails for any reason other than ENOENT: a
613
+ * verification fault must never relabel a genuinely-successful run.
614
+ */
615
+ researchClusterJournalWritten(event, result) {
616
+ const data = (event.data ?? {});
617
+ const slug = typeof data.slug === "string" ? data.slug : null;
618
+ // Defense in depth against path traversal even though the slug comes
619
+ // from the daemon's own cluster table — same sanitized character set
620
+ // the context-API whitelist enforces (PLACEHOLDER_SEGMENT_RE).
621
+ if (!slug || !/^[a-z0-9._-]+$/.test(slug)) {
622
+ logger.warn({ correlationId: event.correlationId, slug }, "research_cluster_update: missing/invalid slug — skipping journal-write verification");
623
+ return true;
624
+ }
625
+ // Resolve the dir WITHOUT the db argument, mirroring the context
626
+ // route's own `getCurrentContextDir` (api/routes/context/index.ts):
627
+ // with `db`, `getContextDir` falls back to the legacy
628
+ // `<dataDir>/context` while the vault is degraded — but the write
629
+ // route never writes there (degraded mode 503s every request), so
630
+ // statting the fallback could mislabel a run that wrote to the real
631
+ // vault just before degraded mode engaged. Always stat the path the
632
+ // agent's writes would have landed at.
633
+ const journalPath = join(getContextDir(this.config), "research", `${slug}.md`);
634
+ // Anchor the window at the event's enqueue time when it is older than
635
+ // `now − durationMs`: `durationMs` covers only the FINAL backend
636
+ // attempt, so a write made during an earlier `executeWithRetry`
637
+ // attempt (or before any dispatcher latency between run end and this
638
+ // check) would otherwise fall outside the window and downgrade a run
639
+ // that DID write. Widening backwards is safe — F1 guarantees at most
640
+ // one run per cluster per agent day and no sibling flow writes
641
+ // `<slug>.md`, so the only possible writer inside the widened window
642
+ // is this run.
643
+ const bufferMs = 5_000;
644
+ const eventCreatedMs = event.timestamp instanceof Date
645
+ ? event.timestamp.getTime()
646
+ : Date.parse(String(event.timestamp));
647
+ const runStartMs = Date.now() - (result.durationMs ?? 0);
648
+ const windowStartMs = (Number.isFinite(eventCreatedMs)
649
+ ? Math.min(eventCreatedMs, runStartMs)
650
+ : runStartMs) - bufferMs;
651
+ try {
652
+ return statSync(journalPath).mtimeMs >= windowStartMs;
653
+ }
654
+ catch (err) {
655
+ if (err.code === "ENOENT") {
656
+ // File never created — the strongest "not written" signal.
657
+ return false;
658
+ }
659
+ /* c8 ignore next 5 — non-ENOENT stat failure (e.g. EACCES) is not
660
+ * reproducible in the test harness; the conservative fall-through
661
+ * (treat as written) is asserted indirectly by the ENOENT path. */
662
+ logger.warn({ err, journalPath, correlationId: event.correlationId }, "research_cluster_update: journal stat failed — skipping verification");
663
+ return true;
664
+ }
665
+ }
556
666
  /**
557
667
  * Confirm that a `wiki.ingest_url` session actually wrote a raw note via
558
668
  * the Wiki API before letting the agent's claimed success DM reach the
@@ -620,3 +730,49 @@ export class ResultProcessor {
620
730
  return `Failed ${url ?? "<url>"} — agent reported completion but no raw note was POSTed via the Wiki API; the vault is unchanged.`;
621
731
  }
622
732
  }
733
+ export function readTaskDeliveryRecord(event) {
734
+ const raw = event.data
735
+ ?.task_delivery_record;
736
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
737
+ return null;
738
+ const record = raw;
739
+ if (record.notificationType !== "task_result"
740
+ && record.notificationType !== "task_clarification"
741
+ // Phase 4 autonomous-forward natural delivery: the active weave turn
742
+ // carries a task_delivery_record whose notificationType is
743
+ // "proactive_forward" (autonomous forwards have no task row, so they
744
+ // reuse the proactive_forward type). Its metadata still tags the woven
745
+ // message with taskKind/deliveredTaskId so `deliverActive`'s
746
+ // message-existence check can confirm the weave landed and skip the
747
+ // verbatim re-send. Without accepting it here the metadata is dropped,
748
+ // the existence check misses, and the owner receives BOTH the woven DM
749
+ // and a verbatim duplicate.
750
+ && record.notificationType !== "proactive_forward") {
751
+ return null;
752
+ }
753
+ const metadata = record.metadata
754
+ && typeof record.metadata === "object"
755
+ && !Array.isArray(record.metadata)
756
+ ? record.metadata
757
+ : {};
758
+ return {
759
+ notificationType: record.notificationType,
760
+ metadata,
761
+ };
762
+ }
763
+ /**
764
+ * Resolved deliverable-file refs the task.delivery handler stashed on the
765
+ * synthetic `scheduled.dm` event (BACKGROUND_TASK_RUNNER_DESIGN.md Phase 1
766
+ * — delivery assets). Returns `[]` for every ordinary event. Shape is
767
+ * validated loosely — a malformed entry is dropped rather than thrown so a
768
+ * bad ref never blocks the woven reply.
769
+ */
770
+ function readTaskDeliveryAttachments(event) {
771
+ const raw = event.data?.[TASK_DELIVERY_ATTACHMENTS_KEY];
772
+ if (!Array.isArray(raw))
773
+ return [];
774
+ return raw.filter((a) => !!a
775
+ && typeof a === "object"
776
+ && typeof a.path === "string"
777
+ && typeof a.id === "string");
778
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Dispatcher handler for `scheduled.background_task`
3
+ * (BACKGROUND_TASK_RUNNER_DESIGN.md §4.2).
4
+ *
5
+ * Lifts fire-time row creation + runner handoff out of `dispatcher.ts`,
6
+ * mirroring `dispatcher-scheduled-browser-task.ts` but with the whole
7
+ * allowlist / site-registry plane removed — a background task carries
8
+ * only a self-contained brief.
9
+ *
10
+ * Flow:
11
+ * 1. Re-validate the persisted `task_context` (a hand-crafted DB row
12
+ * cannot smuggle invalid fields through the scheduler boundary).
13
+ * 2. Dedup on `preGeneratedTaskId` (a scheduler/dispatcher restart
14
+ * between event.put and dispatch must not double-insert).
15
+ * 3. Insert the `background_task` row pinned to the pre-generated id.
16
+ * 4. Hand off to the runner. The runner's RunResult drives the
17
+ * `background_task` lifecycle from here; the `agent_schedule` row's
18
+ * status is independent (the dispatcher marks it completed on
19
+ * successful dispatch, failed on rejection).
20
+ */
21
+ import type Database from "better-sqlite3";
22
+ import type { ScheduledBackgroundTaskEvent } from "@aitne/shared";
23
+ import type { BackgroundTaskRunner } from "../services/background-task/background-task-runner.js";
24
+ export type ScheduledBackgroundTaskOutcome = {
25
+ kind: "dispatched";
26
+ taskId: string;
27
+ } | {
28
+ kind: "task_context_invalid";
29
+ reason: string;
30
+ } | {
31
+ kind: "row_already_exists";
32
+ taskId: string;
33
+ } | {
34
+ kind: "runner_unavailable";
35
+ taskId: string;
36
+ };
37
+ export interface BackgroundTaskDispatchDeps {
38
+ db: Database.Database;
39
+ runner: BackgroundTaskRunner | null;
40
+ nowFn?: () => number;
41
+ }
42
+ export declare function handleScheduledBackgroundTask(deps: BackgroundTaskDispatchDeps, event: ScheduledBackgroundTaskEvent): Promise<ScheduledBackgroundTaskOutcome>;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Dispatcher handler for `scheduled.background_task`
3
+ * (BACKGROUND_TASK_RUNNER_DESIGN.md §4.2).
4
+ *
5
+ * Lifts fire-time row creation + runner handoff out of `dispatcher.ts`,
6
+ * mirroring `dispatcher-scheduled-browser-task.ts` but with the whole
7
+ * allowlist / site-registry plane removed — a background task carries
8
+ * only a self-contained brief.
9
+ *
10
+ * Flow:
11
+ * 1. Re-validate the persisted `task_context` (a hand-crafted DB row
12
+ * cannot smuggle invalid fields through the scheduler boundary).
13
+ * 2. Dedup on `preGeneratedTaskId` (a scheduler/dispatcher restart
14
+ * between event.put and dispatch must not double-insert).
15
+ * 3. Insert the `background_task` row pinned to the pre-generated id.
16
+ * 4. Hand off to the runner. The runner's RunResult drives the
17
+ * `background_task` lifecycle from here; the `agent_schedule` row's
18
+ * status is independent (the dispatcher marks it completed on
19
+ * successful dispatch, failed on rejection).
20
+ */
21
+ import { z } from "zod";
22
+ import { createBackgroundTask, getBackgroundTask, markTerminal, } from "../db/background-task-store.js";
23
+ import { createLogger } from "../logging.js";
24
+ const logger = createLogger("dispatcher-scheduled-background-task");
25
+ const taskContextSchema = z.object({
26
+ preGeneratedTaskId: z.string().uuid(),
27
+ brief: z.string().min(1).max(16_384),
28
+ title: z.string().min(1).max(200).nullable().optional(),
29
+ notificationPolicy: z
30
+ .enum(["always", "if_significant", "silent"])
31
+ .optional(),
32
+ significanceCriteria: z
33
+ .array(z.string().min(1).max(500))
34
+ .max(12)
35
+ .nullable()
36
+ .optional(),
37
+ tier: z.enum(["lite", "medium", "high"]).nullable().optional(),
38
+ maxBudgetUsd: z.number().positive().max(15).nullable().optional(),
39
+ originatingChannel: z.string().nullable().optional(),
40
+ });
41
+ export async function handleScheduledBackgroundTask(deps, event) {
42
+ const now = deps.nowFn ?? (() => Date.now());
43
+ const parsed = taskContextSchema.safeParse(event.taskContext);
44
+ if (!parsed.success) {
45
+ const reason = parsed.error.issues
46
+ .slice(0, 3)
47
+ .map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`)
48
+ .join("; ");
49
+ logger.error({ scheduleId: event.scheduleId, reason }, "scheduled.background_task: task_context failed schema validation");
50
+ return { kind: "task_context_invalid", reason };
51
+ }
52
+ const ctx = parsed.data;
53
+ const existing = getBackgroundTask(deps.db, ctx.preGeneratedTaskId);
54
+ if (existing) {
55
+ logger.warn({ taskId: ctx.preGeneratedTaskId, scheduleId: event.scheduleId, state: existing.state }, "scheduled.background_task: row already exists for preGeneratedTaskId — skipping re-dispatch");
56
+ return { kind: "row_already_exists", taskId: ctx.preGeneratedTaskId };
57
+ }
58
+ createBackgroundTask(deps.db, {
59
+ id: ctx.preGeneratedTaskId,
60
+ brief: ctx.brief,
61
+ title: ctx.title ?? null,
62
+ notificationPolicy: ctx.notificationPolicy ?? "always",
63
+ significanceCriteria: ctx.significanceCriteria ?? null,
64
+ originatingChannel: ctx.originatingChannel ?? null,
65
+ correlationId: event.correlationId ?? null,
66
+ scheduleRowId: event.scheduleId,
67
+ tier: ctx.tier ?? null,
68
+ maxBudgetUsd: ctx.maxBudgetUsd ?? null,
69
+ createdAt: now(),
70
+ });
71
+ if (!deps.runner) {
72
+ markTerminal(deps.db, {
73
+ id: ctx.preGeneratedTaskId,
74
+ state: "failed",
75
+ outcomeDetail: "runner_unavailable",
76
+ finishedAt: now(),
77
+ report: "The background-task runner was not wired at fire time.",
78
+ draft: "That scheduled task couldn't start — the runner was unavailable.",
79
+ notify: true,
80
+ });
81
+ logger.warn({ taskId: ctx.preGeneratedTaskId, scheduleId: event.scheduleId }, "scheduled.background_task: runner not wired — marked failed (runner_unavailable)");
82
+ return { kind: "runner_unavailable", taskId: ctx.preGeneratedTaskId };
83
+ }
84
+ void deps.runner.runFromScheduleRow(ctx.preGeneratedTaskId).catch((err) => {
85
+ logger.error({ err, taskId: ctx.preGeneratedTaskId, scheduleId: event.scheduleId }, "background-task runFromScheduleRow threw — task left in pending state");
86
+ });
87
+ logger.info({ taskId: ctx.preGeneratedTaskId, scheduleId: event.scheduleId }, "scheduled.background_task dispatched to runner");
88
+ return { kind: "dispatched", taskId: ctx.preGeneratedTaskId };
89
+ }
@@ -46,6 +46,7 @@
46
46
  import type Database from "better-sqlite3";
47
47
  import type { AgentTaskEvent, BackendId, Event } from "@aitne/shared";
48
48
  import type { AgentConfig } from "../config.js";
49
+ import type { TodayWriteLockManager } from "./today-write-lock.js";
49
50
  import type { IAgentRouter } from "./backends/backend-router.js";
50
51
  import type { RoadmapWriteLockManager } from "./roadmap-write-lock.js";
51
52
  import type { AgentWriteTracker } from "../safety/agent-write-tracker.js";
@@ -195,6 +196,29 @@ export declare const SKILL_CURATION_OPTIMIZER_ALLOWED_TOOLS: readonly ["Read", "
195
196
  * consciously.
196
197
  */
197
198
  export declare const REFRESH_ARCHITECTURE_ALLOWED_TOOLS: readonly ["Read", "Glob", "Grep", "Bash(curl http://localhost:8321/api/repositories/*/architecture-section*)", "Bash(jq *)"];
199
+ /**
200
+ * BACKGROUND_TASK_RUNNER_DESIGN.md §4.5 / §4.5-bis / Phase 4 — the active
201
+ * delivery turn is a NO-TOOL DM turn. Its sole job is to weave the
202
+ * already-injected artifact (`taskContext.task_delivery.report` carries the
203
+ * full verbatim result) into the live conversation; the agent's reply text
204
+ * IS the DM (recorded by the result processor) and any deliverable files
205
+ * are attached by the daemon, not by the agent. So the turn needs no tools
206
+ * at all — and an EMPTY override structurally prevents it from taking
207
+ * "further action" (spawning another task, writing memory, sending mail)
208
+ * during what should be a pure phrasing turn. Follow-up turns ("what did it
209
+ * find?") are ordinary DM turns and keep the full envelope, including the
210
+ * `GET /api/background-task/:id` read affordance.
211
+ */
212
+ export declare const TASK_DELIVERY_TURN_ALLOWED_TOOLS: readonly string[];
213
+ /**
214
+ * True when `taskCtx` is a synthetic `scheduled.dm` event minted by the
215
+ * task-delivery handler (`createScheduledDmDeliveryEvent`) — the only place
216
+ * that sets the `task_delivery` block. Used to pin the no-tool clamp above.
217
+ * Keying off this structural marker (not `event.source`) is fail-safe: the
218
+ * clamp only ever NARROWS the envelope, so a false positive degrades a turn
219
+ * to no-tool rather than widening anything.
220
+ */
221
+ export declare function isTaskDeliveryTurn(taskCtx: AgentTaskEvent["taskContext"]): boolean;
198
222
  /**
199
223
  * Backends that honor the per-execute `allowedToolsOverride` clamp end-to-
200
224
  * end. Claude consumes the list verbatim through the SDK's `dontAsk` +
@@ -206,6 +230,14 @@ export declare const REFRESH_ARCHITECTURE_ALLOWED_TOOLS: readonly ["Read", "Glob
206
230
  * envelope; the operator sees an `agent_actions` row of action_type
207
231
  * `scheduled_task_clamp_unsupported` and a clear log line.
208
232
  *
233
+ * Exception — the Phase-4 task-delivery turn (`isTaskDeliveryTurn`)
234
+ * consumes this same set but DEGRADES rather than refuses: when the
235
+ * resolved backend can't enforce `[]` it still runs the delivery turn
236
+ * with the default envelope (logged), because failing to deliver the
237
+ * owner's result is worse than running the phrasing turn untooled. The
238
+ * clamp is keyed off `binding.main.backendId`, so — as with the refuse
239
+ * path — a runtime fallback to a non-claude backend is not re-evaluated.
240
+ *
209
241
  * Add a backend here only after verifying its core threads
210
242
  * `allowedToolsOverride` through to its concrete deny enforcement layer
211
243
  * — NOT just into the CLI flag set.
@@ -226,12 +258,21 @@ export interface ScheduledTaskRunnerDeps {
226
258
  * in `ROUTINE_WINDOWS` (today_refresh / evening_review / weekly_review;
227
259
  * monthly_review is registered but has zero rows so the runner
228
260
  * short-circuits without dispatching a session). Idempotent against
229
- * the morning_routine + hourly_check paths: when the upstream
261
+ * the morning_routine + activity_scan paths: when the upstream
230
262
  * dispatcher already attached a `fetchReportBlock`, `executeDefault`
231
263
  * skips re-running the pre-pass.
232
264
  */
233
265
  fetchWindowRunner: RoutineFetchWindowRunner;
234
266
  roadmapWriteLock: RoadmapWriteLockManager | undefined;
267
+ /**
268
+ * Cross-session today.md write lock. Used by `executeDefault` to seed a
269
+ * `today.md` skeleton (lock-aware, absent-only) before a
270
+ * `routine.today_refresh` session so its section PATCH never 404s — see
271
+ * `ensureTodaySkeleton`. Undefined when the dispatcher was constructed
272
+ * without a lock (tests / degraded boot), in which case the seed is
273
+ * skipped and the pre-existing behaviour is preserved.
274
+ */
275
+ todayWriteLock: TodayWriteLockManager | undefined;
235
276
  writeTracker: AgentWriteTracker | undefined;
236
277
  /**
237
278
  * Returns the dispatcher's currently-configured "services" the
@@ -271,6 +312,7 @@ export declare class ScheduledTaskRunner {
271
312
  private readonly morningRoutine;
272
313
  private readonly fetchWindowRunner;
273
314
  private readonly roadmapWriteLock;
315
+ private readonly todayWriteLock;
274
316
  private readonly writeTracker;
275
317
  private readonly getConfiguredServices;
276
318
  private readonly getActiveMailAccounts;
@@ -440,6 +482,67 @@ export declare class ScheduledTaskRunner {
440
482
  * the journal line is the defensive trace.
441
483
  */
442
484
  private runWeeklyInterestsReflectionPreHook;
485
+ /**
486
+ * FEEDBACK_LEARNING_LOOP_DESIGN.md §4 — the deterministic consolidation
487
+ * pre-step. Reads unconsumed `feedback_signals` (user + agent + `agent:<slug>`
488
+ * scope as of Phase 4), reads each lessons store's current contents, and
489
+ * composes the `<feedback_worksheet>` block via the pure `core/feedback/*`
490
+ * modules. Returns the block string, or `null` when feedback learning is off,
491
+ * nothing pends, or anything throws — so the caller simply skips stamping and
492
+ * the evening review proceeds unchanged.
493
+ *
494
+ * The DB read + per-scope file read live here (the FS-/DB-heavy dispatcher
495
+ * is coverage-excluded); the byte-deterministic worksheet composition lives
496
+ * in `buildFeedbackWorksheet`, which is 100% unit-tested.
497
+ */
498
+ private prepareFeedbackWorksheet;
499
+ /**
500
+ * SELF_TUNING_REVIEW_CYCLE_DESIGN.md §3.1 + §3.2 / Phases 1–2 — the
501
+ * deterministic Measure + Recommend pre-steps. Computes the 7-day window +
502
+ * 7-day-prior baseline SQL aggregates over `agent_actions` /
503
+ * `notification_log` / the `runtime_state.self_tuning:*` ledger, reads each
504
+ * lesson store's byte pressure (§3.5), and composes the
505
+ * `<self_performance>` block via the pure
506
+ * `core/feedback/self-performance-prep.ts` module. The same gathered data
507
+ * then feeds the Phase 2 rule table (`core/feedback/tuning-recommender.ts`):
508
+ * the resulting pending cycle is persisted to
509
+ * `runtime_state.self_tuning.pending_cycle` — overwriting (and thereby
510
+ * expiring, §3.4 single-use ids) the previous cycle even when this week
511
+ * produced zero recommendations — and rendered as the
512
+ * `<tuning_recommendations>` block for the Phase 3c verdict step.
513
+ *
514
+ * Either field is `null` when there is nothing to inject or its step threw —
515
+ * the caller simply skips stamping and the weekly review proceeds
516
+ * unchanged. The Recommend step is failure-isolated from the Measure step:
517
+ * a recommender throw never drops the `<self_performance>` block.
518
+ *
519
+ * The DB handle + lesson-file FS reads live here (the dispatcher is
520
+ * coverage-excluded); the byte-deterministic aggregation, rule table, and
521
+ * rendering live in the pure modules, which are 100% unit-tested. Unlike
522
+ * the consolidation/re-generalization pre-steps this is NOT gated on
523
+ * `feedbackLearningEnabled` — it measures core daemon telemetry, not the
524
+ * lesson loop; nor on `selfTuningEnabled` — that flag gates Phase 3
525
+ * *actuation* only, while recommendation generation + verdict recording IS
526
+ * the Phase 2 shadow period (§7). An unreadable lesson store only drops the
527
+ * `<lesson_stores>` rows / the R5 input, never the whole block.
528
+ */
529
+ private prepareSelfTuningBlocks;
530
+ /**
531
+ * FEEDBACK_LEARNING_LOOP_DESIGN.md §4 "Monthly re-generalization" / Phase 5 —
532
+ * the deterministic monthly pre-step. Enumerates the consolidated lesson
533
+ * stores on disk (the global `policies/agent-lessons.md` plus every per-agent
534
+ * `policies/agents/<slug>/lessons.md`), reads their contents, and composes a
535
+ * `<feedback_regeneralization>` block via the pure
536
+ * `buildRegeneralizationWorksheet`. Returns the block, or `null` when feedback
537
+ * learning is off, no store holds enough lessons to collapse, or anything
538
+ * throws — so the caller simply skips stamping and the monthly review
539
+ * proceeds unchanged.
540
+ *
541
+ * The FS enumeration lives here (the dispatcher is coverage-excluded); the
542
+ * byte-deterministic composition lives in `buildRegeneralizationWorksheet`,
543
+ * which is 100% unit-tested.
544
+ */
545
+ private prepareRegeneralizationWorksheet;
443
546
  /**
444
547
  * Append a single bullet under `## Weekly interests reflection`
445
548
  * inside `context/journal/agent.md`, creating the section (and the