@xopcai/xopc 0.0.95 → 0.0.97

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 (442) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  3. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  4. package/dist/extensions/telegram/src/plugin.js +1 -1
  5. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  6. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  7. package/dist/extensions/telegram/xopc.extension.json +1 -1
  8. package/dist/extensions/weixin/src/api/api.js +2 -2
  9. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  10. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  11. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  12. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  13. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  14. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  15. package/dist/extensions/weixin/src/plugin.js +1 -1
  16. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  17. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  18. package/dist/gateway/static/root/assets/{agents-CKe2LMnz.js → agents-B_YUvNi6.js} +2 -2
  19. package/dist/gateway/static/root/assets/{apps-page-Mi9mMIZ1.js → apps-page-BmwG5aur.js} +1 -1
  20. package/dist/gateway/static/root/assets/{channels-settings-BrdyC101.js → channels-settings-BiwkeKPb.js} +1 -1
  21. package/dist/gateway/static/root/assets/{channels-status-swr-D55Bu0nn.js → channels-status-swr-ChyN473C.js} +1 -1
  22. package/dist/gateway/static/root/assets/{cron-api-CPpx2l-E.js → cron-api-CvSifIfJ.js} +1 -1
  23. package/dist/gateway/static/root/assets/{cron-page-Bx2jB0YN.js → cron-page-BDqTDFy6.js} +1 -1
  24. package/dist/gateway/static/root/assets/{dist-D_AiG_Kg.js → dist-DxsUrjpy.js} +1 -1
  25. package/dist/gateway/static/root/assets/{extension-debug-page-6ieHsxRE.js → extension-debug-page-DV_Av5Jq.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-B8nywHRO.js → extension-page-CwZwRhWw.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-DrskdEIV.js → extension-settings-page-Bb7TR1Se.js} +1 -1
  28. package/dist/gateway/static/root/assets/{fetch-B0aeeY0q.js → fetch-BLLOP2CM.js} +1 -1
  29. package/dist/gateway/static/root/assets/{field-primitives--9ooY8Xl.js → field-primitives-CyqVu1QR.js} +1 -1
  30. package/dist/gateway/static/root/assets/{heartbeat-config-api-DUZ_W1w-.js → heartbeat-config-api-Cd4M1eHt.js} +1 -1
  31. package/dist/gateway/static/root/assets/{index-Dj9FuxCm.js → index-0tS9lV85.js} +74 -74
  32. package/dist/gateway/static/root/assets/index-BJDmBCSl.css +1 -0
  33. package/dist/gateway/static/root/assets/{logs-page-CaXqhpKf.js → logs-page-BsAOSowN.js} +1 -1
  34. package/dist/gateway/static/root/assets/{note-detail-page-B91pLkEI.css → note-detail-page-D4ZIVQbk.css} +1 -1
  35. package/dist/gateway/static/root/assets/{note-detail-page-DYzym2B0.js → note-detail-page-Dlxoy6Ap.js} +54 -53
  36. package/dist/gateway/static/root/assets/{note-time-B-vSi2dR.js → note-time-B-r8yTpQ.js} +1 -1
  37. package/dist/gateway/static/root/assets/{notes-page-BkhWdGiT.js → notes-page-CHFcyqYW.js} +1 -1
  38. package/dist/gateway/static/root/assets/{sessions-page-53YFokoe.js → sessions-page-Ctu0kgt7.js} +1 -1
  39. package/dist/gateway/static/root/assets/{settings-advanced-gate-BaZmaklx.js → settings-advanced-gate-Dh0TyOOg.js} +1 -1
  40. package/dist/gateway/static/root/assets/{settings-form-section-DIJPKpTR.js → settings-form-section-DXMCEW1d.js} +1 -1
  41. package/dist/gateway/static/root/assets/{settings-page-Dvb230FF.js → settings-page-CIkZ7233.js} +1 -1
  42. package/dist/gateway/static/root/assets/{share-preview-page-CRyjTAG6.js → share-preview-page-7RV65xhJ.js} +1 -1
  43. package/dist/gateway/static/root/assets/{skills-page-C5ZJbfAe.js → skills-page-D_Az1SlU.js} +1 -1
  44. package/dist/gateway/static/root/assets/{theme-store-Cg_SuBw0.js → theme-store-e2q2yjs4.js} +1 -1
  45. package/dist/gateway/static/root/assets/url-DpFBIyN9.js +3 -0
  46. package/dist/gateway/static/root/assets/{utils-lMYoWhqo.js → utils-OA_b1q0Q.js} +1 -1
  47. package/dist/gateway/static/root/assets/{voice-api-key-field-Dda2pcUU.js → voice-api-key-field-SJml1hAt.js} +1 -1
  48. package/dist/gateway/static/root/assets/{workflow-page.utils-KIladUrU.js → workflow-page.utils-D90VVCzC.js} +1 -1
  49. package/dist/gateway/static/root/assets/{workflows-page-BTis4Z7Y.js → workflows-page-y7Btji0J.js} +1 -1
  50. package/dist/gateway/static/root/index.html +5 -5
  51. package/dist/package.js +1 -1
  52. package/dist/src/agent/agent-manager.js +12 -8
  53. package/dist/src/agent/agent-manager.js.map +1 -1
  54. package/dist/src/agent/agent-scope.d.ts +0 -1
  55. package/dist/src/agent/agent-scope.js +2 -5
  56. package/dist/src/agent/agent-scope.js.map +1 -1
  57. package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +2 -0
  58. package/dist/src/agent/bootstrap/bootstrap-cache.js +10 -1
  59. package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
  60. package/dist/src/agent/bootstrap/bootstrap-files.d.ts +2 -1
  61. package/dist/src/agent/bootstrap/bootstrap-files.js +34 -12
  62. package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
  63. package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +1 -2
  64. package/dist/src/agent/bootstrap/load-bootstrap-files.js +6 -12
  65. package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
  66. package/dist/src/agent/bootstrap/types.d.ts +5 -5
  67. package/dist/src/agent/context/workspace-seed.js +6 -6
  68. package/dist/src/agent/context/workspace-seed.js.map +1 -1
  69. package/dist/src/agent/context/workspace-state.d.ts +20 -0
  70. package/dist/src/agent/context/workspace-state.js +57 -0
  71. package/dist/src/agent/context/workspace-state.js.map +1 -0
  72. package/dist/src/agent/context/workspace-templates/AGENTS.md +0 -4
  73. package/dist/src/agent/embedded/index.d.ts +2 -2
  74. package/dist/src/agent/embedded/index.js +3 -3
  75. package/dist/src/agent/embedded/run-turn.js +0 -3
  76. package/dist/src/agent/embedded/run-turn.js.map +1 -1
  77. package/dist/src/agent/embedded/session-manager-init.d.ts +0 -17
  78. package/dist/src/agent/embedded/session-manager-init.js +1 -36
  79. package/dist/src/agent/embedded/session-manager-init.js.map +1 -1
  80. package/dist/src/agent/embedded/session-runner.d.ts +3 -12
  81. package/dist/src/agent/embedded/session-runner.js +12 -26
  82. package/dist/src/agent/embedded/session-runner.js.map +1 -1
  83. package/dist/src/agent/embedded/session-tool-result-guard.js +2 -4
  84. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  85. package/dist/src/agent/embedded/sqlite-hydrating-session-manager.d.ts +10 -0
  86. package/dist/src/agent/embedded/sqlite-hydrating-session-manager.js +34 -0
  87. package/dist/src/agent/embedded/sqlite-hydrating-session-manager.js.map +1 -0
  88. package/dist/src/agent/goals/goal-run-store.js +4 -4
  89. package/dist/src/agent/goals/persistent-goal-service.js +8 -15
  90. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  91. package/dist/src/agent/goals/post-turn.js +2 -2
  92. package/dist/src/agent/image/load-image-media.js +2 -2
  93. package/dist/src/agent/ipc/bus.js +1 -1
  94. package/dist/src/agent/ipc/inbox.js +2 -2
  95. package/dist/src/agent/ipc/socket.js +1 -1
  96. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  97. package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -2
  98. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  99. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  100. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  101. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  102. package/dist/src/agent/memory/dreaming/events.js +1 -1
  103. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  104. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  105. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  106. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  107. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  108. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  109. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  110. package/dist/src/agent/models/manager.js +1 -1
  111. package/dist/src/agent/prompt/memory/index.d.ts +1 -0
  112. package/dist/src/agent/prompt/memory/index.js +34 -80
  113. package/dist/src/agent/prompt/memory/index.js.map +1 -1
  114. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  115. package/dist/src/agent/prompt/system-prompt.js +0 -1
  116. package/dist/src/agent/prompt/system-prompt.js.map +1 -1
  117. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  118. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  119. package/dist/src/agent/sandbox/path-policy.js +2 -2
  120. package/dist/src/agent/service/build-direct-message-content.js +1 -1
  121. package/dist/src/agent/service/process-direct-one-shot.js +8 -17
  122. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  123. package/dist/src/agent/service/process-direct-streaming.js +14 -23
  124. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  125. package/dist/src/agent/service.js +7 -11
  126. package/dist/src/agent/service.js.map +1 -1
  127. package/dist/src/agent/session/session-inspector.js +1 -1
  128. package/dist/src/agent/skills/config.js +1 -1
  129. package/dist/src/agent/skills/hub-hash.js +2 -2
  130. package/dist/src/agent/skills/hub-lock.js +1 -1
  131. package/dist/src/agent/skills/hub-pull.js +3 -3
  132. package/dist/src/agent/skills/index.js +1 -1
  133. package/dist/src/agent/skills/managed-store.js +1 -1
  134. package/dist/src/agent/skills/scanner.js +1 -1
  135. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  136. package/dist/src/agent/skills/skill-manager.js +1 -1
  137. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  138. package/dist/src/agent/tools/factory.js +1 -1
  139. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  140. package/dist/src/agent/tools/index.d.ts +0 -1
  141. package/dist/src/agent/tools/index.js +1 -2
  142. package/dist/src/agent/tools/send-media.js +1 -1
  143. package/dist/src/agent/tools/session-search-tool.d.ts +0 -1
  144. package/dist/src/agent/tools/session-search-tool.js +11 -6
  145. package/dist/src/agent/tools/session-search-tool.js.map +1 -1
  146. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  147. package/dist/src/agent/tools/tool-paths.js +1 -3
  148. package/dist/src/agent/tools/tool-paths.js.map +1 -1
  149. package/dist/src/agent/tools/workflow-tool.js +1 -1
  150. package/dist/src/agent/tools/write.js +1 -1
  151. package/dist/src/agent/workflow/catalog.js +1 -1
  152. package/dist/src/auth/credentials.js +3 -3
  153. package/dist/src/auth/profiles/store.js +1 -1
  154. package/dist/src/auth/sync-provider-auth.js +1 -1
  155. package/dist/src/browser/cache-dir-policy.js +1 -1
  156. package/dist/src/browser/cdp-local-launcher.js +2 -2
  157. package/dist/src/browser/providers/browser-ext-install.js +4 -4
  158. package/dist/src/browser/providers/cloakbrowser.js +4 -4
  159. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  160. package/dist/src/browser/stealth.js +1 -1
  161. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  162. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  163. package/dist/src/channels/outbound/persist-store.js +1 -1
  164. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  165. package/dist/src/channels/pairing/pairing-store.js +2 -2
  166. package/dist/src/chat-commands/agent-edit.js +3 -4
  167. package/dist/src/chat-commands/agent-edit.js.map +1 -1
  168. package/dist/src/chat-commands/builtins/config.js +2 -2
  169. package/dist/src/chat-commands/context.js +1 -1
  170. package/dist/src/cli/commands/config.js +1 -1
  171. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  172. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  173. package/dist/src/cli/commands/doctor/checks/session-integrity.js +32 -95
  174. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
  175. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  176. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  177. package/dist/src/cli/commands/extension-dev.js +1 -1
  178. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  179. package/dist/src/cli/commands/extension-pack.js +1 -1
  180. package/dist/src/cli/commands/gateway/logs.js +1 -1
  181. package/dist/src/cli/commands/image.js +1 -1
  182. package/dist/src/cli/commands/init.js +5 -7
  183. package/dist/src/cli/commands/init.js.map +1 -1
  184. package/dist/src/cli/commands/onboard.js +0 -8
  185. package/dist/src/cli/commands/onboard.js.map +1 -1
  186. package/dist/src/cli/templates.d.ts +3 -10
  187. package/dist/src/cli/templates.js +4 -32
  188. package/dist/src/cli/templates.js.map +1 -1
  189. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  190. package/dist/src/commands/agents.config.js +1 -1
  191. package/dist/src/config/agent-profile.js +1 -1
  192. package/dist/src/config/gateway-bind.js +1 -1
  193. package/dist/src/config/index.js +7 -8
  194. package/dist/src/config/index.js.map +1 -1
  195. package/dist/src/config/loader.js +2 -2
  196. package/dist/src/config/models-json.js +2 -2
  197. package/dist/src/config/paths-state.d.ts +3 -0
  198. package/dist/src/config/paths-state.js +7 -3
  199. package/dist/src/config/paths-state.js.map +1 -1
  200. package/dist/src/config/paths.d.ts +5 -36
  201. package/dist/src/config/paths.js +7 -52
  202. package/dist/src/config/paths.js.map +1 -1
  203. package/dist/src/config/profile.js +2 -2
  204. package/dist/src/config/schema.d.ts +15 -0
  205. package/dist/src/config/schema.js +11 -0
  206. package/dist/src/config/schema.js.map +1 -1
  207. package/dist/src/config/workspace-path.js +1 -1
  208. package/dist/src/cron/execution-types.d.ts +42 -0
  209. package/dist/src/cron/executor.js +2 -2
  210. package/dist/src/cron/persistence.js +1 -1
  211. package/dist/src/cron/run-log-store.d.ts +4 -8
  212. package/dist/src/cron/run-log-store.js +26 -78
  213. package/dist/src/cron/run-log-store.js.map +1 -1
  214. package/dist/src/cron/service.d.ts +3 -3
  215. package/dist/src/cron/service.js +2 -2
  216. package/dist/src/cron/service.js.map +1 -1
  217. package/dist/src/cron/types.d.ts +1 -42
  218. package/dist/src/daemon/constants.js +1 -1
  219. package/dist/src/daemon/install-plan.js +2 -2
  220. package/dist/src/daemon/launchd.js +2 -2
  221. package/dist/src/daemon/schtasks.js +2 -2
  222. package/dist/src/daemon/systemd.js +2 -2
  223. package/dist/src/extensions/bundle-mcp.js +1 -1
  224. package/dist/src/extensions/discover-extensions.js +1 -1
  225. package/dist/src/extensions/health.js +1 -1
  226. package/dist/src/extensions/loader.js +1 -1
  227. package/dist/src/extensions/lockfile.js +2 -2
  228. package/dist/src/extensions/update.js +1 -1
  229. package/dist/src/gateway/agents-admin.js +4 -4
  230. package/dist/src/gateway/agents-admin.js.map +1 -1
  231. package/dist/src/gateway/file-path-classifier.d.ts +0 -1
  232. package/dist/src/gateway/file-path-classifier.js +2 -8
  233. package/dist/src/gateway/file-path-classifier.js.map +1 -1
  234. package/dist/src/gateway/heartbeat/service.js +1 -1
  235. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  236. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  237. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  238. package/dist/src/gateway/hono/oauth.js +1 -1
  239. package/dist/src/gateway/hono/routes/agents.js +1 -1
  240. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  241. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  242. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  243. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  244. package/dist/src/gateway/hono/routes/models.js +1 -1
  245. package/dist/src/gateway/hono/routes/shares.js +1 -1
  246. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  247. package/dist/src/gateway/lock.js +3 -3
  248. package/dist/src/gateway/ports.js +1 -1
  249. package/dist/src/gateway/service/agent-runner.js +2 -2
  250. package/dist/src/gateway/service/marketplace-service.js +2 -2
  251. package/dist/src/gateway/service.js +5 -1
  252. package/dist/src/gateway/service.js.map +1 -1
  253. package/dist/src/gateway/session-reset-service.d.ts +1 -1
  254. package/dist/src/gateway/session-reset-service.js +1 -1
  255. package/dist/src/gateway/session-reset-service.js.map +1 -1
  256. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  257. package/dist/src/heartbeat/index.js +1 -1
  258. package/dist/src/infra/brew.js +1 -1
  259. package/dist/src/infra/node-sqlite.d.ts +1 -0
  260. package/dist/src/infra/node-sqlite.js +17 -0
  261. package/dist/src/infra/node-sqlite.js.map +1 -0
  262. package/dist/src/infra/package-json.js +1 -1
  263. package/dist/src/infra/package-update-steps.js +1 -1
  264. package/dist/src/infra/path-env.js +2 -2
  265. package/dist/src/infra/restart.js +2 -2
  266. package/dist/src/infra/sqlite-errors.d.ts +1 -0
  267. package/dist/src/infra/sqlite-errors.js +77 -0
  268. package/dist/src/infra/sqlite-errors.js.map +1 -0
  269. package/dist/src/infra/stable-node-path.js +1 -1
  270. package/dist/src/infra/unhandled-rejections.d.ts +1 -0
  271. package/dist/src/infra/unhandled-rejections.js +25 -0
  272. package/dist/src/infra/unhandled-rejections.js.map +1 -0
  273. package/dist/src/infra/update-check.js +1 -1
  274. package/dist/src/infra/update-global.js +1 -1
  275. package/dist/src/infra/update-lock.js +3 -3
  276. package/dist/src/infra/update-runner.js +1 -1
  277. package/dist/src/infra/update-startup.js +2 -2
  278. package/dist/src/infra/warning-filter.d.ts +7 -0
  279. package/dist/src/infra/warning-filter.js +59 -0
  280. package/dist/src/infra/warning-filter.js.map +1 -0
  281. package/dist/src/infra/write-file-atomic.js +2 -2
  282. package/dist/src/notes/store.d.ts +3 -9
  283. package/dist/src/notes/store.js +22 -196
  284. package/dist/src/notes/store.js.map +1 -1
  285. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  286. package/dist/src/providers/index.js +2 -2
  287. package/dist/src/providers/model-registry.js +1 -1
  288. package/dist/src/session/config-store.d.ts +6 -75
  289. package/dist/src/session/config-store.js +38 -144
  290. package/dist/src/session/config-store.js.map +1 -1
  291. package/dist/src/session/config-types.d.ts +15 -0
  292. package/dist/src/session/config-types.js +1 -0
  293. package/dist/src/session/index.d.ts +1 -3
  294. package/dist/src/session/index.js +3 -5
  295. package/dist/src/session/init-session-turn.d.ts +0 -6
  296. package/dist/src/session/init-session-turn.js +18 -18
  297. package/dist/src/session/init-session-turn.js.map +1 -1
  298. package/dist/src/session/lifecycle-timestamps.d.ts +5 -2
  299. package/dist/src/session/lifecycle-timestamps.js.map +1 -1
  300. package/dist/src/session/{parity/load-jsonl-entries.js → load-jsonl-entries.js} +1 -1
  301. package/dist/src/session/load-jsonl-entries.js.map +1 -0
  302. package/dist/src/session/manager.d.ts +5 -3
  303. package/dist/src/session/manager.js +1 -5
  304. package/dist/src/session/manager.js.map +1 -1
  305. package/dist/src/session/resolve-session.d.ts +3 -6
  306. package/dist/src/session/resolve-session.js +26 -31
  307. package/dist/src/session/resolve-session.js.map +1 -1
  308. package/dist/src/session/session-context-for-llm.js +5 -1
  309. package/dist/src/session/session-context-for-llm.js.map +1 -1
  310. package/dist/src/session/session-id.js +12 -0
  311. package/dist/src/session/session-id.js.map +1 -0
  312. package/dist/src/session/session-title.js +2 -2
  313. package/dist/src/session/session-workspace.d.ts +1 -1
  314. package/dist/src/session/session-workspace.js.map +1 -1
  315. package/dist/src/session/store.d.ts +14 -63
  316. package/dist/src/session/store.js +172 -847
  317. package/dist/src/session/store.js.map +1 -1
  318. package/dist/src/session/stored-rows-to-file-entries.d.ts +11 -0
  319. package/dist/src/session/stored-rows-to-file-entries.js +95 -0
  320. package/dist/src/session/stored-rows-to-file-entries.js.map +1 -0
  321. package/dist/src/session/transcript-events.d.ts +1 -2
  322. package/dist/src/session/transcript-events.js +5 -12
  323. package/dist/src/session/transcript-events.js.map +1 -1
  324. package/dist/src/session/transcript-format.d.ts +1 -1
  325. package/dist/src/session/transcript-format.js.map +1 -1
  326. package/dist/src/session/transcript-stats.d.ts +1 -0
  327. package/dist/src/session/transcript-stats.js +10 -0
  328. package/dist/src/session/transcript-stats.js.map +1 -0
  329. package/dist/src/share/share-auto.js +2 -2
  330. package/dist/src/share/share-store.js +3 -3
  331. package/dist/src/share/share-thumbnail.js +2 -2
  332. package/dist/src/share/share-zip.js +1 -1
  333. package/dist/src/share/site-share-store.js +3 -3
  334. package/dist/src/share/site-static-serve.js +1 -1
  335. package/dist/src/storage/sqlite/config-repository.d.ts +6 -0
  336. package/dist/src/storage/sqlite/config-repository.js +56 -0
  337. package/dist/src/storage/sqlite/config-repository.js.map +1 -0
  338. package/dist/src/storage/sqlite/connection.d.ts +38 -0
  339. package/dist/src/storage/sqlite/connection.js +258 -0
  340. package/dist/src/storage/sqlite/connection.js.map +1 -0
  341. package/dist/src/storage/sqlite/cron-run-repository.d.ts +5 -0
  342. package/dist/src/storage/sqlite/cron-run-repository.js +97 -0
  343. package/dist/src/storage/sqlite/cron-run-repository.js.map +1 -0
  344. package/dist/src/storage/sqlite/fts.d.ts +2 -0
  345. package/dist/src/storage/sqlite/fts.js +11 -0
  346. package/dist/src/storage/sqlite/fts.js.map +1 -0
  347. package/dist/src/storage/sqlite/index.d.ts +12 -0
  348. package/dist/src/storage/sqlite/index.js +13 -0
  349. package/dist/src/storage/sqlite/memory-index-repository.d.ts +18 -0
  350. package/dist/src/storage/sqlite/memory-index-repository.js +132 -0
  351. package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -0
  352. package/dist/src/storage/sqlite/notes-repository.d.ts +11 -0
  353. package/dist/src/storage/sqlite/notes-repository.js +191 -0
  354. package/dist/src/storage/sqlite/notes-repository.js.map +1 -0
  355. package/dist/src/storage/sqlite/paths.d.ts +1 -0
  356. package/dist/src/storage/sqlite/paths.js +7 -0
  357. package/dist/src/storage/sqlite/paths.js.map +1 -0
  358. package/dist/src/storage/sqlite/row-mappers.d.ts +82 -0
  359. package/dist/src/storage/sqlite/row-mappers.js +164 -0
  360. package/dist/src/storage/sqlite/row-mappers.js.map +1 -0
  361. package/dist/src/storage/sqlite/schema.d.ts +5 -0
  362. package/dist/src/storage/sqlite/schema.js +43 -0
  363. package/dist/src/storage/sqlite/schema.js.map +1 -0
  364. package/dist/src/storage/sqlite/schema.sql +195 -0
  365. package/dist/src/storage/sqlite/session-metadata.d.ts +8 -0
  366. package/dist/src/storage/sqlite/session-metadata.js +83 -0
  367. package/dist/src/storage/sqlite/session-metadata.js.map +1 -0
  368. package/dist/src/storage/sqlite/session-repository.d.ts +29 -0
  369. package/dist/src/storage/sqlite/session-repository.js +268 -0
  370. package/dist/src/storage/sqlite/session-repository.js.map +1 -0
  371. package/dist/src/storage/sqlite/transaction.d.ts +11 -0
  372. package/dist/src/storage/sqlite/transaction.js +115 -0
  373. package/dist/src/storage/sqlite/transaction.js.map +1 -0
  374. package/dist/src/storage/sqlite/transcript-repository.d.ts +34 -0
  375. package/dist/src/storage/sqlite/transcript-repository.js +241 -0
  376. package/dist/src/storage/sqlite/transcript-repository.js.map +1 -0
  377. package/dist/src/tui/clipboard-image.js +3 -3
  378. package/dist/src/tui/theme-manager.js +1 -1
  379. package/dist/src/tui/tui-keybindings-file.js +1 -1
  380. package/dist/src/tui/tui-scoped-models.js +2 -2
  381. package/dist/src/tui/tui-settings.js +1 -1
  382. package/dist/src/tui/tui.js +3 -3
  383. package/dist/src/tunnel/frpc-binary.js +3 -3
  384. package/dist/src/tunnel/frpc-config.js +1 -1
  385. package/dist/src/tunnel/frpc-extract.js +1 -1
  386. package/dist/src/tunnel/tunnel-state.js +1 -1
  387. package/dist/src/utils/logger/audit.js +1 -1
  388. package/dist/src/utils/logger/log-store.js +1 -1
  389. package/dist/src/utils/logger/rotation.js +1 -1
  390. package/dist/src/voice/tts/audio.js +1 -1
  391. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  392. package/dist/src/workflows/service/workflow-session-bridge.js +41 -64
  393. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  394. package/dist/src/workflows/store/event-store.js +1 -1
  395. package/dist/src/workflows/store/run-store.js +1 -1
  396. package/package.json +2 -2
  397. package/dist/gateway/static/root/assets/index-Bj_l8QDp.css +0 -1
  398. package/dist/gateway/static/root/assets/url-BHHmdJYc.js +0 -3
  399. package/dist/src/agent/context/workspace-templates/BOOTSTRAP.md +0 -61
  400. package/dist/src/agent/embedded/session-manager-cache.d.ts +0 -19
  401. package/dist/src/agent/embedded/session-manager-cache.js +0 -48
  402. package/dist/src/agent/embedded/session-manager-cache.js.map +0 -1
  403. package/dist/src/session/parity/artifacts.d.ts +0 -16
  404. package/dist/src/session/parity/artifacts.js +0 -80
  405. package/dist/src/session/parity/artifacts.js.map +0 -1
  406. package/dist/src/session/parity/jsonl-transcript-io.d.ts +0 -54
  407. package/dist/src/session/parity/jsonl-transcript-io.js +0 -236
  408. package/dist/src/session/parity/jsonl-transcript-io.js.map +0 -1
  409. package/dist/src/session/parity/load-jsonl-entries.js.map +0 -1
  410. package/dist/src/session/parity/session-id.js +0 -18
  411. package/dist/src/session/parity/session-id.js.map +0 -1
  412. package/dist/src/session/parity/sessions-json-cache.d.ts +0 -14
  413. package/dist/src/session/parity/sessions-json-cache.js +0 -98
  414. package/dist/src/session/parity/sessions-json-cache.js.map +0 -1
  415. package/dist/src/session/parity/sessions-json-file-read.d.ts +0 -6
  416. package/dist/src/session/parity/sessions-json-file-read.js +0 -19
  417. package/dist/src/session/parity/sessions-json-file-read.js.map +0 -1
  418. package/dist/src/session/parity/sessions-json-file.d.ts +0 -11
  419. package/dist/src/session/parity/sessions-json-file.js +0 -52
  420. package/dist/src/session/parity/sessions-json-file.js.map +0 -1
  421. package/dist/src/session/parity/sessions-json-patch.d.ts +0 -14
  422. package/dist/src/session/parity/sessions-json-patch.js +0 -40
  423. package/dist/src/session/parity/sessions-json-patch.js.map +0 -1
  424. package/dist/src/session/parity/transcript-file-lock.d.ts +0 -22
  425. package/dist/src/session/parity/transcript-file-lock.js +0 -142
  426. package/dist/src/session/parity/transcript-file-lock.js.map +0 -1
  427. package/dist/src/session/parity/transcript-pagination.d.ts +0 -29
  428. package/dist/src/session/parity/transcript-pagination.js +0 -132
  429. package/dist/src/session/parity/transcript-pagination.js.map +0 -1
  430. package/dist/src/session/parity/transcript-paths.d.ts +0 -13
  431. package/dist/src/session/parity/transcript-paths.js +0 -64
  432. package/dist/src/session/parity/transcript-paths.js.map +0 -1
  433. package/dist/src/session/parity/xopc-session-disk-entry.d.ts +0 -22
  434. package/dist/src/session/search-index-cache.d.ts +0 -6
  435. package/dist/src/session/search-index-cache.js +0 -44
  436. package/dist/src/session/search-index-cache.js.map +0 -1
  437. package/dist/src/session/search-index.d.ts +0 -20
  438. package/dist/src/session/search-index.js +0 -124
  439. package/dist/src/session/search-index.js.map +0 -1
  440. /package/dist/src/{session/parity/xopc-session-disk-entry.js → cron/execution-types.js} +0 -0
  441. /package/dist/src/session/{parity/load-jsonl-entries.d.ts → load-jsonl-entries.d.ts} +0 -0
  442. /package/dist/src/session/{parity/session-id.d.ts → session-id.d.ts} +0 -0
