@mycadet/assistant 0.12.9 → 0.12.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 (658) hide show
  1. package/Dockerfile +0 -8
  2. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +1 -1
  3. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
  4. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
  5. package/node_modules/@mycadet/ces-client/src/http-credentials.ts +18 -1
  6. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
  7. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
  8. package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
  9. package/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
  10. package/openapi.yaml +62 -910
  11. package/package.json +3 -7
  12. package/scripts/build-test-fixtures.ts +1 -1
  13. package/scripts/generate-openapi.ts +22 -6
  14. package/scripts/postinstall.ts +4 -10
  15. package/scripts/run-tests.ts +0 -21
  16. package/src/__tests__/adaptive-thinking-repair.test.ts +19 -57
  17. package/src/__tests__/agent-loop.test.ts +0 -76
  18. package/src/__tests__/anthropic-provider.test.ts +6 -6
  19. package/src/__tests__/assert-not-live-db.ts +1 -1
  20. package/src/__tests__/assistant-id-boundary-guard.test.ts +3 -3
  21. package/src/__tests__/attachments-store-heic-normalize.test.ts +1 -1
  22. package/src/__tests__/attachments-store.test.ts +1 -1
  23. package/src/__tests__/audit-log-rotation.test.ts +1 -1
  24. package/src/__tests__/btw-routes.test.ts +1 -1
  25. package/src/__tests__/byok-default-profile-ensure.test.ts +21 -27
  26. package/src/__tests__/call-conversation-messages.test.ts +0 -5
  27. package/src/__tests__/call-recovery.test.ts +2 -7
  28. package/src/__tests__/call-routes-http.test.ts +0 -12
  29. package/src/__tests__/call-store.test.ts +2 -7
  30. package/src/__tests__/catalog-files.test.ts +7 -5
  31. package/src/__tests__/checker.test.ts +1 -1
  32. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +4 -4
  33. package/src/__tests__/cloud-client-verify-credential.test.ts +0 -4
  34. package/src/__tests__/cloud-credential-catalog-cli.test.ts +14 -14
  35. package/src/__tests__/cloud-profile-guard.test.ts +87 -404
  36. package/src/__tests__/compaction-events.test.ts +2 -2
  37. package/src/__tests__/config-loader-backfill.test.ts +74 -163
  38. package/src/__tests__/config-loader-cloud-defaults.test.ts +11 -11
  39. package/src/__tests__/config-loader-corrupt.test.ts +10 -10
  40. package/src/__tests__/config-loader-quarantine-notice.test.ts +7 -7
  41. package/src/__tests__/config-loader-validation-reset-notice.test.ts +11 -11
  42. package/src/__tests__/config-schema.test.ts +26 -27
  43. package/src/__tests__/config-set-route.test.ts +2 -6
  44. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +28 -300
  45. package/src/__tests__/conversation-agent-loop-overflow.test.ts +39 -246
  46. package/src/__tests__/conversation-agent-loop.test.ts +2 -58
  47. package/src/__tests__/conversation-clear-safety.test.ts +0 -30
  48. package/src/__tests__/conversation-inference-profile-route.test.ts +1 -1
  49. package/src/__tests__/conversation-queue.test.ts +1 -1
  50. package/src/__tests__/conversation-runtime-assembly.test.ts +1 -1
  51. package/src/__tests__/conversation-skill-tools.test.ts +4 -444
  52. package/src/__tests__/conversation-slash-commands.test.ts +1 -1
  53. package/src/__tests__/conversation-store.test.ts +1 -84
  54. package/src/__tests__/conversation-surface-state.test.ts +0 -16
  55. package/src/__tests__/credential-health-service.test.ts +14 -1
  56. package/src/__tests__/credential-record-retire.test.ts +1 -1
  57. package/src/__tests__/credential-record-write-through.test.ts +1 -1
  58. package/src/__tests__/credential-security-invariants.test.ts +0 -145
  59. package/src/__tests__/custom-profile-ensure.test.ts +1 -1
  60. package/src/__tests__/default-profile-catalog-fallback.test.ts +5 -15
  61. package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -2
  62. package/src/__tests__/dictation-profile-store.test.ts +6 -6
  63. package/src/__tests__/disk-usage.test.ts +28 -164
  64. package/src/__tests__/docker-signing-key-bootstrap.test.ts +1 -1
  65. package/src/__tests__/embedding-cloud-proxy-selection.test.ts +1 -1
  66. package/src/__tests__/emit-event-signal.test.ts +1 -1
  67. package/src/__tests__/gateway-client-cloud-outbound.test.ts +3 -3
  68. package/src/__tests__/gateway-only-enforcement.test.ts +1 -1
  69. package/src/__tests__/guardian-dispatch.test.ts +0 -13
  70. package/src/__tests__/helpers/seed-app.ts +1 -1
  71. package/src/__tests__/host-cu-routes-targeted.test.ts +1 -1
  72. package/src/__tests__/host-shell-tool.test.ts +1 -1
  73. package/src/__tests__/identity-routes.test.ts +1 -1
  74. package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
  75. package/src/__tests__/inference-profile-session-ipc.test.ts +1 -1
  76. package/src/__tests__/injector-chain.test.ts +1 -1
  77. package/src/__tests__/injector-config-quarantine-notice.test.ts +1 -1
  78. package/src/__tests__/injector-config-validation-reset-notice.test.ts +1 -1
  79. package/src/__tests__/injector-pkb-v2-silenced.test.ts +1 -1
  80. package/src/__tests__/{platform.test.ts → layout.test.ts} +1 -1
  81. package/src/__tests__/list-all-apps.test.ts +1 -1
  82. package/src/__tests__/live-workspace-guard.test.ts +2 -2
  83. package/src/__tests__/llm-resolver-override-or-default.test.ts +5 -6
  84. package/src/__tests__/llm-resolver.test.ts +7 -7
  85. package/src/__tests__/llm-schema-fallback-profile.test.ts +9 -10
  86. package/src/__tests__/llm-usage-store.test.ts +0 -495
  87. package/src/__tests__/log-export-routes.test.ts +1 -1
  88. package/src/__tests__/mcp-config-secret-boundary.test.ts +12 -53
  89. package/src/__tests__/mcp-list-plugin-servers.test.ts +1 -1
  90. package/src/__tests__/memory-config-file-parity.test.ts +1 -1
  91. package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
  92. package/src/__tests__/messages-read-boundary-guard.test.ts +0 -2
  93. package/src/__tests__/notification-guardian-path.test.ts +0 -7
  94. package/src/__tests__/onboarding-persona-write.test.ts +1 -1
  95. package/src/__tests__/openai-provider.test.ts +8 -8
  96. package/src/__tests__/path-policy.test.ts +1 -1
  97. package/src/__tests__/persona-resolver.test.ts +1 -1
  98. package/src/__tests__/plugin-app-serve-routes.test.ts +1 -1
  99. package/src/__tests__/plugin-effective-enabled-set.test.ts +1 -1
  100. package/src/__tests__/plugin-import-boundary-guard.test.ts +4 -6
  101. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -3
  102. package/src/__tests__/provider-cloud-proxy-integration.test.ts +1 -5
  103. package/src/__tests__/provider-connections-backfill.test.ts +10 -10
  104. package/src/__tests__/prune-old-conversations-job.test.ts +6 -31
  105. package/src/__tests__/resolve-app.test.ts +1 -1
  106. package/src/__tests__/run-due-schedules.test.ts +1 -1
  107. package/src/__tests__/scaffold-managed-skill-tool.test.ts +0 -53
  108. package/src/__tests__/schedule-routes.test.ts +1 -1
  109. package/src/__tests__/schedule-store.test.ts +1 -1
  110. package/src/__tests__/secret-routes-cloud-proxy.test.ts +1 -1
  111. package/src/__tests__/skill-load-plugin-scope.test.ts +1 -1
  112. package/src/__tests__/surface-completion-compaction-boundary.test.ts +1 -1
  113. package/src/__tests__/tool-approval-handler.test.ts +1 -1
  114. package/src/__tests__/tool-audit.test.ts +5 -235
  115. package/src/__tests__/tool-executor-lifecycle-events.test.ts +54 -114
  116. package/src/__tests__/tools-get-route.test.ts +1 -1
  117. package/src/__tests__/turn-outcome-read.test.ts +1 -1
  118. package/src/__tests__/twilio-routes.test.ts +0 -1
  119. package/src/__tests__/usage-attribution.test.ts +0 -31
  120. package/src/__tests__/verification-control-plane-policy.test.ts +3 -10
  121. package/src/__tests__/visible-app-context.test.ts +1 -1
  122. package/src/__tests__/voice-ingress-preflight.test.ts +1 -1
  123. package/src/__tests__/workspace-git-service.test.ts +1 -1
  124. package/src/__tests__/workspace-greetings.test.ts +1 -1
  125. package/src/acp/__tests__/helpers/acp-config-stub.ts +1 -1
  126. package/src/activation/progress-store.ts +1 -1
  127. package/src/activation/turn-hooks.ts +1 -1
  128. package/src/agent/loop.ts +0 -51
  129. package/src/apps/app-store.ts +1 -1
  130. package/src/avatar/__tests__/avatar-store.test.ts +2 -172
  131. package/src/avatar/accent-backfill.ts +1 -1
  132. package/src/avatar/avatar-manifest.ts +1 -1
  133. package/src/avatar/avatar-store.ts +10 -69
  134. package/src/avatar/ensure-raster.ts +1 -1
  135. package/src/avatar/identity-avatar.ts +1 -1
  136. package/src/avatar/sync-avatar.ts +1 -1
  137. package/src/avatar/traits-png-sync.ts +1 -1
  138. package/src/bundler/compiler-tools.ts +1 -1
  139. package/src/bundler/package-resolver.ts +1 -1
  140. package/src/calls/__tests__/call-controller.test.ts +25 -27
  141. package/src/calls/active-call-lease.ts +1 -1
  142. package/src/calls/call-controller.ts +3 -3
  143. package/src/calls/call-domain.ts +4 -8
  144. package/src/calls/call-store.ts +2 -76
  145. package/src/calls/resolve-call-tts-provider.ts +3 -3
  146. package/src/calls/twilio-config.ts +3 -3
  147. package/src/calls/twilio-rest.ts +2 -2
  148. package/src/calls/voice-ingress-preflight.ts +2 -2
  149. package/src/cli/bundled-modules.ts +0 -2
  150. package/src/cli/commands/__tests__/apps.test.ts +1 -1
  151. package/src/cli/commands/__tests__/plugins.test.ts +9 -66
  152. package/src/cli/commands/__tests__/ps.test.ts +67 -0
  153. package/src/cli/commands/auth.help.ts +2 -2
  154. package/src/cli/commands/avatar.ts +1 -1
  155. package/src/cli/commands/changelog.ts +1 -1
  156. package/src/cli/commands/cloud/__tests__/subscription.test.ts +2 -2
  157. package/src/cli/commands/cloud/index.help.ts +1 -1
  158. package/src/cli/commands/cloud/index.ts +2 -2
  159. package/src/cli/commands/db/refresh.ts +1 -1
  160. package/src/cli/commands/db/repair-step-conversation-backfill.ts +1 -1
  161. package/src/cli/commands/db/repair.ts +1 -1
  162. package/src/cli/commands/db/status.ts +1 -1
  163. package/src/cli/commands/inference-profiles.ts +1 -12
  164. package/src/cli/commands/memory/__tests__/memory-v3.test.ts +1 -116
  165. package/src/cli/commands/memory/index.help.ts +1 -43
  166. package/src/cli/commands/memory/memory-v3.ts +0 -64
  167. package/src/cli/commands/plugins.ts +54 -205
  168. package/src/cli/commands/ps.ts +5 -2
  169. package/src/cli/commands/status.ts +1 -1
  170. package/src/cli/index.help.ts +0 -2
  171. package/src/cli/lib/__tests__/inspect-plugin.test.ts +36 -66
  172. package/src/cli/lib/__tests__/install-from-cloud.test.ts +1 -1
  173. package/src/cli/lib/__tests__/install-from-github.test.ts +41 -117
  174. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +2 -185
  175. package/src/cli/lib/__tests__/plugin-catalog-resolve.test.ts +36 -66
  176. package/src/cli/lib/__tests__/plugin-catalog-visibility.test.ts +4 -6
  177. package/src/cli/lib/__tests__/plugin-details.test.ts +113 -96
  178. package/src/cli/lib/__tests__/search-plugins.test.ts +9 -16
  179. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +1 -1
  180. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +38 -15
  181. package/src/cli/lib/diff-plugin.ts +1 -1
  182. package/src/cli/lib/inspect-plugin.ts +13 -97
  183. package/src/cli/lib/install-from-cloud.ts +1 -1
  184. package/src/cli/lib/install-from-github.ts +75 -154
  185. package/src/cli/lib/install-plugin-dependencies.ts +1 -1
  186. package/src/cli/lib/list-installed-plugins.ts +1 -1
  187. package/src/cli/lib/open-browser.ts +1 -1
  188. package/src/cli/lib/plugin-catalog-cache.ts +8 -51
  189. package/src/cli/lib/plugin-catalog-resolve.ts +3 -22
  190. package/src/cli/lib/plugin-details.ts +5 -27
  191. package/src/cli/lib/plugin-marketplace.ts +18 -266
  192. package/src/cli/lib/search-plugins.ts +23 -43
  193. package/src/cli/lib/toggle-plugin.ts +1 -1
  194. package/src/cli/lib/uninstall-plugin.ts +1 -1
  195. package/src/cli/lib/upgrade-plugin.ts +3 -49
  196. package/src/cli/program.ts +1 -3
  197. package/src/cli.ts +1 -1
  198. package/src/cloud/client.ts +0 -6
  199. package/src/cloud/consent-cache.test.ts +22 -201
  200. package/src/cloud/consent-cache.ts +16 -111
  201. package/src/cloud/sync-identity.ts +1 -1
  202. package/src/config/__tests__/chat-settings.test.ts +1 -1
  203. package/src/config/__tests__/cloud-identity.test.ts +15 -2
  204. package/src/config/__tests__/default-plugin-skill-discovery.test.ts +1 -1
  205. package/src/config/__tests__/default-profile-catalog.test.ts +12 -51
  206. package/src/config/__tests__/deployment-context-defaults.test.ts +13 -13
  207. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +4 -4
  208. package/src/config/__tests__/loader-last-known-good.test.ts +9 -9
  209. package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +7 -7
  210. package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +1 -1
  211. package/src/config/__tests__/profile-materialization.test.ts +2 -4
  212. package/src/config/__tests__/sync-gated-profiles.test.ts +1 -106
  213. package/src/config/acp-agent-write.ts +1 -1
  214. package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +1 -1
  215. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
  216. package/src/config/call-site-defaults.ts +0 -6
  217. package/src/config/cloud-identity.ts +12 -5
  218. package/src/config/composer-preferences.ts +1 -1
  219. package/src/config/default-profile-catalog.ts +8 -75
  220. package/src/config/default-profile-names.ts +2 -25
  221. package/src/config/env-registry.ts +1 -14
  222. package/src/config/env.ts +8 -6
  223. package/src/config/llm-resolver.ts +1 -2
  224. package/src/config/loader.ts +13 -17
  225. package/src/config/profile-materialization.ts +1 -1
  226. package/src/config/schema.ts +1 -7
  227. package/src/config/schemas/call-site-catalog.ts +0 -7
  228. package/src/config/schemas/llm.ts +25 -32
  229. package/src/config/seed-inference-profiles.ts +16 -17
  230. package/src/config/skills.ts +2 -2
  231. package/src/config/sync-gated-profiles.ts +6 -24
  232. package/src/credential-health/credential-health-service.ts +10 -3
  233. package/src/daemon/approval-generators.ts +3 -3
  234. package/src/daemon/config-watcher.ts +2 -2
  235. package/src/daemon/conversation-agent-loop-handlers.ts +0 -18
  236. package/src/daemon/conversation-agent-loop.ts +6 -97
  237. package/src/daemon/conversation-process.ts +1 -1
  238. package/src/daemon/conversation-skill-tools.ts +4 -72
  239. package/src/daemon/conversation-store.ts +1 -1
  240. package/src/daemon/conversation-surface-state.ts +0 -33
  241. package/src/daemon/conversation-surfaces.ts +1 -86
  242. package/src/daemon/conversation-tool-setup.test.ts +1 -1
  243. package/src/daemon/conversation-tool-setup.ts +0 -23
  244. package/src/daemon/conversation.ts +3 -5
  245. package/src/daemon/daemon-control.ts +3 -3
  246. package/src/daemon/dictation-profile-store.ts +3 -3
  247. package/src/daemon/event-loop-watchdog.test.ts +2 -198
  248. package/src/daemon/event-loop-watchdog.ts +0 -185
  249. package/src/daemon/external-plugins-bootstrap.ts +1 -1
  250. package/src/daemon/first-greeting.ts +1 -1
  251. package/src/daemon/handlers/skills.ts +1 -1
  252. package/src/daemon/host-app-control-proxy.ts +1 -1
  253. package/src/daemon/host-cu-proxy.ts +2 -2
  254. package/src/daemon/identity-helpers.ts +1 -1
  255. package/src/daemon/lifecycle.ts +11 -15
  256. package/src/daemon/main.ts +1 -1
  257. package/src/daemon/now-scratchpad.ts +1 -1
  258. package/src/daemon/process-message.ts +4 -4
  259. package/src/daemon/profiler-run-store.ts +2 -2
  260. package/src/daemon/providers-setup.ts +2 -2
  261. package/src/daemon/shutdown-handlers.ts +0 -10
  262. package/src/daemon/sqlite-corruption-watchdog.test.ts +2 -142
  263. package/src/daemon/sqlite-corruption-watchdog.ts +17 -81
  264. package/src/daemon/tool-side-effects.ts +1 -1
  265. package/src/desktop/desktop-session-manager.ts +1 -1
  266. package/src/desktop/desktop-wallpaper-renderer.ts +1 -1
  267. package/src/heartbeat/heartbeat-service.ts +1 -1
  268. package/src/home/feed-writer.ts +1 -1
  269. package/src/home/home-greeting-cache.ts +1 -1
  270. package/src/home/relationship-state-writer.ts +2 -2
  271. package/src/hooks/__tests__/hook-live-reload.test.ts +1 -1
  272. package/src/hooks/hook-loader.ts +2 -2
  273. package/src/inbound/__tests__/oauth-callback-url.test.ts +2 -2
  274. package/src/inbound/oauth-callback-url.ts +3 -3
  275. package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
  276. package/src/ipc/socket-path.ts +1 -1
  277. package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -1
  278. package/src/live-voice/__tests__/live-voice-vad.test.ts +1 -1
  279. package/src/live-voice/live-voice-session.ts +3 -66
  280. package/src/mcp/__tests__/effective-config.test.ts +1 -1
  281. package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +2 -2
  282. package/src/mcp/__tests__/mcp-oauth-provider.test.ts +2 -3
  283. package/src/mcp/__tests__/reload-signal-emission.test.ts +1 -1
  284. package/src/mcp/__tests__/reload-signal.test.ts +1 -1
  285. package/src/mcp/__tests__/workspace-mcp-config.test.ts +19 -21
  286. package/src/mcp/reload-signal.ts +1 -1
  287. package/src/mcp/workspace-mcp-config.ts +1 -23
  288. package/src/messaging/draft-store.ts +1 -1
  289. package/src/monitoring/__tests__/active-conversations.test.ts +1 -1
  290. package/src/monitoring/__tests__/page-cache.test.ts +1 -1
  291. package/src/monitoring/__tests__/stall-capture.test.ts +1 -1
  292. package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +1 -1
  293. package/src/monitoring/active-conversations.ts +1 -1
  294. package/src/monitoring/control.ts +1 -1
  295. package/src/monitoring/daemon-boot-time.ts +1 -1
  296. package/src/monitoring/daemon-heartbeat.ts +1 -1
  297. package/src/monitoring/page-cache.ts +1 -1
  298. package/src/monitoring/plugin-auto-update.ts +1 -7
  299. package/src/monitoring/plugin-source-watch.ts +1 -1
  300. package/src/monitoring/recovery/db.ts +1 -1
  301. package/src/monitoring/recovery/inflight-content.ts +1 -1
  302. package/src/monitoring/resource-sampler.ts +3 -14
  303. package/src/monitoring/stall-capture.ts +1 -1
  304. package/src/monitoring/worker.ts +9 -76
  305. package/src/monitoring/workspace-git-heartbeat.ts +1 -1
  306. package/src/oauth/connect-orchestrator.ts +4 -4
  307. package/src/permissions/checker.ts +1 -1
  308. package/src/permissions/workspace-policy.ts +1 -1
  309. package/src/persistence/__tests__/main-db-readonly-probe.ts +27 -52
  310. package/src/persistence/__tests__/message-content-file.test.ts +1 -1
  311. package/src/persistence/__tests__/slow-sync-log.test.ts +0 -2
  312. package/src/persistence/attachments-store.ts +1 -1
  313. package/src/persistence/conversation-crud.ts +1 -38
  314. package/src/persistence/conversation-directories.ts +1 -1
  315. package/src/persistence/conversation-types.ts +0 -8
  316. package/src/persistence/db-async-query.ts +1 -1
  317. package/src/persistence/db-connection.ts +11 -1
  318. package/src/persistence/db-init.ts +1 -1
  319. package/src/persistence/db-maintenance.ts +1 -1
  320. package/src/persistence/embeddings/__tests__/embedding-local-lifecycle.test.ts +1 -1
  321. package/src/persistence/embeddings/embedding-local.ts +4 -4
  322. package/src/persistence/embeddings/embedding-runtime-manager.ts +1 -1
  323. package/src/persistence/embeddings/qdrant-client.ts +1 -1
  324. package/src/persistence/embeddings/qdrant-manager.ts +1 -1
  325. package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +1 -1
  326. package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +1 -1
  327. package/src/persistence/job-handlers/cleanup.ts +8 -17
  328. package/src/persistence/llm-usage-store.ts +2 -229
  329. package/src/persistence/message-content-file.ts +1 -1
  330. package/src/persistence/migrations/209-strip-thinking-from-consolidated.ts +1 -1
  331. package/src/persistence/migrations/222-strip-placeholder-sentinels-from-messages.ts +1 -1
  332. package/src/persistence/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +1 -1
  333. package/src/persistence/migrations/306-rewrite-frontier-profile-pins.test.ts +1 -1
  334. package/src/persistence/migrations/329-move-onboarding-events-to-telemetry-db.test.ts +13 -0
  335. package/src/persistence/migrations/330-move-auth-fallback-events-to-telemetry-db.test.ts +13 -0
  336. package/src/persistence/migrations/331-move-lifecycle-events-to-telemetry-db.test.ts +13 -0
  337. package/src/persistence/migrations/332-move-skill-loaded-events-to-telemetry-db.test.ts +13 -0
  338. package/src/persistence/migrations/333-create-telemetry-events-table.test.ts +7 -4
  339. package/src/persistence/migrations/334-backfill-telemetry-events-outbox.test.ts +13 -0
  340. package/src/persistence/migrations/387-drop-telemetry-tables.ts +51 -0
  341. package/src/persistence/migrations/__tests__/327-create-flush-checkpoints.test.ts +9 -1
  342. package/src/persistence/migrations/__tests__/387-drop-telemetry-tables.test.ts +79 -0
  343. package/src/persistence/migrations/helpers/relocation.ts +1 -1
  344. package/src/persistence/migrations/run-migrations.ts +1 -1
  345. package/src/persistence/migrations/validate-migration-state.ts +1 -1
  346. package/src/persistence/raw-query.ts +1 -29
  347. package/src/persistence/slow-sync-log.ts +0 -23
  348. package/src/persistence/steps.ts +2 -0
  349. package/src/{telemetry → persistence}/tool-audit.ts +6 -121
  350. package/src/plugin-api/index.ts +1 -1
  351. package/src/plugin-api/plugin-name-env.ts +1 -1
  352. package/src/plugins/__tests__/installed-plugin-dirs.test.ts +1 -1
  353. package/src/plugins/collect-source-versions.ts +1 -1
  354. package/src/plugins/defaults/channel/package.json +1 -1
  355. package/src/plugins/defaults/cloud-hosted/package.json +1 -1
  356. package/src/plugins/defaults/compaction/package.json +1 -1
  357. package/src/plugins/defaults/documents/package.json +1 -1
  358. package/src/plugins/defaults/empty-response/package.json +1 -1
  359. package/src/plugins/defaults/exploration-drift/package.json +1 -1
  360. package/src/plugins/defaults/image-fallback/package.json +1 -1
  361. package/src/plugins/defaults/image-recovery/package.json +1 -1
  362. package/src/plugins/defaults/max-tokens-continue/package.json +1 -1
  363. package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +1 -1
  364. package/src/plugins/defaults/memory/__tests__/db-maintenance.test.ts +1 -1
  365. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +0 -82
  366. package/src/plugins/defaults/memory/__tests__/memory-retrospective-skill-card.test.ts +0 -41
  367. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -2
  368. package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -52
  369. package/src/plugins/defaults/memory/memory-retrospective-skill-card.ts +0 -18
  370. package/src/plugins/defaults/memory/package.json +1 -1
  371. package/src/plugins/defaults/memory/paths.ts +4 -4
  372. package/src/plugins/defaults/memory/src/__tests__/memory-worker-routes.test.ts +1 -1
  373. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +5 -5
  374. package/src/plugins/defaults/memory/src/memory-v3-routes.ts +0 -207
  375. package/src/plugins/defaults/memory/src/memory-worker-routes.ts +1 -1
  376. package/src/plugins/defaults/memory/startup.ts +1 -22
  377. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +2 -253
  378. package/src/plugins/defaults/memory/v3/orchestrate.ts +5 -129
  379. package/src/plugins/defaults/memory/worker-control.ts +1 -1
  380. package/src/plugins/defaults/memory/worker.ts +2 -2
  381. package/src/plugins/defaults/session/package.json +1 -1
  382. package/src/plugins/defaults/surface-completion-nudge/package.json +1 -1
  383. package/src/plugins/defaults/task-progress/package.json +1 -1
  384. package/src/plugins/defaults/task-progress-nudge/package.json +1 -1
  385. package/src/plugins/defaults/title-generate/package.json +1 -1
  386. package/src/plugins/defaults/tool-error/package.json +1 -1
  387. package/src/plugins/defaults/tool-result-truncate/package.json +1 -1
  388. package/src/plugins/defaults/turn-context/package.json +1 -1
  389. package/src/plugins/defaults/workspace/injectors.ts +1 -1
  390. package/src/plugins/defaults/workspace/package.json +1 -1
  391. package/src/plugins/disabled-state.ts +1 -1
  392. package/src/plugins/ensure-plugin-api-shim.ts +1 -1
  393. package/src/plugins/ensure-shared-dep-links.ts +1 -1
  394. package/src/plugins/installed-plugin-dirs.ts +1 -1
  395. package/src/plugins/mcp-servers.ts +7 -9
  396. package/src/plugins/mtime-cache.ts +2 -2
  397. package/src/plugins/source-versions.ts +1 -1
  398. package/src/prompts/bootstrap-cleanup.ts +1 -1
  399. package/src/prompts/persona-resolver.ts +1 -1
  400. package/src/prompts/sections.ts +2 -2
  401. package/src/prompts/system-prompt.ts +10 -42
  402. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +0 -37
  403. package/src/providers/__tests__/cadet-connection-routing.test.ts +2 -2
  404. package/src/providers/cadet/client.ts +1 -1
  405. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -1
  406. package/src/providers/inference/adapter-factory.ts +1 -1
  407. package/src/providers/inference/backfill.ts +3 -10
  408. package/src/providers/inference/profile-probe.ts +1 -1
  409. package/src/providers/retry.ts +0 -2
  410. package/src/providers/types.ts +0 -7
  411. package/src/providers/usage-tracking.ts +1 -1
  412. package/src/routes/__tests__/route-host.test.ts +1 -1
  413. package/src/routes/control.ts +1 -1
  414. package/src/routes/route-host-client.ts +1 -1
  415. package/src/routes/worker.ts +2 -2
  416. package/src/runtime/agent-wake.ts +1 -1
  417. package/src/runtime/assistant-stream-state.ts +1 -1
  418. package/src/runtime/auth/token-service.ts +1 -1
  419. package/src/runtime/background-job-runner.ts +1 -1
  420. package/src/runtime/middleware/twilio-validation.ts +2 -2
  421. package/src/runtime/routes/__tests__/app-pin-routes.test.ts +1 -1
  422. package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +1 -1
  423. package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +3 -33
  424. package/src/runtime/routes/__tests__/cloud-credits-routes.test.ts +5 -4
  425. package/src/runtime/routes/__tests__/cloud-invoice-routes.test.ts +4 -3
  426. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +72 -298
  427. package/src/runtime/routes/__tests__/default-plugin-routes.test.ts +1 -1
  428. package/src/runtime/routes/__tests__/deprecated-route-context.test.ts +15 -62
  429. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +105 -12
  430. package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +1 -1
  431. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -1
  432. package/src/runtime/routes/__tests__/plugins-routes.test.ts +47 -211
  433. package/src/runtime/routes/__tests__/route-host-worker-routes.test.ts +1 -1
  434. package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +1 -1
  435. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +1 -1
  436. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +1 -1
  437. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +1 -1
  438. package/src/runtime/routes/__tests__/user-routes-cli.test.ts +1 -1
  439. package/src/runtime/routes/__tests__/user-routes-notices.test.ts +1 -1
  440. package/src/runtime/routes/__tests__/user-routes-request.test.ts +1 -1
  441. package/src/runtime/routes/app-management-routes.ts +1 -1
  442. package/src/runtime/routes/attachment-routes.ts +1 -1
  443. package/src/runtime/routes/audit-routes.ts +1 -1
  444. package/src/runtime/routes/avatar-routes.ts +3 -10
  445. package/src/runtime/routes/cloud-routes.ts +3 -3
  446. package/src/runtime/routes/content-source-routes.ts +1 -1
  447. package/src/runtime/routes/conversation-query-routes.ts +49 -706
  448. package/src/runtime/routes/conversation-routes.ts +1 -38
  449. package/src/runtime/routes/debug-routes.ts +1 -1
  450. package/src/runtime/routes/deprecated-route-context.ts +5 -61
  451. package/src/runtime/routes/heartbeat-routes.ts +1 -1
  452. package/src/runtime/routes/identity-routes.ts +1 -1
  453. package/src/runtime/routes/index.ts +0 -6
  454. package/src/runtime/routes/inference-profile-session-handler.ts +3 -3
  455. package/src/runtime/routes/inference-profiles-routes.ts +48 -21
  456. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -1
  457. package/src/runtime/routes/llm-call-sites-routes.ts +3 -3
  458. package/src/runtime/routes/log-export/__tests__/installed-inventory.test.ts +1 -1
  459. package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +1 -1
  460. package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +1 -1
  461. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  462. package/src/runtime/routes/log-export-routes.ts +17 -15
  463. package/src/runtime/routes/migration-rollback-routes.ts +1 -1
  464. package/src/runtime/routes/migration-routes.ts +2 -3
  465. package/src/runtime/routes/monitoring-routes.ts +2 -2
  466. package/src/runtime/routes/oauth-providers.ts +5 -5
  467. package/src/runtime/routes/plugins-routes.ts +38 -163
  468. package/src/runtime/routes/profiler-routes.ts +1 -1
  469. package/src/runtime/routes/route-host-worker-routes.ts +1 -1
  470. package/src/runtime/routes/sanity-routes.ts +1 -1
  471. package/src/runtime/routes/schedule-routes.ts +1 -1
  472. package/src/runtime/routes/schedule-worker-routes.ts +1 -1
  473. package/src/runtime/routes/settings-routes.ts +1 -1
  474. package/src/runtime/routes/sounds-config-routes.ts +1 -1
  475. package/src/runtime/routes/surface-conversation-resolver.ts +1 -7
  476. package/src/runtime/routes/user-route-dispatcher.ts +1 -3
  477. package/src/runtime/routes/user-route-import.ts +1 -1
  478. package/src/runtime/routes/user-route-resolution.ts +1 -1
  479. package/src/runtime/routes/user-routes-cli.ts +1 -1
  480. package/src/runtime/routes/workspace-commit-routes.ts +1 -1
  481. package/src/runtime/routes/workspace-greetings.ts +1 -1
  482. package/src/runtime/routes/workspace-routes.ts +1 -1
  483. package/src/runtime/routes/workspace-utils.ts +1 -1
  484. package/src/runtime/sync/resource-sync-events.ts +1 -1
  485. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +1 -1
  486. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1 -1
  487. package/src/schedule/plugin-schedule-availability.ts +1 -1
  488. package/src/schedule/plugin-schedule-declarations.ts +1 -1
  489. package/src/schedule/run-script.ts +1 -1
  490. package/src/schedule/scheduler.ts +1 -11
  491. package/src/schedule/worker-control.ts +1 -1
  492. package/src/schedule/worker.ts +3 -3
  493. package/src/security/oauth2.ts +2 -2
  494. package/src/security/secret-allowlist.ts +1 -1
  495. package/src/signals/cancel.ts +1 -1
  496. package/src/signals/conversation-undo.ts +1 -1
  497. package/src/signals/emit-event.ts +1 -1
  498. package/src/signals/event-stream.ts +1 -1
  499. package/src/signals/user-message.ts +1 -1
  500. package/src/skills/catalog-install.ts +2 -1
  501. package/src/skills/clawhub.ts +1 -1
  502. package/src/skills/cloud-store.ts +1 -1
  503. package/src/skills/path-classifier.ts +1 -1
  504. package/src/skills/skill-history.ts +1 -1
  505. package/src/skills/skillssh-registry.ts +1 -1
  506. package/src/skills/uninstall.ts +1 -1
  507. package/src/skills/workspace-skill-md-signature.ts +1 -1
  508. package/src/subagent/manager.ts +1 -1
  509. package/src/theme/workspace-theme.ts +1 -1
  510. package/src/tools/browser/auth-cache.ts +1 -1
  511. package/src/tools/browser/browser-manager.ts +1 -1
  512. package/src/tools/browser/runtime-check.ts +1 -1
  513. package/src/tools/executor.ts +4 -4
  514. package/src/tools/filesystem/write.ts +1 -1
  515. package/src/tools/permission-checker.ts +2 -51
  516. package/src/tools/run-standalone.ts +1 -1
  517. package/src/tools/skills/format-input-schema.ts +1 -1
  518. package/src/tools/skills/load.ts +1 -1
  519. package/src/tools/skills/scaffold-cloud.ts +0 -32
  520. package/src/tools/terminal/safe-env.ts +1 -2
  521. package/src/tools/terminal/sanitized-bash.ts +1 -1
  522. package/src/tools/terminal/shell.ts +1 -1
  523. package/src/tools/tool-approval-handler.ts +4 -1
  524. package/src/tools/workflows/manage-workflows.ts +2 -2
  525. package/src/tools/workflows/run-workflow.test.ts +1 -1
  526. package/src/tools/workspace-tools/loader.ts +1 -1
  527. package/src/tts/synthesis-stream.ts +2 -2
  528. package/src/usage/attribution.ts +1 -11
  529. package/src/util/browser.ts +1 -1
  530. package/src/util/bun-runtime.ts +2 -1
  531. package/src/util/device-id.ts +1 -1
  532. package/src/util/disk-usage.ts +4 -139
  533. package/src/util/layout.ts +3 -3
  534. package/src/util/logger.ts +1 -1
  535. package/src/util/logs-db-path.ts +1 -1
  536. package/src/util/memory-db-path.ts +1 -1
  537. package/src/util/{platform.ts → os.ts} +5 -30
  538. package/src/util/process-tree.ts +19 -0
  539. package/src/util/sqlite3-runtime.ts +1 -1
  540. package/src/util/telemetry-db-path.ts +1 -1
  541. package/src/watcher/__tests__/engine.test.ts +0 -23
  542. package/src/watcher/engine.ts +0 -7
  543. package/src/windows-compiled-cli.ts +0 -4
  544. package/src/windows-compiled-worker-entry.ts +0 -6
  545. package/src/workflows/leaf-runner.test.ts +1 -1
  546. package/src/workflows/leaf-runner.ts +1 -1
  547. package/src/workflows/library.ts +1 -1
  548. package/src/workspace/adaptive-thinking-repair.ts +5 -24
  549. package/src/workspace/byok-default-profile-ensure.ts +24 -26
  550. package/src/workspace/custom-profile-ensure.ts +2 -2
  551. package/src/workspace/git-service.ts +1 -1
  552. package/src/workspace/hatched-date.ts +1 -1
  553. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +2 -2
  554. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +1 -1
  555. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +1 -1
  556. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +1 -1
  557. package/src/workspace/migrations/registry.ts +0 -4
  558. package/src/workspace/turn-commit.ts +1 -1
  559. package/docs/activation-funnel-telemetry.md +0 -324
  560. package/scripts/bundled-plugin-packages.ts +0 -154
  561. package/scripts/generate-bundled-plugin-packages.ts +0 -29
  562. package/src/__tests__/activation-early-marking.test.ts +0 -114
  563. package/src/__tests__/auth-fallback-events-store.test.ts +0 -99
  564. package/src/__tests__/config-get-vision-flag.test.ts +0 -139
  565. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +0 -400
  566. package/src/__tests__/internal-telemetry-routes.test.ts +0 -213
  567. package/src/__tests__/telemetry-routes.test.ts +0 -182
  568. package/src/__tests__/turn-events-store.test.ts +0 -376
  569. package/src/__tests__/ui-channel-variants.test.ts +0 -53
  570. package/src/avatar/__tests__/avatar-changed-telemetry.test.ts +0 -217
  571. package/src/avatar/avatar-changed-telemetry.ts +0 -128
  572. package/src/calls/__tests__/call-funnel-telemetry.test.ts +0 -204
  573. package/src/cli/commands/telemetry.help.ts +0 -27
  574. package/src/cli/commands/telemetry.ts +0 -83
  575. package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +0 -251
  576. package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +0 -113
  577. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +0 -384
  578. package/src/cli/lib/__tests__/plugin-pin-history.test.ts +0 -164
  579. package/src/cli/lib/__tests__/plugins-install-offline.test.ts +0 -228
  580. package/src/cli/lib/bundled-marketplace.json +0 -1575
  581. package/src/cli/lib/bundled-plugin-packages.json +0 -827
  582. package/src/cli/lib/bundled-plugin-packages.ts +0 -87
  583. package/src/cli/lib/plugin-catalog-local.ts +0 -94
  584. package/src/cli/lib/plugin-pin-history.ts +0 -276
  585. package/src/cloud/feature-gate.ts +0 -8
  586. package/src/config/__tests__/cloud-rehydration.test.ts +0 -180
  587. package/src/config/cloud-rehydration.ts +0 -35
  588. package/src/daemon/__tests__/auto-profile-router.test.ts +0 -380
  589. package/src/daemon/auto-profile-router.ts +0 -428
  590. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +0 -391
  591. package/src/monitoring/__tests__/db-integrity-sample.test.ts +0 -113
  592. package/src/monitoring/__tests__/oom-kill-reporter.test.ts +0 -374
  593. package/src/monitoring/db-integrity-check.ts +0 -163
  594. package/src/monitoring/db-integrity-sample.ts +0 -176
  595. package/src/monitoring/oom-kill-reporter.ts +0 -469
  596. package/src/onboarding/__tests__/onboarding-events-store.test.ts +0 -158
  597. package/src/onboarding/onboarding-events-store.ts +0 -296
  598. package/src/persistence/__tests__/raw-query-telemetry.test.ts +0 -76
  599. package/src/persistence/lifecycle-events-store.test.ts +0 -134
  600. package/src/persistence/lifecycle-events-store.ts +0 -110
  601. package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +0 -76
  602. package/src/plugins/defaults/memory/activation-session-store.ts +0 -50
  603. package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +0 -281
  604. package/src/runtime/routes/auto-profile-routes.ts +0 -83
  605. package/src/runtime/routes/internal-telemetry-routes.ts +0 -142
  606. package/src/runtime/routes/telemetry-routes.ts +0 -274
  607. package/src/security/auth-fallback-events-store.ts +0 -57
  608. package/src/telemetry/__tests__/activation-funnel.test.ts +0 -95
  609. package/src/telemetry/__tests__/config-setting-events-store.test.ts +0 -63
  610. package/src/telemetry/__tests__/config-setting-snapshot.test.ts +0 -143
  611. package/src/telemetry/__tests__/flush-checkpoints.test.ts +0 -56
  612. package/src/telemetry/__tests__/live-voice-funnel.test.ts +0 -174
  613. package/src/telemetry/__tests__/outbox-test-harness.ts +0 -85
  614. package/src/telemetry/__tests__/phone-call-funnel.test.ts +0 -72
  615. package/src/telemetry/__tests__/telemetry-event-fixtures.ts +0 -282
  616. package/src/telemetry/__tests__/watchdog-events-store.test.ts +0 -71
  617. package/src/telemetry/activation-funnel.ts +0 -172
  618. package/src/telemetry/config-setting-events-store.ts +0 -40
  619. package/src/telemetry/config-setting-snapshot.ts +0 -170
  620. package/src/telemetry/flush-checkpoints.ts +0 -70
  621. package/src/telemetry/live-voice-funnel.ts +0 -185
  622. package/src/telemetry/memory-corpus-size.test.ts +0 -120
  623. package/src/telemetry/memory-corpus-size.ts +0 -184
  624. package/src/telemetry/memory-tier-reporter.test.ts +0 -195
  625. package/src/telemetry/memory-tier-reporter.ts +0 -130
  626. package/src/telemetry/phone-call-funnel.ts +0 -144
  627. package/src/telemetry/skill-loaded-events-store.test.ts +0 -93
  628. package/src/telemetry/skill-loaded-events-store.ts +0 -39
  629. package/src/telemetry/telemetry-event-sources.test.ts +0 -223
  630. package/src/telemetry/telemetry-event-sources.ts +0 -597
  631. package/src/telemetry/telemetry-events-outbox.test.ts +0 -375
  632. package/src/telemetry/telemetry-events-outbox.ts +0 -237
  633. package/src/telemetry/telemetry-main-db.ts +0 -48
  634. package/src/telemetry/telemetry-wire-source.json +0 -4
  635. package/src/telemetry/telemetry-wire-validation.test.ts +0 -157
  636. package/src/telemetry/telemetry-wire-validation.ts +0 -162
  637. package/src/telemetry/telemetry-wire.generated.ts +0 -483
  638. package/src/telemetry/tool-executed-events-store.test.ts +0 -210
  639. package/src/telemetry/tool-executed-events-store.ts +0 -102
  640. package/src/telemetry/trace-collection-policy.test.ts +0 -28
  641. package/src/telemetry/trace-collection-policy.ts +0 -30
  642. package/src/telemetry/turn-events-store.ts +0 -216
  643. package/src/telemetry/turn-trace-store.test.ts +0 -884
  644. package/src/telemetry/turn-trace-store.ts +0 -399
  645. package/src/telemetry/types.test.ts +0 -38
  646. package/src/telemetry/types.ts +0 -780
  647. package/src/telemetry/usage-telemetry-reporter.test.ts +0 -3445
  648. package/src/telemetry/usage-telemetry-reporter.ts +0 -566
  649. package/src/telemetry/watchdog-direct-emit.test.ts +0 -112
  650. package/src/telemetry/watchdog-direct-emit.ts +0 -104
  651. package/src/telemetry/watchdog-events-store.ts +0 -31
  652. package/src/tools/ui-surface/channel-variants.ts +0 -52
  653. package/src/watcher/__tests__/telemetry.test.ts +0 -178
  654. package/src/watcher/telemetry.ts +0 -93
  655. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +0 -165
  656. package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +0 -151
  657. /package/src/{telemetry → persistence}/tool-usage-store.ts +0 -0
  658. /package/src/{telemetry → persistence}/turn-outcome.ts +0 -0
