@xopcai/xopc 0.0.114 → 0.0.116

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 (328) hide show
  1. package/README.md +5 -4
  2. package/README.zh-CN.md +5 -4
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Fp-p7bP1.js → agent-avatar-dicebear-CWM1UU5P.js} +1 -1
  6. package/dist/gateway/static/root/assets/agent-browser-settings-page-D1SyFYeh.js +6 -0
  7. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-C9YxgvuI.js +1 -0
  8. package/dist/gateway/static/root/assets/agents-CteVs3UO.js +71 -0
  9. package/dist/gateway/static/root/assets/app-management-settings-panel-yXSXY_bu.js +1 -0
  10. package/dist/gateway/static/root/assets/{appearance-settings-ycbdJRuZ.js → appearance-settings-DjY1P_ug.js} +1 -1
  11. package/dist/gateway/static/root/assets/apps-page-CVQ1M8Ax.js +1 -0
  12. package/dist/gateway/static/root/assets/{archive-plugin-CJzSADJo.js → archive-plugin-CytE5j-e.js} +1 -1
  13. package/dist/gateway/static/root/assets/{attachment-load-BTAB4zGS.js → attachment-load-BvvrN6rF.js} +1 -1
  14. package/dist/gateway/static/root/assets/{binary-plugins-DXR1-mct.js → binary-plugins-IBWSitnj.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-CzQri9h2.js → block-editor-C-wDpsf-.js} +44 -44
  16. package/dist/gateway/static/root/assets/channels-settings-Cd3JbeQ1.js +1 -0
  17. package/dist/gateway/static/root/assets/{config-api-DRqjEvAx.js → config-api-C4RAtTKW.js} +1 -1
  18. package/dist/gateway/static/root/assets/connectors-page-MsMa5qBr.js +2 -0
  19. package/dist/gateway/static/root/assets/{cron-api-BXaZXv1o.js → cron-api-sJNMqB6P.js} +1 -1
  20. package/dist/gateway/static/root/assets/cron-page-D30CSwkn.js +3 -0
  21. package/dist/gateway/static/root/assets/dreaming-settings-6fCUWRQf.js +1 -0
  22. package/dist/gateway/static/root/assets/{extension-debug-page-DSkqMYo7.js → extension-debug-page-BAIyjDlq.js} +1 -1
  23. package/dist/gateway/static/root/assets/{extension-page-h2dGDbMN.js → extension-page-DEhv2GpC.js} +1 -1
  24. package/dist/gateway/static/root/assets/{extension-settings-page-hN99RhOi.js → extension-settings-page-DOuAxTDW.js} +1 -1
  25. package/dist/gateway/static/root/assets/{fetch-D9QqUtzZ.js → fetch-CTsREQIe.js} +1 -1
  26. package/dist/gateway/static/root/assets/{format-interval-label-D6E687rG.js → format-interval-label-D35Bfhtx.js} +1 -1
  27. package/dist/gateway/static/root/assets/{gateway-config-api-CLt_SKTC.js → gateway-config-api-C6989a-W.js} +1 -1
  28. package/dist/gateway/static/root/assets/gateway-settings-BpF26t91.js +1 -0
  29. package/dist/gateway/static/root/assets/{gateway-startup-retry-N7Z_sz7p.js → gateway-startup-retry-C1KAHrd2.js} +1 -1
  30. package/dist/gateway/static/root/assets/goal-detail-page-DOjhmRyf.js +1 -0
  31. package/dist/gateway/static/root/assets/goals-config-api-KnLGpu6h.js +1 -0
  32. package/dist/gateway/static/root/assets/goals-page-Xl9_wrFc.js +2 -0
  33. package/dist/gateway/static/root/assets/goals-settings-DtPtqZi8.js +1 -0
  34. package/dist/gateway/static/root/assets/{heartbeat-config-api-DGPadTw-.js → heartbeat-config-api-uKw1f0IG.js} +1 -1
  35. package/dist/gateway/static/root/assets/heartbeat-settings-DN9vEj9P.js +1 -0
  36. package/dist/gateway/static/root/assets/index-C8ytlAF2.js +122 -0
  37. package/dist/gateway/static/root/assets/index-CVpJW2NS.css +1 -0
  38. package/dist/gateway/static/root/assets/{interval-presets-CEklPQ_r.js → interval-presets-Dq0FXJ65.js} +1 -1
  39. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-Ce_aQ8Iv.js → keyboard-shortcuts-settings-C9_t4m7t.js} +1 -1
  40. package/dist/gateway/static/root/assets/logs-page-SNkWzidV.js +2 -0
  41. package/dist/gateway/static/root/assets/{markdown-split-BMz3xPXO.js → markdown-split-Ca87W8-h.js} +1 -1
  42. package/dist/gateway/static/root/assets/{media-plugins-BalOSoz9.js → media-plugins-BAcUjPRJ.js} +1 -1
  43. package/dist/gateway/static/root/assets/messages-BqzIDrlr.js +3 -0
  44. package/dist/gateway/static/root/assets/models-hub-panel-BO4o-GmO.js +2 -0
  45. package/dist/gateway/static/root/assets/note-detail-page-DLV_XDmT.js +2 -0
  46. package/dist/gateway/static/root/assets/{note-image-lightbox-C5D1Q5mY.js → note-image-lightbox-hnSX5SSn.js} +1 -1
  47. package/dist/gateway/static/root/assets/notes-page-ycsDlkFA.js +1 -0
  48. package/dist/gateway/static/root/assets/{preview-open-alternatives-CYFR5U9l.js → preview-open-alternatives-CNgM20H5.js} +1 -1
  49. package/dist/gateway/static/root/assets/remote-access-hub-DQpnE8K9.js +1 -0
  50. package/dist/gateway/static/root/assets/{save-bar-controls-BQ79Z5IP.js → save-bar-controls-CcdjGcfT.js} +1 -1
  51. package/dist/gateway/static/root/assets/{schedule-field-Bgk6Emue.js → schedule-field-CYr39z76.js} +1 -1
  52. package/dist/gateway/static/root/assets/{schema-form-DzS36TMa.js → schema-form-BRAJgZQ2.js} +1 -1
  53. package/dist/gateway/static/root/assets/sessions-page-BZui7iAY.js +1 -0
  54. package/dist/gateway/static/root/assets/settings-advanced-gate-DEfzZ1ax.js +1 -0
  55. package/dist/gateway/static/root/assets/{settings-collapsible-section-CdjFnSAy.js → settings-collapsible-section-BhzjeGWi.js} +1 -1
  56. package/dist/gateway/static/root/assets/{settings-form-section-DZLy_exu.js → settings-form-section-Cz3Pcr9b.js} +1 -1
  57. package/dist/gateway/static/root/assets/settings-page-CLuSsu1-.js +1 -0
  58. package/dist/gateway/static/root/assets/setup-status-panel-Cq4qpXLi.js +1 -0
  59. package/dist/gateway/static/root/assets/{share-preview-page-_qRDr4g_.js → share-preview-page-DL4y9K5e.js} +1 -1
  60. package/dist/gateway/static/root/assets/shares-settings-B9F3HyYQ.js +1 -0
  61. package/dist/gateway/static/root/assets/skill-reload-api-Bp9UPPwm.js +1 -0
  62. package/dist/gateway/static/root/assets/skills-page-BIoBsfSV.js +2 -0
  63. package/dist/gateway/static/root/assets/system-settings-panel-FD2jxRZ3.js +1 -0
  64. package/dist/gateway/static/root/assets/use-agent-defaults-form-Cz2_pPzu.js +1 -0
  65. package/dist/gateway/static/root/assets/{use-channel-catalog-CbXq97rT.js → use-channel-catalog-BInPrfR5.js} +1 -1
  66. package/dist/gateway/static/root/assets/{use-settings-tab-guard-DwS3drWK.js → use-settings-tab-guard-nuHMmZQv.js} +1 -1
  67. package/dist/gateway/static/root/assets/voice-api-key-field-BUIrKb8s.js +1 -0
  68. package/dist/gateway/static/root/assets/{voice-player-store-DSuOd9zy.js → voice-player-store-1U3vFppm.js} +1 -1
  69. package/dist/gateway/static/root/assets/workflows-page-qE3SexnO.js +18 -0
  70. package/dist/gateway/static/root/index.html +5 -5
  71. package/dist/gateway/static/root/logo.svg +4 -3
  72. package/dist/package.js +1 -1
  73. package/dist/src/agent/embedded/session-tool-result-guard.js +8 -1
  74. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  75. package/dist/src/agent/goals/checklist-judge.d.ts +2 -0
  76. package/dist/src/agent/goals/checklist-judge.js +4 -3
  77. package/dist/src/agent/goals/checklist-judge.js.map +1 -1
  78. package/dist/src/agent/goals/evaluate-turn.d.ts +2 -1
  79. package/dist/src/agent/goals/evaluate-turn.js +2 -0
  80. package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
  81. package/dist/src/agent/goals/post-turn.d.ts +6 -1
  82. package/dist/src/agent/goals/post-turn.js +20 -4
  83. package/dist/src/agent/goals/post-turn.js.map +1 -1
  84. package/dist/src/agent/image/understanding/pi-ai-provider.js +5 -2
  85. package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
  86. package/dist/src/agent/image/understanding/provider-registry.d.ts +1 -0
  87. package/dist/src/agent/image/understanding/provider-registry.js +16 -2
  88. package/dist/src/agent/image/understanding/provider-registry.js.map +1 -1
  89. package/dist/src/agent/tools/composio-tool.d.ts +8 -0
  90. package/dist/src/agent/tools/composio-tool.js +46 -0
  91. package/dist/src/agent/tools/composio-tool.js.map +1 -0
  92. package/dist/src/agent/tools/factory.js +13 -8
  93. package/dist/src/agent/tools/factory.js.map +1 -1
  94. package/dist/src/agent/tools/index.d.ts +1 -0
  95. package/dist/src/agent/tools/index.js +2 -1
  96. package/dist/src/agent/workflow/builtins/audit-repo.d.ts +1 -1
  97. package/dist/src/agent/workflow/builtins/audit-repo.js +15 -2
  98. package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -1
  99. package/dist/src/agent/workflow/builtins/client-proposal.d.ts +1 -1
  100. package/dist/src/agent/workflow/builtins/client-proposal.js +10 -1
  101. package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -1
  102. package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +1 -1
  103. package/dist/src/agent/workflow/builtins/competitor-scan.js +16 -2
  104. package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -1
  105. package/dist/src/agent/workflow/builtins/content-draft.d.ts +1 -1
  106. package/dist/src/agent/workflow/builtins/content-draft.js +15 -2
  107. package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -1
  108. package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +1 -1
  109. package/dist/src/agent/workflow/builtins/content-repurpose.js +10 -1
  110. package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -1
  111. package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
  112. package/dist/src/agent/workflow/builtins/debug-incident.js +9 -1
  113. package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
  114. package/dist/src/agent/workflow/builtins/decision-compare.d.ts +1 -1
  115. package/dist/src/agent/workflow/builtins/decision-compare.js +16 -2
  116. package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -1
  117. package/dist/src/agent/workflow/builtins/implementation-plan.d.ts +1 -1
  118. package/dist/src/agent/workflow/builtins/implementation-plan.js +11 -1
  119. package/dist/src/agent/workflow/builtins/implementation-plan.js.map +1 -1
  120. package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +1 -1
  121. package/dist/src/agent/workflow/builtins/inbox-triage.js +11 -1
  122. package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -1
  123. package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +1 -1
  124. package/dist/src/agent/workflow/builtins/meeting-prep.js +9 -1
  125. package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -1
  126. package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +1 -1
  127. package/dist/src/agent/workflow/builtins/multi-perspective-review.js +9 -1
  128. package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -1
  129. package/dist/src/agent/workflow/builtins/offer-design.d.ts +1 -1
  130. package/dist/src/agent/workflow/builtins/offer-design.js +10 -1
  131. package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -1
  132. package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
  133. package/dist/src/agent/workflow/builtins/pr-review.js +9 -1
  134. package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
  135. package/dist/src/agent/workflow/builtins/release-check.d.ts +1 -1
  136. package/dist/src/agent/workflow/builtins/release-check.js +10 -1
  137. package/dist/src/agent/workflow/builtins/release-check.js.map +1 -1
  138. package/dist/src/agent/workflow/builtins/research.d.ts +1 -1
  139. package/dist/src/agent/workflow/builtins/research.js +16 -2
  140. package/dist/src/agent/workflow/builtins/research.js.map +1 -1
  141. package/dist/src/agent/workflow/builtins/weekly-review.d.ts +1 -1
  142. package/dist/src/agent/workflow/builtins/weekly-review.js +9 -1
  143. package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -1
  144. package/dist/src/agent/workflow/snapshot.d.ts +10 -0
  145. package/dist/src/agent/workflow/snapshot.js +136 -1
  146. package/dist/src/agent/workflow/snapshot.js.map +1 -1
  147. package/dist/src/channels/catalog/channel-catalog-service.d.ts +2 -1
  148. package/dist/src/channels/catalog/channel-catalog-service.js +133 -16
  149. package/dist/src/channels/catalog/channel-catalog-service.js.map +1 -1
  150. package/dist/src/channels/catalog/channel-catalog-types.d.ts +13 -0
  151. package/dist/src/cli/commands/doctor/checks/channel-config.js +14 -1
  152. package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -1
  153. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  154. package/dist/src/config/index.js +2 -2
  155. package/dist/src/config/schema.d.ts +15 -0
  156. package/dist/src/config/schema.js +12 -3
  157. package/dist/src/config/schema.js.map +1 -1
  158. package/dist/src/config/web-patch.d.ts +1 -0
  159. package/dist/src/config/web-patch.js +1 -0
  160. package/dist/src/config/web-patch.js.map +1 -1
  161. package/dist/src/connectors/composio-triggers.d.ts +10 -0
  162. package/dist/src/connectors/composio-triggers.js +32 -0
  163. package/dist/src/connectors/composio-triggers.js.map +1 -0
  164. package/dist/src/connectors/composio.d.ts +54 -0
  165. package/dist/src/connectors/composio.js +334 -0
  166. package/dist/src/connectors/composio.js.map +1 -0
  167. package/dist/src/connectors/health.js +16 -1
  168. package/dist/src/connectors/health.js.map +1 -1
  169. package/dist/src/connectors/install.d.ts +2 -1
  170. package/dist/src/connectors/install.js +50 -13
  171. package/dist/src/connectors/install.js.map +1 -1
  172. package/dist/src/connectors/instances.js +57 -6
  173. package/dist/src/connectors/instances.js.map +1 -1
  174. package/dist/src/connectors/lifecycle.d.ts +3 -0
  175. package/dist/src/connectors/lifecycle.js +23 -0
  176. package/dist/src/connectors/lifecycle.js.map +1 -0
  177. package/dist/src/connectors/materialize.js +2 -1
  178. package/dist/src/connectors/materialize.js.map +1 -1
  179. package/dist/src/connectors/providers.d.ts +1 -0
  180. package/dist/src/connectors/providers.js +10 -2
  181. package/dist/src/connectors/providers.js.map +1 -1
  182. package/dist/src/connectors/registries/modelscope.d.ts +2 -0
  183. package/dist/src/connectors/registries/modelscope.js +205 -0
  184. package/dist/src/connectors/registries/modelscope.js.map +1 -0
  185. package/dist/src/connectors/registries/official-mcp.d.ts +2 -0
  186. package/dist/src/connectors/registries/official-mcp.js +142 -0
  187. package/dist/src/connectors/registries/official-mcp.js.map +1 -0
  188. package/dist/src/connectors/registries/search.d.ts +12 -0
  189. package/dist/src/connectors/registries/search.js +89 -0
  190. package/dist/src/connectors/registries/search.js.map +1 -0
  191. package/dist/src/connectors/registries/smithery.d.ts +2 -0
  192. package/dist/src/connectors/registries/smithery.js +98 -0
  193. package/dist/src/connectors/registries/smithery.js.map +1 -0
  194. package/dist/src/connectors/registries/types.d.ts +20 -0
  195. package/dist/src/connectors/registries/types.js +1 -0
  196. package/dist/src/connectors/secret-store.js +4 -2
  197. package/dist/src/connectors/secret-store.js.map +1 -1
  198. package/dist/src/connectors/setup-secrets.d.ts +15 -0
  199. package/dist/src/connectors/setup-secrets.js +64 -0
  200. package/dist/src/connectors/setup-secrets.js.map +1 -0
  201. package/dist/src/connectors/supervisor.d.ts +15 -0
  202. package/dist/src/connectors/supervisor.js +73 -0
  203. package/dist/src/connectors/supervisor.js.map +1 -0
  204. package/dist/src/connectors/types.d.ts +27 -3
  205. package/dist/src/connectors/usage.js +6 -1
  206. package/dist/src/connectors/usage.js.map +1 -1
  207. package/dist/src/gateway/hono/app.js +5 -1
  208. package/dist/src/gateway/hono/app.js.map +1 -1
  209. package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -1
  210. package/dist/src/gateway/hono/lib/config-payload.js +7 -4
  211. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  212. package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
  213. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +19 -5
  214. package/dist/src/gateway/hono/middleware/strict-rate-limit.js.map +1 -1
  215. package/dist/src/gateway/hono/routes/channels.js +18 -14
  216. package/dist/src/gateway/hono/routes/channels.js.map +1 -1
  217. package/dist/src/gateway/hono/routes/connectors.js +230 -3
  218. package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
  219. package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
  220. package/dist/src/gateway/hono/routes/goals.js +52 -5
  221. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  222. package/dist/src/gateway/hono/routes/voice.js +14 -1
  223. package/dist/src/gateway/hono/routes/voice.js.map +1 -1
  224. package/dist/src/gateway/hono/sse.js.map +1 -1
  225. package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
  226. package/dist/src/gateway/rate-limit/buckets.js +12 -0
  227. package/dist/src/gateway/rate-limit/buckets.js.map +1 -1
  228. package/dist/src/gateway/service/agent-runner.d.ts +5 -12
  229. package/dist/src/gateway/service/agent-runner.js +8 -8
  230. package/dist/src/gateway/service/agent-runner.js.map +1 -1
  231. package/dist/src/gateway/service/run-gateway-agent.d.ts +2 -10
  232. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  233. package/dist/src/gateway/service.d.ts +1 -1
  234. package/dist/src/gateway/service.js +9 -4
  235. package/dist/src/gateway/service.js.map +1 -1
  236. package/dist/src/gateway/user-turn-input.d.ts +18 -0
  237. package/dist/src/gateway/user-turn-input.js +16 -0
  238. package/dist/src/gateway/user-turn-input.js.map +1 -0
  239. package/dist/src/goals/goal-queue-store.d.ts +2 -1
  240. package/dist/src/goals/goal-queue-store.js +2 -2
  241. package/dist/src/goals/goal-queue-store.js.map +1 -1
  242. package/dist/src/goals/goal-queue-types.d.ts +4 -3
  243. package/dist/src/goals/goal-runner.js +25 -3
  244. package/dist/src/goals/goal-runner.js.map +1 -1
  245. package/dist/src/goals/goal-service.d.ts +6 -1
  246. package/dist/src/goals/goal-service.js +9 -2
  247. package/dist/src/goals/goal-service.js.map +1 -1
  248. package/dist/src/goals/goal-store.d.ts +7 -1
  249. package/dist/src/goals/goal-store.js +42 -0
  250. package/dist/src/goals/goal-store.js.map +1 -1
  251. package/dist/src/goals/types.d.ts +10 -0
  252. package/dist/src/storage/sqlite/migrations/011_goal_context_messages.sql +8 -0
  253. package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
  254. package/dist/src/storage/sqlite/migrations/runner.js +4 -4
  255. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  256. package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
  257. package/dist/src/storage/sqlite/schema.js +3 -3
  258. package/dist/src/storage/sqlite/schema.sql +9 -0
  259. package/dist/src/tui/backends/embedded-backend.d.ts +8 -1
  260. package/dist/src/tui/backends/embedded-backend.js +73 -0
  261. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  262. package/dist/src/tui/backends/gateway-sse-backend.d.ts +2 -1
  263. package/dist/src/tui/backends/gateway-sse-backend.js +24 -0
  264. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  265. package/dist/src/tui/components/chat-log.d.ts +2 -0
  266. package/dist/src/tui/components/chat-log.js +19 -0
  267. package/dist/src/tui/components/chat-log.js.map +1 -1
  268. package/dist/src/tui/extension-host/autocomplete.d.ts +3 -2
  269. package/dist/src/tui/extension-host/autocomplete.js +17 -3
  270. package/dist/src/tui/extension-host/autocomplete.js.map +1 -1
  271. package/dist/src/tui/extension-host/runtime.d.ts +5 -0
  272. package/dist/src/tui/extension-host/runtime.js +1 -1
  273. package/dist/src/tui/extension-host/runtime.js.map +1 -1
  274. package/dist/src/tui/tui-backend.d.ts +14 -0
  275. package/dist/src/tui/tui-commands.d.ts +16 -3
  276. package/dist/src/tui/tui-commands.js +47 -19
  277. package/dist/src/tui/tui-commands.js.map +1 -1
  278. package/dist/src/tui/tui-startup-text.js +1 -1
  279. package/dist/src/tui/tui-startup-text.js.map +1 -1
  280. package/dist/src/tui/tui.js +72 -1
  281. package/dist/src/tui/tui.js.map +1 -1
  282. package/dist/src/voice/tts/openai-compatible-speech.d.ts +1 -1
  283. package/dist/src/voice/tts/openai-compatible-speech.js.map +1 -1
  284. package/dist/src/voice/tts/providers/edge-speech.js +14 -2
  285. package/dist/src/voice/tts/providers/edge-speech.js.map +1 -1
  286. package/dist/src/voice/tts/speak-core.js +3 -3
  287. package/dist/src/voice/tts/speak-core.js.map +1 -1
  288. package/dist/src/voice/tts/speech-provider-types.d.ts +2 -2
  289. package/dist/src/voice/tts/types.js +1 -1
  290. package/dist/src/voice/tts/types.js.map +1 -1
  291. package/dist/src/workflows/domain/result.d.ts +0 -1
  292. package/dist/src/workflows/engine/workflow-engine.js +7 -23
  293. package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
  294. package/package.json +2 -2
  295. package/dist/gateway/static/root/assets/agent-browser-settings-page-CWh7trjd.js +0 -6
  296. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-kC8OuLoj.js +0 -1
  297. package/dist/gateway/static/root/assets/agents-DJWG26Si.js +0 -71
  298. package/dist/gateway/static/root/assets/app-management-settings-panel-v24i25Oj.js +0 -1
  299. package/dist/gateway/static/root/assets/apps-page-0V3DXZ7J.js +0 -1
  300. package/dist/gateway/static/root/assets/channels-settings-CIKOkYdO.js +0 -1
  301. package/dist/gateway/static/root/assets/connectors-settings-ClrDS5jH.js +0 -2
  302. package/dist/gateway/static/root/assets/cron-page-Chi_4u4P.js +0 -3
  303. package/dist/gateway/static/root/assets/dreaming-settings-B0_rs2tj.js +0 -1
  304. package/dist/gateway/static/root/assets/gateway-settings-1PDi4lI0.js +0 -1
  305. package/dist/gateway/static/root/assets/goal-detail-page-D_wwXL-t.js +0 -1
  306. package/dist/gateway/static/root/assets/goals-page-DZ2toZ8y.js +0 -2
  307. package/dist/gateway/static/root/assets/goals-settings-LFlwtIKE.js +0 -1
  308. package/dist/gateway/static/root/assets/heartbeat-settings-BHHAs8ZX.js +0 -1
  309. package/dist/gateway/static/root/assets/index-DefIdW9q.js +0 -122
  310. package/dist/gateway/static/root/assets/index-DzmWBkq-.css +0 -1
  311. package/dist/gateway/static/root/assets/logs-page-j_D2QTuQ.js +0 -2
  312. package/dist/gateway/static/root/assets/messages-BN_WiUg0.js +0 -3
  313. package/dist/gateway/static/root/assets/models-hub-panel-CMH_TmZz.js +0 -2
  314. package/dist/gateway/static/root/assets/note-detail-page-O18BrQPq.js +0 -2
  315. package/dist/gateway/static/root/assets/notes-page-B_ZYCmY9.js +0 -1
  316. package/dist/gateway/static/root/assets/remote-access-hub-CwKgWixY.js +0 -1
  317. package/dist/gateway/static/root/assets/sessions-page-C4fcD-7B.js +0 -1
  318. package/dist/gateway/static/root/assets/settings-advanced-gate-Ad2OJ86w.js +0 -1
  319. package/dist/gateway/static/root/assets/settings-page-D2BMY5wo.js +0 -1
  320. package/dist/gateway/static/root/assets/setup-status-panel-aWwxl_E1.js +0 -1
  321. package/dist/gateway/static/root/assets/shares-settings-DUE83uIf.js +0 -1
  322. package/dist/gateway/static/root/assets/skill-reload-api-mWKJcrog.js +0 -1
  323. package/dist/gateway/static/root/assets/skills-page-0Sx1Q58n.js +0 -2
  324. package/dist/gateway/static/root/assets/system-settings-panel-hqaBF5aG.js +0 -1
  325. package/dist/gateway/static/root/assets/use-agent-defaults-form-zbVIQLOA.js +0 -1
  326. package/dist/gateway/static/root/assets/voice-api-key-field-D6HR0hR2.js +0 -1
  327. package/dist/gateway/static/root/assets/workflow-page.utils-C0Uq3xyq.js +0 -1
  328. package/dist/gateway/static/root/assets/workflows-page-DW0fmWhQ.js +0 -18