@@ -1,13 +1,13 @@
1
- import { init_agent_scope, resolveAgentHomeDir } from "../agent-scope.js";
2
- import { extractProfileAgentId } from "../../config/agent-profile.js";
1
+ import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
3
2
  import { createLogger } from "../../utils/logger/index.js";
4
3
  import { init_logger } from "../../utils/logger.js";
5
- import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
4
+ import { init_agent_scope, resolveAgentHomeDir } from "../agent-scope.js";
5
+ import { extractProfileAgentId } from "../../config/agent-profile.js";
6
6
  import { checklistCounts } from "./checklist-types.js";
7
7
  import "./goal-run-types.js";
8
- import { join } from "node:path";
9
8
  import { createHash, randomUUID } from "node:crypto";
10
9
  import { readFile } from "node:fs/promises";
10
+ import { join } from "node:path";
11
11
  //#region src/agent/goals/goal-run-store.ts
12
12
  init_agent_scope();
13
13
  init_write_file_atomic();
@@ -1,7 +1,6 @@
1
- import { init_session_key, parseSessionKey } from "../../routing/session-key.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
4
- import { appendPiTranscriptMessage } from "../../session/parity/jsonl-transcript-io.js";
3
+ import { init_session_key, parseSessionKey } from "../../routing/session-key.js";
5
4
  import { handlePersistentGoalPostTurn } from "./post-turn.js";