@@ -1,566 +0,0 @@
1
- /**
2
- * Usage telemetry reporter.
3
- *
4
- * Periodically flushes unreported telemetry events (LLM usage, turns,
5
- * lifecycle, ...) from the local SQLite databases and POSTs them to the
6
- * platform telemetry endpoint. Each event type is a
7
- * {@link TelemetryEventSource}; the reporter is a generic engine over the
8
- * source list it is constructed with, acknowledging each source after a
9
- * successful upload in one of two modes: watermark-mode sources advance a
10
- * compound `(createdAt, id)` cursor in the telemetry DB's
11
- * `flush_checkpoints` table, and ack-mode sources (those defining `ack`)
12
- * delete their shipped rows instead.
13
- *
14
- * Flushing is split across two processes, each running its own reporter
15
- * instance over a disjoint source partition: the daemon flushes turn events
16
- * (their completeness barrier and consented traces read live in-memory
17
- * conversation state), and the resource monitor process flushes everything
18
- * else off the daemon's event loop — see `monitoring/worker.ts`. The
19
- * per-source watermark cursors live in the telemetry DB, which both
20
- * processes open read-write; each instance only touches its own sources'
21
- * cursors, so the split shares no flush state.
22
- *
23
- * Authenticated-only: events are sent via the cloud proxy context
24
- * (Api-Key header). When no cloud credentials are available, or when
25
- * platform features are disabled (CADET_DISABLE_CLOUD in local mode), the
26
- * flush is skipped and retried next cycle.
27
- */
28
-
29
- import { CadetCloudClient } from "../cloud/client.js";
30
- import { getRawShareAnalytics } from "../cloud/consent-cache.js";
31
- import { areCloudFeaturesEnabled } from "../cloud/feature-gate.js";
32
- import { getCloudOrganizationId, getCloudUserId } from "../config/env.js";
33
- import { getDeviceId } from "../util/device-id.js";
34
- import { getLogger } from "../util/logger.js";
35
- import { APP_VERSION } from "../version.js";
36
- import {
37
- type FlushCheckpointStore,
38
- telemetryDbFlushCheckpointStore,
39
- } from "./flush-checkpoints.js";
40
- import {
41
- DAEMON_TELEMETRY_EVENT_SOURCES,
42
- MONITOR_TELEMETRY_EVENT_SOURCES,
43
- type TelemetryEventSource,
44
- type TelemetryEventSourceBatch,
45
- TOOL_EXECUTED_SOURCE_ID,
46
- watermarkKeysForSource,
47
- } from "./telemetry-event-sources.js";
48
- import {
49
- deleteTelemetryOutboxEventsBefore,
50
- OUTBOX_MAX_ROW_AGE_MS,
51
- } from "./telemetry-events-outbox.js";
52
- import { useReadOnlyMainDbForTelemetry } from "./telemetry-main-db.js";
53
- import { validateWireEvents } from "./telemetry-wire-validation.js";
54
-
55
- const log = getLogger("usage-telemetry");
56
-
57
- // ---------------------------------------------------------------------------
58
- // Constants
59
- // ---------------------------------------------------------------------------
60
-
61
- // Written into the `*_id` watermark checkpoints by the opt-out flush branch.
62
- // Sorts lexicographically above every real row ID (all event stores generate
63
- // lowercase v4 UUIDs), so the compound cursor's same-millisecond arm
64
- // (`createdAt == watermark AND id > afterId`) can never match an opt-out row.
65
- const OPT_OUT_WATERMARK_ID_SENTINEL = "ffffffff-ffff-ffff-ffff-ffffffffffff";
66
- const REPORT_INTERVAL_MS = 5 * 60 * 1000;
67
- const INITIAL_FLUSH_DELAY_MS = 30_000; // Delay first flush to let CES handshake complete
68
- const BATCH_SIZE = 500;
69
- const MAX_CONSECUTIVE_BATCHES = 10;
70
- const TELEMETRY_PATH = "/v1/telemetry/ingest/";
71
-
72
- /**
73
- * Outcome of a {@link UsageTelemetryReporter.flush} call. `flushed: true` means
74
- * at least one batch reached the cloud (2xx). `sent` is the count the daemon
75
- * POSTed; `persisted` is the count the cloud confirmed written; `dropped` is
76
- * `sent - persisted` — folding server-side drops (opt-out, unauthenticated) and
77
- * events silently skipped at ingest validation (unknown/invalid type) into one
78
- * "did not land" number. `flushed: false` carries a kebab-case skip reason.
79
- */
80
- export type TelemetryFlushSummary =
81
- | { flushed: true; sent: number; persisted: number; dropped: number }
82
- | { flushed: false; reason: string };
83
-
84
- interface FlushAccumulator {
85
- sent: number;
86
- persisted: number;
87
- }
88
-
89
- /**
90
- * Read `persisted` from an ingest response body. Falls back to `fallback`
91
- * (the POSTed count — assume all landed) on a malformed body or an older
92
- * platform that omits the field. Never throws.
93
- */
94
- function parsePersistedCount(body: string, fallback: number): number {
95
- try {
96
- const parsed: unknown = JSON.parse(body);
97
- if (parsed && typeof parsed === "object") {
98
- const p = (parsed as { persisted?: unknown }).persisted;
99
- if (typeof p === "number" && Number.isFinite(p) && p >= 0) {
100
- return p;
101
- }
102
- }
103
- } catch {
104
- // Malformed/empty body — assume everything persisted.
105
- }
106
- return fallback;
107
- }
108
-
109
- // ---------------------------------------------------------------------------
110
- // Singleton access
111
- // ---------------------------------------------------------------------------
112
-
113
- let _instance: UsageTelemetryReporter | null = null;
114
-
115
- export function getUsageTelemetryReporter(): UsageTelemetryReporter | null {
116
- return _instance;
117
- }
118
-
119
- function startReporterWithSources(
120
- sources: readonly TelemetryEventSource[],
121
- label: string,
122
- ): void {
123
- if (process.env.CADET_DEV === "1") {
124
- return;
125
- }
126
- if (_instance) {
127
- return;
128
- }
129
- _instance = new UsageTelemetryReporter(sources);
130
- _instance.start();
131
- log.info(`${label} telemetry reporter started`);
132
- }
133
-
134
- /**
135
- * Construct and start the daemon's singleton telemetry reporter, flushing
136
- * the daemon-owned sources (turn events). No-op in dev mode (CADET_DEV=1)
137
- * and idempotent if already started.
138
- *
139
- * Started even when share_analytics consent is opted out: flush() re-checks
140
- * consent each cycle and, when opted out, sends nothing but advances its
141
- * sources' watermarks (including the final flush in stop()). Not gated on DB
142
- * readiness: getDb() can still work when initializeDb() failed mid-migration,
143
- * in which case message writes keep producing rows the opt-out branch must
144
- * keep covered. The reporter is degraded-mode safe — flush() treats DB errors
145
- * as non-fatal.
146
- *
147
- * Also initializes the tool_executed absent-watermark epoch even though that
148
- * source is flushed by the monitor process: the "no flush has ever advanced
149
- * it" guard needs the before-any-tool-runs ordering only daemon startup can
150
- * provide (the monitor boots concurrently with the daemon serving turns).
151
- */
152
- export function startUsageTelemetryReporter(): void {
153
- if (process.env.CADET_DEV === "1") {
154
- return;
155
- }
156
- initToolExecutedWatermarkIfAbsent(telemetryDbFlushCheckpointStore);
157
- startReporterWithSources(DAEMON_TELEMETRY_EVENT_SOURCES, "Daemon");
158
- }
159
-
160
- /**
161
- * Construct and start the resource monitor process's singleton telemetry
162
- * reporter, flushing every non-turn source off the daemon's event loop.
163
- * No-op in dev mode (CADET_DEV=1) and idempotent if already started.
164
- *
165
- * Switches this process's telemetry main-DB reads to the dedicated
166
- * read-only connection first: the monitor observes the daemon's main DB
167
- * (WAL permits cross-process readers) and must never write to it or create
168
- * it. The caller (monitoring/worker.ts) is responsible for the consent
169
- * refresh loop the share_analytics gate reads.
170
- */
171
- export function startMonitorUsageTelemetryReporter(): void {
172
- if (process.env.CADET_DEV === "1") {
173
- return;
174
- }
175
- useReadOnlyMainDbForTelemetry();
176
- startReporterWithSources(MONITOR_TELEMETRY_EVENT_SOURCES, "Monitor");
177
- }
178
-
179
- /**
180
- * Stop the singleton usage telemetry reporter (final flush + timer teardown)
181
- * and clear it. No-op when the reporter was never started (e.g. dev mode).
182
- */
183
- export async function stopUsageTelemetryReporter(): Promise<void> {
184
- if (!_instance) {
185
- return;
186
- }
187
- try {
188
- await _instance.stop();
189
- } finally {
190
- _instance = null;
191
- }
192
- }
193
-
194
- /**
195
- * Initialize the tool_executed flush watermark to "now" when absent.
196
- *
197
- * `tool_invocations` is an always-on audit table that predates the reporter
198
- * shipping its rows: an absent watermark means no flush (opted in or out) has
199
- * ever advanced it, so rows recorded before this build — including any
200
- * opted-out period under older builds that gated the reporter on the
201
- * usage-data opt-out — would otherwise ship retroactively. Runs at daemon
202
- * startup, before any tool can run, so no legitimate row falls behind the
203
- * epoch; the checkpoint persists immediately so a crash can't leave it absent
204
- * and re-initialize later. An EXISTING watermark is never touched: opted-out
205
- * sessions keep it advancing via the opt-out flush branch, and overwriting it
206
- * would drop a legitimate unshipped backlog. The other sources need no init:
207
- * their recording is either consent-gated at write time (opt-out rows never
208
- * exist) or covered by the same watermark discipline from first boot.
209
- *
210
- * Best-effort: DB init failures are tolerated at daemon startup (degraded
211
- * mode), so this never throws — matching flush(), which treats DB errors as
212
- * non-fatal.
213
- */
214
- export function initToolExecutedWatermarkIfAbsent(
215
- checkpoints: FlushCheckpointStore,
216
- ): void {
217
- try {
218
- const key = watermarkKeysForSource(TOOL_EXECUTED_SOURCE_ID).at;
219
- if (checkpoints.get(key) == null) {
220
- checkpoints.set(key, String(Date.now()));
221
- }
222
- } catch (err) {
223
- log.warn(
224
- { err },
225
- "tool_executed watermark init failed — non-fatal; a later run with a working DB re-runs the absent-checkpoint init",
226
- );
227
- }
228
- }
229
-
230
- // ---------------------------------------------------------------------------
231
- // Reporter
232
- // ---------------------------------------------------------------------------
233
-
234
- export class UsageTelemetryReporter {
235
- private initialFlushTimer: ReturnType<typeof setTimeout> | null = null;
236
- private timer: ReturnType<typeof setInterval> | null = null;
237
- private activeFlush: Promise<TelemetryFlushSummary> | null = null;
238
- private readonly sources: readonly TelemetryEventSource[];
239
- private readonly checkpoints: FlushCheckpointStore;
240
-
241
- constructor(
242
- sources: readonly TelemetryEventSource[],
243
- checkpoints: FlushCheckpointStore = telemetryDbFlushCheckpointStore,
244
- ) {
245
- this.sources = sources;
246
- this.checkpoints = checkpoints;
247
- // Backstop for the tool_executed absent-watermark epoch (see
248
- // initToolExecutedWatermarkIfAbsent) — the authoritative init runs at
249
- // daemon startup, which alone guarantees the before-any-tool-runs
250
- // ordering; constructing an instance that flushes the source re-runs the
251
- // guarded init in case that never happened (e.g. a standalone monitor
252
- // started out of band).
253
- if (this.sources.some((s) => s.id === TOOL_EXECUTED_SOURCE_ID)) {
254
- initToolExecutedWatermarkIfAbsent(this.checkpoints);
255
- }
256
- }
257
-
258
- start(): void {
259
- // Delay the first flush to allow the credential infrastructure (CES
260
- // handshake) to complete. Without this delay, CadetCloudClient.create()
261
- // returns null because the credential backend hasn't resolved yet, causing
262
- // the initial flush to be skipped (we send authenticated-only); the
263
- // delay lets credentials resolve so the first flush can actually ship.
264
- this.initialFlushTimer = setTimeout(() => {
265
- this.initialFlushTimer = null;
266
- this.flush().catch((err) => {
267
- log.warn({ err }, "Initial usage telemetry flush failed");
268
- });
269
- }, INITIAL_FLUSH_DELAY_MS);
270
- this.timer = setInterval(() => {
271
- this.flush().catch((err) => {
272
- log.warn({ err }, "Scheduled usage telemetry flush failed");
273
- });
274
- }, REPORT_INTERVAL_MS);
275
- }
276
-
277
- async stop(): Promise<void> {
278
- if (this.initialFlushTimer) {
279
- clearTimeout(this.initialFlushTimer);
280
- this.initialFlushTimer = null;
281
- }
282
- if (this.timer) {
283
- clearInterval(this.timer);
284
- this.timer = null;
285
- }
286
- if (this.activeFlush) {
287
- await this.activeFlush;
288
- }
289
- await this.flush();
290
- }
291
-
292
- async flush(): Promise<TelemetryFlushSummary> {
293
- if (this.activeFlush) {
294
- return this.activeFlush; // overlap guard — share the in-flight result
295
- }
296
- this.activeFlush = this._doFlush();
297
- try {
298
- return await this.activeFlush;
299
- } finally {
300
- this.activeFlush = null;
301
- }
302
- }
303
-
304
- private async _doFlush(
305
- batchCount = 0,
306
- acc: FlushAccumulator = { sent: 0, persisted: 0 },
307
- ): Promise<TelemetryFlushSummary> {
308
- // Once any batch has shipped (acc.sent > 0), a later skip/defer/error is
309
- // just the natural end of the flush — report what landed, not a failure.
310
- const flushed = (): TelemetryFlushSummary => ({
311
- flushed: true,
312
- sent: acc.sent,
313
- persisted: acc.persisted,
314
- dropped: Math.max(0, acc.sent - acc.persisted),
315
- });
316
- const settle = (reason: string): TelemetryFlushSummary =>
317
- acc.sent > 0 ? flushed() : { flushed: false, reason };
318
-
319
- try {
320
- if (batchCount >= MAX_CONSECUTIVE_BATCHES) {
321
- return flushed();
322
- }
323
-
324
- // Age-bound the ack-mode outbox before any skip gate (platform,
325
- // checkpoint store, consent three-way), so the bound holds in every
326
- // state — including the unknown-consent deferral below. Only the
327
- // reporter partition that flushes the outbox (ack-mode sources)
328
- // prunes it.
329
- if (batchCount === 0 && this.sources.some((source) => source.ack)) {
330
- const prunedCount = deleteTelemetryOutboxEventsBefore(
331
- Date.now() - OUTBOX_MAX_ROW_AGE_MS,
332
- );
333
- if (prunedCount > 0) {
334
- log.debug(
335
- { prunedCount },
336
- "Telemetry flush: pruned expired outbox rows",
337
- );
338
- }
339
- }
340
-
341
- // Skip when platform features are disabled (CADET_DISABLE_CLOUD in
342
- // local mode; the flag is ignored when IS_CLOUD is set, matching
343
- // CadetCloudClient.create()). Watermarks are NOT advanced here: this
344
- // is a deployment/local-mode toggle, not a privacy opt-out, so the unsent
345
- // backlog ships once the flag is cleared.
346
- if (!areCloudFeaturesEnabled()) {
347
- return settle("disabled");
348
- }
349
-
350
- // Skip when the flush-checkpoint store (telemetry DB) is unreachable.
351
- // An unreadable watermark must not be mistaken for cursor 0 — that
352
- // would requery and re-ship history from the beginning. Nothing is
353
- // advanced or sent; the cycle retries once the store is back.
354
- if (!this.checkpoints.isAvailable()) {
355
- log.warn(
356
- "Telemetry flush: flush-checkpoint store unavailable — skipping, will retry next cycle",
357
- );
358
- return settle("checkpoint-unavailable");
359
- }
360
-
361
- // Tri-state consent gate: `true` ships, `false` purges, `"unknown"`
362
- // defers.
363
- const shareAnalytics = getRawShareAnalytics();
364
-
365
- // `"unknown"` (boot before the first successful consent refresh, no
366
- // platform session, no resolvable owner) is not an opt-out: nothing is
367
- // sent, acked, discarded, or advanced — the same shape as the
368
- // checkpoint-unavailable skip above. Purging here would silently
369
- // destroy events recorded before the cache warmed up; instead the
370
- // backlog ships (or is purged) on a later cycle once the 5-minute
371
- // refresh loop resolves the cache to a confirmed value. Bounded by
372
- // the age prune above.
373
- if (shareAnalytics === "unknown") {
374
- log.debug(
375
- "Telemetry flush: share_analytics consent unknown — skipping, will retry next cycle",
376
- );
377
- return settle("unknown-consent");
378
- }
379
-
380
- // Respect a confirmed opt-out: if the cloud owner declined
381
- // `share_analytics` consent, skip the flush and advance watermarks so
382
- // events recorded during the opt-out window are never sent
383
- // retroactively. The daemon runs the reporter even when opted out
384
- // specifically so this branch keeps executing — every cycle plus the
385
- // final flush in stop() — which is what lets a later opt-in (runtime or
386
- // via restart) resume from a watermark that already covers the opt-out
387
- // window. One caveat: a RUNTIME false→true flip can still ship up to one
388
- // flush interval (≤5 min) of pre-toggle rows recorded since the last
389
- // opted-out flush;
390
- // the restart path is fully covered by the final flush in stop(). The
391
- // caveat applies to the always-on tables without a write-time opt-out
392
- // gate (llm_usage, turn events) and to tool_invocations rows recorded
393
- // under builds predating the audit listener's write-time gate — new
394
- // opted-out tool_invocations rows persist NULL telemetry columns and
395
- // are unreportable by construction regardless of watermark timing.
396
- if (shareAnalytics === false) {
397
- // Ack-mode sources drop their pending rows outright. Watermark-mode
398
- // sources advance the timestamp watermarks and pin the ID watermarks
399
- // to a sentinel that sorts above any real UUID. The sentinel (rather
400
- // than "") keeps the compound-cursor branch active — a falsy ID would
401
- // downgrade the query to a timestamp-only `gt(createdAt, watermark)`
402
- // — while making its same-millisecond arm unsatisfiable, so a row
403
- // written in the same millisecond as this flush's Date.now() can
404
- // never ship after a later opt-in. The next opted-in flush that
405
- // ships events overwrites the sentinel with a real row ID.
406
- const now = String(Date.now());
407
- for (const source of this.sources) {
408
- if (source.ack) {
409
- source.ack.discardPending();
410
- continue;
411
- }
412
- const keys = watermarkKeysForSource(source.id);
413
- this.checkpoints.set(keys.at, now);
414
- this.checkpoints.set(keys.id, OPT_OUT_WATERMARK_ID_SENTINEL);
415
- }
416
- return settle("opted-out");
417
- }
418
-
419
- // Read each source's watermark (compound cursor: createdAt + id) and
420
- // collect its reportable batch. Absent checkpoints default to cursor 0
421
- // — safe for the consent-gated tables (opted-out rows never exist) and
422
- // for tool_executed, whose absent watermark was initialized at
423
- // construction (see the constructor).
424
- const batches: Array<{
425
- source: TelemetryEventSource;
426
- batch: TelemetryEventSourceBatch;
427
- }> = this.sources.map((source) => {
428
- const keys = watermarkKeysForSource(source.id);
429
- const afterCreatedAt = Number(this.checkpoints.get(keys.at) ?? "0");
430
- const afterId = this.checkpoints.get(keys.id) ?? undefined;
431
- return {
432
- source,
433
- batch: source.collect(afterCreatedAt, afterId, BATCH_SIZE),
434
- };
435
- });
436
-
437
- // Ack-mode batches must carry a row id per event: without them nothing
438
- // can be acknowledged post-2xx, so shipping would re-send the same rows
439
- // on every flush. Exclude such a batch from the POST instead.
440
- for (const entry of batches) {
441
- const { source, batch } = entry;
442
- if (
443
- source.ack &&
444
- batch.events.length > 0 &&
445
- (batch.rowIds ?? []).length !== batch.events.length
446
- ) {
447
- log.warn(
448
- {
449
- sourceId: source.id,
450
- eventCount: batch.events.length,
451
- rowIdCount: batch.rowIds?.length ?? 0,
452
- },
453
- "Telemetry flush: ack-mode batch missing/mismatched rowIds — excluding from POST",
454
- );
455
- entry.batch = {
456
- events: [],
457
- rowIds: [],
458
- lastCursor: null,
459
- fullBatch: false,
460
- };
461
- }
462
- }
463
-
464
- if (batches.every(({ batch }) => batch.events.length === 0)) {
465
- return settle("nothing-pending");
466
- }
467
-
468
- // Resolve auth context. We send authenticated-only: if no platform
469
- // credentials are available yet, skip without advancing watermarks so the
470
- // backlog ships on a later cycle once credentials resolve.
471
- const client = await CadetCloudClient.create();
472
- if (!client) {
473
- log.debug(
474
- {
475
- pendingEventCount: batches.reduce(
476
- (total, { batch }) => total + batch.events.length,
477
- 0,
478
- ),
479
- },
480
- "Telemetry flush: no cloud credentials — skipping, will retry next cycle",
481
- );
482
- return settle("no-credentials");
483
- }
484
- log.debug(
485
- {
486
- counts: Object.fromEntries(
487
- batches.map(({ source, batch }) => [
488
- source.id,
489
- batch.events.length,
490
- ]),
491
- ),
492
- },
493
- "Telemetry flush: resolved auth context",
494
- );
495
-
496
- // Build payload — sources in construction order, each source's events
497
- // in cursor order.
498
- const typedEvents = batches.flatMap(({ batch }) => batch.events);
499
-
500
- // Pre-flush wire validation — observability only: warns about events
501
- // the server would silently drop; the batch is POSTed unchanged.
502
- validateWireEvents(typedEvents, log);
503
-
504
- const organizationId = getCloudOrganizationId() || undefined;
505
- const userId = getCloudUserId() || undefined;
506
- const payload = {
507
- device_id: getDeviceId(),
508
- assistant_version: APP_VERSION,
509
- ...(organizationId ? { organization_id: organizationId } : {}),
510
- ...(userId ? { user_id: userId } : {}),
511
- events: typedEvents,
512
- };
513
-
514
- // Send
515
- const fetchInit: RequestInit = {
516
- method: "POST",
517
- headers: {
518
- "Content-Type": "application/json",
519
- },
520
- body: JSON.stringify(payload),
521
- };
522
-
523
- const resp = await client.fetch(TELEMETRY_PATH, fetchInit);
524
-
525
- if (!resp.ok) {
526
- const body = await resp.text();
527
- log.warn(
528
- { status: resp.status, body },
529
- "Usage telemetry POST failed — will retry next cycle",
530
- );
531
- return settle("post-failed");
532
- }
533
-
534
- // Read the ingest response so `persisted` reflects what actually landed;
535
- // consuming the body also releases the connection.
536
- const body = await resp.text();
537
- acc.sent += typedEvents.length;
538
- acc.persisted += parsePersistedCount(body, typedEvents.length);
539
-
540
- // Acknowledge each source's shipped rows: ack-mode sources delete them
541
- // (never touching flush_checkpoints), watermark-mode sources advance
542
- // their compound cursor to the last reported row.
543
- for (const { source, batch } of batches) {
544
- if (source.ack) {
545
- if (batch.events.length > 0) {
546
- source.ack.acknowledge(batch.rowIds ?? []);
547
- }
548
- } else if (batch.lastCursor) {
549
- const keys = watermarkKeysForSource(source.id);
550
- this.checkpoints.set(keys.at, String(batch.lastCursor.createdAt));
551
- this.checkpoints.set(keys.id, batch.lastCursor.id);
552
- }
553
- }
554
-
555
- // If any source produced a full batch, there may be more — recurse,
556
- // threading the accumulator so counts span every batch in this flush.
557
- if (batches.some(({ batch }) => batch.fullBatch)) {
558
- return this._doFlush(batchCount + 1, acc);
559
- }
560
- return flushed();
561
- } catch (err) {
562
- log.warn({ err }, "Usage telemetry flush error — non-fatal, will retry");
563
- return settle("error");
564
- }
565
- }
566
- }
@@ -1,112 +0,0 @@
1
- /**
2
- * Tests for the direct (unbuffered) watchdog telemetry emit.
3
- *
4
- * Unlike the batched reporter, this POSTs a single event straight to the
5
- * platform ingest. It must honor the `share_analytics` opt-out and the
6
- * platform-features gate, skip cleanly when credentials aren't resolved yet,
7
- * and otherwise send a well-formed single-event payload.
8
- */
9
- import { beforeEach, describe, expect, mock, test } from "bun:test";
10
-
11
- import type { ConsentState } from "../cloud/consent-cache.js";
12
-
13
- let shareAnalytics: ConsentState = true;
14
- mock.module("../cloud/consent-cache.js", () => ({
15
- getRawShareAnalytics: () => shareAnalytics,
16
- }));
17
-
18
- let platformEnabled = true;
19
- mock.module("../cloud/feature-gate.js", () => ({
20
- areCloudFeaturesEnabled: () => platformEnabled,
21
- }));
22
-
23
- const fetchCalls: Array<{ path: string; body: string }> = [];
24
- let clientAvailable = true;
25
- mock.module("../cloud/client.js", () => ({
26
- CadetCloudClient: {
27
- create: async () =>
28
- clientAvailable
29
- ? {
30
- fetch: async (path: string, init: { body: string }) => {
31
- fetchCalls.push({ path, body: init.body });
32
- return new Response("", { status: 200 });
33
- },
34
- }
35
- : null,
36
- },
37
- }));
38
-
39
- import { setCloudOrganizationId, setCloudUserId } from "../config/env.js";
40
- setCloudOrganizationId("org-1");
41
- setCloudUserId("user-1");
42
-
43
- mock.module("../util/device-id.js", () => ({
44
- getDeviceId: () => "device-xyz",
45
- }));
46
- mock.module("../version.js", () => ({ APP_VERSION: "9.9.9" }));
47
-
48
- import { emitWatchdogEventDirect } from "./watchdog-direct-emit.js";
49
-
50
- describe("emitWatchdogEventDirect", () => {
51
- beforeEach(() => {
52
- fetchCalls.length = 0;
53
- shareAnalytics = true;
54
- platformEnabled = true;
55
- clientAvailable = true;
56
- });
57
-
58
- test("POSTs a single well-formed watchdog event when opted in", async () => {
59
- await emitWatchdogEventDirect("sqlite_corrupted", {
60
- database: "main",
61
- error: "database disk image is malformed",
62
- });
63
-
64
- expect(fetchCalls).toHaveLength(1);
65
- expect(fetchCalls[0].path).toBe("/v1/telemetry/ingest/");
66
- const payload = JSON.parse(fetchCalls[0].body) as {
67
- device_id: string;
68
- assistant_version: string;
69
- organization_id?: string;
70
- user_id?: string;
71
- events: Array<Record<string, unknown>>;
72
- };
73
- expect(payload.device_id).toBe("device-xyz");
74
- expect(payload.assistant_version).toBe("9.9.9");
75
- expect(payload.organization_id).toBe("org-1");
76
- expect(payload.user_id).toBe("user-1");
77
- expect(payload.events).toHaveLength(1);
78
- const event = payload.events[0];
79
- expect(event.type).toBe("watchdog");
80
- expect(event.check_name).toBe("sqlite_corrupted");
81
- expect(event.value).toBeNull();
82
- expect(event.daemon_event_id).toBeString();
83
- expect(event.detail).toMatchObject({
84
- database: "main",
85
- error: "database disk image is malformed",
86
- });
87
- });
88
-
89
- test("sends nothing when share_analytics is a confirmed opt-out", async () => {
90
- shareAnalytics = false;
91
- await emitWatchdogEventDirect("sqlite_corrupted", { database: "main" });
92
- expect(fetchCalls).toHaveLength(0);
93
- });
94
-
95
- test("emits while consent is unknown (no buffer to defer into)", async () => {
96
- shareAnalytics = "unknown";
97
- await emitWatchdogEventDirect("sqlite_corrupted", { database: "main" });
98
- expect(fetchCalls).toHaveLength(1);
99
- });
100
-
101
- test("sends nothing when platform features are disabled", async () => {
102
- platformEnabled = false;
103
- await emitWatchdogEventDirect("sqlite_corrupted", { database: "main" });
104
- expect(fetchCalls).toHaveLength(0);
105
- });
106
-
107
- test("sends nothing (no throw) when credentials aren't resolved yet", async () => {
108
- clientAvailable = false;
109
- await emitWatchdogEventDirect("sqlite_corrupted", { database: "main" });
110
- expect(fetchCalls).toHaveLength(0);
111
- });
112
- });