@@ -1 +1 @@
1
- {"version":3,"file":"goal-runner.js","names":[],"sources":["../../../src/goals/goal-runner.ts"],"sourcesContent":["import { GoalQueueStore } from './goal-queue-store.js';\nimport { GoalService } from './goal-service.js';\nimport type { EnqueueGoalRunOptions, GoalQueueItemSnapshot, GoalQueueStatus, GoalRunnerOptions } from './goal-queue-types.js';\nimport type { GoalWithDetails } from './types.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('GoalRunner');\n\nfunction terminalGoalStatus(status: GoalWithDetails['status']): boolean {\n return status === 'done' || status === 'archived';\n}\n\nexport class GoalRunner {\n private readonly goals = new GoalService();\n private readonly store = new GoalQueueStore();\n private active = 0;\n private pumpTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(private readonly opts: GoalRunnerOptions) {\n this.store.resetRunningToRetry();\n this.schedulePump(0);\n }\n\n enqueue(goalId: string, options: EnqueueGoalRunOptions = {}): GoalQueueItemSnapshot {\n const item = this.store.enqueue({\n goalId,\n maxRetries: Math.max(0, Math.floor(options.maxRetries ?? this.opts.defaultMaxRetries ?? 2)),\n message: options.message?.trim() || undefined,\n source: options.source ?? 'api',\n });\n this.emit('goal.queue.updated', item);\n this.schedulePump(0);\n return item;\n }\n\n snapshot(): GoalQueueItemSnapshot[] {\n return this.store.list();\n }\n\n private schedulePump(delayMs: number): void {\n if (this.pumpTimer) return;\n this.pumpTimer = setTimeout(() => {\n this.pumpTimer = null;\n void this.pump();\n }, delayMs);\n }\n\n private async pump(): Promise<void> {\n const maxConcurrent = Math.max(1, Math.floor(this.opts.maxConcurrent ?? 1));\n while (this.active < maxConcurrent) {\n const item = this.store.claimNext();\n if (!item) break;\n this.active += 1;\n void this.runItem(item).finally(() => {\n this.active -= 1;\n this.schedulePump(0);\n });\n }\n\n const nextRetry = this.store.list()\n .filter((item) => item.status === 'retry_waiting' && item.nextRunAt)\n .sort((a, b) => (a.nextRunAt ?? 0) - (b.nextRunAt ?? 0))[0];\n if (nextRetry) this.schedulePump(Math.max(0, (nextRetry.nextRunAt ?? Date.now()) - Date.now()));\n }\n\n private async runItem(item: GoalQueueItemSnapshot): Promise<void> {\n this.emit('goal.queue.updated', item);\n try {\n const goal = this.goals.get(item.goalId);\n if (!goal) {\n this.finish(item, 'failed', 'Goal not found');\n return;\n }\n if (terminalGoalStatus(goal.status)) {\n this.finish(item, 'skipped', `Goal is ${goal.status}`);\n return;\n }\n const activeGoal =\n goal.status === 'paused' || goal.status === 'blocked' || goal.status === 'needs_input'\n ? this.goals.resume(goal.id)\n : goal;\n if (!activeGoal) {\n this.finish(item, 'failed', 'Goal not found');\n return;\n }\n const sessionKey = activeGoal.activeSessionKey ?? (await this.opts.ensureSession(activeGoal));\n item = this.store.setSessionKey(item.id, sessionKey) ?? { ...item, sessionKey };\n if (this.opts.hasActiveRun(sessionKey)) {\n this.retry(item, 'Goal session already has an active run');\n return;\n }\n const message = item.message || activeGoal.nextAction || activeGoal.title;\n await this.opts.runContinuation(sessionKey, message);\n this.finish(item, 'succeeded');\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (item.attempts <= item.maxRetries) {\n this.retry(item, message);\n } else {\n this.finish(item, 'failed', message);\n }\n }\n }\n\n private retry(item: GoalQueueItemSnapshot, error: string): void {\n const base = Math.max(1_000, this.opts.retryBaseMs ?? 5_000);\n item.status = 'retry_waiting';\n item.lastError = error;\n item.nextRunAt = Date.now() + base * 2 ** Math.max(0, item.attempts - 1);\n item = this.store.markRetry(item.id, error, item.nextRunAt) ?? item;\n log.warn({ goalId: item.goalId, attempts: item.attempts, nextRunAt: item.nextRunAt, errorMessage: error }, `Goal run queued for retry: ${error}`);\n this.emit('goal.queue.updated', item);\n this.schedulePump(Math.max(0, item.nextRunAt - Date.now()));\n }\n\n private finish(item: GoalQueueItemSnapshot, status: GoalQueueStatus, error?: string): void {\n item = this.store.markFinished(item.id, status, error) ?? { ...item, status, finishedAt: Date.now(), lastError: error };\n if (status === 'failed') {\n log.warn({ goalId: item.goalId, attempts: item.attempts, errorMessage: error }, `Goal run failed: ${error}`);\n }\n this.emit('goal.queue.updated', item);\n }\n\n private emit(type: string, item: GoalQueueItemSnapshot): void {\n this.opts.emit?.(type, { item: { ...item } });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"goal-runner.js","names":[],"sources":["../../../src/goals/goal-runner.ts"],"sourcesContent":["import { GoalQueueStore } from './goal-queue-store.js';\nimport { GoalService } from './goal-service.js';\nimport type { EnqueueGoalRunOptions, GoalQueueItemSnapshot, GoalQueueStatus, GoalRunnerOptions } from './goal-queue-types.js';\nimport type { GoalWithDetails } from './types.js';\nimport { mediaRefsToUserTurnAttachments, type UserTurnInput } from '../gateway/user-turn-input.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('GoalRunner');\n\nfunction terminalGoalStatus(status: GoalWithDetails['status']): boolean {\n return status === 'done' || status === 'archived';\n}\n\nfunction buildInitialGoalTurn(goal: GoalWithDetails): UserTurnInput {\n const context = goal.contextMessage;\n const parts = [`Goal:\\n${goal.title}`];\n if (context?.text.trim()) {\n parts.push(`Context:\\n${context.text.trim()}`);\n }\n if (goal.checklist.length > 0) {\n parts.push(`User-provided acceptance criteria:\\n${goal.checklist.map((item, index) => `${index + 1}. ${item.text}`).join('\\n')}`);\n }\n return {\n text: parts.join('\\n\\n'),\n attachments: mediaRefsToUserTurnAttachments(context?.attachments),\n clientCreatedAtMs: Date.now(),\n };\n}\n\nfunction buildFollowupGoalTurn(goal: GoalWithDetails): UserTurnInput {\n return {\n text: goal.nextAction || goal.title,\n clientCreatedAtMs: Date.now(),\n };\n}\n\nexport class GoalRunner {\n private readonly goals = new GoalService();\n private readonly store = new GoalQueueStore();\n private active = 0;\n private pumpTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(private readonly opts: GoalRunnerOptions) {\n this.store.resetRunningToRetry();\n this.schedulePump(0);\n }\n\n enqueue(goalId: string, options: EnqueueGoalRunOptions = {}): GoalQueueItemSnapshot {\n const item = this.store.enqueue({\n goalId,\n maxRetries: Math.max(0, Math.floor(options.maxRetries ?? this.opts.defaultMaxRetries ?? 2)),\n userTurn: options.userTurn && (options.userTurn.text.trim() || options.userTurn.attachments?.length)\n ? {\n ...options.userTurn,\n text: options.userTurn.text.trim(),\n clientCreatedAtMs: options.userTurn.clientCreatedAtMs ?? Date.now(),\n }\n : undefined,\n source: options.source ?? 'api',\n });\n this.emit('goal.queue.updated', item);\n this.schedulePump(0);\n return item;\n }\n\n snapshot(): GoalQueueItemSnapshot[] {\n return this.store.list();\n }\n\n private schedulePump(delayMs: number): void {\n if (this.pumpTimer) return;\n this.pumpTimer = setTimeout(() => {\n this.pumpTimer = null;\n void this.pump();\n }, delayMs);\n }\n\n private async pump(): Promise<void> {\n const maxConcurrent = Math.max(1, Math.floor(this.opts.maxConcurrent ?? 1));\n while (this.active < maxConcurrent) {\n const item = this.store.claimNext();\n if (!item) break;\n this.active += 1;\n void this.runItem(item).finally(() => {\n this.active -= 1;\n this.schedulePump(0);\n });\n }\n\n const nextRetry = this.store.list()\n .filter((item) => item.status === 'retry_waiting' && item.nextRunAt)\n .sort((a, b) => (a.nextRunAt ?? 0) - (b.nextRunAt ?? 0))[0];\n if (nextRetry) this.schedulePump(Math.max(0, (nextRetry.nextRunAt ?? Date.now()) - Date.now()));\n }\n\n private async runItem(item: GoalQueueItemSnapshot): Promise<void> {\n this.emit('goal.queue.updated', item);\n try {\n const goal = this.goals.get(item.goalId);\n if (!goal) {\n this.finish(item, 'failed', 'Goal not found');\n return;\n }\n if (terminalGoalStatus(goal.status)) {\n this.finish(item, 'skipped', `Goal is ${goal.status}`);\n return;\n }\n const activeGoal =\n goal.status === 'paused' || goal.status === 'blocked' || goal.status === 'needs_input'\n ? this.goals.resume(goal.id)\n : goal;\n if (!activeGoal) {\n this.finish(item, 'failed', 'Goal not found');\n return;\n }\n const sessionKey = activeGoal.activeSessionKey ?? (await this.opts.ensureSession(activeGoal));\n item = this.store.setSessionKey(item.id, sessionKey) ?? { ...item, sessionKey };\n if (this.opts.hasActiveRun(sessionKey)) {\n this.retry(item, 'Goal session already has an active run');\n return;\n }\n const userTurn = item.userTurn ?? (activeGoal.turnsUsed === 0 ? buildInitialGoalTurn(activeGoal) : buildFollowupGoalTurn(activeGoal));\n await this.opts.runTurn(sessionKey, userTurn);\n this.finish(item, 'succeeded');\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if (item.attempts <= item.maxRetries) {\n this.retry(item, message);\n } else {\n this.finish(item, 'failed', message);\n }\n }\n }\n\n private retry(item: GoalQueueItemSnapshot, error: string): void {\n const base = Math.max(1_000, this.opts.retryBaseMs ?? 5_000);\n item.status = 'retry_waiting';\n item.lastError = error;\n item.nextRunAt = Date.now() + base * 2 ** Math.max(0, item.attempts - 1);\n item = this.store.markRetry(item.id, error, item.nextRunAt) ?? item;\n log.warn({ goalId: item.goalId, attempts: item.attempts, nextRunAt: item.nextRunAt, errorMessage: error }, `Goal run queued for retry: ${error}`);\n this.emit('goal.queue.updated', item);\n this.schedulePump(Math.max(0, item.nextRunAt - Date.now()));\n }\n\n private finish(item: GoalQueueItemSnapshot, status: GoalQueueStatus, error?: string): void {\n item = this.store.markFinished(item.id, status, error) ?? { ...item, status, finishedAt: Date.now(), lastError: error };\n if (status === 'failed') {\n log.warn({ goalId: item.goalId, attempts: item.attempts, errorMessage: error }, `Goal run failed: ${error}`);\n }\n this.emit('goal.queue.updated', item);\n }\n\n private emit(type: string, item: GoalQueueItemSnapshot): void {\n this.opts.emit?.(type, { item: { ...item } });\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { Config } from '../config/schema.js';
2
2
  import { GoalStore } from './goal-store.js';
3
- import type { CreateGoalInput, Goal, GoalChecklistAddedBy, GoalChecklistStatus, GoalJudgeDecision, GoalListQuery, GoalSource, GoalStatus, GoalUiLocale, GoalWithDetails } from './types.js';
3
+ import type { CreateGoalInput, Goal, GoalChecklistAddedBy, GoalChecklistStatus, GoalContextAttachment, GoalJudgeDecision, GoalListQuery, GoalSource, GoalStatus, GoalUiLocale, GoalWithDetails } from './types.js';
4
4
  export declare class GoalService {
5
5
  private readonly store;
6
6
  constructor(store?: GoalStore);
@@ -12,6 +12,11 @@ export declare class GoalService {
12
12
  get(goalId: string): GoalWithDetails | null;
13
13
  getActiveForSession(sessionKey: string): GoalWithDetails | null;
14
14
  list(query?: GoalListQuery): GoalWithDetails[];
15
+ setContextMessage(input: {
16
+ goalId: string;
17
+ text: string;
18
+ attachments?: GoalContextAttachment[];
19
+ }): GoalWithDetails | null;
15
20
  update(goalId: string, patch: Partial<Pick<Goal, 'title' | 'description' | 'priority' | 'deadlineAt' | 'maxTurns' | 'judgeModelRef' | 'nextAction' | 'blockedReason' | 'activeSessionKey' | 'uiLocale'>>): GoalWithDetails | null;
16
21
  setStatus(goalId: string, status: GoalStatus, opts?: {
17
22
  reason?: string;
@@ -39,7 +39,8 @@ var GoalService = class {
39
39
  return {
40
40
  ...goal,
41
41
  checklist: this.store.listChecklist(goalId),
42
- latestRun: this.store.listRuns(goalId, 1)[0]
42
+ latestRun: this.store.listRuns(goalId, 1)[0],
43
+ contextMessage: this.store.getContextMessage(goalId) ?? void 0
43
44
  };
44
45
  }
45
46
  getActiveForSession(sessionKey) {
@@ -50,9 +51,15 @@ var GoalService = class {
50
51
  return this.store.list(query).map((goal) => ({
51
52
  ...goal,
52
53
  checklist: this.store.listChecklist(goal.id),
53
- latestRun: this.store.listRuns(goal.id, 1)[0]
54
+ latestRun: this.store.listRuns(goal.id, 1)[0],
55
+ contextMessage: this.store.getContextMessage(goal.id) ?? void 0
54
56
  }));
55
57
  }
58
+ setContextMessage(input) {
59
+ if (!this.store.get(input.goalId)) return null;
60
+ this.store.setContextMessage(input);
61
+ return this.get(input.goalId);
62
+ }
56
63
  update(goalId, patch) {
57
64
  const normalized = { ...patch };
58
65
  if (typeof normalized.title === "string") normalized.title = normalizeTitle(normalized.title);
@@ -1 +1 @@
1
- {"version":3,"file":"goal-service.js","names":[],"sources":["../../../src/goals/goal-service.ts"],"sourcesContent":["import type { Config } from '../config/schema.js';\nimport { defaultMaxTurns } from '../agent/goals/state.js';\nimport { GoalStore } from './goal-store.js';\nimport type {\n CreateGoalInput,\n Goal,\n GoalChecklistAddedBy,\n GoalChecklistStatus,\n GoalJudgeDecision,\n GoalListQuery,\n GoalSource,\n GoalStatus,\n GoalUiLocale,\n GoalWithDetails,\n} from './types.js';\n\nfunction normalizeTitle(title: string): string {\n const t = title.trim();\n if (!t) throw new Error('Goal title is required');\n return t;\n}\n\nfunction toTerminalStatus(verdict: GoalJudgeDecision['verdict']): GoalStatus {\n if (verdict === 'done') return 'done';\n if (verdict === 'blocked') return 'blocked';\n if (verdict === 'needs_input') return 'needs_input';\n return 'active';\n}\n\nexport class GoalService {\n private readonly store: GoalStore;\n\n constructor(store = new GoalStore()) {\n this.store = store;\n }\n\n create(input: Omit<CreateGoalInput, 'maxTurns' | 'agentId'> & {\n maxTurns?: number;\n agentId?: string;\n config?: Config;\n }): Goal {\n const sessionKey = input.sessionKey;\n const cfg = input.config?.goals;\n return this.store.create({\n title: normalizeTitle(input.title),\n description: input.description,\n agentId: input.agentId ?? 'main',\n sessionKey,\n priority: input.priority,\n deadlineAt: input.deadlineAt,\n judgeModelRef: input.judgeModelRef ?? cfg?.judgeModelRef,\n maxTurns: input.maxTurns ?? defaultMaxTurns(cfg),\n uiLocale: input.uiLocale,\n source: input.source,\n });\n }\n\n get(goalId: string): GoalWithDetails | null {\n const goal = this.store.get(goalId);\n if (!goal) return null;\n return {\n ...goal,\n checklist: this.store.listChecklist(goalId),\n latestRun: this.store.listRuns(goalId, 1)[0],\n };\n }\n\n getActiveForSession(sessionKey: string): GoalWithDetails | null {\n const goal = this.store.getActiveForSession(sessionKey);\n return goal ? this.get(goal.id) : null;\n }\n\n list(query: GoalListQuery = {}): GoalWithDetails[] {\n return this.store.list(query).map((goal) => ({\n ...goal,\n checklist: this.store.listChecklist(goal.id),\n latestRun: this.store.listRuns(goal.id, 1)[0],\n }));\n }\n\n update(goalId: string, patch: Partial<Pick<\n Goal,\n | 'title'\n | 'description'\n | 'priority'\n | 'deadlineAt'\n | 'maxTurns'\n | 'judgeModelRef'\n | 'nextAction'\n | 'blockedReason'\n | 'activeSessionKey'\n | 'uiLocale'\n >>): GoalWithDetails | null {\n const normalized: typeof patch = { ...patch };\n if (typeof normalized.title === 'string') {\n normalized.title = normalizeTitle(normalized.title);\n }\n if (typeof normalized.description === 'string') {\n normalized.description = normalized.description.trim() || undefined;\n }\n if (typeof normalized.judgeModelRef === 'string') {\n normalized.judgeModelRef = normalized.judgeModelRef.trim() || undefined;\n }\n if (typeof normalized.nextAction === 'string') {\n normalized.nextAction = normalized.nextAction.trim() || undefined;\n }\n if (typeof normalized.blockedReason === 'string') {\n normalized.blockedReason = normalized.blockedReason.trim() || undefined;\n }\n if (typeof normalized.maxTurns === 'number') {\n normalized.maxTurns = Math.max(1, Math.min(500, Math.floor(normalized.maxTurns)));\n }\n const goal = this.store.update(goalId, normalized);\n return goal ? this.get(goal.id) : null;\n }\n\n setStatus(goalId: string, status: GoalStatus, opts?: { reason?: string }): GoalWithDetails | null {\n const now = Date.now();\n const goal = this.store.update(goalId, {\n status,\n completedAt: status === 'done' ? now : undefined,\n archivedAt: status === 'archived' ? now : undefined,\n blockedReason: status === 'blocked' || status === 'needs_input' ? opts?.reason : undefined,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n pause(goalId: string, reason = 'user-paused'): GoalWithDetails | null {\n const goal = this.store.update(goalId, {\n status: 'paused',\n blockedReason: reason,\n completedAt: undefined,\n archivedAt: undefined,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n resume(goalId: string): GoalWithDetails | null {\n const goal = this.store.update(goalId, {\n status: 'active',\n blockedReason: undefined,\n completedAt: undefined,\n archivedAt: undefined,\n turnsUsed: 0,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n reopen(goalId: string): GoalWithDetails | null {\n const goal = this.store.update(goalId, {\n status: 'active',\n blockedReason: undefined,\n completedAt: undefined,\n archivedAt: undefined,\n turnsUsed: 0,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n complete(goalId: string): GoalWithDetails | null {\n return this.setStatus(goalId, 'done');\n }\n\n archive(goalId: string): GoalWithDetails | null {\n return this.setStatus(goalId, 'archived');\n }\n\n unarchive(goalId: string): GoalWithDetails | null {\n const goal = this.store.update(goalId, {\n status: 'paused',\n archivedAt: undefined,\n completedAt: undefined,\n blockedReason: undefined,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n attachSession(goalId: string, sessionKey: string): GoalWithDetails | null {\n const goal = this.store.update(goalId, { activeSessionKey: sessionKey });\n return goal ? this.get(goal.id) : null;\n }\n\n updateChecklist(goalId: string, op: {\n type: 'add';\n text: string;\n addedBy?: GoalChecklistAddedBy;\n } | {\n type: 'mark';\n itemId: string;\n status: GoalChecklistStatus;\n evidenceSummary?: string;\n } | {\n type: 'remove';\n itemId: string;\n } | {\n type: 'reset';\n }): GoalWithDetails | null {\n if (op.type === 'add') {\n const text = op.text.trim();\n if (!text) throw new Error('Checklist item text is required');\n this.store.addChecklistItem({ goalId, text, addedBy: op.addedBy ?? 'user' });\n } else if (op.type === 'mark') {\n this.store.updateChecklistItem(op.itemId, {\n status: op.status,\n evidenceSummary: op.evidenceSummary,\n });\n } else if (op.type === 'remove') {\n this.store.removeChecklistItem(op.itemId);\n } else {\n this.store.clearChecklist(goalId);\n }\n return this.get(goalId);\n }\n\n recordJudgeDecision(input: {\n goalId: string;\n sessionKey: string;\n source: GoalSource;\n decision: GoalJudgeDecision;\n }): GoalWithDetails | null {\n const goal = this.store.get(input.goalId);\n if (!goal) return null;\n const nextStatus = toTerminalStatus(input.decision.verdict);\n const turnsUsed = goal.turnsUsed + 1;\n const status = turnsUsed >= goal.maxTurns && nextStatus === 'active' ? 'paused' : nextStatus;\n const reason =\n status === 'paused' && turnsUsed >= goal.maxTurns\n ? `turn budget exhausted (${turnsUsed}/${goal.maxTurns})`\n : input.decision.reason;\n\n const run = this.store.appendRun({\n goalId: input.goalId,\n sessionKey: input.sessionKey,\n source: input.source,\n status: 'succeeded',\n finishedAt: Date.now(),\n verdict: input.decision.verdict,\n reason: input.decision.reason,\n nextAction: input.decision.nextAction,\n assistantPreview: input.decision.assistantPreview,\n checklistProgress: input.decision.checklistProgress,\n confidence: input.decision.confidence,\n missingEvidence: input.decision.missingEvidence,\n userQuestion: input.decision.userQuestion,\n completedChecklistItemIds: input.decision.completedChecklistItemIds,\n });\n\n this.store.update(input.goalId, {\n status,\n turnsUsed,\n currentRunId: run.id,\n nextAction: input.decision.nextAction,\n blockedReason: status === 'blocked' || status === 'needs_input' || status === 'paused' ? reason : undefined,\n completedAt: status === 'done' ? Date.now() : undefined,\n });\n\n return this.get(input.goalId);\n }\n\n syncPostTurnState(input: {\n goalId: string;\n sessionKey: string;\n source: GoalSource;\n status: GoalStatus;\n turnsUsed: number;\n maxTurns: number;\n reason?: string;\n nextAction?: string;\n assistantPreview?: string;\n verdict: 'continue' | 'done' | 'blocked' | 'needs_input' | 'decompose';\n confidence?: number;\n missingEvidence?: string[];\n userQuestion?: string;\n completedChecklistItemIds?: string[];\n checklist?: Array<{\n text: string;\n status: 'pending' | 'completed' | 'impossible';\n addedBy: 'user' | 'judge';\n addedAt?: number;\n completedAt?: number;\n evidenceSummary?: string;\n }>;\n }): GoalWithDetails | null {\n const goal = this.store.get(input.goalId);\n if (!goal) return null;\n if (input.checklist) {\n this.store.replaceChecklist(input.goalId, input.checklist);\n }\n const total = input.checklist?.length ?? this.store.listChecklist(input.goalId).length;\n const done = (input.checklist ?? this.store.listChecklist(input.goalId)).filter(\n (it) => it.status === 'completed' || it.status === 'impossible',\n ).length;\n const run = this.store.appendRun({\n goalId: input.goalId,\n sessionKey: input.sessionKey,\n source: input.source,\n status: 'succeeded',\n finishedAt: Date.now(),\n verdict: input.verdict,\n reason: input.reason,\n nextAction: input.nextAction,\n assistantPreview: input.assistantPreview,\n checklistProgress: total > 0 ? { done, total } : undefined,\n confidence: input.confidence,\n missingEvidence: input.missingEvidence,\n userQuestion: input.userQuestion,\n completedChecklistItemIds: input.completedChecklistItemIds,\n });\n for (const item of input.checklist ?? []) {\n if ((item.status === 'completed' || item.status === 'impossible') && item.evidenceSummary?.trim()) {\n this.store.addEvidence({\n goalId: input.goalId,\n runId: run.id,\n kind: 'message',\n title: `Checklist evidence: ${item.text.slice(0, 80)}`,\n summary: item.evidenceSummary.trim(),\n });\n }\n }\n for (const missing of input.missingEvidence ?? []) {\n if (!missing.trim()) continue;\n this.store.addEvidence({\n goalId: input.goalId,\n runId: run.id,\n kind: 'message',\n title: `Missing evidence: ${missing.slice(0, 80)}`,\n summary: missing,\n });\n }\n if (input.userQuestion?.trim()) {\n this.store.addEvidence({\n goalId: input.goalId,\n runId: run.id,\n kind: 'message',\n title: 'User input requested',\n summary: input.userQuestion.trim(),\n });\n }\n this.store.update(input.goalId, {\n status: input.status,\n turnsUsed: input.turnsUsed,\n maxTurns: input.maxTurns,\n currentRunId: run.id,\n nextAction: input.nextAction,\n blockedReason:\n input.status === 'blocked' || input.status === 'needs_input' || input.status === 'paused'\n ? input.reason\n : undefined,\n completedAt: input.status === 'done' ? Date.now() : undefined,\n });\n return this.get(input.goalId);\n }\n\n listRuns(goalId: string, limit?: number) {\n return this.store.listRuns(goalId, limit);\n }\n\n listRunsForSession(sessionKey: string, limit?: number) {\n return this.store.listRunsForSession(sessionKey, limit);\n }\n\n listEvents(goalId: string, limit?: number) {\n return this.store.listEvents(goalId, limit);\n }\n\n addEvidence(input: Parameters<GoalStore['addEvidence']>[0]) {\n return this.store.addEvidence(input);\n }\n\n listEvidence(goalId: string, limit?: number) {\n return this.store.listEvidence(goalId, limit);\n }\n}\n\nexport function normalizeGoalUiLocale(raw: unknown): GoalUiLocale | undefined {\n return raw === 'en' || raw === 'zh' ? raw : undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"goal-service.js","names":[],"sources":["../../../src/goals/goal-service.ts"],"sourcesContent":["import type { Config } from '../config/schema.js';\nimport { defaultMaxTurns } from '../agent/goals/state.js';\nimport { GoalStore } from './goal-store.js';\nimport type {\n CreateGoalInput,\n Goal,\n GoalChecklistAddedBy,\n GoalChecklistStatus,\n GoalContextAttachment,\n GoalJudgeDecision,\n GoalListQuery,\n GoalSource,\n GoalStatus,\n GoalUiLocale,\n GoalWithDetails,\n} from './types.js';\n\nfunction normalizeTitle(title: string): string {\n const t = title.trim();\n if (!t) throw new Error('Goal title is required');\n return t;\n}\n\nfunction toTerminalStatus(verdict: GoalJudgeDecision['verdict']): GoalStatus {\n if (verdict === 'done') return 'done';\n if (verdict === 'blocked') return 'blocked';\n if (verdict === 'needs_input') return 'needs_input';\n return 'active';\n}\n\nexport class GoalService {\n private readonly store: GoalStore;\n\n constructor(store = new GoalStore()) {\n this.store = store;\n }\n\n create(input: Omit<CreateGoalInput, 'maxTurns' | 'agentId'> & {\n maxTurns?: number;\n agentId?: string;\n config?: Config;\n }): Goal {\n const sessionKey = input.sessionKey;\n const cfg = input.config?.goals;\n return this.store.create({\n title: normalizeTitle(input.title),\n description: input.description,\n agentId: input.agentId ?? 'main',\n sessionKey,\n priority: input.priority,\n deadlineAt: input.deadlineAt,\n judgeModelRef: input.judgeModelRef ?? cfg?.judgeModelRef,\n maxTurns: input.maxTurns ?? defaultMaxTurns(cfg),\n uiLocale: input.uiLocale,\n source: input.source,\n });\n }\n\n get(goalId: string): GoalWithDetails | null {\n const goal = this.store.get(goalId);\n if (!goal) return null;\n return {\n ...goal,\n checklist: this.store.listChecklist(goalId),\n latestRun: this.store.listRuns(goalId, 1)[0],\n contextMessage: this.store.getContextMessage(goalId) ?? undefined,\n };\n }\n\n getActiveForSession(sessionKey: string): GoalWithDetails | null {\n const goal = this.store.getActiveForSession(sessionKey);\n return goal ? this.get(goal.id) : null;\n }\n\n list(query: GoalListQuery = {}): GoalWithDetails[] {\n return this.store.list(query).map((goal) => ({\n ...goal,\n checklist: this.store.listChecklist(goal.id),\n latestRun: this.store.listRuns(goal.id, 1)[0],\n contextMessage: this.store.getContextMessage(goal.id) ?? undefined,\n }));\n }\n\n setContextMessage(input: {\n goalId: string;\n text: string;\n attachments?: GoalContextAttachment[];\n }): GoalWithDetails | null {\n if (!this.store.get(input.goalId)) return null;\n this.store.setContextMessage(input);\n return this.get(input.goalId);\n }\n\n update(goalId: string, patch: Partial<Pick<\n Goal,\n | 'title'\n | 'description'\n | 'priority'\n | 'deadlineAt'\n | 'maxTurns'\n | 'judgeModelRef'\n | 'nextAction'\n | 'blockedReason'\n | 'activeSessionKey'\n | 'uiLocale'\n >>): GoalWithDetails | null {\n const normalized: typeof patch = { ...patch };\n if (typeof normalized.title === 'string') {\n normalized.title = normalizeTitle(normalized.title);\n }\n if (typeof normalized.description === 'string') {\n normalized.description = normalized.description.trim() || undefined;\n }\n if (typeof normalized.judgeModelRef === 'string') {\n normalized.judgeModelRef = normalized.judgeModelRef.trim() || undefined;\n }\n if (typeof normalized.nextAction === 'string') {\n normalized.nextAction = normalized.nextAction.trim() || undefined;\n }\n if (typeof normalized.blockedReason === 'string') {\n normalized.blockedReason = normalized.blockedReason.trim() || undefined;\n }\n if (typeof normalized.maxTurns === 'number') {\n normalized.maxTurns = Math.max(1, Math.min(500, Math.floor(normalized.maxTurns)));\n }\n const goal = this.store.update(goalId, normalized);\n return goal ? this.get(goal.id) : null;\n }\n\n setStatus(goalId: string, status: GoalStatus, opts?: { reason?: string }): GoalWithDetails | null {\n const now = Date.now();\n const goal = this.store.update(goalId, {\n status,\n completedAt: status === 'done' ? now : undefined,\n archivedAt: status === 'archived' ? now : undefined,\n blockedReason: status === 'blocked' || status === 'needs_input' ? opts?.reason : undefined,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n pause(goalId: string, reason = 'user-paused'): GoalWithDetails | null {\n const goal = this.store.update(goalId, {\n status: 'paused',\n blockedReason: reason,\n completedAt: undefined,\n archivedAt: undefined,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n resume(goalId: string): GoalWithDetails | null {\n const goal = this.store.update(goalId, {\n status: 'active',\n blockedReason: undefined,\n completedAt: undefined,\n archivedAt: undefined,\n turnsUsed: 0,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n reopen(goalId: string): GoalWithDetails | null {\n const goal = this.store.update(goalId, {\n status: 'active',\n blockedReason: undefined,\n completedAt: undefined,\n archivedAt: undefined,\n turnsUsed: 0,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n complete(goalId: string): GoalWithDetails | null {\n return this.setStatus(goalId, 'done');\n }\n\n archive(goalId: string): GoalWithDetails | null {\n return this.setStatus(goalId, 'archived');\n }\n\n unarchive(goalId: string): GoalWithDetails | null {\n const goal = this.store.update(goalId, {\n status: 'paused',\n archivedAt: undefined,\n completedAt: undefined,\n blockedReason: undefined,\n });\n return goal ? this.get(goal.id) : null;\n }\n\n attachSession(goalId: string, sessionKey: string): GoalWithDetails | null {\n const goal = this.store.update(goalId, { activeSessionKey: sessionKey });\n return goal ? this.get(goal.id) : null;\n }\n\n updateChecklist(goalId: string, op: {\n type: 'add';\n text: string;\n addedBy?: GoalChecklistAddedBy;\n } | {\n type: 'mark';\n itemId: string;\n status: GoalChecklistStatus;\n evidenceSummary?: string;\n } | {\n type: 'remove';\n itemId: string;\n } | {\n type: 'reset';\n }): GoalWithDetails | null {\n if (op.type === 'add') {\n const text = op.text.trim();\n if (!text) throw new Error('Checklist item text is required');\n this.store.addChecklistItem({ goalId, text, addedBy: op.addedBy ?? 'user' });\n } else if (op.type === 'mark') {\n this.store.updateChecklistItem(op.itemId, {\n status: op.status,\n evidenceSummary: op.evidenceSummary,\n });\n } else if (op.type === 'remove') {\n this.store.removeChecklistItem(op.itemId);\n } else {\n this.store.clearChecklist(goalId);\n }\n return this.get(goalId);\n }\n\n recordJudgeDecision(input: {\n goalId: string;\n sessionKey: string;\n source: GoalSource;\n decision: GoalJudgeDecision;\n }): GoalWithDetails | null {\n const goal = this.store.get(input.goalId);\n if (!goal) return null;\n const nextStatus = toTerminalStatus(input.decision.verdict);\n const turnsUsed = goal.turnsUsed + 1;\n const status = turnsUsed >= goal.maxTurns && nextStatus === 'active' ? 'paused' : nextStatus;\n const reason =\n status === 'paused' && turnsUsed >= goal.maxTurns\n ? `turn budget exhausted (${turnsUsed}/${goal.maxTurns})`\n : input.decision.reason;\n\n const run = this.store.appendRun({\n goalId: input.goalId,\n sessionKey: input.sessionKey,\n source: input.source,\n status: 'succeeded',\n finishedAt: Date.now(),\n verdict: input.decision.verdict,\n reason: input.decision.reason,\n nextAction: input.decision.nextAction,\n assistantPreview: input.decision.assistantPreview,\n checklistProgress: input.decision.checklistProgress,\n confidence: input.decision.confidence,\n missingEvidence: input.decision.missingEvidence,\n userQuestion: input.decision.userQuestion,\n completedChecklistItemIds: input.decision.completedChecklistItemIds,\n });\n\n this.store.update(input.goalId, {\n status,\n turnsUsed,\n currentRunId: run.id,\n nextAction: input.decision.nextAction,\n blockedReason: status === 'blocked' || status === 'needs_input' || status === 'paused' ? reason : undefined,\n completedAt: status === 'done' ? Date.now() : undefined,\n });\n\n return this.get(input.goalId);\n }\n\n syncPostTurnState(input: {\n goalId: string;\n sessionKey: string;\n source: GoalSource;\n status: GoalStatus;\n turnsUsed: number;\n maxTurns: number;\n reason?: string;\n nextAction?: string;\n assistantPreview?: string;\n verdict: 'continue' | 'done' | 'blocked' | 'needs_input' | 'decompose';\n confidence?: number;\n missingEvidence?: string[];\n userQuestion?: string;\n completedChecklistItemIds?: string[];\n checklist?: Array<{\n text: string;\n status: 'pending' | 'completed' | 'impossible';\n addedBy: 'user' | 'judge';\n addedAt?: number;\n completedAt?: number;\n evidenceSummary?: string;\n }>;\n }): GoalWithDetails | null {\n const goal = this.store.get(input.goalId);\n if (!goal) return null;\n if (input.checklist) {\n this.store.replaceChecklist(input.goalId, input.checklist);\n }\n const total = input.checklist?.length ?? this.store.listChecklist(input.goalId).length;\n const done = (input.checklist ?? this.store.listChecklist(input.goalId)).filter(\n (it) => it.status === 'completed' || it.status === 'impossible',\n ).length;\n const run = this.store.appendRun({\n goalId: input.goalId,\n sessionKey: input.sessionKey,\n source: input.source,\n status: 'succeeded',\n finishedAt: Date.now(),\n verdict: input.verdict,\n reason: input.reason,\n nextAction: input.nextAction,\n assistantPreview: input.assistantPreview,\n checklistProgress: total > 0 ? { done, total } : undefined,\n confidence: input.confidence,\n missingEvidence: input.missingEvidence,\n userQuestion: input.userQuestion,\n completedChecklistItemIds: input.completedChecklistItemIds,\n });\n for (const item of input.checklist ?? []) {\n if ((item.status === 'completed' || item.status === 'impossible') && item.evidenceSummary?.trim()) {\n this.store.addEvidence({\n goalId: input.goalId,\n runId: run.id,\n kind: 'message',\n title: `Checklist evidence: ${item.text.slice(0, 80)}`,\n summary: item.evidenceSummary.trim(),\n });\n }\n }\n for (const missing of input.missingEvidence ?? []) {\n if (!missing.trim()) continue;\n this.store.addEvidence({\n goalId: input.goalId,\n runId: run.id,\n kind: 'message',\n title: `Missing evidence: ${missing.slice(0, 80)}`,\n summary: missing,\n });\n }\n if (input.userQuestion?.trim()) {\n this.store.addEvidence({\n goalId: input.goalId,\n runId: run.id,\n kind: 'message',\n title: 'User input requested',\n summary: input.userQuestion.trim(),\n });\n }\n this.store.update(input.goalId, {\n status: input.status,\n turnsUsed: input.turnsUsed,\n maxTurns: input.maxTurns,\n currentRunId: run.id,\n nextAction: input.nextAction,\n blockedReason:\n input.status === 'blocked' || input.status === 'needs_input' || input.status === 'paused'\n ? input.reason\n : undefined,\n completedAt: input.status === 'done' ? Date.now() : undefined,\n });\n return this.get(input.goalId);\n }\n\n listRuns(goalId: string, limit?: number) {\n return this.store.listRuns(goalId, limit);\n }\n\n listRunsForSession(sessionKey: string, limit?: number) {\n return this.store.listRunsForSession(sessionKey, limit);\n }\n\n listEvents(goalId: string, limit?: number) {\n return this.store.listEvents(goalId, limit);\n }\n\n addEvidence(input: Parameters<GoalStore['addEvidence']>[0]) {\n return this.store.addEvidence(input);\n }\n\n listEvidence(goalId: string, limit?: number) {\n return this.store.listEvidence(goalId, limit);\n }\n}\n\nexport function normalizeGoalUiLocale(raw: unknown): GoalUiLocale | undefined {\n return raw === 'en' || raw === 'zh' ? raw : undefined;\n}\n"],"mappings":";;;AAiBA,SAAS,eAAe,OAAuB;CAC7C,MAAM,IAAI,MAAM,MAAM;AACtB,KAAI,CAAC,EAAG,OAAM,IAAI,MAAM,yBAAyB;AACjD,QAAO;;AAGT,SAAS,iBAAiB,SAAmD;AAC3E,KAAI,YAAY,OAAQ,QAAO;AAC/B,KAAI,YAAY,UAAW,QAAO;AAClC,KAAI,YAAY,cAAe,QAAO;AACtC,QAAO;;AAGT,IAAa,cAAb,MAAyB;CACvB;CAEA,YAAY,QAAQ,IAAI,WAAW,EAAE;AACnC,OAAK,QAAQ;;CAGf,OAAO,OAIE;EACP,MAAM,aAAa,MAAM;EACzB,MAAM,MAAM,MAAM,QAAQ;AAC1B,SAAO,KAAK,MAAM,OAAO;GACvB,OAAO,eAAe,MAAM,MAAM;GAClC,aAAa,MAAM;GACnB,SAAS,MAAM,WAAW;GAC1B;GACA,UAAU,MAAM;GAChB,YAAY,MAAM;GAClB,eAAe,MAAM,iBAAiB,KAAK;GAC3C,UAAU,MAAM,YAAY,gBAAgB,IAAI;GAChD,UAAU,MAAM;GAChB,QAAQ,MAAM;GACf,CAAC;;CAGJ,IAAI,QAAwC;EAC1C,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO;AACnC,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO;GACL,GAAG;GACH,WAAW,KAAK,MAAM,cAAc,OAAO;GAC3C,WAAW,KAAK,MAAM,SAAS,QAAQ,EAAE,CAAC;GAC1C,gBAAgB,KAAK,MAAM,kBAAkB,OAAO,IAAI,KAAA;GACzD;;CAGH,oBAAoB,YAA4C;EAC9D,MAAM,OAAO,KAAK,MAAM,oBAAoB,WAAW;AACvD,SAAO,OAAO,KAAK,IAAI,KAAK,GAAG,GAAG;;CAGpC,KAAK,QAAuB,EAAE,EAAqB;AACjD,SAAO,KAAK,MAAM,KAAK,MAAM,CAAC,KAAK,UAAU;GAC3C,GAAG;GACH,WAAW,KAAK,MAAM,cAAc,KAAK,GAAG;GAC5C,WAAW,KAAK,MAAM,SAAS,KAAK,IAAI,EAAE,CAAC;GAC3C,gBAAgB,KAAK,MAAM,kBAAkB,KAAK,GAAG,IAAI,KAAA;GAC1D,EAAE;;CAGL,kBAAkB,OAIS;AACzB,MAAI,CAAC,KAAK,MAAM,IAAI,MAAM,OAAO,CAAE,QAAO;AAC1C,OAAK,MAAM,kBAAkB,MAAM;AACnC,SAAO,KAAK,IAAI,MAAM,OAAO;;CAG/B,OAAO,QAAgB,OAYK;EAC1B,MAAM,aAA2B,EAAE,GAAG,OAAO;AAC7C,MAAI,OAAO,WAAW,UAAU,SAC9B,YAAW,QAAQ,eAAe,WAAW,MAAM;AAErD,MAAI,OAAO,WAAW,gBAAgB,SACpC,YAAW,cAAc,WAAW,YAAY,MAAM,IAAI,KAAA;AAE5D,MAAI,OAAO,WAAW,kBAAkB,SACtC,YAAW,gBAAgB,WAAW,cAAc,MAAM,IAAI,KAAA;AAEhE,MAAI,OAAO,WAAW,eAAe,SACnC,YAAW,aAAa,WAAW,WAAW,MAAM,IAAI,KAAA;AAE1D,MAAI,OAAO,WAAW,kBAAkB,SACtC,YAAW,gBAAgB,WAAW,cAAc,MAAM,IAAI,KAAA;AAEhE,MAAI,OAAO,WAAW,aAAa,SACjC,YAAW,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,WAAW,SAAS,CAAC,CAAC;EAEnF,MAAM,OAAO,KAAK,MAAM,OAAO,QAAQ,WAAW;AAClD,SAAO,OAAO,KAAK,IAAI,KAAK,GAAG,GAAG;;CAGpC,UAAU,QAAgB,QAAoB,MAAoD;EAChG,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,OAAO,KAAK,MAAM,OAAO,QAAQ;GACrC;GACA,aAAa,WAAW,SAAS,MAAM,KAAA;GACvC,YAAY,WAAW,aAAa,MAAM,KAAA;GAC1C,eAAe,WAAW,aAAa,WAAW,gBAAgB,MAAM,SAAS,KAAA;GAClF,CAAC;AACF,SAAO,OAAO,KAAK,IAAI,KAAK,GAAG,GAAG;;CAGpC,MAAM,QAAgB,SAAS,eAAuC;EACpE,MAAM,OAAO,KAAK,MAAM,OAAO,QAAQ;GACrC,QAAQ;GACR,eAAe;GACf,aAAa,KAAA;GACb,YAAY,KAAA;GACb,CAAC;AACF,SAAO,OAAO,KAAK,IAAI,KAAK,GAAG,GAAG;;CAGpC,OAAO,QAAwC;EAC7C,MAAM,OAAO,KAAK,MAAM,OAAO,QAAQ;GACrC,QAAQ;GACR,eAAe,KAAA;GACf,aAAa,KAAA;GACb,YAAY,KAAA;GACZ,WAAW;GACZ,CAAC;AACF,SAAO,OAAO,KAAK,IAAI,KAAK,GAAG,GAAG;;CAGpC,OAAO,QAAwC;EAC7C,MAAM,OAAO,KAAK,MAAM,OAAO,QAAQ;GACrC,QAAQ;GACR,eAAe,KAAA;GACf,aAAa,KAAA;GACb,YAAY,KAAA;GACZ,WAAW;GACZ,CAAC;AACF,SAAO,OAAO,KAAK,IAAI,KAAK,GAAG,GAAG;;CAGpC,SAAS,QAAwC;AAC/C,SAAO,KAAK,UAAU,QAAQ,OAAO;;CAGvC,QAAQ,QAAwC;AAC9C,SAAO,KAAK,UAAU,QAAQ,WAAW;;CAG3C,UAAU,QAAwC;EAChD,MAAM,OAAO,KAAK,MAAM,OAAO,QAAQ;GACrC,QAAQ;GACR,YAAY,KAAA;GACZ,aAAa,KAAA;GACb,eAAe,KAAA;GAChB,CAAC;AACF,SAAO,OAAO,KAAK,IAAI,KAAK,GAAG,GAAG;;CAGpC,cAAc,QAAgB,YAA4C;EACxE,MAAM,OAAO,KAAK,MAAM,OAAO,QAAQ,EAAE,kBAAkB,YAAY,CAAC;AACxE,SAAO,OAAO,KAAK,IAAI,KAAK,GAAG,GAAG;;CAGpC,gBAAgB,QAAgB,IAcL;AACzB,MAAI,GAAG,SAAS,OAAO;GACrB,MAAM,OAAO,GAAG,KAAK,MAAM;AAC3B,OAAI,CAAC,KAAM,OAAM,IAAI,MAAM,kCAAkC;AAC7D,QAAK,MAAM,iBAAiB;IAAE;IAAQ;IAAM,SAAS,GAAG,WAAW;IAAQ,CAAC;aACnE,GAAG,SAAS,OACrB,MAAK,MAAM,oBAAoB,GAAG,QAAQ;GACxC,QAAQ,GAAG;GACX,iBAAiB,GAAG;GACrB,CAAC;WACO,GAAG,SAAS,SACrB,MAAK,MAAM,oBAAoB,GAAG,OAAO;MAEzC,MAAK,MAAM,eAAe,OAAO;AAEnC,SAAO,KAAK,IAAI,OAAO;;CAGzB,oBAAoB,OAKO;EACzB,MAAM,OAAO,KAAK,MAAM,IAAI,MAAM,OAAO;AACzC,MAAI,CAAC,KAAM,QAAO;EAClB,MAAM,aAAa,iBAAiB,MAAM,SAAS,QAAQ;EAC3D,MAAM,YAAY,KAAK,YAAY;EACnC,MAAM,SAAS,aAAa,KAAK,YAAY,eAAe,WAAW,WAAW;EAClF,MAAM,SACJ,WAAW,YAAY,aAAa,KAAK,WACrC,0BAA0B,UAAU,GAAG,KAAK,SAAS,KACrD,MAAM,SAAS;EAErB,MAAM,MAAM,KAAK,MAAM,UAAU;GAC/B,QAAQ,MAAM;GACd,YAAY,MAAM;GAClB,QAAQ,MAAM;GACd,QAAQ;GACR,YAAY,KAAK,KAAK;GACtB,SAAS,MAAM,SAAS;GACxB,QAAQ,MAAM,SAAS;GACvB,YAAY,MAAM,SAAS;GAC3B,kBAAkB,MAAM,SAAS;GACjC,mBAAmB,MAAM,SAAS;GAClC,YAAY,MAAM,SAAS;GAC3B,iBAAiB,MAAM,SAAS;GAChC,cAAc,MAAM,SAAS;GAC7B,2BAA2B,MAAM,SAAS;GAC3C,CAAC;AAEF,OAAK,MAAM,OAAO,MAAM,QAAQ;GAC9B;GACA;GACA,cAAc,IAAI;GAClB,YAAY,MAAM,SAAS;GAC3B,eAAe,WAAW,aAAa,WAAW,iBAAiB,WAAW,WAAW,SAAS,KAAA;GAClG,aAAa,WAAW,SAAS,KAAK,KAAK,GAAG,KAAA;GAC/C,CAAC;AAEF,SAAO,KAAK,IAAI,MAAM,OAAO;;CAG/B,kBAAkB,OAuBS;AAEzB,MAAI,CADS,KAAK,MAAM,IAAI,MAAM,OACzB,CAAE,QAAO;AAClB,MAAI,MAAM,UACR,MAAK,MAAM,iBAAiB,MAAM,QAAQ,MAAM,UAAU;EAE5D,MAAM,QAAQ,MAAM,WAAW,UAAU,KAAK,MAAM,cAAc,MAAM,OAAO,CAAC;EAChF,MAAM,QAAQ,MAAM,aAAa,KAAK,MAAM,cAAc,MAAM,OAAO,EAAE,QACtE,OAAO,GAAG,WAAW,eAAe,GAAG,WAAW,aACpD,CAAC;EACF,MAAM,MAAM,KAAK,MAAM,UAAU;GAC/B,QAAQ,MAAM;GACd,YAAY,MAAM;GAClB,QAAQ,MAAM;GACd,QAAQ;GACR,YAAY,KAAK,KAAK;GACtB,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,YAAY,MAAM;GAClB,kBAAkB,MAAM;GACxB,mBAAmB,QAAQ,IAAI;IAAE;IAAM;IAAO,GAAG,KAAA;GACjD,YAAY,MAAM;GAClB,iBAAiB,MAAM;GACvB,cAAc,MAAM;GACpB,2BAA2B,MAAM;GAClC,CAAC;AACF,OAAK,MAAM,QAAQ,MAAM,aAAa,EAAE,CACtC,MAAK,KAAK,WAAW,eAAe,KAAK,WAAW,iBAAiB,KAAK,iBAAiB,MAAM,CAC/F,MAAK,MAAM,YAAY;GACrB,QAAQ,MAAM;GACd,OAAO,IAAI;GACX,MAAM;GACN,OAAO,uBAAuB,KAAK,KAAK,MAAM,GAAG,GAAG;GACpD,SAAS,KAAK,gBAAgB,MAAM;GACrC,CAAC;AAGN,OAAK,MAAM,WAAW,MAAM,mBAAmB,EAAE,EAAE;AACjD,OAAI,CAAC,QAAQ,MAAM,CAAE;AACrB,QAAK,MAAM,YAAY;IACrB,QAAQ,MAAM;IACd,OAAO,IAAI;IACX,MAAM;IACN,OAAO,qBAAqB,QAAQ,MAAM,GAAG,GAAG;IAChD,SAAS;IACV,CAAC;;AAEJ,MAAI,MAAM,cAAc,MAAM,CAC5B,MAAK,MAAM,YAAY;GACrB,QAAQ,MAAM;GACd,OAAO,IAAI;GACX,MAAM;GACN,OAAO;GACP,SAAS,MAAM,aAAa,MAAM;GACnC,CAAC;AAEJ,OAAK,MAAM,OAAO,MAAM,QAAQ;GAC9B,QAAQ,MAAM;GACd,WAAW,MAAM;GACjB,UAAU,MAAM;GAChB,cAAc,IAAI;GAClB,YAAY,MAAM;GAClB,eACE,MAAM,WAAW,aAAa,MAAM,WAAW,iBAAiB,MAAM,WAAW,WAC7E,MAAM,SACN,KAAA;GACN,aAAa,MAAM,WAAW,SAAS,KAAK,KAAK,GAAG,KAAA;GACrD,CAAC;AACF,SAAO,KAAK,IAAI,MAAM,OAAO;;CAG/B,SAAS,QAAgB,OAAgB;AACvC,SAAO,KAAK,MAAM,SAAS,QAAQ,MAAM;;CAG3C,mBAAmB,YAAoB,OAAgB;AACrD,SAAO,KAAK,MAAM,mBAAmB,YAAY,MAAM;;CAGzD,WAAW,QAAgB,OAAgB;AACzC,SAAO,KAAK,MAAM,WAAW,QAAQ,MAAM;;CAG7C,YAAY,OAAgD;AAC1D,SAAO,KAAK,MAAM,YAAY,MAAM;;CAGtC,aAAa,QAAgB,OAAgB;AAC3C,SAAO,KAAK,MAAM,aAAa,QAAQ,MAAM;;;AAIjD,SAAgB,sBAAsB,KAAwC;AAC5E,QAAO,QAAQ,QAAQ,QAAQ,OAAO,MAAM,KAAA"}
@@ -1,7 +1,13 @@
1
- import type { CreateGoalInput, Goal, GoalChecklistAddedBy, GoalChecklistItem, GoalChecklistStatus, GoalEvent, GoalEvidence, GoalListQuery, GoalRun } from './types.js';
1
+ import type { CreateGoalInput, Goal, GoalChecklistAddedBy, GoalChecklistItem, GoalChecklistStatus, GoalContextAttachment, GoalContextMessage, GoalEvent, GoalEvidence, GoalListQuery, GoalRun } from './types.js';
2
2
  export declare class GoalStore {
3
3
  create(input: CreateGoalInput): Goal;
4
4
  get(goalId: string): Goal | null;
5
+ setContextMessage(input: {
6
+ goalId: string;
7
+ text: string;
8
+ attachments?: GoalContextAttachment[];
9
+ }): GoalContextMessage;
10
+ getContextMessage(goalId: string): GoalContextMessage | null;
5
11
  getActiveForSession(sessionKey: string): Goal | null;
6
12
  list(query?: GoalListQuery): Goal[];
7
13
  update(goalId: string, patch: Partial<Pick<Goal, 'title' | 'description' | 'status' | 'priority' | 'deadlineAt' | 'completedAt' | 'archivedAt' | 'activeSessionKey' | 'currentRunId' | 'nextAction' | 'blockedReason' | 'judgeModelRef' | 'maxTurns' | 'turnsUsed' | 'uiLocale'>>): Goal | null;
@@ -75,6 +75,24 @@ function parseJsonStringArray(raw) {
75
75
  const rows = value.filter((item) => typeof item === "string" && item.trim().length > 0);
76
76
  return rows.length ? rows : void 0;
77
77
  }
78
+ function parseGoalContextAttachments(raw) {
79
+ const parsed = parseJsonField(raw);
80
+ if (!Array.isArray(parsed)) return [];
81
+ return parsed.filter((item) => {
82
+ if (!item || typeof item !== "object") return false;
83
+ const ref = item;
84
+ return typeof ref.id === "string" && (ref.bucket === "inbound" || ref.bucket === "tts" || ref.bucket === "outbound") && typeof ref.type === "string" && typeof ref.mimeType === "string" && typeof ref.name === "string" && typeof ref.size === "number" && typeof ref.uri === "string" && typeof ref.path === "string";
85
+ });
86
+ }
87
+ function goalContextFromRow(row) {
88
+ return {
89
+ goalId: row.goal_id,
90
+ text: row.text,
91
+ attachments: parseGoalContextAttachments(row.attachments_json),
92
+ createdAt: row.created_at,
93
+ updatedAt: row.updated_at
94
+ };
95
+ }
78
96
  function eventFromRow(row) {
79
97
  return {
80
98
  id: row.event_id,
@@ -157,6 +175,30 @@ var GoalStore = class {
157
175
  const row = getSqliteDatabase().prepare(`SELECT * FROM goals WHERE goal_id = ?`).get(goalId);
158
176
  return row ? goalFromRow(row) : null;
159
177
  }
178
+ setContextMessage(input) {
179
+ return runSqliteWriteTransaction((db) => {
180
+ const now = Date.now();
181
+ const existing = db.prepare(`SELECT created_at FROM goal_context_messages WHERE goal_id = ?`).get(input.goalId);
182
+ db.prepare(`INSERT INTO goal_context_messages (goal_id, text, attachments_json, created_at, updated_at)
183
+ VALUES (?, ?, ?, ?, ?)
184
+ ON CONFLICT(goal_id) DO UPDATE SET
185
+ text = excluded.text,
186
+ attachments_json = excluded.attachments_json,
187
+ updated_at = excluded.updated_at`).run(input.goalId, input.text.trim(), JSON.stringify(input.attachments ?? []), existing?.created_at ?? now, now);
188
+ insertGoalEvent(db, {
189
+ goalId: input.goalId,
190
+ kind: "context_updated",
191
+ message: input.text.trim() || `${input.attachments?.length ?? 0} attachment(s)`,
192
+ data: { attachmentCount: input.attachments?.length ?? 0 },
193
+ createdAt: now
194
+ });
195
+ return goalContextFromRow(db.prepare(`SELECT * FROM goal_context_messages WHERE goal_id = ?`).get(input.goalId));
196
+ });
197
+ }
198
+ getContextMessage(goalId) {
199
+ const row = getSqliteDatabase().prepare(`SELECT * FROM goal_context_messages WHERE goal_id = ?`).get(goalId);
200
+ return row ? goalContextFromRow(row) : null;
201
+ }
160
202
  getActiveForSession(sessionKey) {
161
203
  const row = getSqliteDatabase().prepare(`SELECT * FROM goals
162
204
  WHERE active_session_key = ?
@@ -1 +1 @@
1
- {"version":3,"file":"goal-store.js","names":[],"sources":["../../../src/goals/goal-store.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { getSqliteDatabase, runSqliteWriteTransaction } from '../storage/sqlite/transaction.js';\nimport type {\n CreateGoalInput,\n Goal,\n GoalChecklistAddedBy,\n GoalChecklistItem,\n GoalChecklistStatus,\n GoalEvent,\n GoalEvidence,\n GoalListQuery,\n GoalPriority,\n GoalRun,\n GoalRunStatus,\n GoalRunVerdict,\n GoalSource,\n GoalStatus,\n} from './types.js';\n\ntype GoalRow = {\n goal_id: string;\n title: string;\n description: string | null;\n status: string;\n agent_id: string;\n priority: string;\n deadline_at: number | null;\n created_at: number;\n updated_at: number;\n completed_at: number | null;\n archived_at: number | null;\n active_session_key: string | null;\n current_run_id: string | null;\n next_action: string | null;\n blocked_reason: string | null;\n judge_model_ref: string | null;\n max_turns: number;\n turns_used: number;\n ui_locale: string | null;\n source: string;\n};\n\ntype ChecklistRow = {\n item_id: string;\n goal_id: string;\n text: string;\n status: string;\n added_by: string;\n added_at: number;\n completed_at: number | null;\n evidence_summary: string | null;\n sort_order: number;\n};\n\ntype GoalRunRow = {\n run_id: string;\n goal_id: string;\n session_key: string;\n source: string;\n status: string;\n started_at: number;\n finished_at: number | null;\n verdict: string | null;\n reason: string | null;\n next_action: string | null;\n assistant_preview: string | null;\n checklist_done: number | null;\n checklist_total: number | null;\n confidence: number | null;\n missing_evidence_json: string | null;\n user_question: string | null;\n completed_checklist_item_ids_json: string | null;\n};\n\ntype EventRow = {\n event_id: string;\n goal_id: string;\n run_id: string | null;\n kind: string;\n message: string;\n data_json: string | null;\n created_at: number;\n};\n\ntype EvidenceRow = {\n evidence_id: string;\n goal_id: string;\n run_id: string | null;\n kind: GoalEvidence['kind'];\n title: string;\n summary: string | null;\n uri: string | null;\n data_json: string | null;\n created_at: number;\n};\n\nfunction goalFromRow(row: GoalRow): Goal {\n return {\n id: row.goal_id,\n title: row.title,\n description: row.description ?? undefined,\n status: row.status as GoalStatus,\n agentId: row.agent_id,\n priority: row.priority as GoalPriority,\n deadlineAt: row.deadline_at ?? undefined,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n completedAt: row.completed_at ?? undefined,\n archivedAt: row.archived_at ?? undefined,\n activeSessionKey: row.active_session_key ?? undefined,\n currentRunId: row.current_run_id ?? undefined,\n nextAction: row.next_action ?? undefined,\n blockedReason: row.blocked_reason ?? undefined,\n judgeModelRef: row.judge_model_ref ?? undefined,\n maxTurns: row.max_turns,\n turnsUsed: row.turns_used,\n uiLocale: row.ui_locale === 'en' || row.ui_locale === 'zh' ? row.ui_locale : undefined,\n source: row.source as GoalSource,\n };\n}\n\nfunction checklistFromRow(row: ChecklistRow): GoalChecklistItem {\n return {\n id: row.item_id,\n goalId: row.goal_id,\n text: row.text,\n status: row.status as GoalChecklistStatus,\n addedBy: row.added_by as GoalChecklistAddedBy,\n addedAt: row.added_at,\n completedAt: row.completed_at ?? undefined,\n evidenceSummary: row.evidence_summary ?? undefined,\n sortOrder: row.sort_order,\n };\n}\n\nfunction runFromRow(row: GoalRunRow): GoalRun {\n return {\n id: row.run_id,\n goalId: row.goal_id,\n sessionKey: row.session_key,\n source: row.source as GoalSource,\n status: row.status as GoalRunStatus,\n startedAt: row.started_at,\n finishedAt: row.finished_at ?? undefined,\n verdict: row.verdict ? (row.verdict as GoalRunVerdict) : undefined,\n reason: row.reason ?? undefined,\n nextAction: row.next_action ?? undefined,\n assistantPreview: row.assistant_preview ?? undefined,\n checklistProgress:\n row.checklist_done != null && row.checklist_total != null\n ? { done: row.checklist_done, total: row.checklist_total }\n : undefined,\n confidence: row.confidence ?? undefined,\n missingEvidence: parseJsonStringArray(row.missing_evidence_json),\n userQuestion: row.user_question ?? undefined,\n completedChecklistItemIds: parseJsonStringArray(row.completed_checklist_item_ids_json),\n };\n}\n\nfunction parseJsonField(raw: string | null): unknown {\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonStringArray(raw: string | null): string[] | undefined {\n const value = parseJsonField(raw);\n if (!Array.isArray(value)) return undefined;\n const rows = value.filter((item): item is string => typeof item === 'string' && item.trim().length > 0);\n return rows.length ? rows : undefined;\n}\n\nfunction eventFromRow(row: EventRow): GoalEvent {\n return {\n id: row.event_id,\n goalId: row.goal_id,\n runId: row.run_id ?? undefined,\n kind: row.kind,\n message: row.message,\n data: parseJsonField(row.data_json),\n createdAt: row.created_at,\n };\n}\n\nfunction evidenceFromRow(row: EvidenceRow): GoalEvidence {\n return {\n id: row.evidence_id,\n goalId: row.goal_id,\n runId: row.run_id ?? undefined,\n kind: row.kind,\n title: row.title,\n summary: row.summary ?? undefined,\n uri: row.uri ?? undefined,\n data: parseJsonField(row.data_json),\n createdAt: row.created_at,\n };\n}\n\nfunction clampLimit(n: number | undefined, fallback: number): number {\n return Math.min(500, Math.max(1, Math.floor(n ?? fallback)));\n}\n\nfunction insertGoalEvent(db: ReturnType<typeof getSqliteDatabase>, input: {\n goalId: string;\n runId?: string;\n kind: string;\n message: string;\n data?: unknown;\n createdAt?: number;\n}): GoalEvent {\n const event: GoalEvent = {\n id: randomUUID(),\n goalId: input.goalId,\n runId: input.runId,\n kind: input.kind,\n message: input.message,\n data: input.data,\n createdAt: input.createdAt ?? Date.now(),\n };\n db.prepare(\n `INSERT INTO goal_events (event_id, goal_id, run_id, kind, message, data_json, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n event.id,\n event.goalId,\n event.runId ?? null,\n event.kind,\n event.message,\n event.data === undefined ? null : JSON.stringify(event.data),\n event.createdAt,\n );\n return event;\n}\n\nexport class GoalStore {\n create(input: CreateGoalInput): Goal {\n const now = Date.now();\n const goal: Goal = {\n id: randomUUID(),\n title: input.title.trim(),\n description: input.description?.trim() || undefined,\n status: 'active',\n agentId: input.agentId,\n priority: input.priority ?? 'normal',\n deadlineAt: input.deadlineAt,\n createdAt: now,\n updatedAt: now,\n activeSessionKey: input.sessionKey,\n judgeModelRef: input.judgeModelRef?.trim() || undefined,\n maxTurns: Math.max(1, Math.min(500, Math.floor(input.maxTurns))),\n turnsUsed: 0,\n uiLocale: input.uiLocale,\n source: input.source ?? 'chat',\n };\n\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO goals (\n goal_id, title, description, status, agent_id, priority, deadline_at,\n created_at, updated_at, active_session_key, judge_model_ref,\n max_turns, turns_used, ui_locale, source\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n goal.id,\n goal.title,\n goal.description ?? null,\n goal.status,\n goal.agentId,\n goal.priority,\n goal.deadlineAt ?? null,\n goal.createdAt,\n goal.updatedAt,\n goal.activeSessionKey ?? null,\n goal.judgeModelRef ?? null,\n goal.maxTurns,\n goal.turnsUsed,\n goal.uiLocale ?? null,\n goal.source,\n );\n if (goal.activeSessionKey) {\n db.prepare(\n `INSERT OR REPLACE INTO goal_session_links (goal_id, session_key, linked_at)\n VALUES (?, ?, ?)`,\n ).run(goal.id, goal.activeSessionKey, now);\n }\n insertGoalEvent(db, { goalId: goal.id, kind: 'created', message: 'Goal created', createdAt: now });\n });\n\n return goal;\n }\n\n get(goalId: string): Goal | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT * FROM goals WHERE goal_id = ?`)\n .get(goalId) as GoalRow | undefined;\n return row ? goalFromRow(row) : null;\n }\n\n getActiveForSession(sessionKey: string): Goal | null {\n const row = getSqliteDatabase()\n .prepare(\n `SELECT * FROM goals\n WHERE active_session_key = ?\n AND status IN ('active', 'paused', 'blocked', 'needs_input', 'done')\n ORDER BY updated_at DESC\n LIMIT 1`,\n )\n .get(sessionKey) as GoalRow | undefined;\n return row ? goalFromRow(row) : null;\n }\n\n list(query: GoalListQuery = {}): Goal[] {\n const conditions: string[] = [];\n const params: Array<string | number> = [];\n if (query.status) {\n const statuses = Array.isArray(query.status) ? query.status : [query.status];\n conditions.push(`status IN (${statuses.map(() => '?').join(', ')})`);\n params.push(...statuses);\n }\n if (query.agentId) {\n conditions.push(`agent_id = ?`);\n params.push(query.agentId);\n }\n if (query.sessionKey) {\n conditions.push(`goal_id IN (SELECT goal_id FROM goal_session_links WHERE session_key = ?)`);\n params.push(query.sessionKey);\n }\n const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';\n const limit = clampLimit(query.limit, 50);\n const offset = Math.max(0, Math.floor(query.offset ?? 0));\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goals ${where} ORDER BY updated_at DESC LIMIT ? OFFSET ?`)\n .all(...params, limit, offset) as GoalRow[];\n return rows.map(goalFromRow);\n }\n\n update(goalId: string, patch: Partial<Pick<\n Goal,\n | 'title'\n | 'description'\n | 'status'\n | 'priority'\n | 'deadlineAt'\n | 'completedAt'\n | 'archivedAt'\n | 'activeSessionKey'\n | 'currentRunId'\n | 'nextAction'\n | 'blockedReason'\n | 'judgeModelRef'\n | 'maxTurns'\n | 'turnsUsed'\n | 'uiLocale'\n >>): Goal | null {\n const before = this.get(goalId);\n if (!before) return null;\n const next = { ...before, ...patch, updatedAt: Date.now() };\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `UPDATE goals SET\n title = ?, description = ?, status = ?, priority = ?, deadline_at = ?,\n updated_at = ?, completed_at = ?, archived_at = ?, active_session_key = ?,\n current_run_id = ?, next_action = ?, blocked_reason = ?, judge_model_ref = ?,\n max_turns = ?, turns_used = ?, ui_locale = ?\n WHERE goal_id = ?`,\n ).run(\n next.title,\n next.description ?? null,\n next.status,\n next.priority,\n next.deadlineAt ?? null,\n next.updatedAt,\n next.completedAt ?? null,\n next.archivedAt ?? null,\n next.activeSessionKey ?? null,\n next.currentRunId ?? null,\n next.nextAction ?? null,\n next.blockedReason ?? null,\n next.judgeModelRef ?? null,\n next.maxTurns,\n next.turnsUsed,\n next.uiLocale ?? null,\n goalId,\n );\n if (next.activeSessionKey) {\n db.prepare(\n `INSERT OR REPLACE INTO goal_session_links (goal_id, session_key, linked_at)\n VALUES (?, ?, ?)`,\n ).run(goalId, next.activeSessionKey, next.updatedAt);\n }\n });\n return this.get(goalId);\n }\n\n listChecklist(goalId: string): GoalChecklistItem[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_checklist_items WHERE goal_id = ? ORDER BY sort_order ASC, added_at ASC`)\n .all(goalId) as ChecklistRow[];\n return rows.map(checklistFromRow);\n }\n\n addChecklistItem(input: {\n goalId: string;\n text: string;\n addedBy: GoalChecklistAddedBy;\n status?: GoalChecklistStatus;\n }): GoalChecklistItem {\n return runSqliteWriteTransaction((db) => {\n const maxRow = db\n .prepare(`SELECT COALESCE(MAX(sort_order), 0) AS max_sort FROM goal_checklist_items WHERE goal_id = ?`)\n .get(input.goalId) as { max_sort: number };\n const now = Date.now();\n const item: GoalChecklistItem = {\n id: randomUUID(),\n goalId: input.goalId,\n text: input.text.trim(),\n status: input.status ?? 'pending',\n addedBy: input.addedBy,\n addedAt: now,\n sortOrder: maxRow.max_sort + 1,\n };\n db.prepare(\n `INSERT INTO goal_checklist_items (\n item_id, goal_id, text, status, added_by, added_at, sort_order\n ) VALUES (?, ?, ?, ?, ?, ?, ?)`,\n ).run(item.id, item.goalId, item.text, item.status, item.addedBy, item.addedAt, item.sortOrder);\n insertGoalEvent(db, {\n goalId: input.goalId,\n kind: 'checklist_added',\n message: item.text,\n data: { itemId: item.id, addedBy: item.addedBy },\n createdAt: now,\n });\n return item;\n });\n }\n\n updateChecklistItem(\n itemId: string,\n patch: Partial<Pick<GoalChecklistItem, 'text' | 'status' | 'evidenceSummary'>>,\n ): GoalChecklistItem | null {\n return runSqliteWriteTransaction((db) => {\n const row = db\n .prepare(`SELECT * FROM goal_checklist_items WHERE item_id = ?`)\n .get(itemId) as ChecklistRow | undefined;\n if (!row) return null;\n const before = checklistFromRow(row);\n const status = patch.status ?? before.status;\n const completedAt =\n status === 'completed' || status === 'impossible'\n ? (before.completedAt ?? Date.now())\n : null;\n db.prepare(\n `UPDATE goal_checklist_items SET text = ?, status = ?, completed_at = ?, evidence_summary = ?\n WHERE item_id = ?`,\n ).run(\n patch.text?.trim() || before.text,\n status,\n completedAt,\n patch.evidenceSummary ?? before.evidenceSummary ?? null,\n itemId,\n );\n insertGoalEvent(db, {\n goalId: before.goalId,\n kind: 'checklist_updated',\n message: patch.text?.trim() || before.text,\n data: { itemId, status },\n });\n const next = db\n .prepare(`SELECT * FROM goal_checklist_items WHERE item_id = ?`)\n .get(itemId) as ChecklistRow;\n return checklistFromRow(next);\n });\n }\n\n removeChecklistItem(itemId: string): boolean {\n return runSqliteWriteTransaction((db) => {\n const row = db\n .prepare(`SELECT goal_id, text FROM goal_checklist_items WHERE item_id = ?`)\n .get(itemId) as { goal_id: string; text: string } | undefined;\n if (!row) return false;\n db.prepare(`DELETE FROM goal_checklist_items WHERE item_id = ?`).run(itemId);\n insertGoalEvent(db, {\n goalId: row.goal_id,\n kind: 'checklist_removed',\n message: row.text,\n data: { itemId },\n });\n return true;\n });\n }\n\n clearChecklist(goalId: string): void {\n runSqliteWriteTransaction((db) => {\n db.prepare(`DELETE FROM goal_checklist_items WHERE goal_id = ?`).run(goalId);\n insertGoalEvent(db, { goalId, kind: 'checklist_cleared', message: 'Checklist cleared' });\n });\n }\n\n replaceChecklist(goalId: string, items: Array<{\n text: string;\n status: GoalChecklistStatus;\n addedBy: GoalChecklistAddedBy;\n addedAt?: number;\n completedAt?: number;\n evidenceSummary?: string;\n }>): GoalChecklistItem[] {\n return runSqliteWriteTransaction((db) => {\n db.prepare(`DELETE FROM goal_checklist_items WHERE goal_id = ?`).run(goalId);\n const now = Date.now();\n const next: GoalChecklistItem[] = [];\n for (let i = 0; i < items.length; i++) {\n const raw = items[i]!;\n const item: GoalChecklistItem = {\n id: randomUUID(),\n goalId,\n text: raw.text.trim(),\n status: raw.status,\n addedBy: raw.addedBy,\n addedAt: raw.addedAt ?? now,\n completedAt: raw.completedAt,\n evidenceSummary: raw.evidenceSummary,\n sortOrder: i + 1,\n };\n if (!item.text) continue;\n db.prepare(\n `INSERT INTO goal_checklist_items (\n item_id, goal_id, text, status, added_by, added_at, completed_at, evidence_summary, sort_order\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n item.id,\n item.goalId,\n item.text,\n item.status,\n item.addedBy,\n item.addedAt,\n item.completedAt ?? null,\n item.evidenceSummary ?? null,\n item.sortOrder,\n );\n next.push(item);\n }\n insertGoalEvent(db, {\n goalId,\n kind: 'checklist_replaced',\n message: `Checklist replaced (${next.length} items)`,\n });\n return next;\n });\n }\n\n appendRun(run: Omit<GoalRun, 'id' | 'startedAt'> & { id?: string; startedAt?: number }): GoalRun {\n const record: GoalRun = {\n id: run.id ?? randomUUID(),\n goalId: run.goalId,\n sessionKey: run.sessionKey,\n source: run.source,\n status: run.status,\n startedAt: run.startedAt ?? Date.now(),\n finishedAt: run.finishedAt,\n verdict: run.verdict,\n reason: run.reason,\n nextAction: run.nextAction,\n assistantPreview: run.assistantPreview,\n checklistProgress: run.checklistProgress,\n };\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO goal_runs (\n run_id, goal_id, session_key, source, status, started_at, finished_at,\n verdict, reason, next_action, assistant_preview, checklist_done, checklist_total,\n confidence, missing_evidence_json, user_question, completed_checklist_item_ids_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n record.id,\n record.goalId,\n record.sessionKey,\n record.source,\n record.status,\n record.startedAt,\n record.finishedAt ?? null,\n record.verdict ?? null,\n record.reason ?? null,\n record.nextAction ?? null,\n record.assistantPreview ?? null,\n record.checklistProgress?.done ?? null,\n record.checklistProgress?.total ?? null,\n record.confidence ?? null,\n record.missingEvidence ? JSON.stringify(record.missingEvidence) : null,\n record.userQuestion ?? null,\n record.completedChecklistItemIds ? JSON.stringify(record.completedChecklistItemIds) : null,\n );\n db.prepare(`UPDATE goals SET current_run_id = ?, updated_at = ? WHERE goal_id = ?`).run(\n record.id,\n record.finishedAt ?? record.startedAt,\n record.goalId,\n );\n insertGoalEvent(db, {\n goalId: record.goalId,\n runId: record.id,\n kind: 'run_recorded',\n message: record.reason ?? record.status,\n data: {\n verdict: record.verdict,\n status: record.status,\n confidence: record.confidence,\n missingEvidence: record.missingEvidence,\n userQuestion: record.userQuestion,\n completedChecklistItemIds: record.completedChecklistItemIds,\n },\n createdAt: record.finishedAt ?? record.startedAt,\n });\n });\n return record;\n }\n\n listRuns(goalId: string, limit?: number): GoalRun[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_runs WHERE goal_id = ? ORDER BY started_at DESC LIMIT ?`)\n .all(goalId, clampLimit(limit, 50)) as GoalRunRow[];\n return rows.map(runFromRow);\n }\n\n listRunsForSession(sessionKey: string, limit?: number): GoalRun[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_runs WHERE session_key = ? ORDER BY started_at DESC LIMIT ?`)\n .all(sessionKey, clampLimit(limit, 50)) as GoalRunRow[];\n return rows.map(runFromRow);\n }\n\n listEvents(goalId: string, limit?: number): GoalEvent[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_events WHERE goal_id = ? ORDER BY created_at DESC LIMIT ?`)\n .all(goalId, clampLimit(limit, 100)) as EventRow[];\n return rows.map(eventFromRow);\n }\n\n addEvidence(input: Omit<GoalEvidence, 'id' | 'createdAt'> & { id?: string; createdAt?: number }): GoalEvidence {\n const evidence: GoalEvidence = {\n id: input.id ?? randomUUID(),\n goalId: input.goalId,\n runId: input.runId,\n kind: input.kind,\n title: input.title,\n summary: input.summary,\n uri: input.uri,\n data: input.data,\n createdAt: input.createdAt ?? Date.now(),\n };\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO goal_evidence (\n evidence_id, goal_id, run_id, kind, title, summary, uri, data_json, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n evidence.id,\n evidence.goalId,\n evidence.runId ?? null,\n evidence.kind,\n evidence.title,\n evidence.summary ?? null,\n evidence.uri ?? null,\n evidence.data === undefined ? null : JSON.stringify(evidence.data),\n evidence.createdAt,\n );\n insertGoalEvent(db, {\n goalId: evidence.goalId,\n runId: evidence.runId,\n kind: 'evidence_added',\n message: evidence.title,\n data: { evidenceId: evidence.id, kind: evidence.kind },\n createdAt: evidence.createdAt,\n });\n });\n return evidence;\n }\n\n listEvidence(goalId: string, limit?: number): GoalEvidence[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_evidence WHERE goal_id = ? ORDER BY created_at DESC LIMIT ?`)\n .all(goalId, clampLimit(limit, 100)) as EvidenceRow[];\n return rows.map(evidenceFromRow);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"goal-store.js","names":[],"sources":["../../../src/goals/goal-store.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { getSqliteDatabase, runSqliteWriteTransaction } from '../storage/sqlite/transaction.js';\nimport type {\n CreateGoalInput,\n Goal,\n GoalChecklistAddedBy,\n GoalChecklistItem,\n GoalChecklistStatus,\n GoalContextAttachment,\n GoalContextMessage,\n GoalEvent,\n GoalEvidence,\n GoalListQuery,\n GoalPriority,\n GoalRun,\n GoalRunStatus,\n GoalRunVerdict,\n GoalSource,\n GoalStatus,\n} from './types.js';\n\ntype GoalRow = {\n goal_id: string;\n title: string;\n description: string | null;\n status: string;\n agent_id: string;\n priority: string;\n deadline_at: number | null;\n created_at: number;\n updated_at: number;\n completed_at: number | null;\n archived_at: number | null;\n active_session_key: string | null;\n current_run_id: string | null;\n next_action: string | null;\n blocked_reason: string | null;\n judge_model_ref: string | null;\n max_turns: number;\n turns_used: number;\n ui_locale: string | null;\n source: string;\n};\n\ntype ChecklistRow = {\n item_id: string;\n goal_id: string;\n text: string;\n status: string;\n added_by: string;\n added_at: number;\n completed_at: number | null;\n evidence_summary: string | null;\n sort_order: number;\n};\n\ntype GoalRunRow = {\n run_id: string;\n goal_id: string;\n session_key: string;\n source: string;\n status: string;\n started_at: number;\n finished_at: number | null;\n verdict: string | null;\n reason: string | null;\n next_action: string | null;\n assistant_preview: string | null;\n checklist_done: number | null;\n checklist_total: number | null;\n confidence: number | null;\n missing_evidence_json: string | null;\n user_question: string | null;\n completed_checklist_item_ids_json: string | null;\n};\n\ntype EventRow = {\n event_id: string;\n goal_id: string;\n run_id: string | null;\n kind: string;\n message: string;\n data_json: string | null;\n created_at: number;\n};\n\ntype EvidenceRow = {\n evidence_id: string;\n goal_id: string;\n run_id: string | null;\n kind: GoalEvidence['kind'];\n title: string;\n summary: string | null;\n uri: string | null;\n data_json: string | null;\n created_at: number;\n};\n\ntype GoalContextRow = {\n goal_id: string;\n text: string;\n attachments_json: string;\n created_at: number;\n updated_at: number;\n};\n\nfunction goalFromRow(row: GoalRow): Goal {\n return {\n id: row.goal_id,\n title: row.title,\n description: row.description ?? undefined,\n status: row.status as GoalStatus,\n agentId: row.agent_id,\n priority: row.priority as GoalPriority,\n deadlineAt: row.deadline_at ?? undefined,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n completedAt: row.completed_at ?? undefined,\n archivedAt: row.archived_at ?? undefined,\n activeSessionKey: row.active_session_key ?? undefined,\n currentRunId: row.current_run_id ?? undefined,\n nextAction: row.next_action ?? undefined,\n blockedReason: row.blocked_reason ?? undefined,\n judgeModelRef: row.judge_model_ref ?? undefined,\n maxTurns: row.max_turns,\n turnsUsed: row.turns_used,\n uiLocale: row.ui_locale === 'en' || row.ui_locale === 'zh' ? row.ui_locale : undefined,\n source: row.source as GoalSource,\n };\n}\n\nfunction checklistFromRow(row: ChecklistRow): GoalChecklistItem {\n return {\n id: row.item_id,\n goalId: row.goal_id,\n text: row.text,\n status: row.status as GoalChecklistStatus,\n addedBy: row.added_by as GoalChecklistAddedBy,\n addedAt: row.added_at,\n completedAt: row.completed_at ?? undefined,\n evidenceSummary: row.evidence_summary ?? undefined,\n sortOrder: row.sort_order,\n };\n}\n\nfunction runFromRow(row: GoalRunRow): GoalRun {\n return {\n id: row.run_id,\n goalId: row.goal_id,\n sessionKey: row.session_key,\n source: row.source as GoalSource,\n status: row.status as GoalRunStatus,\n startedAt: row.started_at,\n finishedAt: row.finished_at ?? undefined,\n verdict: row.verdict ? (row.verdict as GoalRunVerdict) : undefined,\n reason: row.reason ?? undefined,\n nextAction: row.next_action ?? undefined,\n assistantPreview: row.assistant_preview ?? undefined,\n checklistProgress:\n row.checklist_done != null && row.checklist_total != null\n ? { done: row.checklist_done, total: row.checklist_total }\n : undefined,\n confidence: row.confidence ?? undefined,\n missingEvidence: parseJsonStringArray(row.missing_evidence_json),\n userQuestion: row.user_question ?? undefined,\n completedChecklistItemIds: parseJsonStringArray(row.completed_checklist_item_ids_json),\n };\n}\n\nfunction parseJsonField(raw: string | null): unknown {\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonStringArray(raw: string | null): string[] | undefined {\n const value = parseJsonField(raw);\n if (!Array.isArray(value)) return undefined;\n const rows = value.filter((item): item is string => typeof item === 'string' && item.trim().length > 0);\n return rows.length ? rows : undefined;\n}\n\nfunction parseGoalContextAttachments(raw: string): GoalContextAttachment[] {\n const parsed = parseJsonField(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter((item): item is GoalContextAttachment => {\n if (!item || typeof item !== 'object') return false;\n const ref = item as Partial<GoalContextAttachment>;\n return (\n typeof ref.id === 'string' &&\n (ref.bucket === 'inbound' || ref.bucket === 'tts' || ref.bucket === 'outbound') &&\n typeof ref.type === 'string' &&\n typeof ref.mimeType === 'string' &&\n typeof ref.name === 'string' &&\n typeof ref.size === 'number' &&\n typeof ref.uri === 'string' &&\n typeof ref.path === 'string'\n );\n });\n}\n\nfunction goalContextFromRow(row: GoalContextRow): GoalContextMessage {\n return {\n goalId: row.goal_id,\n text: row.text,\n attachments: parseGoalContextAttachments(row.attachments_json),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nfunction eventFromRow(row: EventRow): GoalEvent {\n return {\n id: row.event_id,\n goalId: row.goal_id,\n runId: row.run_id ?? undefined,\n kind: row.kind,\n message: row.message,\n data: parseJsonField(row.data_json),\n createdAt: row.created_at,\n };\n}\n\nfunction evidenceFromRow(row: EvidenceRow): GoalEvidence {\n return {\n id: row.evidence_id,\n goalId: row.goal_id,\n runId: row.run_id ?? undefined,\n kind: row.kind,\n title: row.title,\n summary: row.summary ?? undefined,\n uri: row.uri ?? undefined,\n data: parseJsonField(row.data_json),\n createdAt: row.created_at,\n };\n}\n\nfunction clampLimit(n: number | undefined, fallback: number): number {\n return Math.min(500, Math.max(1, Math.floor(n ?? fallback)));\n}\n\nfunction insertGoalEvent(db: ReturnType<typeof getSqliteDatabase>, input: {\n goalId: string;\n runId?: string;\n kind: string;\n message: string;\n data?: unknown;\n createdAt?: number;\n}): GoalEvent {\n const event: GoalEvent = {\n id: randomUUID(),\n goalId: input.goalId,\n runId: input.runId,\n kind: input.kind,\n message: input.message,\n data: input.data,\n createdAt: input.createdAt ?? Date.now(),\n };\n db.prepare(\n `INSERT INTO goal_events (event_id, goal_id, run_id, kind, message, data_json, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n event.id,\n event.goalId,\n event.runId ?? null,\n event.kind,\n event.message,\n event.data === undefined ? null : JSON.stringify(event.data),\n event.createdAt,\n );\n return event;\n}\n\nexport class GoalStore {\n create(input: CreateGoalInput): Goal {\n const now = Date.now();\n const goal: Goal = {\n id: randomUUID(),\n title: input.title.trim(),\n description: input.description?.trim() || undefined,\n status: 'active',\n agentId: input.agentId,\n priority: input.priority ?? 'normal',\n deadlineAt: input.deadlineAt,\n createdAt: now,\n updatedAt: now,\n activeSessionKey: input.sessionKey,\n judgeModelRef: input.judgeModelRef?.trim() || undefined,\n maxTurns: Math.max(1, Math.min(500, Math.floor(input.maxTurns))),\n turnsUsed: 0,\n uiLocale: input.uiLocale,\n source: input.source ?? 'chat',\n };\n\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO goals (\n goal_id, title, description, status, agent_id, priority, deadline_at,\n created_at, updated_at, active_session_key, judge_model_ref,\n max_turns, turns_used, ui_locale, source\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n goal.id,\n goal.title,\n goal.description ?? null,\n goal.status,\n goal.agentId,\n goal.priority,\n goal.deadlineAt ?? null,\n goal.createdAt,\n goal.updatedAt,\n goal.activeSessionKey ?? null,\n goal.judgeModelRef ?? null,\n goal.maxTurns,\n goal.turnsUsed,\n goal.uiLocale ?? null,\n goal.source,\n );\n if (goal.activeSessionKey) {\n db.prepare(\n `INSERT OR REPLACE INTO goal_session_links (goal_id, session_key, linked_at)\n VALUES (?, ?, ?)`,\n ).run(goal.id, goal.activeSessionKey, now);\n }\n insertGoalEvent(db, { goalId: goal.id, kind: 'created', message: 'Goal created', createdAt: now });\n });\n\n return goal;\n }\n\n get(goalId: string): Goal | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT * FROM goals WHERE goal_id = ?`)\n .get(goalId) as GoalRow | undefined;\n return row ? goalFromRow(row) : null;\n }\n\n setContextMessage(input: {\n goalId: string;\n text: string;\n attachments?: GoalContextAttachment[];\n }): GoalContextMessage {\n return runSqliteWriteTransaction((db) => {\n const now = Date.now();\n const existing = db\n .prepare(`SELECT created_at FROM goal_context_messages WHERE goal_id = ?`)\n .get(input.goalId) as { created_at: number } | undefined;\n db.prepare(\n `INSERT INTO goal_context_messages (goal_id, text, attachments_json, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(goal_id) DO UPDATE SET\n text = excluded.text,\n attachments_json = excluded.attachments_json,\n updated_at = excluded.updated_at`,\n ).run(\n input.goalId,\n input.text.trim(),\n JSON.stringify(input.attachments ?? []),\n existing?.created_at ?? now,\n now,\n );\n insertGoalEvent(db, {\n goalId: input.goalId,\n kind: 'context_updated',\n message: input.text.trim() || `${input.attachments?.length ?? 0} attachment(s)`,\n data: { attachmentCount: input.attachments?.length ?? 0 },\n createdAt: now,\n });\n const row = db\n .prepare(`SELECT * FROM goal_context_messages WHERE goal_id = ?`)\n .get(input.goalId) as GoalContextRow;\n return goalContextFromRow(row);\n });\n }\n\n getContextMessage(goalId: string): GoalContextMessage | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_context_messages WHERE goal_id = ?`)\n .get(goalId) as GoalContextRow | undefined;\n return row ? goalContextFromRow(row) : null;\n }\n\n getActiveForSession(sessionKey: string): Goal | null {\n const row = getSqliteDatabase()\n .prepare(\n `SELECT * FROM goals\n WHERE active_session_key = ?\n AND status IN ('active', 'paused', 'blocked', 'needs_input', 'done')\n ORDER BY updated_at DESC\n LIMIT 1`,\n )\n .get(sessionKey) as GoalRow | undefined;\n return row ? goalFromRow(row) : null;\n }\n\n list(query: GoalListQuery = {}): Goal[] {\n const conditions: string[] = [];\n const params: Array<string | number> = [];\n if (query.status) {\n const statuses = Array.isArray(query.status) ? query.status : [query.status];\n conditions.push(`status IN (${statuses.map(() => '?').join(', ')})`);\n params.push(...statuses);\n }\n if (query.agentId) {\n conditions.push(`agent_id = ?`);\n params.push(query.agentId);\n }\n if (query.sessionKey) {\n conditions.push(`goal_id IN (SELECT goal_id FROM goal_session_links WHERE session_key = ?)`);\n params.push(query.sessionKey);\n }\n const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';\n const limit = clampLimit(query.limit, 50);\n const offset = Math.max(0, Math.floor(query.offset ?? 0));\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goals ${where} ORDER BY updated_at DESC LIMIT ? OFFSET ?`)\n .all(...params, limit, offset) as GoalRow[];\n return rows.map(goalFromRow);\n }\n\n update(goalId: string, patch: Partial<Pick<\n Goal,\n | 'title'\n | 'description'\n | 'status'\n | 'priority'\n | 'deadlineAt'\n | 'completedAt'\n | 'archivedAt'\n | 'activeSessionKey'\n | 'currentRunId'\n | 'nextAction'\n | 'blockedReason'\n | 'judgeModelRef'\n | 'maxTurns'\n | 'turnsUsed'\n | 'uiLocale'\n >>): Goal | null {\n const before = this.get(goalId);\n if (!before) return null;\n const next = { ...before, ...patch, updatedAt: Date.now() };\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `UPDATE goals SET\n title = ?, description = ?, status = ?, priority = ?, deadline_at = ?,\n updated_at = ?, completed_at = ?, archived_at = ?, active_session_key = ?,\n current_run_id = ?, next_action = ?, blocked_reason = ?, judge_model_ref = ?,\n max_turns = ?, turns_used = ?, ui_locale = ?\n WHERE goal_id = ?`,\n ).run(\n next.title,\n next.description ?? null,\n next.status,\n next.priority,\n next.deadlineAt ?? null,\n next.updatedAt,\n next.completedAt ?? null,\n next.archivedAt ?? null,\n next.activeSessionKey ?? null,\n next.currentRunId ?? null,\n next.nextAction ?? null,\n next.blockedReason ?? null,\n next.judgeModelRef ?? null,\n next.maxTurns,\n next.turnsUsed,\n next.uiLocale ?? null,\n goalId,\n );\n if (next.activeSessionKey) {\n db.prepare(\n `INSERT OR REPLACE INTO goal_session_links (goal_id, session_key, linked_at)\n VALUES (?, ?, ?)`,\n ).run(goalId, next.activeSessionKey, next.updatedAt);\n }\n });\n return this.get(goalId);\n }\n\n listChecklist(goalId: string): GoalChecklistItem[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_checklist_items WHERE goal_id = ? ORDER BY sort_order ASC, added_at ASC`)\n .all(goalId) as ChecklistRow[];\n return rows.map(checklistFromRow);\n }\n\n addChecklistItem(input: {\n goalId: string;\n text: string;\n addedBy: GoalChecklistAddedBy;\n status?: GoalChecklistStatus;\n }): GoalChecklistItem {\n return runSqliteWriteTransaction((db) => {\n const maxRow = db\n .prepare(`SELECT COALESCE(MAX(sort_order), 0) AS max_sort FROM goal_checklist_items WHERE goal_id = ?`)\n .get(input.goalId) as { max_sort: number };\n const now = Date.now();\n const item: GoalChecklistItem = {\n id: randomUUID(),\n goalId: input.goalId,\n text: input.text.trim(),\n status: input.status ?? 'pending',\n addedBy: input.addedBy,\n addedAt: now,\n sortOrder: maxRow.max_sort + 1,\n };\n db.prepare(\n `INSERT INTO goal_checklist_items (\n item_id, goal_id, text, status, added_by, added_at, sort_order\n ) VALUES (?, ?, ?, ?, ?, ?, ?)`,\n ).run(item.id, item.goalId, item.text, item.status, item.addedBy, item.addedAt, item.sortOrder);\n insertGoalEvent(db, {\n goalId: input.goalId,\n kind: 'checklist_added',\n message: item.text,\n data: { itemId: item.id, addedBy: item.addedBy },\n createdAt: now,\n });\n return item;\n });\n }\n\n updateChecklistItem(\n itemId: string,\n patch: Partial<Pick<GoalChecklistItem, 'text' | 'status' | 'evidenceSummary'>>,\n ): GoalChecklistItem | null {\n return runSqliteWriteTransaction((db) => {\n const row = db\n .prepare(`SELECT * FROM goal_checklist_items WHERE item_id = ?`)\n .get(itemId) as ChecklistRow | undefined;\n if (!row) return null;\n const before = checklistFromRow(row);\n const status = patch.status ?? before.status;\n const completedAt =\n status === 'completed' || status === 'impossible'\n ? (before.completedAt ?? Date.now())\n : null;\n db.prepare(\n `UPDATE goal_checklist_items SET text = ?, status = ?, completed_at = ?, evidence_summary = ?\n WHERE item_id = ?`,\n ).run(\n patch.text?.trim() || before.text,\n status,\n completedAt,\n patch.evidenceSummary ?? before.evidenceSummary ?? null,\n itemId,\n );\n insertGoalEvent(db, {\n goalId: before.goalId,\n kind: 'checklist_updated',\n message: patch.text?.trim() || before.text,\n data: { itemId, status },\n });\n const next = db\n .prepare(`SELECT * FROM goal_checklist_items WHERE item_id = ?`)\n .get(itemId) as ChecklistRow;\n return checklistFromRow(next);\n });\n }\n\n removeChecklistItem(itemId: string): boolean {\n return runSqliteWriteTransaction((db) => {\n const row = db\n .prepare(`SELECT goal_id, text FROM goal_checklist_items WHERE item_id = ?`)\n .get(itemId) as { goal_id: string; text: string } | undefined;\n if (!row) return false;\n db.prepare(`DELETE FROM goal_checklist_items WHERE item_id = ?`).run(itemId);\n insertGoalEvent(db, {\n goalId: row.goal_id,\n kind: 'checklist_removed',\n message: row.text,\n data: { itemId },\n });\n return true;\n });\n }\n\n clearChecklist(goalId: string): void {\n runSqliteWriteTransaction((db) => {\n db.prepare(`DELETE FROM goal_checklist_items WHERE goal_id = ?`).run(goalId);\n insertGoalEvent(db, { goalId, kind: 'checklist_cleared', message: 'Checklist cleared' });\n });\n }\n\n replaceChecklist(goalId: string, items: Array<{\n text: string;\n status: GoalChecklistStatus;\n addedBy: GoalChecklistAddedBy;\n addedAt?: number;\n completedAt?: number;\n evidenceSummary?: string;\n }>): GoalChecklistItem[] {\n return runSqliteWriteTransaction((db) => {\n db.prepare(`DELETE FROM goal_checklist_items WHERE goal_id = ?`).run(goalId);\n const now = Date.now();\n const next: GoalChecklistItem[] = [];\n for (let i = 0; i < items.length; i++) {\n const raw = items[i]!;\n const item: GoalChecklistItem = {\n id: randomUUID(),\n goalId,\n text: raw.text.trim(),\n status: raw.status,\n addedBy: raw.addedBy,\n addedAt: raw.addedAt ?? now,\n completedAt: raw.completedAt,\n evidenceSummary: raw.evidenceSummary,\n sortOrder: i + 1,\n };\n if (!item.text) continue;\n db.prepare(\n `INSERT INTO goal_checklist_items (\n item_id, goal_id, text, status, added_by, added_at, completed_at, evidence_summary, sort_order\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n item.id,\n item.goalId,\n item.text,\n item.status,\n item.addedBy,\n item.addedAt,\n item.completedAt ?? null,\n item.evidenceSummary ?? null,\n item.sortOrder,\n );\n next.push(item);\n }\n insertGoalEvent(db, {\n goalId,\n kind: 'checklist_replaced',\n message: `Checklist replaced (${next.length} items)`,\n });\n return next;\n });\n }\n\n appendRun(run: Omit<GoalRun, 'id' | 'startedAt'> & { id?: string; startedAt?: number }): GoalRun {\n const record: GoalRun = {\n id: run.id ?? randomUUID(),\n goalId: run.goalId,\n sessionKey: run.sessionKey,\n source: run.source,\n status: run.status,\n startedAt: run.startedAt ?? Date.now(),\n finishedAt: run.finishedAt,\n verdict: run.verdict,\n reason: run.reason,\n nextAction: run.nextAction,\n assistantPreview: run.assistantPreview,\n checklistProgress: run.checklistProgress,\n };\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO goal_runs (\n run_id, goal_id, session_key, source, status, started_at, finished_at,\n verdict, reason, next_action, assistant_preview, checklist_done, checklist_total,\n confidence, missing_evidence_json, user_question, completed_checklist_item_ids_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n record.id,\n record.goalId,\n record.sessionKey,\n record.source,\n record.status,\n record.startedAt,\n record.finishedAt ?? null,\n record.verdict ?? null,\n record.reason ?? null,\n record.nextAction ?? null,\n record.assistantPreview ?? null,\n record.checklistProgress?.done ?? null,\n record.checklistProgress?.total ?? null,\n record.confidence ?? null,\n record.missingEvidence ? JSON.stringify(record.missingEvidence) : null,\n record.userQuestion ?? null,\n record.completedChecklistItemIds ? JSON.stringify(record.completedChecklistItemIds) : null,\n );\n db.prepare(`UPDATE goals SET current_run_id = ?, updated_at = ? WHERE goal_id = ?`).run(\n record.id,\n record.finishedAt ?? record.startedAt,\n record.goalId,\n );\n insertGoalEvent(db, {\n goalId: record.goalId,\n runId: record.id,\n kind: 'run_recorded',\n message: record.reason ?? record.status,\n data: {\n verdict: record.verdict,\n status: record.status,\n confidence: record.confidence,\n missingEvidence: record.missingEvidence,\n userQuestion: record.userQuestion,\n completedChecklistItemIds: record.completedChecklistItemIds,\n },\n createdAt: record.finishedAt ?? record.startedAt,\n });\n });\n return record;\n }\n\n listRuns(goalId: string, limit?: number): GoalRun[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_runs WHERE goal_id = ? ORDER BY started_at DESC LIMIT ?`)\n .all(goalId, clampLimit(limit, 50)) as GoalRunRow[];\n return rows.map(runFromRow);\n }\n\n listRunsForSession(sessionKey: string, limit?: number): GoalRun[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_runs WHERE session_key = ? ORDER BY started_at DESC LIMIT ?`)\n .all(sessionKey, clampLimit(limit, 50)) as GoalRunRow[];\n return rows.map(runFromRow);\n }\n\n listEvents(goalId: string, limit?: number): GoalEvent[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_events WHERE goal_id = ? ORDER BY created_at DESC LIMIT ?`)\n .all(goalId, clampLimit(limit, 100)) as EventRow[];\n return rows.map(eventFromRow);\n }\n\n addEvidence(input: Omit<GoalEvidence, 'id' | 'createdAt'> & { id?: string; createdAt?: number }): GoalEvidence {\n const evidence: GoalEvidence = {\n id: input.id ?? randomUUID(),\n goalId: input.goalId,\n runId: input.runId,\n kind: input.kind,\n title: input.title,\n summary: input.summary,\n uri: input.uri,\n data: input.data,\n createdAt: input.createdAt ?? Date.now(),\n };\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO goal_evidence (\n evidence_id, goal_id, run_id, kind, title, summary, uri, data_json, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n evidence.id,\n evidence.goalId,\n evidence.runId ?? null,\n evidence.kind,\n evidence.title,\n evidence.summary ?? null,\n evidence.uri ?? null,\n evidence.data === undefined ? null : JSON.stringify(evidence.data),\n evidence.createdAt,\n );\n insertGoalEvent(db, {\n goalId: evidence.goalId,\n runId: evidence.runId,\n kind: 'evidence_added',\n message: evidence.title,\n data: { evidenceId: evidence.id, kind: evidence.kind },\n createdAt: evidence.createdAt,\n });\n });\n return evidence;\n }\n\n listEvidence(goalId: string, limit?: number): GoalEvidence[] {\n const rows = getSqliteDatabase()\n .prepare(`SELECT * FROM goal_evidence WHERE goal_id = ? ORDER BY created_at DESC LIMIT ?`)\n .all(goalId, clampLimit(limit, 100)) as EvidenceRow[];\n return rows.map(evidenceFromRow);\n }\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { MediaRef } from '../media/types.js';
1
2
  export type GoalStatus = 'active' | 'paused' | 'blocked' | 'needs_input' | 'done' | 'archived';
2
3
  export type GoalPriority = 'low' | 'normal' | 'high';
3
4
  export type GoalSource = 'chat' | 'cli' | 'cron' | 'workflow' | 'channel' | 'api';
@@ -80,9 +81,18 @@ export interface GoalEvidence {
80
81
  data?: unknown;
81
82
  createdAt: number;
82
83
  }
84
+ export type GoalContextAttachment = MediaRef;
85
+ export interface GoalContextMessage {
86
+ goalId: string;
87
+ text: string;
88
+ attachments: GoalContextAttachment[];
89
+ createdAt: number;
90
+ updatedAt: number;
91
+ }
83
92
  export interface GoalWithDetails extends Goal {
84
93
  checklist: GoalChecklistItem[];
85
94
  latestRun?: GoalRun;
95
+ contextMessage?: GoalContextMessage;
86
96
  }
87
97
  export interface GoalListQuery {
88
98
  status?: GoalStatus | GoalStatus[];
@@ -0,0 +1,8 @@
1
+ CREATE TABLE IF NOT EXISTS goal_context_messages (
2
+ goal_id TEXT PRIMARY KEY,
3
+ text TEXT NOT NULL DEFAULT '',
4
+ attachments_json TEXT NOT NULL DEFAULT '[]',
5
+ created_at INTEGER NOT NULL,
6
+ updated_at INTEGER NOT NULL,
7
+ FOREIGN KEY (goal_id) REFERENCES goals(goal_id) ON DELETE CASCADE
8
+ );
@@ -1,9 +1,9 @@
1
1
  import type { DatabaseSync } from 'node:sqlite';
2
2
  import type { ApplyMigrationsOptions } from './types.js';
3
3
  /** Baseline schema version applied from schema.sql on first open. */
4
- export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 10;
4
+ export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
5
5
  /** Latest schema version this release supports (increment when adding migrations). */
6
- export declare const XOPC_DB_SCHEMA_VERSION = 10;
6
+ export declare const XOPC_DB_SCHEMA_VERSION = 11;
7
7
  export declare function resolveMigrationsDir(override?: string): string;
8
8
  /**
9
9
  * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
@@ -10,9 +10,9 @@ import { fileURLToPath } from "node:url";
10
10
  init_logger();
11
11
  const log = createLogger("Sqlite:Migrations");
12
12
  /** Baseline schema version applied from schema.sql on first open. */
13
- const XOPC_DB_BASELINE_SCHEMA_VERSION = 10;
13
+ const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
14
14
  /** Latest schema version this release supports (increment when adding migrations). */
15
- const XOPC_DB_SCHEMA_VERSION = 10;
15
+ const XOPC_DB_SCHEMA_VERSION = 11;
16
16
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
17
17
  function resolveMigrationsDir(override) {
18
18
  if (override) return override;
@@ -46,7 +46,7 @@ function applySingleMigration(db, migration) {
46
46
  * Each step runs in its own transaction and updates schema_meta on success.
47
47
  */
48
48
  function applyPendingMigrations(db, options = {}) {
49
- const targetVersion = options.targetVersion ?? 10;
49
+ const targetVersion = options.targetVersion ?? 11;
50
50
  let currentVersion = readSchemaVersion(db);
51
51
  if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
52
52
  if (currentVersion >= targetVersion) return currentVersion;
@@ -62,7 +62,7 @@ function applyPendingMigrations(db, options = {}) {
62
62
  }
63
63
  /** Inspect schema version without mutating the database. */
64
64
  function inspectSchemaMigrationStatus(db, options = {}) {
65
- const appVersion = options.targetVersion ?? 10;
65
+ const appVersion = options.targetVersion ?? 11;
66
66
  const dbVersion = readSchemaVersion(db);
67
67
  if (dbVersion > appVersion) return {
68
68
  dbVersion,
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","names":[],"sources":["../../../../../src/storage/sqlite/migrations/runner.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { DatabaseSync } from 'node:sqlite';\n\nimport { createLogger } from '../../../utils/logger.js';\nimport { readSchemaVersion, setSchemaVersion } from '../schema-version.js';\nimport { discoverSqlMigrations } from './discover.js';\nimport {\n DatabaseSchemaMigrationGapError,\n DatabaseSchemaTooNewError,\n} from './errors.js';\nimport type { ApplyMigrationsOptions, SqlMigration } from './types.js';\n\nconst log = createLogger('Sqlite:Migrations');\n\n/** Baseline schema version applied from schema.sql on first open. */\nexport const XOPC_DB_BASELINE_SCHEMA_VERSION = 10;\n\n/** Latest schema version this release supports (increment when adding migrations). */\nexport const XOPC_DB_SCHEMA_VERSION = 10;\n\nconst MODULE_DIR = dirname(fileURLToPath(import.meta.url));\n\nexport function resolveMigrationsDir(override?: string): string {\n if (override) {\n return override;\n }\n // Packaged Electron gateway bundle: `out/server/index.js` + `out/server/migrations/`.\n const siblingDir = join(MODULE_DIR, 'migrations');\n if (existsSync(siblingDir)) {\n return siblingDir;\n }\n // Dev / dist: SQL files live next to `migrations/runner.js`.\n return MODULE_DIR;\n}\n\nfunction migrationByTarget(\n migrations: SqlMigration[],\n targetVersion: number,\n): SqlMigration | undefined {\n return migrations.find((migration) => migration.targetVersion === targetVersion);\n}\n\nfunction applySingleMigration(db: DatabaseSync, migration: SqlMigration): void {\n log.info({ targetVersion: migration.targetVersion, file: migration.filename }, 'Applying SQLite migration');\n db.exec('BEGIN IMMEDIATE');\n try {\n db.exec(migration.sql);\n setSchemaVersion(db, migration.targetVersion);\n db.exec('COMMIT');\n } catch (error) {\n try {\n db.exec('ROLLBACK');\n } catch {\n /* preserve original error */\n }\n const em = error instanceof Error ? error.message : String(error);\n throw new Error(\n `SQLite migration to v${migration.targetVersion} (${migration.filename}) failed: ${em}`,\n { cause: error },\n );\n }\n}\n\n/**\n * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.\n * Each step runs in its own transaction and updates schema_meta on success.\n */\nexport function applyPendingMigrations(\n db: DatabaseSync,\n options: ApplyMigrationsOptions = {},\n): number {\n const targetVersion = options.targetVersion ?? XOPC_DB_SCHEMA_VERSION;\n let currentVersion = readSchemaVersion(db);\n\n if (currentVersion > targetVersion) {\n throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);\n }\n\n if (currentVersion >= targetVersion) {\n return currentVersion;\n }\n\n const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));\n\n while (currentVersion < targetVersion) {\n const nextVersion = currentVersion + 1;\n const migration = migrationByTarget(migrations, nextVersion);\n if (!migration) {\n throw new DatabaseSchemaMigrationGapError(currentVersion, targetVersion, nextVersion);\n }\n applySingleMigration(db, migration);\n currentVersion = nextVersion;\n }\n\n return currentVersion;\n}\n\nexport type SchemaMigrationStatus = {\n dbVersion: number;\n appVersion: number;\n pendingVersions: number[];\n isTooNew: boolean;\n hasMigrationGap: boolean;\n missingVersion: number | null;\n};\n\n/** Inspect schema version without mutating the database. */\nexport function inspectSchemaMigrationStatus(\n db: DatabaseSync,\n options: Pick<ApplyMigrationsOptions, 'migrationsDir' | 'targetVersion'> = {},\n): SchemaMigrationStatus {\n const appVersion = options.targetVersion ?? XOPC_DB_SCHEMA_VERSION;\n const dbVersion = readSchemaVersion(db);\n const isTooNew = dbVersion > appVersion;\n\n if (isTooNew) {\n return {\n dbVersion,\n appVersion,\n pendingVersions: [],\n isTooNew: true,\n hasMigrationGap: false,\n missingVersion: null,\n };\n }\n\n const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));\n const pendingVersions: number[] = [];\n let hasMigrationGap = false;\n let missingVersion: number | null = null;\n\n for (let version = dbVersion + 1; version <= appVersion; version++) {\n if (migrationByTarget(migrations, version)) {\n pendingVersions.push(version);\n } else {\n hasMigrationGap = true;\n missingVersion = version;\n break;\n }\n }\n\n return {\n dbVersion,\n appVersion,\n pendingVersions,\n isTooNew: false,\n hasMigrationGap,\n missingVersion,\n };\n}\n"],"mappings":";;;;;;;;;aAMwD;AASxD,MAAM,MAAM,aAAa,oBAAoB;;AAG7C,MAAa,kCAAkC;;AAG/C,MAAa,yBAAyB;AAEtC,MAAM,aAAa,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAE1D,SAAgB,qBAAqB,UAA2B;AAC9D,KAAI,SACF,QAAO;CAGT,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,KAAI,WAAW,WAAW,CACxB,QAAO;AAGT,QAAO;;AAGT,SAAS,kBACP,YACA,eAC0B;AAC1B,QAAO,WAAW,MAAM,cAAc,UAAU,kBAAkB,cAAc;;AAGlF,SAAS,qBAAqB,IAAkB,WAA+B;AAC7E,KAAI,KAAK;EAAE,eAAe,UAAU;EAAe,MAAM,UAAU;EAAU,EAAE,4BAA4B;AAC3G,IAAG,KAAK,kBAAkB;AAC1B,KAAI;AACF,KAAG,KAAK,UAAU,IAAI;AACtB,mBAAiB,IAAI,UAAU,cAAc;AAC7C,KAAG,KAAK,SAAS;UACV,OAAO;AACd,MAAI;AACF,MAAG,KAAK,WAAW;UACb;EAGR,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACjE,QAAM,IAAI,MACR,wBAAwB,UAAU,cAAc,IAAI,UAAU,SAAS,YAAY,MACnF,EAAE,OAAO,OAAO,CACjB;;;;;;;AAQL,SAAgB,uBACd,IACA,UAAkC,EAAE,EAC5B;CACR,MAAM,gBAAgB,QAAQ,iBAAA;CAC9B,IAAI,iBAAiB,kBAAkB,GAAG;AAE1C,KAAI,iBAAiB,cACnB,OAAM,IAAI,0BAA0B,gBAAgB,cAAc;AAGpE,KAAI,kBAAkB,cACpB,QAAO;CAGT,MAAM,aAAa,sBAAsB,qBAAqB,QAAQ,cAAc,CAAC;AAErF,QAAO,iBAAiB,eAAe;EACrC,MAAM,cAAc,iBAAiB;EACrC,MAAM,YAAY,kBAAkB,YAAY,YAAY;AAC5D,MAAI,CAAC,UACH,OAAM,IAAI,gCAAgC,gBAAgB,eAAe,YAAY;AAEvF,uBAAqB,IAAI,UAAU;AACnC,mBAAiB;;AAGnB,QAAO;;;AAaT,SAAgB,6BACd,IACA,UAA2E,EAAE,EACtD;CACvB,MAAM,aAAa,QAAQ,iBAAA;CAC3B,MAAM,YAAY,kBAAkB,GAAG;AAGvC,KAFiB,YAAY,WAG3B,QAAO;EACL;EACA;EACA,iBAAiB,EAAE;EACnB,UAAU;EACV,iBAAiB;EACjB,gBAAgB;EACjB;CAGH,MAAM,aAAa,sBAAsB,qBAAqB,QAAQ,cAAc,CAAC;CACrF,MAAM,kBAA4B,EAAE;CACpC,IAAI,kBAAkB;CACtB,IAAI,iBAAgC;AAEpC,MAAK,IAAI,UAAU,YAAY,GAAG,WAAW,YAAY,UACvD,KAAI,kBAAkB,YAAY,QAAQ,CACxC,iBAAgB,KAAK,QAAQ;MACxB;AACL,oBAAkB;AAClB,mBAAiB;AACjB;;AAIJ,QAAO;EACL;EACA;EACA;EACA,UAAU;EACV;EACA;EACD"}
1
+ {"version":3,"file":"runner.js","names":[],"sources":["../../../../../src/storage/sqlite/migrations/runner.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { DatabaseSync } from 'node:sqlite';\n\nimport { createLogger } from '../../../utils/logger.js';\nimport { readSchemaVersion, setSchemaVersion } from '../schema-version.js';\nimport { discoverSqlMigrations } from './discover.js';\nimport {\n DatabaseSchemaMigrationGapError,\n DatabaseSchemaTooNewError,\n} from './errors.js';\nimport type { ApplyMigrationsOptions, SqlMigration } from './types.js';\n\nconst log = createLogger('Sqlite:Migrations');\n\n/** Baseline schema version applied from schema.sql on first open. */\nexport const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;\n\n/** Latest schema version this release supports (increment when adding migrations). */\nexport const XOPC_DB_SCHEMA_VERSION = 11;\n\nconst MODULE_DIR = dirname(fileURLToPath(import.meta.url));\n\nexport function resolveMigrationsDir(override?: string): string {\n if (override) {\n return override;\n }\n // Packaged Electron gateway bundle: `out/server/index.js` + `out/server/migrations/`.\n const siblingDir = join(MODULE_DIR, 'migrations');\n if (existsSync(siblingDir)) {\n return siblingDir;\n }\n // Dev / dist: SQL files live next to `migrations/runner.js`.\n return MODULE_DIR;\n}\n\nfunction migrationByTarget(\n migrations: SqlMigration[],\n targetVersion: number,\n): SqlMigration | undefined {\n return migrations.find((migration) => migration.targetVersion === targetVersion);\n}\n\nfunction applySingleMigration(db: DatabaseSync, migration: SqlMigration): void {\n log.info({ targetVersion: migration.targetVersion, file: migration.filename }, 'Applying SQLite migration');\n db.exec('BEGIN IMMEDIATE');\n try {\n db.exec(migration.sql);\n setSchemaVersion(db, migration.targetVersion);\n db.exec('COMMIT');\n } catch (error) {\n try {\n db.exec('ROLLBACK');\n } catch {\n /* preserve original error */\n }\n const em = error instanceof Error ? error.message : String(error);\n throw new Error(\n `SQLite migration to v${migration.targetVersion} (${migration.filename}) failed: ${em}`,\n { cause: error },\n );\n }\n}\n\n/**\n * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.\n * Each step runs in its own transaction and updates schema_meta on success.\n */\nexport function applyPendingMigrations(\n db: DatabaseSync,\n options: ApplyMigrationsOptions = {},\n): number {\n const targetVersion = options.targetVersion ?? XOPC_DB_SCHEMA_VERSION;\n let currentVersion = readSchemaVersion(db);\n\n if (currentVersion > targetVersion) {\n throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);\n }\n\n if (currentVersion >= targetVersion) {\n return currentVersion;\n }\n\n const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));\n\n while (currentVersion < targetVersion) {\n const nextVersion = currentVersion + 1;\n const migration = migrationByTarget(migrations, nextVersion);\n if (!migration) {\n throw new DatabaseSchemaMigrationGapError(currentVersion, targetVersion, nextVersion);\n }\n applySingleMigration(db, migration);\n currentVersion = nextVersion;\n }\n\n return currentVersion;\n}\n\nexport type SchemaMigrationStatus = {\n dbVersion: number;\n appVersion: number;\n pendingVersions: number[];\n isTooNew: boolean;\n hasMigrationGap: boolean;\n missingVersion: number | null;\n};\n\n/** Inspect schema version without mutating the database. */\nexport function inspectSchemaMigrationStatus(\n db: DatabaseSync,\n options: Pick<ApplyMigrationsOptions, 'migrationsDir' | 'targetVersion'> = {},\n): SchemaMigrationStatus {\n const appVersion = options.targetVersion ?? XOPC_DB_SCHEMA_VERSION;\n const dbVersion = readSchemaVersion(db);\n const isTooNew = dbVersion > appVersion;\n\n if (isTooNew) {\n return {\n dbVersion,\n appVersion,\n pendingVersions: [],\n isTooNew: true,\n hasMigrationGap: false,\n missingVersion: null,\n };\n }\n\n const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));\n const pendingVersions: number[] = [];\n let hasMigrationGap = false;\n let missingVersion: number | null = null;\n\n for (let version = dbVersion + 1; version <= appVersion; version++) {\n if (migrationByTarget(migrations, version)) {\n pendingVersions.push(version);\n } else {\n hasMigrationGap = true;\n missingVersion = version;\n break;\n }\n }\n\n return {\n dbVersion,\n appVersion,\n pendingVersions,\n isTooNew: false,\n hasMigrationGap,\n missingVersion,\n };\n}\n"],"mappings":";;;;;;;;;aAMwD;AASxD,MAAM,MAAM,aAAa,oBAAoB;;AAG7C,MAAa,kCAAkC;;AAG/C,MAAa,yBAAyB;AAEtC,MAAM,aAAa,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAE1D,SAAgB,qBAAqB,UAA2B;AAC9D,KAAI,SACF,QAAO;CAGT,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,KAAI,WAAW,WAAW,CACxB,QAAO;AAGT,QAAO;;AAGT,SAAS,kBACP,YACA,eAC0B;AAC1B,QAAO,WAAW,MAAM,cAAc,UAAU,kBAAkB,cAAc;;AAGlF,SAAS,qBAAqB,IAAkB,WAA+B;AAC7E,KAAI,KAAK;EAAE,eAAe,UAAU;EAAe,MAAM,UAAU;EAAU,EAAE,4BAA4B;AAC3G,IAAG,KAAK,kBAAkB;AAC1B,KAAI;AACF,KAAG,KAAK,UAAU,IAAI;AACtB,mBAAiB,IAAI,UAAU,cAAc;AAC7C,KAAG,KAAK,SAAS;UACV,OAAO;AACd,MAAI;AACF,MAAG,KAAK,WAAW;UACb;EAGR,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACjE,QAAM,IAAI,MACR,wBAAwB,UAAU,cAAc,IAAI,UAAU,SAAS,YAAY,MACnF,EAAE,OAAO,OAAO,CACjB;;;;;;;AAQL,SAAgB,uBACd,IACA,UAAkC,EAAE,EAC5B;CACR,MAAM,gBAAgB,QAAQ,iBAAA;CAC9B,IAAI,iBAAiB,kBAAkB,GAAG;AAE1C,KAAI,iBAAiB,cACnB,OAAM,IAAI,0BAA0B,gBAAgB,cAAc;AAGpE,KAAI,kBAAkB,cACpB,QAAO;CAGT,MAAM,aAAa,sBAAsB,qBAAqB,QAAQ,cAAc,CAAC;AAErF,QAAO,iBAAiB,eAAe;EACrC,MAAM,cAAc,iBAAiB;EACrC,MAAM,YAAY,kBAAkB,YAAY,YAAY;AAC5D,MAAI,CAAC,UACH,OAAM,IAAI,gCAAgC,gBAAgB,eAAe,YAAY;AAEvF,uBAAqB,IAAI,UAAU;AACnC,mBAAiB;;AAGnB,QAAO;;;AAaT,SAAgB,6BACd,IACA,UAA2E,EAAE,EACtD;CACvB,MAAM,aAAa,QAAQ,iBAAA;CAC3B,MAAM,YAAY,kBAAkB,GAAG;AAGvC,KAFiB,YAAY,WAG3B,QAAO;EACL;EACA;EACA,iBAAiB,EAAE;EACnB,UAAU;EACV,iBAAiB;EACjB,gBAAgB;EACjB;CAGH,MAAM,aAAa,sBAAsB,qBAAqB,QAAQ,cAAc,CAAC;CACrF,MAAM,kBAA4B,EAAE;CACpC,IAAI,kBAAkB;CACtB,IAAI,iBAAgC;AAEpC,MAAK,IAAI,UAAU,YAAY,GAAG,WAAW,YAAY,UACvD,KAAI,kBAAkB,YAAY,QAAQ,CACxC,iBAAgB,KAAK,QAAQ;MACxB;AACL,oBAAkB;AAClB,mBAAiB;AACjB;;AAIJ,QAAO;EACL;EACA;EACA;EACA,UAAU;EACV;EACA;EACD"}
@@ -16,10 +16,10 @@ import type { ApplyMigrationsOptions, SqlMigration } from './types.js';
16
16
  const log = createLogger('Sqlite:Migrations');
17
17
 
18
18
  /** Baseline schema version applied from schema.sql on first open. */
19
- export const XOPC_DB_BASELINE_SCHEMA_VERSION = 10;
19
+ export const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
20
20
 
21
21
  /** Latest schema version this release supports (increment when adding migrations). */
22
- export const XOPC_DB_SCHEMA_VERSION = 10;
22
+ export const XOPC_DB_SCHEMA_VERSION = 11;
23
23
 
24
24
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
25
25
 
@@ -12,7 +12,7 @@ function bootstrapFreshDatabase(db) {
12
12
  db.exec("BEGIN IMMEDIATE");
13
13
  try {
14
14
  db.exec(readSchemaSql());
15
- setSchemaVersion(db, 10);
15
+ setSchemaVersion(db, 11);
16
16
  db.exec("COMMIT");
17
17
  } catch (error) {
18
18
  try {
@@ -29,9 +29,9 @@ function ensureXopcDatabaseSchema(db) {
29
29
  let currentVersion = readSchemaVersion(db);
30
30
  if (currentVersion === 0) {
31
31
  bootstrapFreshDatabase(db);
32
- currentVersion = 10;
32
+ currentVersion = 11;
33
33
  }
34
- applyPendingMigrations(db, { targetVersion: 10 });
34
+ applyPendingMigrations(db, { targetVersion: 11 });
35
35
  }
36
36
  //#endregion
37
37
  export { SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_SCHEMA_VERSION, ensureSchemaMetaTable, ensureXopcDatabaseSchema, readSchemaVersion, readSchemaVersionForTest, setSchemaVersion };
@@ -308,6 +308,15 @@ CREATE INDEX IF NOT EXISTS idx_goals_agent_updated
308
308
  CREATE INDEX IF NOT EXISTS idx_goals_active_session
309
309
  ON goals(active_session_key);
310
310
 
311
+ CREATE TABLE IF NOT EXISTS goal_context_messages (
312
+ goal_id TEXT PRIMARY KEY,
313
+ text TEXT NOT NULL DEFAULT '',
314
+ attachments_json TEXT NOT NULL DEFAULT '[]',
315
+ created_at INTEGER NOT NULL,
316
+ updated_at INTEGER NOT NULL,
317
+ FOREIGN KEY (goal_id) REFERENCES goals(goal_id) ON DELETE CASCADE
318
+ );
319
+
311
320
  CREATE TABLE IF NOT EXISTS goal_queue (
312
321
  queue_id TEXT PRIMARY KEY,
313
322
  goal_id TEXT NOT NULL,
@@ -1,6 +1,6 @@
1
1
  import type { ExtensionRegistryImpl } from '../../extensions/loader.js';
2
2
  import type { ExportFormat } from '../../session/types.js';
3
- import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry } from '../tui-backend.js';
3
+ import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult } from '../tui-backend.js';
4
4
  import type { SessionInfo } from '../tui-types.js';
5
5
  interface EmbeddedBackendOptions {
6
6
  extensionRegistry?: ExtensionRegistryImpl;
@@ -17,6 +17,11 @@ export declare class EmbeddedBackend implements TuiBackend {
17
17
  private readonly opts?;
18
18
  private bus;
19
19
  private agent;
20
+ private config;
21
+ private workspace;
22
+ private sessionIndex;
23
+ private sessionIndexReady;
24
+ private workflowRunService;
20
25
  private running;
21
26
  private chatAbort;
22
27
  onEvent?: (evt: TuiEvent) => void;
@@ -27,7 +32,9 @@ export declare class EmbeddedBackend implements TuiBackend {
27
32
  start(): void;
28
33
  stop(): void;
29
34
  getActiveSignal(): AbortSignal | undefined;
35
+ private getWorkflowRunService;
30
36
  getStartupResources(sessionKey: string): Promise<import("../tui-backend.js").TuiStartupResources>;
37
+ startWorkflowRun(opts: TuiWorkflowRunStartRequest): Promise<TuiWorkflowRunStartResult>;
31
38
  searchWorkspaceFiles(sessionKey: string, query: string, options?: {
32
39
  limit?: number;
33
40
  }): Promise<TuiWorkspaceFileSearchEntry[]>;