@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
@@ -1,3 +1,4 @@
1
+ import type Database from "better-sqlite3";
1
2
  import type { AgentConfig } from "../config.js";
2
3
  /**
3
4
  * Raw signal entry that gets appended to user/profile.md ## Raw Signals section.
@@ -31,6 +32,7 @@ interface RawSignal {
31
32
  */
32
33
  export declare class SignalDetector {
33
34
  private readonly config;
35
+ private readonly deps;
34
36
  /** Track pending notifications for ignore detection */
35
37
  private readonly pendingNotifications;
36
38
  /** Rolling dedup cache: signal key → expiry timestamp */
@@ -41,7 +43,9 @@ export declare class SignalDetector {
41
43
  private ignoreCheckInterval;
42
44
  /** API base URL for Context File API (self-referencing) */
43
45
  private readonly apiBaseUrl;
44
- constructor(config: AgentConfig);
46
+ constructor(config: AgentConfig, deps?: {
47
+ db?: Database.Database;
48
+ });
45
49
  /** Start the signal detector (periodic ignore check) */
46
50
  start(): void;
47
51
  /** Stop the signal detector */
@@ -67,9 +71,33 @@ export declare class SignalDetector {
67
71
  */
68
72
  onUserMessage(params: {
69
73
  platform: string;
74
+ channel?: string;
70
75
  content: string;
71
76
  responseToNotificationId?: string;
72
77
  }): void;
78
+ /**
79
+ * Record a positive action correlated with a notification. This is the
80
+ * narrow "acted" path: callers must have an actual task/action observation,
81
+ * never silence, before invoking it.
82
+ *
83
+ * NOTE — intentional Phase-1.5 seam, no production caller yet (by design).
84
+ * Firing `acted` deterministically needs the notification's subject
85
+ * `(source, ref)` in `pendingNotifications` to match a later observation,
86
+ * but that subject never reaches `trackNotification`: entity-related
87
+ * proactive DMs are re-authored by an agent turn and delivered via
88
+ * `POST /api/agent/notify`, which carries only message/platform/priority
89
+ * (no subject), and the direct `NotificationManager.send()` paths carry
90
+ * `data:{}`. So this stays correct + silence-safe but dormant — do NOT
91
+ * wire it from a silence- or substring-heuristic source (that re-opens the
92
+ * sign-inversion the promotion gate exists to kill). The loop is complete
93
+ * without it (`explicit` + `replied` drive promotion). See
94
+ * FEEDBACK_LEARNING_LOOP_DESIGN.md §11 v1.9#2 + v1.11.
95
+ */
96
+ onNotificationActed(params: {
97
+ notificationId: string;
98
+ actionRef?: string;
99
+ detail?: string;
100
+ }): void;
73
101
  /** Check for messages that have been ignored (no response within threshold) */
74
102
  private checkIgnoredMessages;
75
103
  /**
@@ -92,5 +120,27 @@ export declare class SignalDetector {
92
120
  static normalizeDedupKey(signal: RawSignal): string;
93
121
  /** Remove expired entries from the dedup cache */
94
122
  private pruneExpiredDedup;
123
+ /**
124
+ * Precision matters more than recall here: a match marks the reply
125
+ * `corrected` (valence `correction`), and the promotion gate treats any
126
+ * correction as an authoritative directive that promotes a lesson on
127
+ * FIRST occurrence — one false positive writes a bogus standing
128
+ * directive into `policies/agent-lessons.md`. So the stop/don't pattern
129
+ * requires imperative shape (sentence-initial, modulo a couple of
130
+ * politeness tokens) paired with an agent-action verb, instead of the
131
+ * old `\b(stop|no)\b.*\b(do|that|…)\b` / bare `don't` catch-alls that
132
+ * matched benign replies like "No worries, that sounds great" or
133
+ * "I don't have anything else today".
134
+ */
135
+ private static isCorrectionContent;
136
+ private findPendingNotificationForReply;
137
+ private resolvePendingNotificationId;
138
+ private lookupNotificationMetadata;
139
+ private resolveAgentIdForNotification;
140
+ private recordNotificationOutcome;
141
+ private updateNotificationReaction;
142
+ private buildOutcomeSummary;
143
+ private sanitizeEvidence;
144
+ private static parseTrackedNotificationId;
95
145
  }
96
146
  export {};
@@ -1,5 +1,7 @@
1
- import { formatSqliteDatetime } from "@aitne/shared";
1
+ import { formatSqliteDatetime, redactSensitiveString } from "@aitne/shared";
2
+ import { hasFeedbackSignalForAction, recordFeedbackSignal, } from "../db/feedback-signals-store.js";
2
3
  import { createLogger } from "../logging.js";
4
+ import { resolveAgentId } from "./agents/agent-id-resolver.js";
3
5
  const logger = createLogger("signal-detector");
4
6
  /**
5
7
  * Maximum number of Raw Signal entries kept in user/profile.md. Prevents
@@ -13,6 +15,26 @@ const MAX_RAW_SIGNALS = 20;
13
15
  * this window are suppressed.
14
16
  */
15
17
  const DEDUP_TTL_MS = 10 * 60 * 1000;
18
+ /**
19
+ * Reaction emoji that signal disapproval. A 👎 must not be recorded as a
20
+ * positive behavioral signal — the consolidation LLM only sees the row's
21
+ * summary, so a mis-valenced reaction would count as positive corroboration
22
+ * for the very notification the owner disliked. Conservative set: ambiguous
23
+ * emoji (😢, 😕, …) stay positive-by-default rather than guessing.
24
+ */
25
+ const NEGATIVE_REACTION_EMOJI = new Set([
26
+ "👎",
27
+ "❌",
28
+ "🚫",
29
+ "🛑",
30
+ "😠",
31
+ "😡",
32
+ "💢",
33
+ ]);
34
+ /** Strip skin-tone modifiers + variation selectors so 👎🏽 matches 👎. */
35
+ function normalizeReactionEmoji(emoji) {
36
+ return emoji.replace(/[\u{1F3FB}-\u{1F3FF}\u{FE0E}\u{FE0F}]/gu, "").trim();
37
+ }
16
38
  /**
17
39
  * SignalDetector — collects implicit user feedback signals (no LLM required).
18
40
  *
@@ -37,6 +59,7 @@ const DEDUP_TTL_MS = 10 * 60 * 1000;
37
59
  */
38
60
  export class SignalDetector {
39
61
  config;
62
+ deps;
40
63
  /** Track pending notifications for ignore detection */
41
64
  pendingNotifications = new Map();
42
65
  /** Rolling dedup cache: signal key → expiry timestamp */
@@ -47,8 +70,9 @@ export class SignalDetector {
47
70
  ignoreCheckInterval = null;
48
71
  /** API base URL for Context File API (self-referencing) */
49
72
  apiBaseUrl;
50
- constructor(config) {
73
+ constructor(config, deps = {}) {
51
74
  this.config = config;
75
+ this.deps = deps;
52
76
  this.ignoreThresholdMs = 30 * 60 * 1000; // 30 minutes
53
77
  this.apiBaseUrl = `http://localhost:${config.apiPort}`;
54
78
  }
@@ -71,10 +95,17 @@ export class SignalDetector {
71
95
  * Called by NotificationManager after successful delivery.
72
96
  */
73
97
  trackNotification(notificationId, platform, content) {
98
+ const metadata = this.lookupNotificationMetadata(notificationId);
74
99
  this.pendingNotifications.set(notificationId, {
75
100
  sentAt: Date.now(),
76
- platform,
77
- content: content.slice(0, 100), // Truncate for signal log
101
+ // Single fallback to the delivered platform here, not redundantly inside
102
+ // the lookup the tracked id's suffix is the delivery platform anyway.
103
+ platform: metadata.platform ?? platform,
104
+ channel: metadata.channel,
105
+ content: (metadata.contentSummary ?? content).slice(0, 100), // Truncate for signal log
106
+ dispatchId: metadata.dispatchId,
107
+ notificationType: metadata.notificationType,
108
+ agentId: metadata.agentId,
78
109
  });
79
110
  }
80
111
  /**
@@ -85,12 +116,26 @@ export class SignalDetector {
85
116
  const { platform, emoji, responseTimeMs } = params;
86
117
  // Remove from pending (user responded)
87
118
  if (params.notificationId) {
88
- this.pendingNotifications.delete(params.notificationId);
119
+ const pendingId = this.resolvePendingNotificationId(params.notificationId);
120
+ this.pendingNotifications.delete(pendingId);
121
+ const negative = NEGATIVE_REACTION_EMOJI.has(normalizeReactionEmoji(emoji));
122
+ this.recordNotificationOutcome({
123
+ notificationId: pendingId,
124
+ reaction: "replied",
125
+ valence: negative ? "negative" : "positive",
126
+ emoji,
127
+ evidence: {
128
+ emoji,
129
+ responseTimeMs,
130
+ weight: 0.5,
131
+ },
132
+ });
89
133
  }
90
134
  const signal = {
91
135
  timestamp: formatSqliteDatetime(new Date()),
92
136
  type: "reaction",
93
- detail: `${emoji} on ${platform}${responseTimeMs ? ` (${Math.round(responseTimeMs / 1000)}s)` : ""}`,
137
+ detail: `${emoji} on ${platform}`
138
+ + `${responseTimeMs ? ` (${Math.round(responseTimeMs / 1000)}s)` : ""}`,
94
139
  };
95
140
  void this.appendSignal(signal);
96
141
  }
@@ -100,29 +145,68 @@ export class SignalDetector {
100
145
  */
101
146
  onUserMessage(params) {
102
147
  const { content, responseToNotificationId } = params;
148
+ const pendingNotificationId = responseToNotificationId
149
+ ? this.resolvePendingNotificationId(responseToNotificationId)
150
+ : this.findPendingNotificationForReply(params.platform, params.channel);
103
151
  // Remove from pending (user responded)
104
- if (responseToNotificationId) {
105
- this.pendingNotifications.delete(responseToNotificationId);
152
+ if (pendingNotificationId) {
153
+ this.pendingNotifications.delete(pendingNotificationId);
106
154
  }
107
155
  // Detect correction instructions
108
- const correctionPatterns = [
109
- /shorter|brief|concise/i,
110
- /more detail|elaborate|expand/i,
111
- /\bin (english|spanish|french|german|portuguese|italian|chinese|japanese|korean|arabic|hindi|russian)\b/i,
112
- /bullet points|bulleted list/i,
113
- ];
114
- for (const pattern of correctionPatterns) {
115
- if (pattern.test(content)) {
116
- const signal = {
117
- timestamp: formatSqliteDatetime(new Date()),
118
- type: "correction",
119
- detail: `"${content.slice(0, 60)}"`,
120
- };
121
- void this.appendSignal(signal);
122
- return; // Only log the first matching correction
123
- }
156
+ const isCorrection = SignalDetector.isCorrectionContent(content);
157
+ if (pendingNotificationId) {
158
+ this.recordNotificationOutcome({
159
+ notificationId: pendingNotificationId,
160
+ reaction: isCorrection ? "corrected" : "replied",
161
+ valence: isCorrection ? "correction" : "positive",
162
+ evidence: {
163
+ excerpt: content.slice(0, 160),
164
+ weight: isCorrection ? 1.0 : 0.5,
165
+ },
166
+ });
167
+ }
168
+ if (isCorrection) {
169
+ const signal = {
170
+ timestamp: formatSqliteDatetime(new Date()),
171
+ type: "correction",
172
+ detail: `"${content.slice(0, 60)}"`,
173
+ };
174
+ void this.appendSignal(signal);
175
+ return; // Only log the first matching correction
124
176
  }
125
177
  }
178
+ /**
179
+ * Record a positive action correlated with a notification. This is the
180
+ * narrow "acted" path: callers must have an actual task/action observation,
181
+ * never silence, before invoking it.
182
+ *
183
+ * NOTE — intentional Phase-1.5 seam, no production caller yet (by design).
184
+ * Firing `acted` deterministically needs the notification's subject
185
+ * `(source, ref)` in `pendingNotifications` to match a later observation,
186
+ * but that subject never reaches `trackNotification`: entity-related
187
+ * proactive DMs are re-authored by an agent turn and delivered via
188
+ * `POST /api/agent/notify`, which carries only message/platform/priority
189
+ * (no subject), and the direct `NotificationManager.send()` paths carry
190
+ * `data:{}`. So this stays correct + silence-safe but dormant — do NOT
191
+ * wire it from a silence- or substring-heuristic source (that re-opens the
192
+ * sign-inversion the promotion gate exists to kill). The loop is complete
193
+ * without it (`explicit` + `replied` drive promotion). See
194
+ * FEEDBACK_LEARNING_LOOP_DESIGN.md §11 v1.9#2 + v1.11.
195
+ */
196
+ onNotificationActed(params) {
197
+ const pendingId = this.resolvePendingNotificationId(params.notificationId);
198
+ this.pendingNotifications.delete(pendingId);
199
+ this.recordNotificationOutcome({
200
+ notificationId: pendingId,
201
+ reaction: "acted",
202
+ valence: "positive",
203
+ evidence: {
204
+ actionRef: params.actionRef,
205
+ detail: params.detail,
206
+ weight: 0.5,
207
+ },
208
+ });
209
+ }
126
210
  /** Check for messages that have been ignored (no response within threshold) */
127
211
  checkIgnoredMessages() {
128
212
  const now = Date.now();
@@ -136,6 +220,16 @@ export class SignalDetector {
136
220
  detail: `${info.platform}: "${info.content}" unread for ${Math.round(elapsed / 60000)}min`,
137
221
  };
138
222
  void this.appendSignal(signal);
223
+ this.recordNotificationOutcome({
224
+ notificationId: id,
225
+ reaction: "ignored",
226
+ valence: "neutral",
227
+ evidence: {
228
+ elapsedMs: elapsed,
229
+ weight: 0.25,
230
+ initiatesLesson: false,
231
+ },
232
+ });
139
233
  toRemove.push(id);
140
234
  }
141
235
  }
@@ -211,4 +305,207 @@ export class SignalDetector {
211
305
  }
212
306
  }
213
307
  }
308
+ /**
309
+ * Precision matters more than recall here: a match marks the reply
310
+ * `corrected` (valence `correction`), and the promotion gate treats any
311
+ * correction as an authoritative directive that promotes a lesson on
312
+ * FIRST occurrence — one false positive writes a bogus standing
313
+ * directive into `policies/agent-lessons.md`. So the stop/don't pattern
314
+ * requires imperative shape (sentence-initial, modulo a couple of
315
+ * politeness tokens) paired with an agent-action verb, instead of the
316
+ * old `\b(stop|no)\b.*\b(do|that|…)\b` / bare `don't` catch-alls that
317
+ * matched benign replies like "No worries, that sounds great" or
318
+ * "I don't have anything else today".
319
+ */
320
+ static isCorrectionContent(content) {
321
+ const correctionPatterns = [
322
+ /\b(shorter|brief|briefly|concise|concisely|less verbose|too long|too verbose)\b/i,
323
+ /\b(more detail|elaborate|expand)\b/i,
324
+ /\bin (english|spanish|french|german|portuguese|italian|chinese|japanese|korean|arabic|hindi|russian)\b/i,
325
+ /\b(bullet points|bulleted list)\b/i,
326
+ // Imperative "stop/don't/no more <agent action>" at the start of the
327
+ // reply: optional politeness tokens, a negation/stop verb, then an
328
+ // agent-action word within the same clause.
329
+ /^\W*(?:(?:please|pls|just|hey|ok|okay|can you|could you|you can|maybe)\s+){0,2}(?:stop|quit|don['’]t|do not|never|no more)\b[^.!?\n]{0,40}?\b(?:notify(?:ing)?|notifications?|messag(?:e|es|ing)|remind(?:er|ers|ing)?|send(?:ing)?|ping(?:ing)?|dm(?:s|ing)?|post(?:ing)?|repeat(?:ing)?|do(?:ing)?\s+(?:that|this))\b/i,
330
+ ];
331
+ return correctionPatterns.some((pattern) => pattern.test(content));
332
+ }
333
+ findPendingNotificationForReply(platform, channel) {
334
+ const now = Date.now();
335
+ let candidate = null;
336
+ for (const [id, info] of this.pendingNotifications) {
337
+ if (info.platform !== platform)
338
+ continue;
339
+ if (channel && info.channel && info.channel !== channel)
340
+ continue;
341
+ if (now - info.sentAt > this.ignoreThresholdMs)
342
+ continue;
343
+ if (candidate === null || info.sentAt > candidate.sentAt) {
344
+ candidate = { id, sentAt: info.sentAt };
345
+ }
346
+ }
347
+ return candidate?.id ?? null;
348
+ }
349
+ resolvePendingNotificationId(notificationId) {
350
+ if (this.pendingNotifications.has(notificationId))
351
+ return notificationId;
352
+ for (const id of this.pendingNotifications.keys()) {
353
+ if (id.startsWith(`${notificationId}:`))
354
+ return id;
355
+ }
356
+ return notificationId;
357
+ }
358
+ lookupNotificationMetadata(notificationId) {
359
+ const parsed = SignalDetector.parseTrackedNotificationId(notificationId);
360
+ if (!this.deps.db || !parsed.dispatchId) {
361
+ return {
362
+ dispatchId: parsed.dispatchId,
363
+ platform: parsed.platform,
364
+ channel: null,
365
+ notificationType: null,
366
+ contentSummary: null,
367
+ agentId: null,
368
+ rowId: null,
369
+ };
370
+ }
371
+ const platformValue = parsed.platform;
372
+ const platformPredicate = platformValue ? "AND platform = ?" : "";
373
+ const values = platformValue
374
+ ? [parsed.dispatchId, platformValue]
375
+ : [parsed.dispatchId];
376
+ const row = this.deps.db
377
+ .prepare(`SELECT id, dispatch_id, platform, delivery_channel, notification_type, content_summary
378
+ FROM notification_log
379
+ WHERE dispatch_id = ? ${platformPredicate}
380
+ ORDER BY id DESC
381
+ LIMIT 1`)
382
+ .get(...values);
383
+ const notificationType = row?.notification_type ?? null;
384
+ return {
385
+ dispatchId: row?.dispatch_id ?? parsed.dispatchId,
386
+ platform: row?.platform ?? parsed.platform,
387
+ channel: row?.delivery_channel ?? null,
388
+ notificationType,
389
+ contentSummary: row?.content_summary ?? null,
390
+ agentId: this.resolveAgentIdForNotification(notificationType),
391
+ rowId: row?.id ?? null,
392
+ };
393
+ }
394
+ resolveAgentIdForNotification(notificationType) {
395
+ if (!this.deps.db || !notificationType?.startsWith("routine."))
396
+ return null;
397
+ // Runs only after a successful notification_log read on the same db, so a
398
+ // connection failure would already have surfaced upstream; the registry
399
+ // lookup + agents existence check are deterministic over a valid handle.
400
+ return resolveAgentId(this.deps.db, {
401
+ routine: notificationType.slice("routine.".length),
402
+ });
403
+ }
404
+ recordNotificationOutcome(params) {
405
+ const db = this.deps.db;
406
+ if (this.config.feedbackLearningEnabled === false || !db)
407
+ return;
408
+ // One guard for the whole behavioral-capture path: the reaction backfill,
409
+ // dedup probe, and signal insert all touch the same connection, so a single
410
+ // catch keeps a DB hiccup from crashing the background detector loop
411
+ // without leaving the reaction column write unguarded.
412
+ try {
413
+ const metadata = this.lookupNotificationMetadata(params.notificationId);
414
+ const dispatchId = metadata.dispatchId;
415
+ if (!dispatchId)
416
+ return;
417
+ this.updateNotificationReaction(db, dispatchId, metadata.platform, params.reaction);
418
+ if (hasFeedbackSignalForAction(db, {
419
+ source: "behavioral",
420
+ actionKind: "notification",
421
+ actionRef: dispatchId,
422
+ valence: params.valence,
423
+ userReaction: params.reaction,
424
+ })) {
425
+ return;
426
+ }
427
+ const scopeType = metadata.agentId ? "agent_slug" : "agent";
428
+ const summary = this.buildOutcomeSummary(params.reaction, metadata, {
429
+ valence: params.valence,
430
+ emoji: params.emoji,
431
+ });
432
+ const evidence = this.sanitizeEvidence({
433
+ ...params.evidence,
434
+ userReaction: params.reaction,
435
+ notificationLogId: metadata.rowId,
436
+ notificationType: metadata.notificationType,
437
+ platform: metadata.platform,
438
+ contentSummary: metadata.contentSummary,
439
+ });
440
+ recordFeedbackSignal(db, {
441
+ source: "behavioral",
442
+ valence: params.valence,
443
+ scopeType,
444
+ scopeRef: metadata.agentId,
445
+ actionKind: "notification",
446
+ actionRef: dispatchId,
447
+ agentId: metadata.agentId,
448
+ summary,
449
+ evidence,
450
+ });
451
+ }
452
+ catch (err) {
453
+ logger.warn({ err, notificationId: params.notificationId, reaction: params.reaction }, "Failed to record notification outcome");
454
+ }
455
+ }
456
+ updateNotificationReaction(db, dispatchId, platform, reaction) {
457
+ if (platform) {
458
+ db.prepare(`UPDATE notification_log
459
+ SET user_reaction = ?, reacted_at = CURRENT_TIMESTAMP
460
+ WHERE dispatch_id = ? AND platform = ?`).run(reaction, dispatchId, platform);
461
+ return;
462
+ }
463
+ db.prepare(`UPDATE notification_log
464
+ SET user_reaction = ?, reacted_at = CURRENT_TIMESTAMP
465
+ WHERE dispatch_id = ?`).run(reaction, dispatchId);
466
+ }
467
+ buildOutcomeSummary(reaction, metadata, opts = {}) {
468
+ const content = metadata.contentSummary
469
+ ? ` "${metadata.contentSummary}"`
470
+ : "";
471
+ const notificationType = metadata.notificationType
472
+ ? ` (${metadata.notificationType})`
473
+ : "";
474
+ const emojiNote = opts.emoji ? ` (${opts.emoji})` : "";
475
+ const raw = reaction === "ignored"
476
+ ? `Owner did not respond to notification${content}${notificationType}`
477
+ : reaction === "corrected"
478
+ ? `Owner corrected notification${content}${notificationType}`
479
+ : reaction === "acted"
480
+ ? `Owner acted on notification${content}${notificationType}`
481
+ : opts.valence === "negative"
482
+ ? `Owner reacted negatively${emojiNote} to notification${content}${notificationType}`
483
+ : opts.emoji
484
+ ? `Owner reacted${emojiNote} to notification${content}${notificationType}`
485
+ : `Owner responded to notification${content}${notificationType}`;
486
+ return redactSensitiveString(raw.replace(/\s+/g, " ").trim()).slice(0, 280);
487
+ }
488
+ sanitizeEvidence(value) {
489
+ const out = {};
490
+ for (const [key, entry] of Object.entries(value)) {
491
+ if (entry === undefined)
492
+ continue;
493
+ if (typeof entry === "string") {
494
+ out[key] = redactSensitiveString(entry.replace(/[\u0000-\u001f\u007f]/g, " ").slice(0, 500));
495
+ }
496
+ else {
497
+ out[key] = entry;
498
+ }
499
+ }
500
+ return out;
501
+ }
502
+ static parseTrackedNotificationId(notificationId) {
503
+ const idx = notificationId.indexOf(":");
504
+ if (idx <= 0)
505
+ return { dispatchId: notificationId || null, platform: null };
506
+ return {
507
+ dispatchId: notificationId.slice(0, idx),
508
+ platform: notificationId.slice(idx + 1) || null,
509
+ };
510
+ }
214
511
  }
@@ -124,7 +124,7 @@ export function buildSameBackendDenyBlock(integrations, sessionBackend) {
124
124
  "## Denied tools (per-integration)",
125
125
  "",
126
126
  "The user has restricted the following connector tools for this session.",
127
- "Do NOT invoke them in any flow — including hourly check, morning routine,",
127
+ "Do NOT invoke them in any flow — including activity scan, morning routine,",
128
128
  "or DM responses. If a workflow appears to require one, stop and tell the",
129
129
  "user the tool is denied.",
130
130
  ];
@@ -157,7 +157,7 @@ function appendCliDenyBlock(content, namespacedDenied) {
157
157
  "## Denied tools (do not invoke)",
158
158
  "",
159
159
  "The user has restricted these connector tools for this integration. Do",
160
- "NOT invoke them in any flow — including hourly check, morning routine,",
160
+ "NOT invoke them in any flow — including activity scan, morning routine,",
161
161
  "or DM responses. If a workflow appears to require one, stop and tell",
162
162
  "the user the tool is denied.",
163
163
  "",
@@ -75,8 +75,8 @@ export declare function refreshSkillIndexBlock(sessionDir: string, backendId: Ba
75
75
  * @deprecated DELEGATED-PROXY-API-DESIGN.md §11 — after Phase D no in-tree
76
76
  * skill uses `{{> base }}`: mail / external-services unified their bodies
77
77
  * during Phase D, and the lone surviving `notion/SKILL.base.md` was
78
- * removed in Phase 9 (its hourly-check read-only constraint moved to
79
- * `routine.hourly_check.md` task-flow where the rule applies in every
78
+ * removed in Phase 9 (its activity-scan read-only constraint moved to
79
+ * `routine.activity_scan.md` task-flow where the rule applies in every
80
80
  * integration mode, including same-backend delegated where the skill
81
81
  * body is dropped). The helper is retained for future composition needs;
82
82
  * remove the call sites in `materializeClaudeSession` /
@@ -203,8 +203,8 @@ export function refreshSkillIndexBlock(sessionDir, backendId) {
203
203
  * @deprecated DELEGATED-PROXY-API-DESIGN.md §11 — after Phase D no in-tree
204
204
  * skill uses `{{> base }}`: mail / external-services unified their bodies
205
205
  * during Phase D, and the lone surviving `notion/SKILL.base.md` was
206
- * removed in Phase 9 (its hourly-check read-only constraint moved to
207
- * `routine.hourly_check.md` task-flow where the rule applies in every
206
+ * removed in Phase 9 (its activity-scan read-only constraint moved to
207
+ * `routine.activity_scan.md` task-flow where the rule applies in every
208
208
  * integration mode, including same-backend delegated where the skill
209
209
  * body is dropped). The helper is retained for future composition needs;
210
210
  * remove the call sites in `materializeClaudeSession` /
@@ -113,5 +113,5 @@ export declare const SKILL_DESCRIPTION_MAX_LENGTH = 280;
113
113
  * MUST use {@link skillBodyTouchesReadSensitive} to keep the
114
114
  * "literal prefix" decision encapsulated.
115
115
  */
116
- export declare const READ_SENSITIVE_API_PREFIXES: readonly ["/api/apple-calendar", "/api/books", "/api/browser-task", "/api/calendar", "/api/context", "/api/entities", "/api/mail", "/api/mcp/servers", "/api/notion", "/api/observations", "/api/obsidian", "/api/receipts", "/api/travel-bookings"];
116
+ export declare const READ_SENSITIVE_API_PREFIXES: readonly ["/api/apple-calendar", "/api/background-task", "/api/books", "/api/browser-task", "/api/calendar", "/api/context", "/api/entities", "/api/mail", "/api/mcp/servers", "/api/notion", "/api/observations", "/api/obsidian", "/api/receipts", "/api/travel-bookings"];
117
117
  export declare function skillBodyTouchesReadSensitive(skillBody: string): boolean;
@@ -311,6 +311,14 @@ export const SKILL_DESCRIPTION_MAX_LENGTH = 280;
311
311
  */
312
312
  export const READ_SENSITIVE_API_PREFIXES = [
313
313
  "/api/apple-calendar",
314
+ // BACKGROUND_TASK_RUNNER_DESIGN.md §7 — list / detail reads on the
315
+ // generic detached-task surface. The artifact JSON (`report` / `brief`
316
+ // / `draft` / `significance`) carries the user's research / audit
317
+ // content, so the GETs are ReadSensitive (the POST spawn + clarify +
318
+ // cancel are Autonomous). A Codex DM session referencing the
319
+ // `background-task` skill body gets the read-token banner so its
320
+ // follow-up `GET /:id` read doesn't 401 silently.
321
+ "/api/background-task",
314
322
  "/api/books",
315
323
  // BROWSER_TASK_REDESIGN_PLAN.md §3 — list / detail / events / screenshot
316
324
  // reads on the open-ended browser sub-agent surface. The screenshot
@@ -2,6 +2,7 @@ import type DatabaseNs from "better-sqlite3";
2
2
  import { type BackendId, type IntegrationKey, type IntegrationState, type ProcessKey } from "@aitne/shared";
3
3
  import type { MailAccount } from "../services/mail/provider.js";
4
4
  import { type SkillCompilerFile } from "./skills-compiler-tree.js";
5
+ export declare const SLIM_CLI_SKILL_SETS: Partial<Record<ProcessKey, readonly string[]>>;
5
6
  interface SessionPromptBundleParams {
6
7
  backendId: BackendId;
7
8
  sessionDir: string;
@@ -334,39 +335,41 @@ export declare class SkillsCompiler {
334
335
  private spliceCurationAnchorsInSkill;
335
336
  /**
336
337
  * docs/design/appendices/skills-unification.md Phase 1 item 15 — the slim path does NOT
337
- * emit a `<skill-index>` block or the skill-discovery preamble. The
338
- * fetch_window system prompt is a self-contained operational contract
339
- * (one-window-one-curl, no sub-tasks, exactly-one JSON-on-stdout) and
340
- * the only skill copied (`observations`) is referenced inline by the
341
- * runner-emitted user prompt. Adding the index would mis-signal the
342
- * fetcher to scan for skills before executing the acquisition plan.
338
+ * emit a `<skill-index>` block or the skill-discovery preamble. The slim
339
+ * system prompt is a self-contained operational contract and its copied
340
+ * skills are referenced inline by the dispatched user prompt / task-flow.
341
+ * Adding the index would mis-signal the agent to scan for skills before
342
+ * executing its mechanical task.
343
343
  *
344
- * docs/design/appendices/fetch-window-cost-reduction.md Phase 1.5 slim instruction-file
345
- * materializer for `routine.fetch_window` on Codex / Gemini CLI.
344
+ * fetch-window-cost-reduction.md Phase 1.5 / RESEARCH_CLUSTER_COST_FIX_PLAN.md
345
+ * F4 — slim instruction-file materializer for a `SLIM_CLI_SKILL_SETS` process
346
+ * key on Codex / Gemini CLI.
346
347
  *
347
- * Mirrors the Claude SDK's Phase 1 systemPrompt swap (the same
348
- * `agent-assets/system-prompts/routine-fetch-window.md` template is the
349
- * single source of truth): write the slim body verbatim as AGENTS.md /
350
- * GEMINI.md and copy only the `observations` skill — the
351
- * `/api/observations/batch` POST contract is the fetcher's sole
352
- * structural assertion. The integration partial inlined by the runner
353
- * (`routine-fetch-window-runner.ts:reassemblePrompt`) covers the
354
- * per-attempt call shape, so `mail` / `notion` / `external-services` /
355
- * `attach` skill bodies are deliberately omitted.
348
+ * Mirrors the Claude SDK's slim-systemPrompt swap (the same
349
+ * `agent-assets/system-prompts/<key>.md` template is the single source of
350
+ * truth, read through the shared `loadSlimSystemPrompt` registry): write the
351
+ * slim body verbatim as AGENTS.md / GEMINI.md and copy only the key's
352
+ * `SLIM_CLI_SKILL_SETS` bundle the wide manifest's other slugs are restated
353
+ * by the dispatched user prompt / task-flow, so their bodies are omitted.
356
354
  *
357
- * No safety preamble / character / behavioral-rules / daemon-API
358
- * sections — the slim template restates the only rules the fetcher
359
- * needs (localhost-only curl, no sub-tasks, no context writes, no
360
- * notify, JSON-on-stdout-and-exit). The destructive-action policy layer
361
- * (absolute-block list, Codex sandbox, Gemini admin TOML) still applies
362
- * unchanged at runtime.
355
+ * No safety preamble / character / behavioral-rules / daemon-API sections —
356
+ * the slim template restates the only rules the session needs. The
357
+ * destructive-action policy layer (absolute-block list, Codex sandbox,
358
+ * Gemini admin TOML) still applies unchanged at runtime.
363
359
  *
364
360
  * The `<mcp-servers>` section is appended downstream by
365
361
  * `services/mcp/session-materializer.ts:appendMcpSection` exactly as on
366
- * the wide path — Phase 3's allowlist filter, when it lands, will scope
367
- * that section without further changes here.
362
+ * the wide path.
368
363
  */
369
- private materializeFetchWindowCliSession;
364
+ private materializeSlimCliSession;
365
+ /**
366
+ * Copy one built-in skill dir into a slim CLI session, applying the same
367
+ * adaptation pipeline the wide CLI path runs (brand tokens, partial /
368
+ * reference includes, integration-mode filter, tool-deny prose, curation
369
+ * anchors). Frontmatter stays intact (skills-unification.md §R6). A
370
+ * no-op when the source SKILL.md is absent.
371
+ */
372
+ private copySlimSkillDir;
370
373
  private materializeCliSession;
371
374
  }
372
375
  export {};