6
5
  //#region src/agent/goals/persistent-goal-service.ts
7
6
  init_session_key();
@@ -58,19 +57,13 @@ var PersistentGoalService = class {
58
57
  appendAssistantReceipt: async (k, text) => {
59
58
  const trimmed = text.trim();
60
59
  if (!trimmed) return;
61
- const { absPath } = await this.opts.sessionStore.resolveTranscriptPath(k);
62
- await appendPiTranscriptMessage({
63
- absPath,
64
- cwd: this.opts.getResolvedWorkspaceForSession(k),
65
- message: {
66
- role: "assistant",
67
- content: [{
68
- type: "text",
69
- text: trimmed
70
- }],
71
- timestamp: Date.now()
72
- },
73
- sessionKey: k
60
+ await this.opts.sessionStore.appendTranscriptMessage(k, {
61
+ role: "assistant",
62
+ content: [{
63
+ type: "text",
64
+ text: trimmed
65
+ }],
66
+ timestamp: Date.now()
74
67
  });
75
68
  this.opts.notifyWebchatTranscriptAppend(k, trimmed);
76
69
  },
@@ -1 +1 @@
1
- {"version":3,"file":"persistent-goal-service.js","names":["parseRoutingSessionKey"],"sources":["../../../../src/agent/goals/persistent-goal-service.ts"],"sourcesContent":["/**\n * PersistentGoalService — owns the \"/goal\" runtime: continuation scheduling,\n * the `PersistentGoalApis` bag that command handlers receive, and the post-turn\n * verdict hook called from `OutboundCoordinator`.\n *\n * Previously this logic was scattered across `AgentService`:\n * - `setPersistentGoalWebchatContinuationScheduler` + a private callback field\n * - `schedulePersistentGoalContinuation` (bus vs webchat fork)\n * - `getPersistentGoalApisForCommand` (~40-line API factory)\n * - `recordPersistentGoalStreamOutcome` / `takePersistentGoalStreamOutcome`\n * - the `/goal` half of `emitSessionTurnComplete` (delegated to\n * `handlePersistentGoalPostTurn`)\n *\n * Concentrating it here gives the rest of `AgentService` a cleaner surface\n * (one collaborator instead of five methods) and makes the goal runtime\n * unit-testable in isolation.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type { SessionStateBag } from '../session/index.js';\nimport { parseSessionKey as parseRoutingSessionKey } from '../../routing/session-key.js';\nimport { appendPiTranscriptMessage } from '../../session/parity/jsonl-transcript-io.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { PersistentGoalApis } from './persistent-goal-apis.js';\nimport { handlePersistentGoalPostTurn } from './post-turn.js';\n\nconst log = createLogger('PersistentGoalService');\n\nexport interface PersistentGoalRouting {\n sessionKey: string;\n channel: string;\n chatId: string;\n inboundMetadata?: Record<string, unknown>;\n}\n\nexport interface SessionTurnCompletionForGoal {\n sessionKey: string;\n channel: string;\n chatId: string;\n assistantPlainText: string;\n aborted: boolean;\n streamError?: string;\n skipPersistentGoalPostTurn?: boolean;\n outboundMetadata?: Record<string, unknown>;\n}\n\nexport interface PersistentGoalServiceOptions {\n bus: MessageBus;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n sessionState: SessionStateBag;\n /** Effective config snapshot accessor. */\n getConfig: () => Config | undefined;\n /** Resolve the workspace directory for `appendAssistantReceipt` writes. */\n getResolvedWorkspaceForSession: (sessionKey: string) => string;\n /** Notify the gateway UI after a metadata change (replaces the in-bag emit). */\n onSessionMetadataUpdated?: (sessionKey: string) => void;\n /** Push an assistant token + transcript refresh into a live webchat stream. */\n notifyWebchatTranscriptAppend: (sessionKey: string, assistantText: string) => void;\n}\n\nexport class PersistentGoalService {\n private readonly opts: PersistentGoalServiceOptions;\n /** Gateway only: webchat continuations bypass the bus and reuse `runGatewayAgent`. */\n private webchatContinuationScheduler?: (sessionKey: string, message: string) => void;\n\n constructor(opts: PersistentGoalServiceOptions) {\n this.opts = opts;\n }\n\n /** Register the gateway-side webchat continuation hook (set from `web-agent` wiring). */\n setWebchatContinuationScheduler(\n fn: ((sessionKey: string, message: string) => void) | undefined,\n ): void {\n this.webchatContinuationScheduler = fn;\n }\n\n /**\n * Continue a session after `/goal` decides the previous turn needs follow-up.\n * Webchat sessions go through the scheduler; bus-driven channels re-publish the\n * follow-up message as an inbound bus event so the existing inbound loop picks it up.\n */\n scheduleContinuation(\n sessionKey: string,\n message: string,\n routing: { channel: string; chatId: string; inboundMetadata?: Record<string, unknown> },\n ): void {\n const parsed = parseRoutingSessionKey(sessionKey);\n if (parsed?.source === 'webchat' && this.webchatContinuationScheduler) {\n this.webchatContinuationScheduler(sessionKey, message);\n return;\n }\n queueMicrotask(() => {\n void this.opts.bus\n .publishInbound({\n channel: routing.channel,\n chat_id: routing.chatId,\n sender_id: 'persistent-goal',\n content: message,\n metadata: { sessionKey, ...routing.inboundMetadata },\n })\n .catch((err) => {\n log.warn({ err, sessionKey }, 'Persistent goal: publishInbound failed');\n });\n });\n }\n\n /** Build the per-command `PersistentGoalApis` bag (transcript writers + scheduler closures). */\n buildApisForRouting(routing: PersistentGoalRouting): PersistentGoalApis {\n return {\n getSessionMetadata: (k) => this.opts.sessionStore.getMetadata(k),\n updateSessionMetadata: async (k, u) => {\n await this.opts.sessionStore.updateMetadata(k, u);\n this.opts.onSessionMetadataUpdated?.(k);\n },\n loadMessages: (k) => this.opts.sessionStore.loadMessages(k),\n appendAssistantReceipt: async (k, text) => {\n const trimmed = text.trim();\n if (!trimmed) return;\n const { absPath } = await this.opts.sessionStore.resolveTranscriptPath(k);\n const workspaceDir = this.opts.getResolvedWorkspaceForSession(k);\n await appendPiTranscriptMessage({\n absPath,\n cwd: workspaceDir,\n message: {\n role: 'assistant',\n content: [{ type: 'text', text: trimmed }],\n timestamp: Date.now(),\n } as AgentMessage,\n sessionKey: k,\n });\n this.opts.notifyWebchatTranscriptAppend(k, trimmed);\n },\n scheduleContinuation: (sk, msg) => {\n this.scheduleContinuation(sk, msg, {\n channel: routing.channel,\n chatId: routing.chatId,\n inboundMetadata: routing.inboundMetadata,\n });\n },\n inboundConcurrentDepth: (sk) => this.opts.sessionState.getInboundTurnDepth(sk),\n };\n }\n\n recordStreamOutcome(sessionKey: string, outcome: { skipPersistentGoalPostTurn: boolean }): void {\n this.opts.sessionState.recordPersistentGoalStreamOutcome(sessionKey, outcome);\n }\n\n takeStreamOutcome(sessionKey: string): { skipPersistentGoalPostTurn: boolean } | undefined {\n return this.opts.sessionState.takePersistentGoalStreamOutcome(sessionKey);\n }\n\n /**\n * Run the `/goal` post-turn verdict for a completed user turn (called from\n * `OutboundCoordinator.emitSessionTurnComplete`).\n */\n async runPostTurn(payload: SessionTurnCompletionForGoal): Promise<void> {\n const apis = this.buildApisForRouting({\n sessionKey: payload.sessionKey,\n channel: payload.channel,\n chatId: payload.chatId,\n inboundMetadata: payload.outboundMetadata,\n });\n\n const src = parseRoutingSessionKey(payload.sessionKey)?.source;\n const isWebchat = src === 'webchat';\n const publishVerdict =\n !isWebchat && payload.channel !== 'cli'\n ? async (text: string) => {\n await this.opts.bus.publishOutbound({\n channel: payload.channel,\n chat_id: payload.chatId,\n content: text,\n type: 'message',\n metadata: {\n accountId: payload.outboundMetadata?.accountId,\n threadId: payload.outboundMetadata?.threadId,\n },\n });\n }\n : undefined;\n\n let runtimeSessionModelRef: string | undefined;\n try {\n runtimeSessionModelRef = this.opts.modelManager.getModelForSession(payload.sessionKey);\n } catch {\n runtimeSessionModelRef = undefined;\n }\n\n await handlePersistentGoalPostTurn({\n apis,\n sessionKey: payload.sessionKey,\n assistantPlainText: payload.assistantPlainText,\n aborted: payload.aborted,\n ...(payload.streamError !== undefined ? { streamError: payload.streamError } : {}),\n skipPersistentGoalPostTurn: payload.skipPersistentGoalPostTurn ?? false,\n config: this.opts.getConfig(),\n runtimeSessionModelRef,\n publishVerdictToChannel: publishVerdict,\n });\n }\n}\n"],"mappings":";;;;;;kBAyByF;aAEpC;AAIrD,MAAM,MAAM,aAAa,wBAAwB;AAmCjD,IAAa,wBAAb,MAAmC;CACjC;;CAEA;CAEA,YAAY,MAAoC;AAC9C,OAAK,OAAO;;;CAId,gCACE,IACM;AACN,OAAK,+BAA+B;;;;;;;CAQtC,qBACE,YACA,SACA,SACM;AAEN,MADeA,gBAAuB,WAC5B,EAAE,WAAW,aAAa,KAAK,8BAA8B;AACrE,QAAK,6BAA6B,YAAY,QAAQ;AACtD;;AAEF,uBAAqB;AACd,QAAK,KAAK,IACZ,eAAe;IACd,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,WAAW;IACX,SAAS;IACT,UAAU;KAAE;KAAY,GAAG,QAAQ;KAAiB;IACrD,CAAC,CACD,OAAO,QAAQ;AACd,QAAI,KAAK;KAAE;KAAK;KAAY,EAAE,yCAAyC;KACvE;IACJ;;;CAIJ,oBAAoB,SAAoD;AACtE,SAAO;GACL,qBAAqB,MAAM,KAAK,KAAK,aAAa,YAAY,EAAE;GAChE,uBAAuB,OAAO,GAAG,MAAM;AACrC,UAAM,KAAK,KAAK,aAAa,eAAe,GAAG,EAAE;AACjD,SAAK,KAAK,2BAA2B,EAAE;;GAEzC,eAAe,MAAM,KAAK,KAAK,aAAa,aAAa,EAAE;GAC3D,wBAAwB,OAAO,GAAG,SAAS;IACzC,MAAM,UAAU,KAAK,MAAM;AAC3B,QAAI,CAAC,QAAS;IACd,MAAM,EAAE,YAAY,MAAM,KAAK,KAAK,aAAa,sBAAsB,EAAE;AAEzE,UAAM,0BAA0B;KAC9B;KACA,KAHmB,KAAK,KAAK,+BAA+B,EAG3C;KACjB,SAAS;MACP,MAAM;MACN,SAAS,CAAC;OAAE,MAAM;OAAQ,MAAM;OAAS,CAAC;MAC1C,WAAW,KAAK,KAAK;MACtB;KACD,YAAY;KACb,CAAC;AACF,SAAK,KAAK,8BAA8B,GAAG,QAAQ;;GAErD,uBAAuB,IAAI,QAAQ;AACjC,SAAK,qBAAqB,IAAI,KAAK;KACjC,SAAS,QAAQ;KACjB,QAAQ,QAAQ;KAChB,iBAAiB,QAAQ;KAC1B,CAAC;;GAEJ,yBAAyB,OAAO,KAAK,KAAK,aAAa,oBAAoB,GAAG;GAC/E;;CAGH,oBAAoB,YAAoB,SAAwD;AAC9F,OAAK,KAAK,aAAa,kCAAkC,YAAY,QAAQ;;CAG/E,kBAAkB,YAAyE;AACzF,SAAO,KAAK,KAAK,aAAa,gCAAgC,WAAW;;;;;;CAO3E,MAAM,YAAY,SAAsD;EACtE,MAAM,OAAO,KAAK,oBAAoB;GACpC,YAAY,QAAQ;GACpB,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,iBAAiB,QAAQ;GAC1B,CAAC;EAIF,MAAM,iBACJ,EAHUA,gBAAuB,QAAQ,WAAW,EAAE,WAC9B,cAEV,QAAQ,YAAY,QAC9B,OAAO,SAAiB;AACtB,SAAM,KAAK,KAAK,IAAI,gBAAgB;IAClC,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,SAAS;IACT,MAAM;IACN,UAAU;KACR,WAAW,QAAQ,kBAAkB;KACrC,UAAU,QAAQ,kBAAkB;KACrC;IACF,CAAC;MAEJ,KAAA;EAEN,IAAI;AACJ,MAAI;AACF,4BAAyB,KAAK,KAAK,aAAa,mBAAmB,QAAQ,WAAW;UAChF;AACN,4BAAyB,KAAA;;AAG3B,QAAM,6BAA6B;GACjC;GACA,YAAY,QAAQ;GACpB,oBAAoB,QAAQ;GAC5B,SAAS,QAAQ;GACjB,GAAI,QAAQ,gBAAgB,KAAA,IAAY,EAAE,aAAa,QAAQ,aAAa,GAAG,EAAE;GACjF,4BAA4B,QAAQ,8BAA8B;GAClE,QAAQ,KAAK,KAAK,WAAW;GAC7B;GACA,yBAAyB;GAC1B,CAAC"}
1
+ {"version":3,"file":"persistent-goal-service.js","names":["parseRoutingSessionKey"],"sources":["../../../../src/agent/goals/persistent-goal-service.ts"],"sourcesContent":["/**\n * PersistentGoalService — owns the \"/goal\" runtime: continuation scheduling,\n * the `PersistentGoalApis` bag that command handlers receive, and the post-turn\n * verdict hook called from `OutboundCoordinator`.\n *\n * Previously this logic was scattered across `AgentService`:\n * - `setPersistentGoalWebchatContinuationScheduler` + a private callback field\n * - `schedulePersistentGoalContinuation` (bus vs webchat fork)\n * - `getPersistentGoalApisForCommand` (~40-line API factory)\n * - `recordPersistentGoalStreamOutcome` / `takePersistentGoalStreamOutcome`\n * - the `/goal` half of `emitSessionTurnComplete` (delegated to\n * `handlePersistentGoalPostTurn`)\n *\n * Concentrating it here gives the rest of `AgentService` a cleaner surface\n * (one collaborator instead of five methods) and makes the goal runtime\n * unit-testable in isolation.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type { SessionStateBag } from '../session/index.js';\nimport { parseSessionKey as parseRoutingSessionKey } from '../../routing/session-key.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { PersistentGoalApis } from './persistent-goal-apis.js';\nimport { handlePersistentGoalPostTurn } from './post-turn.js';\n\nconst log = createLogger('PersistentGoalService');\n\nexport interface PersistentGoalRouting {\n sessionKey: string;\n channel: string;\n chatId: string;\n inboundMetadata?: Record<string, unknown>;\n}\n\nexport interface SessionTurnCompletionForGoal {\n sessionKey: string;\n channel: string;\n chatId: string;\n assistantPlainText: string;\n aborted: boolean;\n streamError?: string;\n skipPersistentGoalPostTurn?: boolean;\n outboundMetadata?: Record<string, unknown>;\n}\n\nexport interface PersistentGoalServiceOptions {\n bus: MessageBus;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n sessionState: SessionStateBag;\n /** Effective config snapshot accessor. */\n getConfig: () => Config | undefined;\n /** Resolve the workspace directory for `appendAssistantReceipt` writes. */\n getResolvedWorkspaceForSession: (sessionKey: string) => string;\n /** Notify the gateway UI after a metadata change (replaces the in-bag emit). */\n onSessionMetadataUpdated?: (sessionKey: string) => void;\n /** Push an assistant token + transcript refresh into a live webchat stream. */\n notifyWebchatTranscriptAppend: (sessionKey: string, assistantText: string) => void;\n}\n\nexport class PersistentGoalService {\n private readonly opts: PersistentGoalServiceOptions;\n /** Gateway only: webchat continuations bypass the bus and reuse `runGatewayAgent`. */\n private webchatContinuationScheduler?: (sessionKey: string, message: string) => void;\n\n constructor(opts: PersistentGoalServiceOptions) {\n this.opts = opts;\n }\n\n /** Register the gateway-side webchat continuation hook (set from `web-agent` wiring). */\n setWebchatContinuationScheduler(\n fn: ((sessionKey: string, message: string) => void) | undefined,\n ): void {\n this.webchatContinuationScheduler = fn;\n }\n\n /**\n * Continue a session after `/goal` decides the previous turn needs follow-up.\n * Webchat sessions go through the scheduler; bus-driven channels re-publish the\n * follow-up message as an inbound bus event so the existing inbound loop picks it up.\n */\n scheduleContinuation(\n sessionKey: string,\n message: string,\n routing: { channel: string; chatId: string; inboundMetadata?: Record<string, unknown> },\n ): void {\n const parsed = parseRoutingSessionKey(sessionKey);\n if (parsed?.source === 'webchat' && this.webchatContinuationScheduler) {\n this.webchatContinuationScheduler(sessionKey, message);\n return;\n }\n queueMicrotask(() => {\n void this.opts.bus\n .publishInbound({\n channel: routing.channel,\n chat_id: routing.chatId,\n sender_id: 'persistent-goal',\n content: message,\n metadata: { sessionKey, ...routing.inboundMetadata },\n })\n .catch((err) => {\n log.warn({ err, sessionKey }, 'Persistent goal: publishInbound failed');\n });\n });\n }\n\n /** Build the per-command `PersistentGoalApis` bag (transcript writers + scheduler closures). */\n buildApisForRouting(routing: PersistentGoalRouting): PersistentGoalApis {\n return {\n getSessionMetadata: (k) => this.opts.sessionStore.getMetadata(k),\n updateSessionMetadata: async (k, u) => {\n await this.opts.sessionStore.updateMetadata(k, u);\n this.opts.onSessionMetadataUpdated?.(k);\n },\n loadMessages: (k) => this.opts.sessionStore.loadMessages(k),\n appendAssistantReceipt: async (k, text) => {\n const trimmed = text.trim();\n if (!trimmed) return;\n await this.opts.sessionStore.appendTranscriptMessage(k, {\n role: 'assistant',\n content: [{ type: 'text', text: trimmed }],\n timestamp: Date.now(),\n } as AgentMessage);\n this.opts.notifyWebchatTranscriptAppend(k, trimmed);\n },\n scheduleContinuation: (sk, msg) => {\n this.scheduleContinuation(sk, msg, {\n channel: routing.channel,\n chatId: routing.chatId,\n inboundMetadata: routing.inboundMetadata,\n });\n },\n inboundConcurrentDepth: (sk) => this.opts.sessionState.getInboundTurnDepth(sk),\n };\n }\n\n recordStreamOutcome(sessionKey: string, outcome: { skipPersistentGoalPostTurn: boolean }): void {\n this.opts.sessionState.recordPersistentGoalStreamOutcome(sessionKey, outcome);\n }\n\n takeStreamOutcome(sessionKey: string): { skipPersistentGoalPostTurn: boolean } | undefined {\n return this.opts.sessionState.takePersistentGoalStreamOutcome(sessionKey);\n }\n\n /**\n * Run the `/goal` post-turn verdict for a completed user turn (called from\n * `OutboundCoordinator.emitSessionTurnComplete`).\n */\n async runPostTurn(payload: SessionTurnCompletionForGoal): Promise<void> {\n const apis = this.buildApisForRouting({\n sessionKey: payload.sessionKey,\n channel: payload.channel,\n chatId: payload.chatId,\n inboundMetadata: payload.outboundMetadata,\n });\n\n const src = parseRoutingSessionKey(payload.sessionKey)?.source;\n const isWebchat = src === 'webchat';\n const publishVerdict =\n !isWebchat && payload.channel !== 'cli'\n ? async (text: string) => {\n await this.opts.bus.publishOutbound({\n channel: payload.channel,\n chat_id: payload.chatId,\n content: text,\n type: 'message',\n metadata: {\n accountId: payload.outboundMetadata?.accountId,\n threadId: payload.outboundMetadata?.threadId,\n },\n });\n }\n : undefined;\n\n let runtimeSessionModelRef: string | undefined;\n try {\n runtimeSessionModelRef = this.opts.modelManager.getModelForSession(payload.sessionKey);\n } catch {\n runtimeSessionModelRef = undefined;\n }\n\n await handlePersistentGoalPostTurn({\n apis,\n sessionKey: payload.sessionKey,\n assistantPlainText: payload.assistantPlainText,\n aborted: payload.aborted,\n ...(payload.streamError !== undefined ? { streamError: payload.streamError } : {}),\n skipPersistentGoalPostTurn: payload.skipPersistentGoalPostTurn ?? false,\n config: this.opts.getConfig(),\n runtimeSessionModelRef,\n publishVerdictToChannel: publishVerdict,\n });\n }\n}\n"],"mappings":";;;;;kBAyByF;aACpC;AAIrD,MAAM,MAAM,aAAa,wBAAwB;AAmCjD,IAAa,wBAAb,MAAmC;CACjC;;CAEA;CAEA,YAAY,MAAoC;AAC9C,OAAK,OAAO;;;CAId,gCACE,IACM;AACN,OAAK,+BAA+B;;;;;;;CAQtC,qBACE,YACA,SACA,SACM;AAEN,MADeA,gBAAuB,WAC5B,EAAE,WAAW,aAAa,KAAK,8BAA8B;AACrE,QAAK,6BAA6B,YAAY,QAAQ;AACtD;;AAEF,uBAAqB;AACd,QAAK,KAAK,IACZ,eAAe;IACd,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,WAAW;IACX,SAAS;IACT,UAAU;KAAE;KAAY,GAAG,QAAQ;KAAiB;IACrD,CAAC,CACD,OAAO,QAAQ;AACd,QAAI,KAAK;KAAE;KAAK;KAAY,EAAE,yCAAyC;KACvE;IACJ;;;CAIJ,oBAAoB,SAAoD;AACtE,SAAO;GACL,qBAAqB,MAAM,KAAK,KAAK,aAAa,YAAY,EAAE;GAChE,uBAAuB,OAAO,GAAG,MAAM;AACrC,UAAM,KAAK,KAAK,aAAa,eAAe,GAAG,EAAE;AACjD,SAAK,KAAK,2BAA2B,EAAE;;GAEzC,eAAe,MAAM,KAAK,KAAK,aAAa,aAAa,EAAE;GAC3D,wBAAwB,OAAO,GAAG,SAAS;IACzC,MAAM,UAAU,KAAK,MAAM;AAC3B,QAAI,CAAC,QAAS;AACd,UAAM,KAAK,KAAK,aAAa,wBAAwB,GAAG;KACtD,MAAM;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAS,CAAC;KAC1C,WAAW,KAAK,KAAK;KACtB,CAAiB;AAClB,SAAK,KAAK,8BAA8B,GAAG,QAAQ;;GAErD,uBAAuB,IAAI,QAAQ;AACjC,SAAK,qBAAqB,IAAI,KAAK;KACjC,SAAS,QAAQ;KACjB,QAAQ,QAAQ;KAChB,iBAAiB,QAAQ;KAC1B,CAAC;;GAEJ,yBAAyB,OAAO,KAAK,KAAK,aAAa,oBAAoB,GAAG;GAC/E;;CAGH,oBAAoB,YAAoB,SAAwD;AAC9F,OAAK,KAAK,aAAa,kCAAkC,YAAY,QAAQ;;CAG/E,kBAAkB,YAAyE;AACzF,SAAO,KAAK,KAAK,aAAa,gCAAgC,WAAW;;;;;;CAO3E,MAAM,YAAY,SAAsD;EACtE,MAAM,OAAO,KAAK,oBAAoB;GACpC,YAAY,QAAQ;GACpB,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,iBAAiB,QAAQ;GAC1B,CAAC;EAIF,MAAM,iBACJ,EAHUA,gBAAuB,QAAQ,WAAW,EAAE,WAC9B,cAEV,QAAQ,YAAY,QAC9B,OAAO,SAAiB;AACtB,SAAM,KAAK,KAAK,IAAI,gBAAgB;IAClC,SAAS,QAAQ;IACjB,SAAS,QAAQ;IACjB,SAAS;IACT,MAAM;IACN,UAAU;KACR,WAAW,QAAQ,kBAAkB;KACrC,UAAU,QAAQ,kBAAkB;KACrC;IACF,CAAC;MAEJ,KAAA;EAEN,IAAI;AACJ,MAAI;AACF,4BAAyB,KAAK,KAAK,aAAa,mBAAmB,QAAQ,WAAW;UAChF;AACN,4BAAyB,KAAA;;AAG3B,QAAM,6BAA6B;GACjC;GACA,YAAY,QAAQ;GACpB,oBAAoB,QAAQ;GAC5B,SAAS,QAAQ;GACjB,GAAI,QAAQ,gBAAgB,KAAA,IAAY,EAAE,aAAa,QAAQ,aAAa,GAAG,EAAE;GACjF,4BAA4B,QAAQ,8BAA8B;GAClE,QAAQ,KAAK,KAAK,WAAW;GAC7B;GACA,yBAAyB;GAC1B,CAAC"}
@@ -1,7 +1,7 @@
1
- import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
2
- import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
3
1
  import { createLogger } from "../../utils/logger/index.js";
4
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
4
+ import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
5
5
  import { PERSISTENT_GOAL_CUSTOM_KEY, mergeCustomDataPatch, readPersistentGoal, serializePersistentGoal } from "./state.js";
6
6
  import { resolveGoalUiLocale } from "./goal-locale.js";
7
7
  import { evaluateAfterTurnHermesLike } from "./evaluate-turn.js";
@@ -1,8 +1,8 @@
1
1
  import { checkFileSafety } from "../prompt/safety.js";
2
2
  import { decodeDataUrl } from "./image-helpers.js";
3
- import { homedir } from "node:os";
4
- import path from "node:path";
5
3
  import { promises } from "node:fs";
4
+ import path from "node:path";
5
+ import { homedir } from "node:os";
6
6
  //#region src/agent/image/load-image-media.ts
7
7
  function expandUser(p) {
8
8
  if (p.startsWith("~/") || p === "~") return path.join(homedir(), p.slice(1));
@@ -1,6 +1,6 @@
1
- import { init_agent_scope, resolveDefaultAgentId } from "../agent-scope.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { init_agent_scope, resolveDefaultAgentId } from "../agent-scope.js";
4
4
  import { createResponseMessage, createSignalMessage, createTaskMessage } from "./types.js";
5
5
  import { AgentInbox } from "./inbox.js";
6
6
  //#region src/agent/ipc/bus.ts
@@ -1,10 +1,10 @@
1
+ import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
1
2
  import { createLogger } from "../../utils/logger/index.js";
2
3
  import { init_logger } from "../../utils/logger.js";
3
4
  import { init_paths, resolveAgentDir } from "../../config/paths.js";
4
- import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
5
+ import { mkdir, readFile, readdir, rename } from "fs/promises";
5
6
  import { join } from "path";
6
7
  import { existsSync, watch } from "fs";
7
- import { mkdir, readFile, readdir, rename } from "fs/promises";
8
8
  //#region src/agent/ipc/inbox.ts
9
9
  init_write_file_atomic();
10
10
  init_logger();
@@ -2,8 +2,8 @@ import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { init_paths, resolveSocketPath } from "../../config/paths.js";
4
4
  import { isValidIPCMessage } from "./types.js";
5
- import { dirname } from "path";
6
5
  import { mkdir } from "fs/promises";
6
+ import { dirname } from "path";
7
7
  import { Socket, createServer } from "net";
8
8
  //#region src/agent/ipc/socket.ts
9
9
  init_logger();
@@ -1,6 +1,6 @@
1
- import { init_string_coerce, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "../../utils/string-coerce.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { init_string_coerce, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "../../utils/string-coerce.js";
4
4
  import { buildSafeToolName, normalizeReservedToolNames } from "./bundle-mcp-names.js";
5
5
  import { setPluginToolMeta } from "./mcp-tool-meta.js";
6
6
  import crypto from "node:crypto";
@@ -1,9 +1,9 @@
1
- import { init_string_coerce, normalizeOptionalString } from "../../utils/string-coerce.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { init_string_coerce, normalizeOptionalString } from "../../utils/string-coerce.js";
4
+ import { resolveGlobalSingleton } from "../../utils/global-singleton.js";
4
5
  import { sanitizeServerName } from "./bundle-mcp-names.js";
5
6
  import { resolveConnectorSecretReferences } from "../../connectors/secret-store.js";
6
- import { resolveGlobalSingleton } from "../../utils/global-singleton.js";
7
7
  import { redactSensitiveUrlLikeString } from "../../utils/redact-sensitive-url.js";
8
8
  import { loadEmbeddedMcpConfig } from "./embedded-mcp.js";
9
9
  import { isMcpConfigRecord } from "./mcp-config-shared.js";
@@ -1,6 +1,6 @@
1
- import { init_string_coerce, normalizeLowercaseStringOrEmpty } from "../../utils/string-coerce.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { init_string_coerce, normalizeLowercaseStringOrEmpty } from "../../utils/string-coerce.js";
4
4
  import { resolveXopcMcpTransportAlias } from "../../config/mcp-config-normalize.js";
5
5
  import { sanitizeForLog } from "../../utils/sanitize-log.js";
6
6
  import { describeHttpMcpServerLaunchConfig, resolveHttpMcpServerLaunchConfig } from "./mcp-http.js";
@@ -1,6 +1,6 @@
1
- import { init_string_coerce, normalizeOptionalString } from "../../utils/string-coerce.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { init_string_coerce, normalizeOptionalString } from "../../utils/string-coerce.js";
4
4
  import { XopcStdioClientTransport } from "./mcp-stdio-transport.js";
5
5
  import { resolveMcpTransportConfig } from "./mcp-transport-config.js";
6
6
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
@@ -1,6 +1,6 @@
1
- import { join } from "node:path";
2
1
  import { existsSync, mkdirSync, readFileSync } from "node:fs";
3
2
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
4
  import lockfile from "proper-lockfile";
5
5
  //#region src/agent/memory/builtin-memory-store.ts
6
6
  /**
@@ -4,8 +4,8 @@ import { MEMORY_MD_FILENAME } from "./constants.js";
4
4
  import { clamp01, compareCandidatesByScore, computeCandidateScore, extractPromotionMarkers, isContaminatedSnippet, isExpiredEntry, isoDay, readFileLines, resolveDeepDefaults, sliceRange, snippetHash } from "./utils.js";
5
5
  import { loadDreamingStore, saveDreamingStore, withDreamingPromotionLock } from "./short-term-store.js";
6
6
  import { emptyDeepPhaseSkipped, writeDreamingDeepLastRun } from "./last-run.js";
7
- import path from "node:path";
8
7
  import fs from "node:fs/promises";
8
+ import path from "node:path";
9
9
  //#region src/agent/memory/dreaming/deep-promotion.ts
10
10
  init_logger();
11
11
  const log = createLogger("Dreaming:Deep");
@@ -1,6 +1,6 @@
1
1
  import { DREAMING_DIR_RELATIVE, DREAMING_EVENTS_LOG_RELATIVE } from "./constants.js";
2
- import path from "node:path";
3
2
  import fs from "node:fs/promises";
3
+ import path from "node:path";
4
4
  //#region src/agent/memory/dreaming/events.ts
5
5
  /**
6
6
  * Append a single event line to `memory/.dreams/events.jsonl`.
@@ -1,6 +1,6 @@
1
1
  import { DREAMING_LAST_RUN_RELATIVE } from "./constants.js";
2
- import path from "node:path";
3
2
  import fs from "node:fs/promises";
3
+ import path from "node:path";
4
4
  //#region src/agent/memory/dreaming/last-run.ts
5
5
  const DREAMING_LAST_RUN_FORMAT_VERSION = 2;
6
6
  function isRecord(v) {
@@ -4,8 +4,8 @@ import { DREAMING_DIR_RELATIVE } from "./constants.js";
4
4
  import { buildEntryKey, isoDay, normalizeMemoryPath, normalizeSnippetForHash, snippetHash } from "./utils.js";
5
5
  import { bumpEntryPhaseSignal, loadDreamingStore, saveDreamingStore } from "./short-term-store.js";
6
6
  import "./last-run.js";
7
- import path from "node:path";
8
7
  import fs from "node:fs/promises";
8
+ import path from "node:path";
9
9
  //#region src/agent/memory/dreaming/light-sweep.ts
10
10
  init_logger();
11
11
  const log = createLogger("Dreaming:Light");
@@ -1,8 +1,8 @@
1
1
  import { MEMORY_MD_FILENAME } from "./constants.js";
2
2
  import { clamp01, compareCandidatesByScore, computeCandidateScore, extractPromotionMarkers, isContaminatedSnippet, isExpiredEntry, readFileLines, resolveDeepDefaults, sliceRange, snippetHash } from "./utils.js";
3
3
  import { loadDreamingStore } from "./short-term-store.js";
4
- import path from "node:path";
5
4
  import fs from "node:fs/promises";
5
+ import path from "node:path";
6
6
  //#region src/agent/memory/dreaming/preview.ts
7
7
  async function previewDreamingDeepPromotion(params) {
8
8
  const cfg = resolveDeepDefaults(params.config);
@@ -4,8 +4,8 @@ import { DREAMING_DIR_RELATIVE, DREAMS_MD_FILENAME, MS_PER_DAY } from "./constan
4
4
  import { isoDay } from "./utils.js";
5
5
  import { bumpEntryPhaseSignal, loadDreamingStore, saveDreamingStore } from "./short-term-store.js";
6
6
  import "./last-run.js";
7
- import path from "node:path";
8
7
  import fs from "node:fs/promises";
8
+ import path from "node:path";
9
9
  //#region src/agent/memory/dreaming/rem-patterns.ts
10
10
  init_logger();
11
11
  const log = createLogger("Dreaming:REM");
@@ -2,9 +2,9 @@ import { createLogger } from "../../../utils/logger/index.js";
2
2
  import { init_logger } from "../../../utils/logger.js";
3
3
  import { SHORT_TERM_PROMOTION_LOCK_RELATIVE, SHORT_TERM_RECALL_STORE_RELATIVE } from "./constants.js";
4
4
  import { buildEntryKey, clamp01, isoDay, normalizeMemoryPath } from "./utils.js";
5
- import path from "node:path";
6
5
  import { createHash, randomUUID } from "node:crypto";
7
6
  import fs from "node:fs/promises";
7
+ import path from "node:path";
8
8
  //#region src/agent/memory/dreaming/short-term-store.ts
9
9
  init_logger();
10
10
  const log = createLogger("Dreaming:Store");
@@ -1,7 +1,7 @@
1
1
  import { DEFAULT_DEEP_CRON, DIVERSITY_WEIGHT, MS_PER_DAY, REINFORCEMENT_WEIGHT } from "./constants.js";
2
- import path from "node:path";
3
2
  import { createHash } from "node:crypto";
4
3
  import fs from "node:fs/promises";
4
+ import path from "node:path";
5
5
  //#region src/agent/memory/dreaming/utils.ts
6
6
  /** Normalize a workspace-relative memory path: forward slashes, no odd ../ escapes at start. */
7
7
  function normalizeMemoryPath(rel) {
@@ -1,5 +1,5 @@
1
- import { dirname, join } from "node:path";
2
1
  import { readdir, stat } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  //#region src/agent/memory/plugin-discovery.ts
5
5
  async function discoverMemoryPlugins() {
@@ -1,6 +1,6 @@
1
- import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
4
4
  import { getAllModels, getDefaultModelSync, init_providers, resolveModel } from "../../providers/index.js";
5
5
  import { resolveAgentTurnTimeoutMs, runAgentTurnWithTimeout } from "../orchestration/run-agent-turn-with-timeout.js";
6
6
  import { isAssistantTurnAborted, isAssistantTurnFailed, maybeRetryTurnAfterTransientLlmFailure } from "../orchestration/llm-turn-retry.js";
@@ -9,6 +9,7 @@ export interface MemorySearchOptions {
9
9
  minScore?: number;
10
10
  /** Absolute path to agent-scoped curated memories dir (MEMORY.md + USER.md). */
11
11
  memoriesDir?: string;
12
+ agentId?: string;
12
13
  }
13
14
  export declare function memorySearch(baseDir: string, query: string, options?: MemorySearchOptions): Promise<MemoryMatch[]>;
14
15
  export declare function memoryGet(baseDir: string, path: string, from?: number, lines?: number, memoriesDir?: string): {
@@ -1,93 +1,47 @@
1
1
  import { createLogger } from "../../../utils/logger/index.js";
2
2
  import { init_logger } from "../../../utils/logger.js";
3
- import { join, relative } from "path";
3
+ import { requireXopcDatabase } from "../../../storage/sqlite/connection.js";
4
+ import { resolveAgentIdFromMemoriesDir, searchMemoryIndex, syncMemoryIndex } from "../../../storage/sqlite/memory-index-repository.js";
5
+ import "../../../storage/sqlite/index.js";
6
+ import { join } from "path";
4
7
  import { existsSync, readFileSync } from "fs";
5
8
  //#region src/agent/prompt/memory/index.ts
6
9
  init_logger();
7
10
  const log = createLogger("MemorySearch");
8
11
  const CURATED_MEMORY_FILENAMES = new Set(["MEMORY.md", "USER.md"]);
9
- function getDailyMemoryPath(baseDir, date) {
10
- const d = date || /* @__PURE__ */ new Date();
11
- return join(baseDir, `memory`, `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}.md`);
12
- }
13
- function getLongTermMemoryPath(baseDir) {
14
- return join(baseDir, "MEMORY.md");
15
- }
16
- function getCuratedMemoryPaths(memoriesDir) {
17
- if (!memoriesDir) return [];
18
- return [join(memoriesDir, "MEMORY.md"), join(memoriesDir, "USER.md")].filter((p) => existsSync(p));
19
- }
20
- function getAllMemoryPaths(baseDir, memoriesDir) {
21
- const paths = [];
22
- paths.push(...getCuratedMemoryPaths(memoriesDir));
23
- const longTermPath = getLongTermMemoryPath(baseDir);
24
- if (existsSync(longTermPath)) paths.push(longTermPath);
25
- if (existsSync(join(baseDir, "memory"))) {
26
- const today = /* @__PURE__ */ new Date();
27
- for (let i = 0; i < 30; i++) {
28
- const date = new Date(today);
29
- date.setDate(date.getDate() - i);
30
- const path = getDailyMemoryPath(baseDir, date);
31
- if (existsSync(path)) paths.push(path);
32
- }
33
- }
34
- return paths;
35
- }
36
- function parseMemoryFile(path) {
37
- return {
38
- path,
39
- content: readFileSync(path, "utf-8"),
40
- modified: (existsSync(path) ? { mtime: /* @__PURE__ */ new Date() } : { mtime: /* @__PURE__ */ new Date() }).mtime
41
- };
42
- }
43
- function fuzzyMatch(query, text) {
44
- const queryLower = query.toLowerCase();
45
- const textLower = text.toLowerCase();
46
- if (textLower.includes(queryLower)) return 1;
47
- const queryWords = queryLower.split(/\s+/);
48
- const textWords = textLower.split(/\s+/);
49
- let matchedWords = 0;
50
- for (const qWord of queryWords) if (textWords.some((tWord) => tWord.includes(qWord) || qWord.includes(tWord))) matchedWords++;
51
- return matchedWords / queryWords.length;
52
- }
53
- function searchInContent(query, content, options = {}) {
54
- const { maxResults = 5, minScore = .3 } = options;
55
- const lines = content.split("\n");
56
- const matches = [];
57
- for (let i = 0; i < lines.length; i++) {
58
- const score = fuzzyMatch(query, lines[i]);
59
- if (score >= minScore) matches.push({
60
- line: lines[i],
61
- index: i,
62
- score
63
- });
64
- }
65
- matches.sort((a, b) => b.score - a.score);
66
- if (matches.length === 0) return null;
67
- const topMatches = matches.slice(0, maxResults);
68
- const lineNumbers = topMatches.map((m) => m.index + 1);
69
- return {
70
- file: "",
71
- lines: topMatches.map((m) => m.line).join("\n"),
72
- score: topMatches[0].score,
73
- lineNumbers
74
- };
12
+ function ensureMemoryDatabase() {
13
+ requireXopcDatabase();
75
14
  }
76
15
  async function memorySearch(baseDir, query, options = {}) {
77
- const { maxResults = 5, minScore = .3, memoriesDir } = options;
78
- const paths = getAllMemoryPaths(baseDir, memoriesDir);
79
- const results = [];
80
- for (const path of paths) try {
81
- const match = searchInContent(query, parseMemoryFile(path).content, options);
82
- if (match) {
83
- match.file = relative(baseDir, path);
84
- if (match.score >= minScore) results.push(match);
85
- }
86
- } catch {
87
- log.warn({ path }, "Could not read memory file");
16
+ const { maxResults = 5, minScore = .3, memoriesDir, agentId } = options;
17
+ const resolvedAgentId = agentId ?? resolveAgentIdFromMemoriesDir(memoriesDir);
18
+ try {
19
+ ensureMemoryDatabase();
20
+ syncMemoryIndex({
21
+ agentId: resolvedAgentId,
22
+ workspaceDir: baseDir,
23
+ memoriesDir
24
+ });
25
+ return searchMemoryIndex({
26
+ agentId: resolvedAgentId,
27
+ query,
28
+ maxResults,
29
+ minScore
30
+ }).map((hit) => ({
31
+ file: hit.path,
32
+ lines: hit.lines,
33
+ score: hit.score,
34
+ lineNumbers: hit.lineNumbers
35
+ }));
36
+ } catch (err) {
37
+ const em = err instanceof Error ? err.message : String(err);
38
+ log.warn({
39
+ err,
40
+ errorMessage: em,
41
+ agentId: resolvedAgentId
42
+ }, `Memory FTS search failed: ${em}`);
43
+ return [];
88
44
  }
89
- results.sort((a, b) => b.score - a.score);
90
- return results.slice(0, maxResults * 3);
91
45
  }
92
46
  function memoryGet(baseDir, path, from, lines, memoriesDir) {
93
47
  let fullPath = path.startsWith("/") ? path : join(baseDir, path);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/agent/prompt/memory/index.ts"],"sourcesContent":["// Memory Search - Semantic memory recall system\nimport { readFileSync, existsSync } from 'fs';\nimport { join, relative } from 'path';\n\nimport { createLogger } from '../../../utils/logger.js';\n\nconst log = createLogger('MemorySearch');\n\n// =============================================================================\n// Types (Internal)\n// =============================================================================\n\ninterface MemoryMatch {\n file: string;\n lines: string;\n score: number;\n lineNumbers: number[];\n}\n\nexport interface MemorySearchOptions {\n maxResults?: number;\n minScore?: number;\n /** Absolute path to agent-scoped curated memories dir (MEMORY.md + USER.md). */\n memoriesDir?: string;\n}\n\ninterface MemoryFile {\n path: string;\n content: string;\n modified: Date;\n}\n\nconst CURATED_MEMORY_FILENAMES = new Set(['MEMORY.md', 'USER.md']);\n\n// =============================================================================\n// Memory Path Utilities (Internal)\n// =============================================================================\n\nfunction getDailyMemoryPath(baseDir: string, date?: Date): string {\n const d = date || new Date();\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return join(baseDir, `memory`, `${year}-${month}-${day}.md`);\n}\n\nfunction getLongTermMemoryPath(baseDir: string): string {\n return join(baseDir, 'MEMORY.md');\n}\n\nfunction getCuratedMemoryPaths(memoriesDir: string | undefined): string[] {\n if (!memoriesDir) return [];\n const curated = [join(memoriesDir, 'MEMORY.md'), join(memoriesDir, 'USER.md')];\n return curated.filter((p) => existsSync(p));\n}\n\nfunction getAllMemoryPaths(baseDir: string, memoriesDir?: string): string[] {\n const paths: string[] = [];\n\n paths.push(...getCuratedMemoryPaths(memoriesDir));\n\n // Long-term memory (workspace root)\n const longTermPath = getLongTermMemoryPath(baseDir);\n if (existsSync(longTermPath)) {\n paths.push(longTermPath);\n }\n\n // Daily memories (last 30 days)\n const memoryDir = join(baseDir, 'memory');\n if (existsSync(memoryDir)) {\n const today = new Date();\n for (let i = 0; i < 30; i++) {\n const date = new Date(today);\n date.setDate(date.getDate() - i);\n const path = getDailyMemoryPath(baseDir, date);\n if (existsSync(path)) {\n paths.push(path);\n }\n }\n }\n\n return paths;\n}\n\n// =============================================================================\n// Content Parsing (Internal)\n// =============================================================================\n\nfunction parseMemoryFile(path: string): MemoryFile {\n const content = readFileSync(path, 'utf-8');\n const stats = existsSync(path) ? { mtime: new Date() } : { mtime: new Date() };\n\n return {\n path,\n content,\n modified: stats.mtime,\n };\n}\n\n// =============================================================================\n// Simple Fuzzy Search (Internal)\n// =============================================================================\n\nfunction fuzzyMatch(query: string, text: string): number {\n const queryLower = query.toLowerCase();\n const textLower = text.toLowerCase();\n\n // Exact match\n if (textLower.includes(queryLower)) {\n return 1.0;\n }\n\n // Word-by-word match\n const queryWords = queryLower.split(/\\s+/);\n const textWords = textLower.split(/\\s+/);\n\n let matchedWords = 0;\n for (const qWord of queryWords) {\n if (textWords.some((tWord) => tWord.includes(qWord) || qWord.includes(tWord))) {\n matchedWords++;\n }\n }\n\n return matchedWords / queryWords.length;\n}\n\nfunction searchInContent(query: string, content: string, options: MemorySearchOptions = {}): MemoryMatch | null {\n const { maxResults = 5, minScore = 0.3 } = options;\n\n const lines = content.split('\\n');\n const matches: Array<{ line: string; index: number; score: number }> = [];\n\n for (let i = 0; i < lines.length; i++) {\n const score = fuzzyMatch(query, lines[i]);\n if (score >= minScore) {\n matches.push({ line: lines[i], index: i, score });\n }\n }\n\n // Sort by score descending\n matches.sort((a, b) => b.score - a.score);\n\n if (matches.length === 0) {\n return null;\n }\n\n // Take top matches\n const topMatches = matches.slice(0, maxResults);\n const lineNumbers = topMatches.map((m) => m.index + 1);\n const linesContent = topMatches.map((m) => m.line).join('\\n');\n\n return {\n file: '', // Will be set by caller\n lines: linesContent,\n score: topMatches[0].score,\n lineNumbers,\n };\n}\n\n// =============================================================================\n// Main Search Function (Exported)\n// =============================================================================\n\nexport async function memorySearch(\n baseDir: string,\n query: string,\n options: MemorySearchOptions = {},\n): Promise<MemoryMatch[]> {\n const { maxResults = 5, minScore = 0.3, memoriesDir } = options;\n\n const paths = getAllMemoryPaths(baseDir, memoriesDir);\n const results: MemoryMatch[] = [];\n\n for (const path of paths) {\n try {\n const memoryFile = parseMemoryFile(path);\n const match = searchInContent(query, memoryFile.content, options);\n\n if (match) {\n match.file = relative(baseDir, path);\n if (match.score >= minScore) {\n results.push(match);\n }\n }\n } catch {\n log.warn({ path }, 'Could not read memory file');\n }\n }\n\n // Sort all results by score\n results.sort((a, b) => b.score - a.score);\n\n // Return top results per file or overall\n return results.slice(0, maxResults * 3); // Return more to allow grouping\n}\n\n// =============================================================================\n// Memory Get (Read Snippet) (Exported)\n// =============================================================================\n\nexport function memoryGet(\n baseDir: string,\n path: string,\n from?: number,\n lines?: number,\n memoriesDir?: string,\n): { content: string; lineNumbers: { start: number; end: number } } | null {\n let fullPath = path.startsWith('/') ? path : join(baseDir, path);\n\n if (!existsSync(fullPath) && memoriesDir) {\n const segments = path.split(/[/\\\\]/);\n const filename = segments.pop() ?? path;\n if (CURATED_MEMORY_FILENAMES.has(filename)) {\n const candidatePath = join(memoriesDir, filename);\n if (existsSync(candidatePath)) {\n fullPath = candidatePath;\n }\n }\n }\n\n if (!existsSync(fullPath)) {\n return null;\n }\n\n const content = readFileSync(fullPath, 'utf-8');\n const allLines = content.split('\\n');\n\n const start = from || 1;\n const count = lines || 10;\n const end = Math.min(start + count - 1, allLines.length);\n\n const snippet = allLines.slice(start - 1, end).join('\\n');\n\n return {\n content: snippet,\n lineNumbers: { start, end },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/agent/prompt/memory/index.ts"],"sourcesContent":["// Memory Search - FTS-backed recall with markdown file reads for snippets\nimport { readFileSync, existsSync } from 'fs';\nimport { join } from 'path';\n\nimport { createLogger } from '../../../utils/logger.js';\nimport {\n requireXopcDatabase,\n resolveAgentIdFromMemoriesDir,\n searchMemoryIndex,\n syncMemoryIndex,\n} from '../../../storage/sqlite/index.js';\n\nconst log = createLogger('MemorySearch');\n\n// =============================================================================\n// Types (Internal)\n// =============================================================================\n\ninterface MemoryMatch {\n file: string;\n lines: string;\n score: number;\n lineNumbers: number[];\n}\n\nexport interface MemorySearchOptions {\n maxResults?: number;\n minScore?: number;\n /** Absolute path to agent-scoped curated memories dir (MEMORY.md + USER.md). */\n memoriesDir?: string;\n agentId?: string;\n}\n\nconst CURATED_MEMORY_FILENAMES = new Set(['MEMORY.md', 'USER.md']);\n\nfunction ensureMemoryDatabase(): void {\n requireXopcDatabase();\n}\n\n// =============================================================================\n// Main Search Function (Exported)\n// =============================================================================\n\nexport async function memorySearch(\n baseDir: string,\n query: string,\n options: MemorySearchOptions = {},\n): Promise<MemoryMatch[]> {\n const { maxResults = 5, minScore = 0.3, memoriesDir, agentId } = options;\n const resolvedAgentId = agentId ?? resolveAgentIdFromMemoriesDir(memoriesDir);\n\n try {\n ensureMemoryDatabase();\n syncMemoryIndex({ agentId: resolvedAgentId, workspaceDir: baseDir, memoriesDir });\n const hits = searchMemoryIndex({\n agentId: resolvedAgentId,\n query,\n maxResults,\n minScore,\n });\n return hits.map((hit) => ({\n file: hit.path,\n lines: hit.lines,\n score: hit.score,\n lineNumbers: hit.lineNumbers,\n }));\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.warn({ err, errorMessage: em, agentId: resolvedAgentId }, `Memory FTS search failed: ${em}`);\n return [];\n }\n}\n\n// =============================================================================\n// Memory Get (Read Snippet) (Exported)\n// =============================================================================\n\nexport function memoryGet(\n baseDir: string,\n path: string,\n from?: number,\n lines?: number,\n memoriesDir?: string,\n): { content: string; lineNumbers: { start: number; end: number } } | null {\n let fullPath = path.startsWith('/') ? path : join(baseDir, path);\n\n if (!existsSync(fullPath) && memoriesDir) {\n const segments = path.split(/[/\\\\]/);\n const filename = segments.pop() ?? path;\n if (CURATED_MEMORY_FILENAMES.has(filename)) {\n const candidatePath = join(memoriesDir, filename);\n if (existsSync(candidatePath)) {\n fullPath = candidatePath;\n }\n }\n }\n\n if (!existsSync(fullPath)) {\n return null;\n }\n\n const content = readFileSync(fullPath, 'utf-8');\n const allLines = content.split('\\n');\n\n const start = from || 1;\n const count = lines || 10;\n const end = Math.min(start + count - 1, allLines.length);\n\n const snippet = allLines.slice(start - 1, end).join('\\n');\n\n return {\n content: snippet,\n lineNumbers: { start, end },\n };\n}\n"],"mappings":";;;;;;;;aAIwD;AAQxD,MAAM,MAAM,aAAa,eAAe;AAqBxC,MAAM,2BAA2B,IAAI,IAAI,CAAC,aAAa,UAAU,CAAC;AAElE,SAAS,uBAA6B;AACpC,sBAAqB;;AAOvB,eAAsB,aACpB,SACA,OACA,UAA+B,EAAE,EACT;CACxB,MAAM,EAAE,aAAa,GAAG,WAAW,IAAK,aAAa,YAAY;CACjE,MAAM,kBAAkB,WAAW,8BAA8B,YAAY;AAE7E,KAAI;AACF,wBAAsB;AACtB,kBAAgB;GAAE,SAAS;GAAiB,cAAc;GAAS;GAAa,CAAC;AAOjF,SANa,kBAAkB;GAC7B,SAAS;GACT;GACA;GACA;GACD,CACU,CAAC,KAAK,SAAS;GACxB,MAAM,IAAI;GACV,OAAO,IAAI;GACX,OAAO,IAAI;GACX,aAAa,IAAI;GAClB,EAAE;UACI,KAAK;EACZ,MAAM,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC3D,MAAI,KAAK;GAAE;GAAK,cAAc;GAAI,SAAS;GAAiB,EAAE,6BAA6B,KAAK;AAChG,SAAO,EAAE;;;AAQb,SAAgB,UACd,SACA,MACA,MACA,OACA,aACyE;CACzE,IAAI,WAAW,KAAK,WAAW,IAAI,GAAG,OAAO,KAAK,SAAS,KAAK;AAEhE,KAAI,CAAC,WAAW,SAAS,IAAI,aAAa;EAExC,MAAM,WADW,KAAK,MAAM,QACH,CAAC,KAAK,IAAI;AACnC,MAAI,yBAAyB,IAAI,SAAS,EAAE;GAC1C,MAAM,gBAAgB,KAAK,aAAa,SAAS;AACjD,OAAI,WAAW,cAAc,CAC3B,YAAW;;;AAKjB,KAAI,CAAC,WAAW,SAAS,CACvB,QAAO;CAIT,MAAM,WADU,aAAa,UAAU,QACf,CAAC,MAAM,KAAK;CAEpC,MAAM,QAAQ,QAAQ;CAEtB,MAAM,MAAM,KAAK,IAAI,SADP,SAAS,MACc,GAAG,SAAS,OAAO;AAIxD,QAAO;EACL,SAHc,SAAS,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,KAGlC;EAChB,aAAa;GAAE;GAAO;GAAK;EAC5B"}
@@ -1,6 +1,6 @@
1
- import { resolveStateDir } from "../../config/paths-state.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { resolveStateDir } from "../../config/paths-state.js";
4
4
  import { init_paths } from "../../config/paths.js";
5
5
  import { DEFAULT_USER_FILENAME } from "../context/workspace.js";
6
6
  import { createSkillConfigManager } from "../skills/config.js";
@@ -8,8 +8,8 @@ import { buildTtsSystemPromptHint } from "../../voice/tts/directives.js";
8
8
  import { mergeTtsConfigFromAppConfig } from "../../voice/tts/merge-config.js";
9
9
  import { selectSkillsVisibleInPrompt } from "../skills/format-skills-prompt.js";
10
10
  import { buildSystemPrompt } from "./system-prompt.js";
11
- import { join } from "node:path";
12
11
  import { existsSync, readFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
13
  //#region src/agent/prompt/service-prompt-builder.ts
14
14
  /**
15
15
  * System Prompt Builder - Builds the complete system prompt
@@ -7,7 +7,6 @@ const CONTEXT_FILE_ORDER = new Map([
7
7
  ["identity.md", 30],
8
8
  ["user.md", 40],
9
9
  ["tools.md", 50],
10
- ["bootstrap.md", 60],
11
10
  ["memory.md", 70]
12
11
  ]);
13
12
  const DYNAMIC_CONTEXT_FILE_BASENAMES = new Set(["heartbeat.md"]);
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.js","names":[],"sources":["../../../../src/agent/prompt/system-prompt.ts"],"sourcesContent":["/**\n * System Prompt Builder — xopc-owned prompt with OpenClaw-style bootstrap injection.\n *\n * Profile Markdown under `agents/<id>/profile/` is injected as Project Context\n * (see `src/agent/bootstrap/`). Runtime owns loading; AGENTS.md instructs agents\n * not to manually reread startup files.\n */\n\nimport type { EmbeddedContextFile } from '../bootstrap/types.js';\nimport { DEFAULT_HEARTBEAT_FILENAME } from '../context/workspace.js';\nimport { PROMPT_CACHE_BOUNDARY } from './cache-boundary.js';\nimport type { PromptMode } from './types.js';\n\nexport type MemoryCitationsMode = 'on' | 'off' | 'source-only';\n\nconst CONTEXT_FILE_ORDER = new Map<string, number>([\n ['agents.md', 10],\n ['soul.md', 20],\n ['identity.md', 30],\n ['user.md', 40],\n ['tools.md', 50],\n ['bootstrap.md', 60],\n ['memory.md', 70],\n]);\n\nconst DYNAMIC_CONTEXT_FILE_BASENAMES = new Set(['heartbeat.md']);\n\nconst DEFAULT_HEARTBEAT_PROMPT_CONTEXT_BLOCK =\n 'Default heartbeat prompt:\\n`Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.`';\n\nfunction normalizeContextFilePath(pathValue: string): string {\n return pathValue.trim().replace(/\\\\/g, '/');\n}\n\nfunction getContextFileBasename(pathValue: string): string {\n const normalizedPath = normalizeContextFilePath(pathValue);\n return (normalizedPath.split('/').pop() ?? normalizedPath).toLowerCase();\n}\n\nfunction isDynamicContextFile(pathValue: string): boolean {\n return DYNAMIC_CONTEXT_FILE_BASENAMES.has(getContextFileBasename(pathValue));\n}\n\nfunction sanitizeContextFileContentForPrompt(content: string): string {\n return content.replaceAll(DEFAULT_HEARTBEAT_PROMPT_CONTEXT_BLOCK, '').replace(/\\n{3,}/g, '\\n\\n');\n}\n\nfunction sortContextFilesForPrompt(contextFiles: EmbeddedContextFile[]): EmbeddedContextFile[] {\n return [...contextFiles].sort((a, b) => {\n const aBase = getContextFileBasename(a.path);\n const bBase = getContextFileBasename(b.path);\n const aOrder = CONTEXT_FILE_ORDER.get(aBase) ?? Number.MAX_SAFE_INTEGER;\n const bOrder = CONTEXT_FILE_ORDER.get(bBase) ?? Number.MAX_SAFE_INTEGER;\n if (aOrder !== bOrder) {\n return aOrder - bOrder;\n }\n if (aBase !== bBase) {\n return aBase.localeCompare(bBase);\n }\n return normalizeContextFilePath(a.path).localeCompare(normalizeContextFilePath(b.path));\n });\n}\n\nfunction buildProjectContextSection(params: {\n files: EmbeddedContextFile[];\n heading: string;\n dynamic: boolean;\n}): string[] {\n if (params.files.length === 0) {\n return [];\n }\n const lines: string[] = [params.heading, ''];\n if (params.dynamic) {\n lines.push(\n 'The following frequently-changing project context files are kept below the cache boundary when possible:',\n '',\n );\n } else {\n const hasSoulFile = params.files.some((file) => getContextFileBasename(file.path) === 'soul.md');\n lines.push('The following project context files have been loaded:');\n if (hasSoulFile) {\n lines.push(\n 'If SOUL.md is present, embody its persona and tone. Avoid stiff, generic replies; follow its guidance unless higher-priority instructions override it.',\n );\n }\n lines.push('');\n }\n for (const file of params.files) {\n lines.push(`## ${file.path}`, '', sanitizeContextFileContentForPrompt(file.content), '');\n }\n return lines;\n}\n\nfunction buildMemorySection(\n citationsMode: MemoryCitationsMode = 'on',\n hasProfileMemory = false,\n): string {\n if (!hasProfileMemory) {\n return '';\n }\n\n const citationInstruction =\n citationsMode === 'off'\n ? 'Citations are disabled: do not mention file paths or line numbers in replies.'\n : citationsMode === 'source-only'\n ? 'Citations: mention file path when it helps (e.g., Source: MEMORY.md).'\n : 'Citations: include Source: <path#line> when it helps the user verify memory snippets.';\n\n return `## Memory Recall\n\n${citationInstruction}\n\nStartup profile files (SOUL, USER, MEMORY, etc.) are already in Project Context above. Do not re-read them unless the user asks or you need lines beyond what was injected.\n\nBefore answering anything about prior work, decisions, dates, people, preferences, or todos:\n1. Run \\`memory_search\\` on profile MEMORY.md and workspace \\`memory/*.md\\`\n2. For **other chat sessions** / cross-session history, use \\`session_search\\` with keywords (or omit \\`query\\` to list recent sessions)\n3. Use \\`memory_get\\` to pull only the needed lines from files\n4. For structured curated notes under agent home \\`memories/\\`, use \\`curated_memory\\`\n5. If low confidence after search, say you checked\n\n### Memory Files\n\n- **Daily notes:** \\`memory/YYYY-MM-DD.md\\` — raw logs (runtime may preload recent days on /new or /reset)\n- **Long-term:** profile \\`MEMORY.md\\` — curated memories in Project Context when present\n- **Curated store:** agent home \\`memories/MEMORY.md\\` and \\`memories/USER.md\\` — use \\`curated_memory\\` for live read/write\n\n### Writing to Memory\n\n- **Declarative vs procedural:** Save facts and preferences via workspace memory files and/or \\`curated_memory\\`. Save reusable task playbooks with \\`skill_manage\\` as skills.\n- **Memory is limited** — if you want to remember something, WRITE IT TO A FILE\n- When someone says \"remember this\" → update \\`memory/YYYY-MM-DD.md\\` or relevant file\n- **Text > Brain**\n`;\n}\n\nfunction buildSkillsSection(availableTools: string[] = []): string {\n if (availableTools.length === 0) {\n return '';\n }\n\n return `## Skills\n\nWhen a solution already exists, do not reinvent the wheel.\n\n**How to use:**\n1. Skim <available_skills> — is anything clearly relevant?\n2. Only one match? → Confirm with skills_list, then load the full text with skill_view(name) and follow it.\n3. Need sub-documents or scripts? → skill_view(name, \"references/…\"), etc.\n4. No match? → Solve it yourself; do not force-fit a skill.\n\n**Division of labor with memory:** Skills = **procedural** workflows; memory / \\`curated_memory\\` = **declarative** facts and preferences.\n`;\n}\n\nfunction buildSafetySection(): string {\n return `## Safety\n\n- You have no independent goals: do not pursue self-preservation, replication, resource acquisition, or power-seeking; avoid long-term plans beyond the user's request.\n- Prioritize safety and human oversight over completion; if instructions conflict, pause and ask; comply with stop/pause/audit requests and never bypass safeguards.\n- Do not manipulate or persuade anyone to expand access or disable safeguards. Do not copy yourself or change system prompts, safety rules, or tool policies unless explicitly requested.`;\n}\n\nfunction buildProblemSolvingSection(): string {\n return `## Problem Solving\n\n**Simple tasks** (< 5 minutes or a single-file change): Do them directly; run a quick verification after changes.\n\n**Complex tasks** (multiple files or design decisions): Use an iterative flow — Plan → Build → Verify → Fix.\n\n**Core principle: Match the complexity; reject ritual for its own sake. Verification matters, but do not verify just to tick a box.**`;\n}\n\nfunction buildAestheticSection(): string {\n return `## Tone & Style\n\n**Default voice:** Direct, concise, concrete.\n\n**SOUL.md takes precedence:** If SOUL.md defines a specific tone, defer to it over the above.`;\n}\n\nfunction buildHeartbeatBehaviorSection(params: {\n enabled: boolean;\n customPrompt?: string;\n userTimezone?: string;\n}): string {\n if (!params.enabled) {\n return '';\n }\n if (params.customPrompt?.trim()) {\n return `## Heartbeats\\n\\n${params.customPrompt.trim()}\\n`;\n }\n let quietHoursNote = '';\n if (params.userTimezone) {\n quietHoursNote = `\\n\\n> Quiet hours: The user is in **${params.userTimezone}**. Avoid proactive checks during late night (23:00-08:00) unless urgent.`;\n }\n return `## Heartbeats\n\nIf the current user message is a heartbeat poll and nothing needs attention, reply exactly: HEARTBEAT_OK\n\nIf something needs attention, do NOT include \"HEARTBEAT_OK\"; reply with the alert text instead.${quietHoursNote}\n`;\n}\n\nfunction buildMessagingSection(channels: string[] = [], isMinimal: boolean = false): string {\n if (isMinimal || channels.length === 0) {\n return '';\n }\n const channelList = channels.join(', ');\n return `## Messaging\n\n- Reply in current session → automatically routes to the source channel (${channelList})\n- Use \\`message\\` for proactive sends + channel actions\n- If you use \\`message\\` to deliver your user-visible reply, respond with ONLY: NO_REPLY (avoid duplicate replies)\n`;\n}\n\nfunction buildTimeSection(timezone?: string): string {\n if (!timezone) {\n return '';\n }\n return `## Current Date & Time\n\nTime zone: ${timezone}\n\nIf you need the current date/time/day-of-week, use the \\`session_status\\` tool or the inbound message timestamp envelope (when present).\n`;\n}\n\nfunction buildRuntimeSection(runtime?: { version?: string; model?: string; channel?: string }): string {\n if (!runtime) {\n return '';\n }\n const parts: string[] = [];\n if (runtime.version) parts.push(`v${runtime.version}`);\n if (runtime.model) parts.push(`model=${runtime.model.split('/').pop()}`);\n if (runtime.channel) parts.push(`ch=${runtime.channel}`);\n return parts.length > 0 ? `[${parts.join(' | ')}]` : '';\n}\n\nfunction buildWorkingDirSection(workspaceDir: string): string {\n return `Working directory: ${workspaceDir}`;\n}\n\nfunction buildExternalMemorySection(text: string | undefined): string {\n const t = text?.trim();\n if (!t) {\n return '';\n }\n return `## External memory provider\\n\\n${t}`;\n}\n\nexport interface SystemPromptOptions {\n /** Bootstrap context files from profile Markdown (Project Context). */\n contextFiles?: EmbeddedContextFile[];\n promptMode?: PromptMode;\n heartbeatEnabled?: boolean;\n heartbeatPrompt?: string;\n availableTools?: string[];\n memoryCitationsMode?: MemoryCitationsMode;\n userTimezone?: string;\n runtime?: {\n version?: string;\n model?: string;\n channel?: string;\n };\n channels?: string[];\n externalMemoryInstructions?: string;\n ttsSystemHint?: string;\n}\n\n/**\n * Build system prompt with bootstrap Project Context integration.\n */\nexport function buildSystemPrompt(workspaceDir: string, options: SystemPromptOptions): string {\n const {\n contextFiles = [],\n promptMode = 'full',\n heartbeatEnabled = false,\n heartbeatPrompt,\n availableTools = [],\n memoryCitationsMode = 'on',\n userTimezone,\n runtime,\n channels = [],\n externalMemoryInstructions,\n ttsSystemHint,\n } = options;\n\n if (promptMode === 'none') {\n return 'You are a personal AI assistant running inside xopc.';\n }\n\n const isMinimal = promptMode === 'minimal';\n const orderedContextFiles = sortContextFilesForPrompt(\n contextFiles.filter((file) => file.path.trim().length > 0),\n );\n const stableContextFiles = orderedContextFiles.filter((file) => !isDynamicContextFile(file.path));\n const dynamicContextFiles = orderedContextFiles.filter((file) => isDynamicContextFile(file.path));\n const hasProfileMemory = orderedContextFiles.some(\n (file) => getContextFileBasename(file.path) === 'memory.md',\n );\n\n const sections: string[] = [\n 'You are a personal AI assistant running inside xopc.',\n '',\n '## Workspace Files (injected)',\n '',\n 'Profile bootstrap files are injected below as Project Context. Do not manually reread them at session start unless the user asks or injected content is insufficient.',\n '',\n ];\n\n if (!isMinimal) {\n sections.push(buildTimeSection(userTimezone));\n sections.push(buildExternalMemorySection(externalMemoryInstructions));\n sections.push(buildMemorySection(memoryCitationsMode, hasProfileMemory));\n }\n\n sections.push(buildSkillsSection(availableTools));\n\n if (!isMinimal) {\n sections.push(buildSafetySection());\n sections.push(buildProblemSolvingSection());\n sections.push(buildAestheticSection());\n }\n\n sections.push(\n ...buildProjectContextSection({\n files: stableContextFiles,\n heading: '# Project Context',\n dynamic: false,\n }),\n );\n\n sections.push(PROMPT_CACHE_BOUNDARY);\n\n sections.push(\n ...buildProjectContextSection({\n files: dynamicContextFiles,\n heading: stableContextFiles.length > 0 ? '# Dynamic Project Context' : '# Project Context',\n dynamic: true,\n }),\n );\n\n sections.push(buildHeartbeatBehaviorSection({ enabled: heartbeatEnabled, customPrompt: heartbeatPrompt, userTimezone }));\n sections.push(buildWorkingDirSection(workspaceDir));\n sections.push(buildMessagingSection(channels, isMinimal));\n\n if (!isMinimal && ttsSystemHint?.trim()) {\n sections.push(`## Voice (TTS)\\n\\n${ttsSystemHint.trim()}`);\n }\n\n sections.push(buildRuntimeSection(runtime));\n\n return sections.filter(Boolean).join('\\n\\n');\n}\n\n/** Whether HEARTBEAT.md is injected as dynamic context (vs behavior-only section). */\nexport function isHeartbeatContextFile(pathValue: string): boolean {\n return getContextFileBasename(pathValue) === DEFAULT_HEARTBEAT_FILENAME.toLowerCase();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"system-prompt.js","names":[],"sources":["../../../../src/agent/prompt/system-prompt.ts"],"sourcesContent":["/**\n * System Prompt Builder — xopc-owned prompt with OpenClaw-style bootstrap injection.\n *\n * Profile Markdown under `agents/<id>/profile/` is injected as Project Context\n * (see `src/agent/bootstrap/`). Runtime owns loading; AGENTS.md instructs agents\n * not to manually reread startup files.\n */\n\nimport type { EmbeddedContextFile } from '../bootstrap/types.js';\nimport { DEFAULT_HEARTBEAT_FILENAME } from '../context/workspace.js';\nimport { PROMPT_CACHE_BOUNDARY } from './cache-boundary.js';\nimport type { PromptMode } from './types.js';\n\nexport type MemoryCitationsMode = 'on' | 'off' | 'source-only';\n\nconst CONTEXT_FILE_ORDER = new Map<string, number>([\n ['agents.md', 10],\n ['soul.md', 20],\n ['identity.md', 30],\n ['user.md', 40],\n ['tools.md', 50],\n ['memory.md', 70],\n]);\n\nconst DYNAMIC_CONTEXT_FILE_BASENAMES = new Set(['heartbeat.md']);\n\nconst DEFAULT_HEARTBEAT_PROMPT_CONTEXT_BLOCK =\n 'Default heartbeat prompt:\\n`Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.`';\n\nfunction normalizeContextFilePath(pathValue: string): string {\n return pathValue.trim().replace(/\\\\/g, '/');\n}\n\nfunction getContextFileBasename(pathValue: string): string {\n const normalizedPath = normalizeContextFilePath(pathValue);\n return (normalizedPath.split('/').pop() ?? normalizedPath).toLowerCase();\n}\n\nfunction isDynamicContextFile(pathValue: string): boolean {\n return DYNAMIC_CONTEXT_FILE_BASENAMES.has(getContextFileBasename(pathValue));\n}\n\nfunction sanitizeContextFileContentForPrompt(content: string): string {\n return content.replaceAll(DEFAULT_HEARTBEAT_PROMPT_CONTEXT_BLOCK, '').replace(/\\n{3,}/g, '\\n\\n');\n}\n\nfunction sortContextFilesForPrompt(contextFiles: EmbeddedContextFile[]): EmbeddedContextFile[] {\n return [...contextFiles].sort((a, b) => {\n const aBase = getContextFileBasename(a.path);\n const bBase = getContextFileBasename(b.path);\n const aOrder = CONTEXT_FILE_ORDER.get(aBase) ?? Number.MAX_SAFE_INTEGER;\n const bOrder = CONTEXT_FILE_ORDER.get(bBase) ?? Number.MAX_SAFE_INTEGER;\n if (aOrder !== bOrder) {\n return aOrder - bOrder;\n }\n if (aBase !== bBase) {\n return aBase.localeCompare(bBase);\n }\n return normalizeContextFilePath(a.path).localeCompare(normalizeContextFilePath(b.path));\n });\n}\n\nfunction buildProjectContextSection(params: {\n files: EmbeddedContextFile[];\n heading: string;\n dynamic: boolean;\n}): string[] {\n if (params.files.length === 0) {\n return [];\n }\n const lines: string[] = [params.heading, ''];\n if (params.dynamic) {\n lines.push(\n 'The following frequently-changing project context files are kept below the cache boundary when possible:',\n '',\n );\n } else {\n const hasSoulFile = params.files.some((file) => getContextFileBasename(file.path) === 'soul.md');\n lines.push('The following project context files have been loaded:');\n if (hasSoulFile) {\n lines.push(\n 'If SOUL.md is present, embody its persona and tone. Avoid stiff, generic replies; follow its guidance unless higher-priority instructions override it.',\n );\n }\n lines.push('');\n }\n for (const file of params.files) {\n lines.push(`## ${file.path}`, '', sanitizeContextFileContentForPrompt(file.content), '');\n }\n return lines;\n}\n\nfunction buildMemorySection(\n citationsMode: MemoryCitationsMode = 'on',\n hasProfileMemory = false,\n): string {\n if (!hasProfileMemory) {\n return '';\n }\n\n const citationInstruction =\n citationsMode === 'off'\n ? 'Citations are disabled: do not mention file paths or line numbers in replies.'\n : citationsMode === 'source-only'\n ? 'Citations: mention file path when it helps (e.g., Source: MEMORY.md).'\n : 'Citations: include Source: <path#line> when it helps the user verify memory snippets.';\n\n return `## Memory Recall\n\n${citationInstruction}\n\nStartup profile files (SOUL, USER, MEMORY, etc.) are already in Project Context above. Do not re-read them unless the user asks or you need lines beyond what was injected.\n\nBefore answering anything about prior work, decisions, dates, people, preferences, or todos:\n1. Run \\`memory_search\\` on profile MEMORY.md and workspace \\`memory/*.md\\`\n2. For **other chat sessions** / cross-session history, use \\`session_search\\` with keywords (or omit \\`query\\` to list recent sessions)\n3. Use \\`memory_get\\` to pull only the needed lines from files\n4. For structured curated notes under agent home \\`memories/\\`, use \\`curated_memory\\`\n5. If low confidence after search, say you checked\n\n### Memory Files\n\n- **Daily notes:** \\`memory/YYYY-MM-DD.md\\` — raw logs (runtime may preload recent days on /new or /reset)\n- **Long-term:** profile \\`MEMORY.md\\` — curated memories in Project Context when present\n- **Curated store:** agent home \\`memories/MEMORY.md\\` and \\`memories/USER.md\\` — use \\`curated_memory\\` for live read/write\n\n### Writing to Memory\n\n- **Declarative vs procedural:** Save facts and preferences via workspace memory files and/or \\`curated_memory\\`. Save reusable task playbooks with \\`skill_manage\\` as skills.\n- **Memory is limited** — if you want to remember something, WRITE IT TO A FILE\n- When someone says \"remember this\" → update \\`memory/YYYY-MM-DD.md\\` or relevant file\n- **Text > Brain**\n`;\n}\n\nfunction buildSkillsSection(availableTools: string[] = []): string {\n if (availableTools.length === 0) {\n return '';\n }\n\n return `## Skills\n\nWhen a solution already exists, do not reinvent the wheel.\n\n**How to use:**\n1. Skim <available_skills> — is anything clearly relevant?\n2. Only one match? → Confirm with skills_list, then load the full text with skill_view(name) and follow it.\n3. Need sub-documents or scripts? → skill_view(name, \"references/…\"), etc.\n4. No match? → Solve it yourself; do not force-fit a skill.\n\n**Division of labor with memory:** Skills = **procedural** workflows; memory / \\`curated_memory\\` = **declarative** facts and preferences.\n`;\n}\n\nfunction buildSafetySection(): string {\n return `## Safety\n\n- You have no independent goals: do not pursue self-preservation, replication, resource acquisition, or power-seeking; avoid long-term plans beyond the user's request.\n- Prioritize safety and human oversight over completion; if instructions conflict, pause and ask; comply with stop/pause/audit requests and never bypass safeguards.\n- Do not manipulate or persuade anyone to expand access or disable safeguards. Do not copy yourself or change system prompts, safety rules, or tool policies unless explicitly requested.`;\n}\n\nfunction buildProblemSolvingSection(): string {\n return `## Problem Solving\n\n**Simple tasks** (< 5 minutes or a single-file change): Do them directly; run a quick verification after changes.\n\n**Complex tasks** (multiple files or design decisions): Use an iterative flow — Plan → Build → Verify → Fix.\n\n**Core principle: Match the complexity; reject ritual for its own sake. Verification matters, but do not verify just to tick a box.**`;\n}\n\nfunction buildAestheticSection(): string {\n return `## Tone & Style\n\n**Default voice:** Direct, concise, concrete.\n\n**SOUL.md takes precedence:** If SOUL.md defines a specific tone, defer to it over the above.`;\n}\n\nfunction buildHeartbeatBehaviorSection(params: {\n enabled: boolean;\n customPrompt?: string;\n userTimezone?: string;\n}): string {\n if (!params.enabled) {\n return '';\n }\n if (params.customPrompt?.trim()) {\n return `## Heartbeats\\n\\n${params.customPrompt.trim()}\\n`;\n }\n let quietHoursNote = '';\n if (params.userTimezone) {\n quietHoursNote = `\\n\\n> Quiet hours: The user is in **${params.userTimezone}**. Avoid proactive checks during late night (23:00-08:00) unless urgent.`;\n }\n return `## Heartbeats\n\nIf the current user message is a heartbeat poll and nothing needs attention, reply exactly: HEARTBEAT_OK\n\nIf something needs attention, do NOT include \"HEARTBEAT_OK\"; reply with the alert text instead.${quietHoursNote}\n`;\n}\n\nfunction buildMessagingSection(channels: string[] = [], isMinimal: boolean = false): string {\n if (isMinimal || channels.length === 0) {\n return '';\n }\n const channelList = channels.join(', ');\n return `## Messaging\n\n- Reply in current session → automatically routes to the source channel (${channelList})\n- Use \\`message\\` for proactive sends + channel actions\n- If you use \\`message\\` to deliver your user-visible reply, respond with ONLY: NO_REPLY (avoid duplicate replies)\n`;\n}\n\nfunction buildTimeSection(timezone?: string): string {\n if (!timezone) {\n return '';\n }\n return `## Current Date & Time\n\nTime zone: ${timezone}\n\nIf you need the current date/time/day-of-week, use the \\`session_status\\` tool or the inbound message timestamp envelope (when present).\n`;\n}\n\nfunction buildRuntimeSection(runtime?: { version?: string; model?: string; channel?: string }): string {\n if (!runtime) {\n return '';\n }\n const parts: string[] = [];\n if (runtime.version) parts.push(`v${runtime.version}`);\n if (runtime.model) parts.push(`model=${runtime.model.split('/').pop()}`);\n if (runtime.channel) parts.push(`ch=${runtime.channel}`);\n return parts.length > 0 ? `[${parts.join(' | ')}]` : '';\n}\n\nfunction buildWorkingDirSection(workspaceDir: string): string {\n return `Working directory: ${workspaceDir}`;\n}\n\nfunction buildExternalMemorySection(text: string | undefined): string {\n const t = text?.trim();\n if (!t) {\n return '';\n }\n return `## External memory provider\\n\\n${t}`;\n}\n\nexport interface SystemPromptOptions {\n /** Bootstrap context files from profile Markdown (Project Context). */\n contextFiles?: EmbeddedContextFile[];\n promptMode?: PromptMode;\n heartbeatEnabled?: boolean;\n heartbeatPrompt?: string;\n availableTools?: string[];\n memoryCitationsMode?: MemoryCitationsMode;\n userTimezone?: string;\n runtime?: {\n version?: string;\n model?: string;\n channel?: string;\n };\n channels?: string[];\n externalMemoryInstructions?: string;\n ttsSystemHint?: string;\n}\n\n/**\n * Build system prompt with bootstrap Project Context integration.\n */\nexport function buildSystemPrompt(workspaceDir: string, options: SystemPromptOptions): string {\n const {\n contextFiles = [],\n promptMode = 'full',\n heartbeatEnabled = false,\n heartbeatPrompt,\n availableTools = [],\n memoryCitationsMode = 'on',\n userTimezone,\n runtime,\n channels = [],\n externalMemoryInstructions,\n ttsSystemHint,\n } = options;\n\n if (promptMode === 'none') {\n return 'You are a personal AI assistant running inside xopc.';\n }\n\n const isMinimal = promptMode === 'minimal';\n const orderedContextFiles = sortContextFilesForPrompt(\n contextFiles.filter((file) => file.path.trim().length > 0),\n );\n const stableContextFiles = orderedContextFiles.filter((file) => !isDynamicContextFile(file.path));\n const dynamicContextFiles = orderedContextFiles.filter((file) => isDynamicContextFile(file.path));\n const hasProfileMemory = orderedContextFiles.some(\n (file) => getContextFileBasename(file.path) === 'memory.md',\n );\n\n const sections: string[] = [\n 'You are a personal AI assistant running inside xopc.',\n '',\n '## Workspace Files (injected)',\n '',\n 'Profile bootstrap files are injected below as Project Context. Do not manually reread them at session start unless the user asks or injected content is insufficient.',\n '',\n ];\n\n if (!isMinimal) {\n sections.push(buildTimeSection(userTimezone));\n sections.push(buildExternalMemorySection(externalMemoryInstructions));\n sections.push(buildMemorySection(memoryCitationsMode, hasProfileMemory));\n }\n\n sections.push(buildSkillsSection(availableTools));\n\n if (!isMinimal) {\n sections.push(buildSafetySection());\n sections.push(buildProblemSolvingSection());\n sections.push(buildAestheticSection());\n }\n\n sections.push(\n ...buildProjectContextSection({\n files: stableContextFiles,\n heading: '# Project Context',\n dynamic: false,\n }),\n );\n\n sections.push(PROMPT_CACHE_BOUNDARY);\n\n sections.push(\n ...buildProjectContextSection({\n files: dynamicContextFiles,\n heading: stableContextFiles.length > 0 ? '# Dynamic Project Context' : '# Project Context',\n dynamic: true,\n }),\n );\n\n sections.push(buildHeartbeatBehaviorSection({ enabled: heartbeatEnabled, customPrompt: heartbeatPrompt, userTimezone }));\n sections.push(buildWorkingDirSection(workspaceDir));\n sections.push(buildMessagingSection(channels, isMinimal));\n\n if (!isMinimal && ttsSystemHint?.trim()) {\n sections.push(`## Voice (TTS)\\n\\n${ttsSystemHint.trim()}`);\n }\n\n sections.push(buildRuntimeSection(runtime));\n\n return sections.filter(Boolean).join('\\n\\n');\n}\n\n/** Whether HEARTBEAT.md is injected as dynamic context (vs behavior-only section). */\nexport function isHeartbeatContextFile(pathValue: string): boolean {\n return getContextFileBasename(pathValue) === DEFAULT_HEARTBEAT_FILENAME.toLowerCase();\n}\n"],"mappings":"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"}