@xopcai/xopc 0.0.124 → 0.0.126

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 (496) hide show
  1. package/README.md +56 -102
  2. package/README.zh-CN.md +51 -98
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/feishu/src/schema/config-schema.d.ts +6 -6
  5. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  6. package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
  7. package/dist/extensions/telegram/src/config-schema.d.ts +8 -8
  8. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  9. package/dist/extensions/telegram/src/plugin.js +1 -1
  10. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  11. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  12. package/dist/extensions/telegram/xopc.extension.json +1 -1
  13. package/dist/extensions/weixin/src/api/api.js +1 -1
  14. package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
  15. package/dist/extensions/weixin/src/plugin.js +1 -1
  16. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  17. package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +41 -0
  18. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B5uSVAyJ.js → agent-avatar-dicebear-C70vgt60.js} +1 -1
  19. package/dist/gateway/static/root/assets/agents-DRYVahI-.js +2 -0
  20. package/dist/gateway/static/root/assets/app-management-settings-panel-D9-HW6cy.js +1 -0
  21. package/dist/gateway/static/root/assets/appearance-settings-BHlahIDL.js +1 -0
  22. package/dist/gateway/static/root/assets/apps-page-BdJ1eQg3.js +1 -0
  23. package/dist/gateway/static/root/assets/{archive-plugin-CXUGRp2i.js → archive-plugin-B-aoIt0w.js} +1 -1
  24. package/dist/gateway/static/root/assets/{attachment-load-Cmiub3Wg.js → attachment-load-BD0G0FD5.js} +1 -1
  25. package/dist/gateway/static/root/assets/automation-suggestion-card-iJRVI7aZ.js +1 -0
  26. package/dist/gateway/static/root/assets/automations-page-D8hYQbkl.js +4 -0
  27. package/dist/gateway/static/root/assets/{binary-plugins-0Izz-N3p.js → binary-plugins-B0mNlVSz.js} +1 -1
  28. package/dist/gateway/static/root/assets/{block-editor-C1Kv0IkJ.js → block-editor-CJY9Lu5G.js} +3 -3
  29. package/dist/gateway/static/root/assets/browser-settings-page-CiWEO-Iy.js +8 -0
  30. package/dist/gateway/static/root/assets/capability-presets-api-Bgc8ag55.js +1 -0
  31. package/dist/gateway/static/root/assets/capability-presets-settings-panel-B1nIi0TC.js +1 -0
  32. package/dist/gateway/static/root/assets/{channel-recipient-api-BeA2aVor.js → channel-recipient-api-0sauApoC.js} +1 -1
  33. package/dist/gateway/static/root/assets/channels-settings-BddPdqVo.js +1 -0
  34. package/dist/gateway/static/root/assets/code-editor-gbRgS14t.js +1 -0
  35. package/dist/gateway/static/root/assets/connectors-page-Ba2GDhSE.js +2 -0
  36. package/dist/gateway/static/root/assets/{directory-picker-path-field-2rjzUu57.js → directory-picker-path-field-CiEc4KmY.js} +1 -1
  37. package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
  38. package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
  39. package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
  40. package/dist/gateway/static/root/assets/dreaming-settings-4bvpk5wr.js +3 -0
  41. package/dist/gateway/static/root/assets/extension-debug-page-BbyczVZ3.js +1 -0
  42. package/dist/gateway/static/root/assets/extension-page-DLN1I3DR.js +1 -0
  43. package/dist/gateway/static/root/assets/extension-settings-page-D9VGHmYJ.js +1 -0
  44. package/dist/gateway/static/root/assets/{fetch-BU5S0Sn7.js → fetch-5V96dUz3.js} +1 -1
  45. package/dist/gateway/static/root/assets/{gateway-config-api-BIPGwrl1.js → gateway-config-api-BtIzObwp.js} +1 -1
  46. package/dist/gateway/static/root/assets/gateway-settings-KFsGGDhg.js +1 -0
  47. package/dist/gateway/static/root/assets/{gateway-startup-retry-Cd0Zz30N.js → gateway-startup-retry-DEMad2wt.js} +1 -1
  48. package/dist/gateway/static/root/assets/goal-create-dialog-4PcF6Sh6.js +1 -0
  49. package/dist/gateway/static/root/assets/goal-detail-page-B482PSaG.js +1 -0
  50. package/dist/gateway/static/root/assets/{goals-config-api-B95KdGMj.js → goals-config-api-CVN7-pdM.js} +1 -1
  51. package/dist/gateway/static/root/assets/goals-page-CUdgJuDn.js +2 -0
  52. package/dist/gateway/static/root/assets/goals-settings-IYCH3-Pi.js +1 -0
  53. package/dist/gateway/static/root/assets/heartbeat-settings-Cf_a2Bmz.js +1 -0
  54. package/dist/gateway/static/root/assets/{html-workspace-editor-CQLWDiwE.js → html-workspace-editor-DV90ddkE.js} +1 -1
  55. package/dist/gateway/static/root/assets/index-CA2tR2vm.js +256 -0
  56. package/dist/gateway/static/root/assets/index-Ds3u0LOk.css +1 -0
  57. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-lKTg6St7.js +1 -0
  58. package/dist/gateway/static/root/assets/logs-page-BCporcNH.js +2 -0
  59. package/dist/gateway/static/root/assets/{markdown-editor-AssmZFx4.js → markdown-editor-BFOjBBla.js} +2 -2
  60. package/dist/gateway/static/root/assets/markdown-split-Bv4k6iGJ.js +1 -0
  61. package/dist/gateway/static/root/assets/{media-plugins-BhIQU5yS.js → media-plugins-Bbi8g3N8.js} +1 -1
  62. package/dist/gateway/static/root/assets/messages-C22hxE1N.js +3 -0
  63. package/dist/gateway/static/root/assets/models-hub-panel-D68Pyow7.js +2 -0
  64. package/dist/gateway/static/root/assets/notes-page-CuUMOiyv.js +1 -0
  65. package/dist/gateway/static/root/assets/notes-workbench-Dx2N5zTk.js +2 -0
  66. package/dist/gateway/static/root/assets/page-tabs-Cp395RYD.js +1 -0
  67. package/dist/gateway/static/root/assets/{preview-open-alternatives-DGzet1d7.js → preview-open-alternatives-DqV5OM4m.js} +1 -1
  68. package/dist/gateway/static/root/assets/project-detail-page-sB8AzZi3.js +1 -0
  69. package/dist/gateway/static/root/assets/projects-page-LBnJqWK2.js +1 -0
  70. package/dist/gateway/static/root/assets/remote-access-hub-Dbj0o6SC.js +1 -0
  71. package/dist/gateway/static/root/assets/{save-bar-controls-Cqgb-jqa.js → save-bar-controls-BItmzAzI.js} +1 -1
  72. package/dist/gateway/static/root/assets/{schedule-field-DVZcI8Yt.js → schedule-field-BQ8IjjCn.js} +1 -1
  73. package/dist/gateway/static/root/assets/{schema-form-Bj7sOxC8.js → schema-form-BRpD6x3d.js} +1 -1
  74. package/dist/gateway/static/root/assets/sessions-page-DhDZKspB.js +1 -0
  75. package/dist/gateway/static/root/assets/settings-advanced-gate-BvXLMNL6.js +1 -0
  76. package/dist/gateway/static/root/assets/{settings-collapsible-section-BmXn-8N6.js → settings-collapsible-section-BKSPQM4R.js} +1 -1
  77. package/dist/gateway/static/root/assets/settings-form-section-BmyfthNQ.js +1 -0
  78. package/dist/gateway/static/root/assets/settings-page-Cfm9UxAr.js +1 -0
  79. package/dist/gateway/static/root/assets/settings-page-layout-Bls5tfbH.js +1 -0
  80. package/dist/gateway/static/root/assets/setup-status-panel-kQEsTGAs.js +1 -0
  81. package/dist/gateway/static/root/assets/{share-preview-page-IB1v8i86.js → share-preview-page-DbYZNAPb.js} +1 -1
  82. package/dist/gateway/static/root/assets/shares-settings-BtR4B0kn.js +1 -0
  83. package/dist/gateway/static/root/assets/skill-reload-api-CJNVOWoK.js +1 -0
  84. package/dist/gateway/static/root/assets/skills-page-DcWDHrt3.js +2 -0
  85. package/dist/gateway/static/root/assets/{system-settings-panel-BxQ384RC.js → system-settings-panel-DKDAojWM.js} +1 -1
  86. package/dist/gateway/static/root/assets/{typed-models-lib-BkcpvFYO.js → typed-models-lib-BCCV4Kkp.js} +1 -1
  87. package/dist/gateway/static/root/assets/{use-channel-catalog-Cd0FaEQ4.js → use-channel-catalog-NBqg3iFY.js} +1 -1
  88. package/dist/gateway/static/root/assets/{user-profile-settings-panel-DQ7NnRSY.js → user-profile-settings-panel-suQ2x-LB.js} +1 -1
  89. package/dist/gateway/static/root/assets/{utils-YKhVf7Ka.js → utils-DPGVr3tS.js} +1 -1
  90. package/dist/gateway/static/root/assets/{vendor-codemirror-CNP1wPe7.js → vendor-codemirror-BvNgyE1Q.js} +1 -1
  91. package/dist/gateway/static/root/assets/voice-api-key-field-DaJASKFP.js +1 -0
  92. package/dist/gateway/static/root/assets/work-item-detail-page-BrCZpAWh.js +1 -0
  93. package/dist/gateway/static/root/assets/workflow-run-setup-panel-BTkRVNAh.js +3 -0
  94. package/dist/gateway/static/root/assets/{workflow-start-dialog-BNJVCWoS.js → workflow-start-dialog-DAImVtdO.js} +1 -1
  95. package/dist/gateway/static/root/assets/workflows-page-vyJ8wSXm.js +18 -0
  96. package/dist/gateway/static/root/index.html +8 -7
  97. package/dist/package.js +1 -1
  98. package/dist/src/activity/context.d.ts +11 -0
  99. package/dist/src/activity/context.js +36 -0
  100. package/dist/src/activity/context.js.map +1 -0
  101. package/dist/src/activity/emitter.d.ts +6 -0
  102. package/dist/src/activity/emitter.js +43 -0
  103. package/dist/src/activity/emitter.js.map +1 -0
  104. package/dist/src/activity/index.d.ts +3 -0
  105. package/dist/src/activity/index.js +3 -0
  106. package/dist/src/activity/service.d.ts +12 -0
  107. package/dist/src/activity/service.js +59 -0
  108. package/dist/src/activity/service.js.map +1 -0
  109. package/dist/src/activity/types.d.ts +109 -0
  110. package/dist/src/activity/types.js +1 -0
  111. package/dist/src/agent/agent-manager.d.ts +7 -0
  112. package/dist/src/agent/agent-manager.js +12 -5
  113. package/dist/src/agent/agent-manager.js.map +1 -1
  114. package/dist/src/agent/child-agent-factory.d.ts +2 -0
  115. package/dist/src/agent/child-agent-factory.js +2 -0
  116. package/dist/src/agent/child-agent-factory.js.map +1 -1
  117. package/dist/src/agent/coding/index.d.ts +1 -0
  118. package/dist/src/agent/coding/index.js +2 -0
  119. package/dist/src/agent/coding/turn-diff-tracker.d.ts +67 -0
  120. package/dist/src/agent/coding/turn-diff-tracker.js +233 -0
  121. package/dist/src/agent/coding/turn-diff-tracker.js.map +1 -0
  122. package/dist/src/agent/context/project-context.js +2 -2
  123. package/dist/src/agent/context/workspace-seed.js +2 -2
  124. package/dist/src/agent/embedded/run-for-session.js +1 -1
  125. package/dist/src/agent/goals/post-turn.js +2 -2
  126. package/dist/src/agent/ipc/bus.js +1 -1
  127. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  128. package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
  129. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  130. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  131. package/dist/src/agent/memory/dreaming/config.d.ts +2 -2
  132. package/dist/src/agent/memory/dreaming/config.js +3 -3
  133. package/dist/src/agent/memory/dreaming/config.js.map +1 -1
  134. package/dist/src/agent/memory/dreaming/constants.d.ts +1 -1
  135. package/dist/src/agent/memory/dreaming/constants.js +1 -1
  136. package/dist/src/agent/memory/dreaming/constants.js.map +1 -1
  137. package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +1 -0
  138. package/dist/src/agent/memory/dreaming/deep-promotion.js +11 -20
  139. package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
  140. package/dist/src/agent/memory/dreaming/events.d.ts +3 -3
  141. package/dist/src/agent/memory/dreaming/events.js +6 -6
  142. package/dist/src/agent/memory/dreaming/events.js.map +1 -1
  143. package/dist/src/agent/memory/dreaming/last-run.d.ts +2 -2
  144. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  145. package/dist/src/agent/memory/dreaming/last-run.js.map +1 -1
  146. package/dist/src/agent/memory/dreaming/light-sweep.d.ts +1 -1
  147. package/dist/src/agent/memory/dreaming/light-sweep.js +3 -3
  148. package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
  149. package/dist/src/agent/memory/dreaming/preview.d.ts +1 -0
  150. package/dist/src/agent/memory/dreaming/preview.js +2 -2
  151. package/dist/src/agent/memory/dreaming/preview.js.map +1 -1
  152. package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +1 -1
  153. package/dist/src/agent/memory/dreaming/rem-patterns.js +13 -13
  154. package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
  155. package/dist/src/agent/memory/dreaming/scope.d.ts +14 -0
  156. package/dist/src/agent/memory/dreaming/scope.js +27 -0
  157. package/dist/src/agent/memory/dreaming/scope.js.map +1 -0
  158. package/dist/src/agent/memory/dreaming/short-term-store.d.ts +4 -4
  159. package/dist/src/agent/memory/dreaming/short-term-store.js +17 -17
  160. package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
  161. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  162. package/dist/src/agent/models/manager.js +1 -1
  163. package/dist/src/agent/orchestration/agent-event-handler.d.ts +2 -0
  164. package/dist/src/agent/orchestration/agent-event-handler.js +13 -0
  165. package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
  166. package/dist/src/agent/orchestration/agent-orchestrator.js +22 -12
  167. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  168. package/dist/src/agent/sandbox/command-validator.js +12 -0
  169. package/dist/src/agent/sandbox/command-validator.js.map +1 -1
  170. package/dist/src/agent/service.d.ts +2 -1
  171. package/dist/src/agent/service.js +24 -9
  172. package/dist/src/agent/service.js.map +1 -1
  173. package/dist/src/agent/service.types.d.ts +7 -0
  174. package/dist/src/agent/session/session-inspector.d.ts +5 -3
  175. package/dist/src/agent/session/session-inspector.js +17 -8
  176. package/dist/src/agent/session/session-inspector.js.map +1 -1
  177. package/dist/src/agent/skills/hub-pull.js +1 -1
  178. package/dist/src/agent/source-context/types.d.ts +1 -1
  179. package/dist/src/agent/source-context/types.js +1 -1
  180. package/dist/src/agent/source-context/types.js.map +1 -1
  181. package/dist/src/agent/tool-manuals/index.js +15 -6
  182. package/dist/src/agent/tool-manuals/index.js.map +1 -1
  183. package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -0
  184. package/dist/src/agent/tool-manuals/xopc-use.js +204 -0
  185. package/dist/src/agent/tool-manuals/xopc-use.js.map +1 -0
  186. package/dist/src/agent/tools/apply-patch.js +116 -62
  187. package/dist/src/agent/tools/apply-patch.js.map +1 -1
  188. package/dist/src/agent/tools/concurrency.d.ts +8 -0
  189. package/dist/src/agent/tools/concurrency.js +31 -0
  190. package/dist/src/agent/tools/concurrency.js.map +1 -0
  191. package/dist/src/agent/tools/dreaming-tool.d.ts +2 -0
  192. package/dist/src/agent/tools/dreaming-tool.js +13 -10
  193. package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
  194. package/dist/src/agent/tools/exec-command.js +4 -0
  195. package/dist/src/agent/tools/exec-command.js.map +1 -1
  196. package/dist/src/agent/tools/executor.d.ts +6 -4
  197. package/dist/src/agent/tools/executor.js +7 -4
  198. package/dist/src/agent/tools/executor.js.map +1 -1
  199. package/dist/src/agent/tools/factory.d.ts +10 -0
  200. package/dist/src/agent/tools/factory.js +16 -1
  201. package/dist/src/agent/tools/factory.js.map +1 -1
  202. package/dist/src/agent/tools/find.js +2 -0
  203. package/dist/src/agent/tools/find.js.map +1 -1
  204. package/dist/src/agent/tools/goal-tool.js +2 -2
  205. package/dist/src/agent/tools/grep.js +2 -0
  206. package/dist/src/agent/tools/grep.js.map +1 -1
  207. package/dist/src/agent/tools/index.d.ts +3 -0
  208. package/dist/src/agent/tools/index.js +4 -1
  209. package/dist/src/agent/tools/list-dir.js +2 -0
  210. package/dist/src/agent/tools/list-dir.js.map +1 -1
  211. package/dist/src/agent/tools/memory-tool.d.ts +1 -0
  212. package/dist/src/agent/tools/memory-tool.js +2 -2
  213. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  214. package/dist/src/agent/tools/metadata.d.ts +15 -0
  215. package/dist/src/agent/tools/metadata.js +26 -0
  216. package/dist/src/agent/tools/metadata.js.map +1 -0
  217. package/dist/src/agent/tools/read.js +2 -0
  218. package/dist/src/agent/tools/read.js.map +1 -1
  219. package/dist/src/agent/tools/workflow-tool.js +1 -1
  220. package/dist/src/agent/tools/write.js +6 -0
  221. package/dist/src/agent/tools/write.js.map +1 -1
  222. package/dist/src/agent/tools/xopc-use-tool.d.ts +34 -0
  223. package/dist/src/agent/tools/xopc-use-tool.js +636 -0
  224. package/dist/src/agent/tools/xopc-use-tool.js.map +1 -0
  225. package/dist/src/agent/workflow/subagent-runner.d.ts +1 -0
  226. package/dist/src/agent/workflow/subagent-runner.js +5 -1
  227. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  228. package/dist/src/agent/workflow/workflow-child-tools.js +5 -0
  229. package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -1
  230. package/dist/src/agent-manifest/schema.d.ts +27 -27
  231. package/dist/src/automations/api/routes.js +1 -1
  232. package/dist/src/automations/domain/validation.d.ts +55 -55
  233. package/dist/src/automations/draft/automation-draft-validator.d.ts +25 -25
  234. package/dist/src/automations/service/action-executor.js +2 -2
  235. package/dist/src/browser/cdp-local-launcher.js +1 -1
  236. package/dist/src/browser/providers/browser-ext-install.js +3 -3
  237. package/dist/src/browser/providers/cloakbrowser.js +2 -2
  238. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  239. package/dist/src/browser/stealth.js +1 -1
  240. package/dist/src/chat-commands/agent-edit.js +1 -1
  241. package/dist/src/chat-commands/builtins/config.js +1 -1
  242. package/dist/src/chat-commands/builtins/goal.js +2 -2
  243. package/dist/src/chat-commands/context.js +1 -1
  244. package/dist/src/cli/commands/agent.js +1 -1
  245. package/dist/src/cli/commands/doctor/checks/database-schema.js +2 -2
  246. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  247. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  248. package/dist/src/cli/commands/extension-pack.js +1 -1
  249. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  250. package/dist/src/cli/commands/goal.js +3 -3
  251. package/dist/src/cli/commands/init.js +1 -1
  252. package/dist/src/cli/commands/project.js +4 -4
  253. package/dist/src/config/agent-profile.js +1 -1
  254. package/dist/src/config/gateway-bind.js +1 -1
  255. package/dist/src/config/index.js +1 -1
  256. package/dist/src/config/loader.js +1 -1
  257. package/dist/src/config/models-json.d.ts +14 -14
  258. package/dist/src/config/models-json.js +1 -1
  259. package/dist/src/config/schema.d.ts +60 -60
  260. package/dist/src/connectors/health.d.ts +2 -1
  261. package/dist/src/connectors/health.js +59 -1
  262. package/dist/src/connectors/health.js.map +1 -1
  263. package/dist/src/connectors/install.d.ts +1 -0
  264. package/dist/src/connectors/install.js +28 -1
  265. package/dist/src/connectors/install.js.map +1 -1
  266. package/dist/src/connectors/instances.js +7 -0
  267. package/dist/src/connectors/instances.js.map +1 -1
  268. package/dist/src/connectors/materialize.js +2 -1
  269. package/dist/src/connectors/materialize.js.map +1 -1
  270. package/dist/src/connectors/registries/modelscope.js +38 -13
  271. package/dist/src/connectors/registries/modelscope.js.map +1 -1
  272. package/dist/src/connectors/types.d.ts +2 -0
  273. package/dist/src/daemon/launchd.js +1 -1
  274. package/dist/src/daemon/systemd.js +1 -1
  275. package/dist/src/extensions/discover-extensions.js +1 -1
  276. package/dist/src/extensions/loader.js +2 -2
  277. package/dist/src/gateway/agents-admin.js +1 -1
  278. package/dist/src/gateway/dreaming-automation-reconciler.d.ts +1 -0
  279. package/dist/src/gateway/dreaming-automation-reconciler.js +62 -42
  280. package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -1
  281. package/dist/src/gateway/hono/app.js +7 -1
  282. package/dist/src/gateway/hono/app.js.map +1 -1
  283. package/dist/src/gateway/hono/lib/config-payload.d.ts +14 -14
  284. package/dist/src/gateway/hono/lib/static-ui.js +1 -1
  285. package/dist/src/gateway/hono/middleware/log-context.js +8 -1
  286. package/dist/src/gateway/hono/middleware/log-context.js.map +1 -1
  287. package/dist/src/gateway/hono/routes/activity.d.ts +14 -0
  288. package/dist/src/gateway/hono/routes/activity.js +72 -0
  289. package/dist/src/gateway/hono/routes/activity.js.map +1 -0
  290. package/dist/src/gateway/hono/routes/connectors.js +46 -2
  291. package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
  292. package/dist/src/gateway/hono/routes/dreaming.js +111 -66
  293. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
  294. package/dist/src/gateway/hono/routes/goals.js +1 -1
  295. package/dist/src/gateway/hono/routes/index.js +2 -0
  296. package/dist/src/gateway/hono/routes/index.js.map +1 -1
  297. package/dist/src/gateway/hono/routes/memory.js +2 -2
  298. package/dist/src/gateway/hono/routes/projects.js +903 -50
  299. package/dist/src/gateway/hono/routes/projects.js.map +1 -1
  300. package/dist/src/gateway/hono/routes/sessions.js +102 -2
  301. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  302. package/dist/src/gateway/hono/routes/workflows.js +2 -2
  303. package/dist/src/gateway/lock.js +1 -1
  304. package/dist/src/gateway/ports.js +1 -1
  305. package/dist/src/gateway/service/sessions-api.d.ts +10 -0
  306. package/dist/src/gateway/service/sessions-api.js +31 -0
  307. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  308. package/dist/src/gateway/service.js +28 -16
  309. package/dist/src/gateway/service.js.map +1 -1
  310. package/dist/src/goals/goal-store.js +1 -1
  311. package/dist/src/goals/goal-store.js.map +1 -1
  312. package/dist/src/goals/goal-workflow-judge.js +1 -1
  313. package/dist/src/infra/ports.js +1 -1
  314. package/dist/src/infra/ssh-tunnel.js +1 -1
  315. package/dist/src/infra/update-check.js +1 -1
  316. package/dist/src/infra/update-restart.js +1 -1
  317. package/dist/src/mcp/channel-bridge.js +1 -1
  318. package/dist/src/media/store.js +1 -1
  319. package/dist/src/media/store.js.map +1 -1
  320. package/dist/src/media/types.d.ts +1 -1
  321. package/dist/src/media/uri.js +2 -1
  322. package/dist/src/media/uri.js.map +1 -1
  323. package/dist/src/migrations/runner.js +1 -1
  324. package/dist/src/notes/service.js +65 -6
  325. package/dist/src/notes/service.js.map +1 -1
  326. package/dist/src/notes/store.js +1 -1
  327. package/dist/src/projects/project-service.d.ts +2 -1
  328. package/dist/src/projects/project-service.js +59 -2
  329. package/dist/src/projects/project-service.js.map +1 -1
  330. package/dist/src/projects/project-store.d.ts +2 -1
  331. package/dist/src/projects/project-store.js +43 -0
  332. package/dist/src/projects/project-store.js.map +1 -1
  333. package/dist/src/projects/types.d.ts +10 -0
  334. package/dist/src/projects/workspace.js +1 -1
  335. package/dist/src/routing/agent-session-key.js +1 -1
  336. package/dist/src/routing/resolve-route.js +1 -1
  337. package/dist/src/routing/resolve-tui-session-key.js +1 -1
  338. package/dist/src/session/client-history.d.ts +3 -0
  339. package/dist/src/session/client-history.js +24 -9
  340. package/dist/src/session/client-history.js.map +1 -1
  341. package/dist/src/session/init-session-turn.js +1 -1
  342. package/dist/src/session/resolve-session.js +1 -1
  343. package/dist/src/session/session-context-for-llm.d.ts +2 -0
  344. package/dist/src/session/session-context-for-llm.js +14 -1
  345. package/dist/src/session/session-context-for-llm.js.map +1 -1
  346. package/dist/src/session/session-title.js +2 -2
  347. package/dist/src/session/store.js +3 -3
  348. package/dist/src/session/store.js.map +1 -1
  349. package/dist/src/session/types.d.ts +4 -0
  350. package/dist/src/session/types.js.map +1 -1
  351. package/dist/src/storage/sqlite/activity-repository.d.ts +8 -0
  352. package/dist/src/storage/sqlite/activity-repository.js +208 -0
  353. package/dist/src/storage/sqlite/activity-repository.js.map +1 -0
  354. package/dist/src/storage/sqlite/connection.js +1 -1
  355. package/dist/src/storage/sqlite/index.d.ts +1 -0
  356. package/dist/src/storage/sqlite/index.js +2 -1
  357. package/dist/src/storage/sqlite/migrations/022_work_items.sql +61 -0
  358. package/dist/src/storage/sqlite/migrations/023_work_item_attachments.sql +15 -0
  359. package/dist/src/storage/sqlite/migrations/024_activity_events.sql +62 -0
  360. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  361. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  362. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  363. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  364. package/dist/src/storage/sqlite/row-mappers.js +1 -1
  365. package/dist/src/storage/sqlite/schema.js +1 -1
  366. package/dist/src/storage/sqlite/schema.sql +141 -0
  367. package/dist/src/storage/sqlite/session-repository.js +11 -0
  368. package/dist/src/storage/sqlite/session-repository.js.map +1 -1
  369. package/dist/src/tui/backends/embedded-backend.d.ts +13 -0
  370. package/dist/src/tui/backends/embedded-backend.js +76 -7
  371. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  372. package/dist/src/tui/backends/gateway-sse-backend.d.ts +13 -0
  373. package/dist/src/tui/backends/gateway-sse-backend.js +53 -0
  374. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  375. package/dist/src/tui/chat-history.js +16 -3
  376. package/dist/src/tui/chat-history.js.map +1 -1
  377. package/dist/src/tui/clipboard-image.js +1 -1
  378. package/dist/src/tui/components/assistant-message.js +12 -2
  379. package/dist/src/tui/components/assistant-message.js.map +1 -1
  380. package/dist/src/tui/components/chat-log.d.ts +23 -3
  381. package/dist/src/tui/components/chat-log.js +68 -9
  382. package/dist/src/tui/components/chat-log.js.map +1 -1
  383. package/dist/src/tui/components/tool-execution.d.ts +8 -0
  384. package/dist/src/tui/components/tool-execution.js +87 -77
  385. package/dist/src/tui/components/tool-execution.js.map +1 -1
  386. package/dist/src/tui/components/tui-bottom-bar.js +9 -5
  387. package/dist/src/tui/components/tui-bottom-bar.js.map +1 -1
  388. package/dist/src/tui/components/visual-truncate.d.ts +1 -0
  389. package/dist/src/tui/components/visual-truncate.js +28 -1
  390. package/dist/src/tui/components/visual-truncate.js.map +1 -1
  391. package/dist/src/tui/tool-summary.d.ts +22 -0
  392. package/dist/src/tui/tool-summary.js +212 -0
  393. package/dist/src/tui/tool-summary.js.map +1 -0
  394. package/dist/src/tui/tui-backend.d.ts +16 -0
  395. package/dist/src/tui/tui-command-formatters.js +2 -2
  396. package/dist/src/tui/tui-commands.d.ts +9 -0
  397. package/dist/src/tui/tui-commands.js +95 -6
  398. package/dist/src/tui/tui-commands.js.map +1 -1
  399. package/dist/src/tui/tui-picker-overlay.d.ts +1 -0
  400. package/dist/src/tui/tui-picker-overlay.js +36 -1
  401. package/dist/src/tui/tui-picker-overlay.js.map +1 -1
  402. package/dist/src/tui/tui-picker-services.d.ts +13 -0
  403. package/dist/src/tui/tui-run-state.js +11 -0
  404. package/dist/src/tui/tui-run-state.js.map +1 -1
  405. package/dist/src/tui/tui-run-status-format.d.ts +3 -0
  406. package/dist/src/tui/tui-run-status-format.js +33 -0
  407. package/dist/src/tui/tui-run-status-format.js.map +1 -0
  408. package/dist/src/tui/tui-session-actions.d.ts +5 -0
  409. package/dist/src/tui/tui-session-actions.js +24 -0
  410. package/dist/src/tui/tui-session-actions.js.map +1 -1
  411. package/dist/src/tui/tui-timeline-picker.d.ts +19 -0
  412. package/dist/src/tui/tui-timeline-picker.js +81 -0
  413. package/dist/src/tui/tui-timeline-picker.js.map +1 -0
  414. package/dist/src/tui/tui-timeline.d.ts +15 -0
  415. package/dist/src/tui/tui-timeline.js +65 -0
  416. package/dist/src/tui/tui-timeline.js.map +1 -0
  417. package/dist/src/tui/tui-tool-diff.d.ts +15 -0
  418. package/dist/src/tui/tui-tool-diff.js +178 -7
  419. package/dist/src/tui/tui-tool-diff.js.map +1 -1
  420. package/dist/src/tui/tui-types.d.ts +1 -0
  421. package/dist/src/tui/tui-types.js +1 -0
  422. package/dist/src/tui/tui-types.js.map +1 -1
  423. package/dist/src/tui/tui.js +31 -25
  424. package/dist/src/tui/tui.js.map +1 -1
  425. package/dist/src/utils/index.js +1 -1
  426. package/dist/src/utils/logger/index.js +1 -1
  427. package/dist/src/utils/logger/stats.d.ts +3 -3
  428. package/dist/src/utils/logger.js +1 -1
  429. package/dist/src/work-items/agent-context.d.ts +7 -0
  430. package/dist/src/work-items/agent-context.js +75 -0
  431. package/dist/src/work-items/agent-context.js.map +1 -0
  432. package/dist/src/work-items/index.d.ts +4 -0
  433. package/dist/src/work-items/index.js +4 -0
  434. package/dist/src/work-items/types.d.ts +112 -0
  435. package/dist/src/work-items/types.js +1 -0
  436. package/dist/src/work-items/work-item-service.d.ts +35 -0
  437. package/dist/src/work-items/work-item-service.js +277 -0
  438. package/dist/src/work-items/work-item-service.js.map +1 -0
  439. package/dist/src/work-items/work-item-store.d.ts +21 -0
  440. package/dist/src/work-items/work-item-store.js +302 -0
  441. package/dist/src/work-items/work-item-store.js.map +1 -0
  442. package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
  443. package/dist/src/workflows/service/workflow-run-service.js +4 -3
  444. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  445. package/dist/src/workflows/service/workflow-session-bridge.js +4 -1
  446. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  447. package/package.json +5 -5
  448. package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
  449. package/dist/gateway/static/root/assets/agents-BjIxt67Z.js +0 -2
  450. package/dist/gateway/static/root/assets/app-management-settings-panel-CYCONLIL.js +0 -1
  451. package/dist/gateway/static/root/assets/appearance-settings-Clw3ryKg.js +0 -1
  452. package/dist/gateway/static/root/assets/apps-page-QICTeGjX.js +0 -1
  453. package/dist/gateway/static/root/assets/automation-suggestion-card-CU0-4nQ-.js +0 -1
  454. package/dist/gateway/static/root/assets/automations-page-Car-jtiz.js +0 -1
  455. package/dist/gateway/static/root/assets/browser-settings-page-CMeBJzlS.js +0 -8
  456. package/dist/gateway/static/root/assets/capability-presets-api-BmQTM9Il.js +0 -1
  457. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DZEJEoCF.js +0 -1
  458. package/dist/gateway/static/root/assets/channels-settings-kkW-xFau.js +0 -1
  459. package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +0 -1
  460. package/dist/gateway/static/root/assets/connectors-page-BvaQvO5F.js +0 -2
  461. package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +0 -1
  462. package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +0 -1
  463. package/dist/gateway/static/root/assets/dreaming-settings-DnHO686d.js +0 -1
  464. package/dist/gateway/static/root/assets/extension-debug-page-BGLRuWVN.js +0 -1
  465. package/dist/gateway/static/root/assets/extension-page-D978ePp9.js +0 -1
  466. package/dist/gateway/static/root/assets/extension-settings-page-B6Ih4Swx.js +0 -1
  467. package/dist/gateway/static/root/assets/gateway-settings-CMEA3r5u.js +0 -1
  468. package/dist/gateway/static/root/assets/goal-create-dialog-B-KHKeXN.js +0 -1
  469. package/dist/gateway/static/root/assets/goal-detail-page-BxrSoWdj.js +0 -1
  470. package/dist/gateway/static/root/assets/goals-page-BTJzIl28.js +0 -2
  471. package/dist/gateway/static/root/assets/goals-settings-BJyEuLLm.js +0 -1
  472. package/dist/gateway/static/root/assets/heartbeat-settings-wkOjYNQT.js +0 -1
  473. package/dist/gateway/static/root/assets/index-BLaXr6Ev.css +0 -1
  474. package/dist/gateway/static/root/assets/index-c_9TVr_C.js +0 -191
  475. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-BT8T4DyC.js +0 -1
  476. package/dist/gateway/static/root/assets/logs-page-CrxBJUgI.js +0 -2
  477. package/dist/gateway/static/root/assets/markdown-split-Dv66bO2b.js +0 -1
  478. package/dist/gateway/static/root/assets/messages-O6TAtdFC.js +0 -3
  479. package/dist/gateway/static/root/assets/models-hub-panel-DOOpz6y1.js +0 -2
  480. package/dist/gateway/static/root/assets/notes-page-Br16pK9v.js +0 -1
  481. package/dist/gateway/static/root/assets/notes-workbench-PSJAi0ZC.js +0 -2
  482. package/dist/gateway/static/root/assets/project-detail-page-CIGGgKuw.js +0 -1
  483. package/dist/gateway/static/root/assets/projects-page-B2grhsBt.js +0 -1
  484. package/dist/gateway/static/root/assets/remote-access-hub-CXMORxBD.js +0 -1
  485. package/dist/gateway/static/root/assets/sessions-page-Bi2wkBzU.js +0 -1
  486. package/dist/gateway/static/root/assets/settings-advanced-gate-B1L3G4IA.js +0 -1
  487. package/dist/gateway/static/root/assets/settings-form-section-BnqYMWHR.js +0 -1
  488. package/dist/gateway/static/root/assets/settings-page-BfRSHJmO.js +0 -1
  489. package/dist/gateway/static/root/assets/settings-page-layout-CdWZU1hd.js +0 -1
  490. package/dist/gateway/static/root/assets/setup-status-panel-CWtPM7RK.js +0 -1
  491. package/dist/gateway/static/root/assets/shares-settings-ngbsBgij.js +0 -1
  492. package/dist/gateway/static/root/assets/skill-reload-api-BIe442Gv.js +0 -1
  493. package/dist/gateway/static/root/assets/skills-page-BfchZRVa.js +0 -2
  494. package/dist/gateway/static/root/assets/voice-api-key-field-C5Ov8Uk_.js +0 -1
  495. package/dist/gateway/static/root/assets/workflow-run-setup-panel-BYD9BtOq.js +0 -3
  496. package/dist/gateway/static/root/assets/workflows-page-BYF29ANm.js +0 -18
@@ -1,20 +1,29 @@
1
1
  import { getSqliteDatabase } from "../../../storage/sqlite/transaction.js";
2
- import { GoalService } from "../../../goals/goal-service.js";
3
- import "../../../goals/index.js";
4
2
  import { getSessionMetadata } from "../../../storage/sqlite/session-repository.js";
5
3
  import { loadTranscriptRowsForSession } from "../../../storage/sqlite/transcript-repository.js";
6
4
  import { listMemoryRecords, upsertMemoryRecord } from "../../../storage/sqlite/memory-records-repository.js";
7
5
  import "../../../storage/sqlite/index.js";
6
+ import { ActivityService } from "../../../activity/service.js";
7
+ import "../../../activity/index.js";
8
+ import { buildSessionKey, init_session_key } from "../../../routing/session-key.js";
9
+ import { resolveEffectiveAgentProfile } from "../../../config/agent-profile.js";
10
+ import { GoalService } from "../../../goals/goal-service.js";
11
+ import "../../../goals/index.js";
8
12
  import { ProjectWorkspaceConflictError, ProjectWorkspaceMissingError } from "../../../projects/workspace-project.js";
9
13
  import { isValidProjectAgentId, normalizeProjectAgentId, resolveProjectAgentId } from "../../../projects/project-agent.js";
10
14
  import { inferProjectKind } from "../../../projects/project-kind.js";
11
15
  import { inferSuggestedProjectDefaultAgentId } from "../../../projects/project-agent-suggestion.js";
12
16
  import { buildProjectLoopOverview } from "../../../projects/project-loop.js";
13
17
  import "../../../projects/index.js";
18
+ import { WORK_ITEM_ATTACHMENT_MAX_BYTES, WorkItemService } from "../../../work-items/work-item-service.js";
19
+ import { buildWorkItemAgentContext } from "../../../work-items/agent-context.js";
20
+ import "../../../work-items/index.js";
14
21
  import { createGatewayRouteLogger } from "../lib/route-logger.js";
22
+ import { parseActivityIncludeRelated, parseActivityQuery } from "./activity.js";
15
23
  import * as path$1 from "node:path";
16
- import { readdir, realpath, stat } from "node:fs/promises";
24
+ import { readFile, readdir, realpath, stat, writeFile } from "node:fs/promises";
17
25
  //#region src/gateway/hono/routes/projects.ts
26
+ init_session_key();
18
27
  const log = createGatewayRouteLogger("Projects");
19
28
  function parseProjectStatus(raw) {
20
29
  return raw === "active" || raw === "paused" || raw === "archived" ? raw : void 0;
@@ -24,6 +33,9 @@ function parseLimit(raw, fallback = 50) {
24
33
  const n = Number.parseInt(raw, 10);
25
34
  return Number.isFinite(n) ? Math.min(500, Math.max(1, n)) : fallback;
26
35
  }
36
+ function isHiddenEmptyProjectChatShell(session) {
37
+ return session.hiddenFromSessionList === true && session.messageCount === 0 && session.customData?.genericNewChatShell !== false && Boolean(session.routing?.peerId?.startsWith("chat_"));
38
+ }
27
39
  function textField(body, key) {
28
40
  const value = body[key];
29
41
  return typeof value === "string" ? value : void 0;
@@ -33,7 +45,104 @@ function optionalTextField(body, key) {
33
45
  const value = body[key];
34
46
  return typeof value === "string" ? value : null;
35
47
  }
48
+ function resolveEffectiveWorkspaceRoot(service, project) {
49
+ const fixedRoot = project.workspaceRoot?.trim();
50
+ if (fixedRoot) return fixedRoot;
51
+ const agentId = resolveProjectAgentId({
52
+ config: service.currentConfig,
53
+ projects: service.projects,
54
+ projectId: project.id
55
+ });
56
+ return resolveEffectiveAgentProfile(service.currentConfig, agentId).resolvedWorkspacePath;
57
+ }
58
+ function enrichProjectWorkspace(service, project) {
59
+ return {
60
+ ...project,
61
+ workspaceMode: project.workspaceRoot?.trim() ? "fixed" : "followAgent",
62
+ effectiveWorkspaceRoot: resolveEffectiveWorkspaceRoot(service, project)
63
+ };
64
+ }
65
+ function finiteNumberField(value) {
66
+ if (typeof value === "number" && Number.isFinite(value)) return value;
67
+ if (typeof value === "string" && value.trim()) {
68
+ const parsed = Number(value);
69
+ return Number.isFinite(parsed) ? parsed : void 0;
70
+ }
71
+ }
72
+ function collectUploadedFiles(body) {
73
+ const raw = body.file ?? body.files ?? body.attachments;
74
+ return (Array.isArray(raw) ? raw : raw ? [raw] : []).filter((value) => value instanceof File);
75
+ }
76
+ function validateUploadedWorkItemFiles(files) {
77
+ if (files.length > 10) return `Too many attachments (max 10)`;
78
+ for (const file of files) if (file.size > 26214400) return `Attachment ${JSON.stringify(file.name || "upload")} exceeds ${Math.floor(WORK_ITEM_ATTACHMENT_MAX_BYTES / (1024 * 1024))}MB limit`;
79
+ return null;
80
+ }
81
+ async function uploadedFileToBuffer(file) {
82
+ return {
83
+ name: file.name || "upload",
84
+ buffer: Buffer.from(await file.arrayBuffer()),
85
+ mimeType: file.type || "application/octet-stream"
86
+ };
87
+ }
88
+ function parseCsvEnum(raw, values) {
89
+ if (!raw) return void 0;
90
+ const allowed = new Set(values);
91
+ const parsed = raw.split(",").map((item) => item.trim()).filter((item) => allowed.has(item));
92
+ return parsed.length > 0 ? [...new Set(parsed)] : void 0;
93
+ }
94
+ function parseEnumValue(raw, values) {
95
+ if (typeof raw !== "string") return void 0;
96
+ return values.includes(raw) ? raw : void 0;
97
+ }
98
+ const WORK_ITEM_STATUSES = [
99
+ "backlog",
100
+ "todo",
101
+ "in_progress",
102
+ "blocked",
103
+ "needs_input",
104
+ "in_review",
105
+ "done",
106
+ "cancelled"
107
+ ];
108
+ const WORK_ITEM_PRIORITIES = [
109
+ "urgent",
110
+ "high",
111
+ "normal",
112
+ "low"
113
+ ];
114
+ const WORK_ITEM_SUGGESTION_STATUSES = [
115
+ "pending",
116
+ "applied",
117
+ "dismissed"
118
+ ];
36
119
  const SKIP_FILE_NAMES = new Set([".git", "node_modules"]);
120
+ const PROJECT_FILE_MIME_BY_EXT = {
121
+ png: "image/png",
122
+ jpg: "image/jpeg",
123
+ jpeg: "image/jpeg",
124
+ gif: "image/gif",
125
+ webp: "image/webp",
126
+ bmp: "image/bmp",
127
+ svg: "image/svg+xml",
128
+ pdf: "application/pdf",
129
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
130
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
131
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
132
+ txt: "text/plain",
133
+ md: "text/markdown",
134
+ json: "application/json",
135
+ html: "text/html",
136
+ css: "text/css",
137
+ js: "text/javascript",
138
+ ts: "text/typescript",
139
+ mp3: "audio/mpeg",
140
+ wav: "audio/wav",
141
+ ogg: "audio/ogg",
142
+ webm: "video/webm",
143
+ mp4: "video/mp4",
144
+ mov: "video/quicktime"
145
+ };
37
146
  function normalizeRelativePath(raw) {
38
147
  return (raw ?? "").trim().replaceAll("\\", "/").replace(/^\/+/, "");
39
148
  }
@@ -41,6 +150,137 @@ function isWithinDirectory(root, target) {
41
150
  const relativePath = path$1.relative(root, target);
42
151
  return relativePath === "" || !relativePath.startsWith("..") && !path$1.isAbsolute(relativePath);
43
152
  }
153
+ async function resolveProjectWorkspaceRoot(service, projectId) {
154
+ const project = service.projects.get(projectId);
155
+ if (!project) return {
156
+ ok: false,
157
+ status: 404,
158
+ error: "Project not found"
159
+ };
160
+ const workspaceRoot = resolveEffectiveWorkspaceRoot(service, project);
161
+ if (!workspaceRoot?.trim()) return {
162
+ ok: false,
163
+ status: 400,
164
+ error: "Project workspace root is not set"
165
+ };
166
+ try {
167
+ const root = await realpath(workspaceRoot);
168
+ if (!(await stat(root)).isDirectory()) return {
169
+ ok: false,
170
+ status: 400,
171
+ error: "Project workspace root is not a directory"
172
+ };
173
+ return {
174
+ ok: true,
175
+ projectId: project.id,
176
+ root
177
+ };
178
+ } catch (err) {
179
+ log.warn({
180
+ err,
181
+ projectId: project.id,
182
+ path: workspaceRoot
183
+ }, "project workspace root unavailable");
184
+ return {
185
+ ok: false,
186
+ status: 404,
187
+ error: "Project workspace root is unavailable"
188
+ };
189
+ }
190
+ }
191
+ async function resolveProjectWorkspacePath(service, projectId, rawPath) {
192
+ const rootResult = await resolveProjectWorkspaceRoot(service, projectId);
193
+ if (rootResult.ok === false) return {
194
+ ok: false,
195
+ status: rootResult.status,
196
+ error: rootResult.error
197
+ };
198
+ const requestedPath = normalizeRelativePath(rawPath);
199
+ const candidate = path$1.resolve(rootResult.root, requestedPath);
200
+ if (!isWithinDirectory(rootResult.root, candidate)) return {
201
+ ok: false,
202
+ status: 400,
203
+ error: "Path is outside project workspace"
204
+ };
205
+ const relativePath = path$1.relative(rootResult.root, candidate).split(path$1.sep).join("/");
206
+ return {
207
+ ok: true,
208
+ projectId: rootResult.projectId,
209
+ root: rootResult.root,
210
+ requestedPath,
211
+ absolutePath: candidate,
212
+ relativePath: relativePath === "." ? "" : relativePath
213
+ };
214
+ }
215
+ async function resolveExistingProjectWorkspacePath(service, projectId, rawPath) {
216
+ const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);
217
+ if (resolved.ok === false) return resolved;
218
+ if (!resolved.requestedPath.trim()) return {
219
+ ok: false,
220
+ status: 400,
221
+ error: "Missing path"
222
+ };
223
+ let realTarget;
224
+ try {
225
+ realTarget = await realpath(resolved.absolutePath);
226
+ } catch {
227
+ return {
228
+ ok: false,
229
+ status: 404,
230
+ error: "Not found"
231
+ };
232
+ }
233
+ if (!isWithinDirectory(resolved.root, realTarget)) return {
234
+ ok: false,
235
+ status: 400,
236
+ error: "Path is outside project workspace"
237
+ };
238
+ const targetStat = await stat(realTarget);
239
+ return {
240
+ ...resolved,
241
+ absolutePath: realTarget,
242
+ stat: targetStat
243
+ };
244
+ }
245
+ async function resolveProjectWorkspaceWritePath(service, projectId, rawPath) {
246
+ const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);
247
+ if (resolved.ok === false) return resolved;
248
+ if (!resolved.requestedPath.trim()) return {
249
+ ok: false,
250
+ status: 400,
251
+ error: "Missing path"
252
+ };
253
+ try {
254
+ const realTarget = await realpath(resolved.absolutePath);
255
+ if (!isWithinDirectory(resolved.root, realTarget)) return {
256
+ ok: false,
257
+ status: 400,
258
+ error: "Path is outside project workspace"
259
+ };
260
+ return {
261
+ ...resolved,
262
+ absolutePath: realTarget,
263
+ existingStat: await stat(realTarget)
264
+ };
265
+ } catch {
266
+ const parentPath = path$1.dirname(resolved.absolutePath);
267
+ try {
268
+ const realParent = await realpath(parentPath);
269
+ if (!isWithinDirectory(resolved.root, realParent)) return {
270
+ ok: false,
271
+ status: 400,
272
+ error: "Path is outside project workspace"
273
+ };
274
+ } catch {
275
+ return {
276
+ ok: false,
277
+ status: 404,
278
+ error: "Parent directory not found"
279
+ };
280
+ }
281
+ return resolved;
282
+ }
283
+ }
44
284
  function textFromTranscriptContent(content) {
45
285
  if (typeof content === "string") return content;
46
286
  if (!Array.isArray(content)) return "";
@@ -66,6 +306,36 @@ function buildSessionSummaryMemoryContent(sessionKey, explicitSummary) {
66
306
  }).filter(Boolean);
67
307
  return lines.length > 0 ? [`Session summary for ${sessionKey}:`, ...lines].join("\n") : `Session summary for ${sessionKey}: no transcript content available.`;
68
308
  }
309
+ function buildWorkItemChatSessionMetadata(params) {
310
+ return {
311
+ name: params.title,
312
+ tags: ["work-item"],
313
+ sourceChannel: "webchat",
314
+ sourceChatId: [
315
+ params.accountId,
316
+ "direct",
317
+ params.peerId
318
+ ].join(":"),
319
+ sessionType: "chat",
320
+ hiddenFromSessionList: true,
321
+ routing: {
322
+ agentId: params.agentId,
323
+ source: "webchat",
324
+ accountId: params.accountId,
325
+ peerKind: "direct",
326
+ peerId: params.peerId
327
+ },
328
+ customData: {
329
+ genericNewChatShell: false,
330
+ sourceBinding: {
331
+ kind: "work_item",
332
+ sourceId: params.workItemId,
333
+ version: String(params.updatedAt),
334
+ attachedAt: Date.now()
335
+ }
336
+ }
337
+ };
338
+ }
69
339
  function listFailedProjectWorkflowRuns(projectId, limit = 5) {
70
340
  return getSqliteDatabase().prepare(`SELECT run_id, definition_id, status, created_at_ms, error_message
71
341
  FROM workflow_runs
@@ -100,7 +370,9 @@ function projectDigestMemoryRecordId(projectId) {
100
370
  }
101
371
  function registerProjectsRoutes(authenticated, deps) {
102
372
  const { service } = deps;
373
+ const activity = new ActivityService();
103
374
  const goals = new GoalService();
375
+ const workItems = new WorkItemService();
104
376
  authenticated.post("/api/projects", async (c) => {
105
377
  const body = await c.req.json().catch(() => ({}));
106
378
  const name = textField(body, "name")?.trim();
@@ -135,7 +407,7 @@ function registerProjectsRoutes(authenticated, deps) {
135
407
  });
136
408
  return c.json({
137
409
  ok: true,
138
- project
410
+ project: enrichProjectWorkspace(service, project)
139
411
  }, 201);
140
412
  } catch (error) {
141
413
  if (error instanceof ProjectWorkspaceConflictError) return c.json({
@@ -168,7 +440,8 @@ function registerProjectsRoutes(authenticated, deps) {
168
440
  });
169
441
  return c.json({
170
442
  ok: true,
171
- ...result
443
+ ...result,
444
+ items: result.items.map((project) => enrichProjectWorkspace(service, project))
172
445
  });
173
446
  });
174
447
  authenticated.get("/api/projects/suggestions", async (c) => {
@@ -274,7 +547,7 @@ function registerProjectsRoutes(authenticated, deps) {
274
547
  return c.json({
275
548
  ok: true,
276
549
  overview: {
277
- project,
550
+ project: enrichProjectWorkspace(service, project),
278
551
  stats: {
279
552
  sessionCount: project.sessionCount,
280
553
  goalCount: project.goalCount,
@@ -298,6 +571,439 @@ function registerProjectsRoutes(authenticated, deps) {
298
571
  }
299
572
  });
300
573
  });
574
+ authenticated.get("/api/projects/:id/activity", (c) => {
575
+ const project = service.projects.get(c.req.param("id"));
576
+ if (!project) return c.json({
577
+ ok: false,
578
+ error: "Project not found"
579
+ }, 404);
580
+ const result = activity.listForProject({
581
+ projectId: project.id,
582
+ includeRelated: parseActivityIncludeRelated(c.req.query("includeRelated")),
583
+ ...parseActivityQuery(c)
584
+ });
585
+ return c.json({
586
+ ok: true,
587
+ ...result
588
+ });
589
+ });
590
+ authenticated.get("/api/projects/:id/work-items", async (c) => {
591
+ const project = service.projects.get(c.req.param("id"));
592
+ if (!project) return c.json({
593
+ ok: false,
594
+ error: "Project not found"
595
+ }, 404);
596
+ const result = workItems.listProjectWorkItems(project.id, {
597
+ status: parseCsvEnum(c.req.query("status"), WORK_ITEM_STATUSES),
598
+ priority: parseCsvEnum(c.req.query("priority"), WORK_ITEM_PRIORITIES),
599
+ includeArchived: c.req.query("includeArchived") === "true",
600
+ search: c.req.query("search"),
601
+ sortBy: c.req.query("sortBy"),
602
+ sortOrder: c.req.query("sortOrder"),
603
+ limit: parseLimit(c.req.query("limit")),
604
+ offset: c.req.query("offset") ? Math.max(0, Number.parseInt(c.req.query("offset"), 10) || 0) : void 0
605
+ });
606
+ return c.json({
607
+ ok: true,
608
+ ...result
609
+ });
610
+ });
611
+ authenticated.post("/api/projects/:id/work-items", async (c) => {
612
+ const project = service.projects.get(c.req.param("id"));
613
+ if (!project) return c.json({
614
+ ok: false,
615
+ error: "Project not found"
616
+ }, 404);
617
+ const contentType = c.req.header("content-type") || "";
618
+ let body;
619
+ let files = [];
620
+ if (contentType.includes("multipart/form-data")) {
621
+ try {
622
+ body = await c.req.parseBody({ all: true });
623
+ } catch {
624
+ return c.json({
625
+ ok: false,
626
+ error: "Invalid multipart body"
627
+ }, 400);
628
+ }
629
+ files = collectUploadedFiles(body);
630
+ } else body = await c.req.json().catch(() => ({}));
631
+ const attachmentError = validateUploadedWorkItemFiles(files);
632
+ if (attachmentError) return c.json({
633
+ ok: false,
634
+ error: attachmentError
635
+ }, 413);
636
+ const title = textField(body, "title")?.trim();
637
+ if (!title) return c.json({
638
+ ok: false,
639
+ error: "Work item title is required"
640
+ }, 400);
641
+ const status = parseEnumValue(body.status, WORK_ITEM_STATUSES);
642
+ const priority = parseEnumValue(body.priority, WORK_ITEM_PRIORITIES);
643
+ const dueAt = finiteNumberField(body.dueAt);
644
+ if (Object.hasOwn(body, "status") && !status) return c.json({
645
+ ok: false,
646
+ error: "Invalid work item status"
647
+ }, 400);
648
+ if (Object.hasOwn(body, "priority") && !priority) return c.json({
649
+ ok: false,
650
+ error: "Invalid work item priority"
651
+ }, 400);
652
+ if (Object.hasOwn(body, "dueAt") && dueAt === void 0 && body.dueAt !== null) return c.json({
653
+ ok: false,
654
+ error: "Invalid dueAt"
655
+ }, 400);
656
+ const uploads = [];
657
+ for (const file of files) uploads.push(await uploadedFileToBuffer(file));
658
+ const item = workItems.createProjectWorkItem(project.id, {
659
+ title,
660
+ description: textField(body, "description"),
661
+ status,
662
+ priority,
663
+ ownerAgentId: textField(body, "ownerAgentId") || project.defaultAgentId || void 0,
664
+ nextAction: textField(body, "nextAction"),
665
+ blockedReason: textField(body, "blockedReason"),
666
+ dueAt
667
+ });
668
+ for (const upload of uploads) await workItems.addAttachment(item.id, upload);
669
+ const created = files.length > 0 ? workItems.getWorkItem(item.id) ?? item : item;
670
+ return c.json({
671
+ ok: true,
672
+ item: created
673
+ }, 201);
674
+ });
675
+ authenticated.get("/api/work-items/:id", async (c) => {
676
+ const item = workItems.getWorkItem(c.req.param("id"));
677
+ if (!item) return c.json({
678
+ ok: false,
679
+ error: "Work item not found"
680
+ }, 404);
681
+ return c.json({
682
+ ok: true,
683
+ item
684
+ });
685
+ });
686
+ authenticated.get("/api/work-items/:id/attachments", async (c) => {
687
+ const attachments = workItems.listAttachments(c.req.param("id"));
688
+ if (!attachments) return c.json({
689
+ ok: false,
690
+ error: "Work item not found"
691
+ }, 404);
692
+ return c.json({
693
+ ok: true,
694
+ attachments
695
+ });
696
+ });
697
+ authenticated.post("/api/work-items/:id/attachments", async (c) => {
698
+ const item = workItems.getWorkItem(c.req.param("id"));
699
+ if (!item) return c.json({
700
+ ok: false,
701
+ error: "Work item not found"
702
+ }, 404);
703
+ let body;
704
+ try {
705
+ body = await c.req.parseBody({ all: true });
706
+ } catch {
707
+ return c.json({
708
+ ok: false,
709
+ error: "Invalid multipart body"
710
+ }, 400);
711
+ }
712
+ const files = collectUploadedFiles(body);
713
+ if (!files.length) return c.json({
714
+ ok: false,
715
+ error: "Missing file field"
716
+ }, 400);
717
+ const attachmentError = validateUploadedWorkItemFiles(files);
718
+ if (attachmentError) return c.json({
719
+ ok: false,
720
+ error: attachmentError
721
+ }, 413);
722
+ const attachments = [];
723
+ for (const file of files) {
724
+ const upload = await uploadedFileToBuffer(file);
725
+ const attachment = await workItems.addAttachment(item.id, upload);
726
+ if (attachment) attachments.push(attachment);
727
+ }
728
+ return c.json({
729
+ ok: true,
730
+ attachments,
731
+ item: workItems.getWorkItem(item.id)
732
+ }, 201);
733
+ });
734
+ authenticated.get("/api/work-items/:id/attachments/:attachmentId/content", async (c) => {
735
+ const result = await workItems.readAttachment(c.req.param("id"), c.req.param("attachmentId"));
736
+ if (!result) return c.json({
737
+ ok: false,
738
+ error: "Attachment not found"
739
+ }, 404);
740
+ return new Response(result.buffer, { headers: {
741
+ "Content-Type": result.attachment.mimeType,
742
+ "Content-Length": String(result.attachment.size),
743
+ "Content-Disposition": `inline; filename="${encodeURIComponent(result.attachment.fileName)}"`,
744
+ "Cache-Control": "private, max-age=31536000, immutable"
745
+ } });
746
+ });
747
+ authenticated.delete("/api/work-items/:id/attachments/:attachmentId", async (c) => {
748
+ const attachment = await workItems.removeAttachment(c.req.param("id"), c.req.param("attachmentId"));
749
+ if (!attachment) return c.json({
750
+ ok: false,
751
+ error: "Attachment not found"
752
+ }, 404);
753
+ return c.json({
754
+ ok: true,
755
+ attachment,
756
+ item: workItems.getWorkItem(c.req.param("id"))
757
+ });
758
+ });
759
+ authenticated.patch("/api/work-items/:id", async (c) => {
760
+ const body = await c.req.json().catch(() => ({}));
761
+ const status = Object.hasOwn(body, "status") ? parseEnumValue(body.status, WORK_ITEM_STATUSES) : void 0;
762
+ const priority = Object.hasOwn(body, "priority") ? parseEnumValue(body.priority, WORK_ITEM_PRIORITIES) : void 0;
763
+ const dueAt = Object.hasOwn(body, "dueAt") ? body.dueAt === null ? null : typeof body.dueAt === "number" && Number.isFinite(body.dueAt) ? body.dueAt : void 0 : void 0;
764
+ const archivedAt = Object.hasOwn(body, "archivedAt") ? body.archivedAt === null ? null : typeof body.archivedAt === "number" && Number.isFinite(body.archivedAt) ? body.archivedAt : void 0 : void 0;
765
+ if (status === void 0 && Object.hasOwn(body, "status")) return c.json({
766
+ ok: false,
767
+ error: "Invalid work item status"
768
+ }, 400);
769
+ if (priority === void 0 && Object.hasOwn(body, "priority")) return c.json({
770
+ ok: false,
771
+ error: "Invalid work item priority"
772
+ }, 400);
773
+ if (dueAt === void 0 && Object.hasOwn(body, "dueAt")) return c.json({
774
+ ok: false,
775
+ error: "Invalid dueAt"
776
+ }, 400);
777
+ if (archivedAt === void 0 && Object.hasOwn(body, "archivedAt")) return c.json({
778
+ ok: false,
779
+ error: "Invalid archivedAt"
780
+ }, 400);
781
+ const item = workItems.updateWorkItem(c.req.param("id"), {
782
+ ...Object.hasOwn(body, "title") ? { title: textField(body, "title") ?? "" } : {},
783
+ ...Object.hasOwn(body, "description") ? { description: optionalTextField(body, "description") } : {},
784
+ ...Object.hasOwn(body, "status") ? { status } : {},
785
+ ...Object.hasOwn(body, "priority") ? { priority } : {},
786
+ ...Object.hasOwn(body, "ownerAgentId") ? { ownerAgentId: optionalTextField(body, "ownerAgentId") } : {},
787
+ ...Object.hasOwn(body, "nextAction") ? { nextAction: optionalTextField(body, "nextAction") } : {},
788
+ ...Object.hasOwn(body, "blockedReason") ? { blockedReason: optionalTextField(body, "blockedReason") } : {},
789
+ ...Object.hasOwn(body, "dueAt") ? { dueAt } : {},
790
+ ...Object.hasOwn(body, "archivedAt") ? { archivedAt } : {}
791
+ });
792
+ if (!item) return c.json({
793
+ ok: false,
794
+ error: "Work item not found"
795
+ }, 404);
796
+ return c.json({
797
+ ok: true,
798
+ item
799
+ });
800
+ });
801
+ authenticated.delete("/api/work-items/:id", async (c) => {
802
+ const item = workItems.updateWorkItem(c.req.param("id"), { archivedAt: Date.now() });
803
+ if (!item) return c.json({
804
+ ok: false,
805
+ error: "Work item not found"
806
+ }, 404);
807
+ return c.json({
808
+ ok: true,
809
+ item
810
+ });
811
+ });
812
+ authenticated.get("/api/work-items/:id/events", async (c) => {
813
+ const item = workItems.getWorkItem(c.req.param("id"));
814
+ if (!item) return c.json({
815
+ ok: false,
816
+ error: "Work item not found"
817
+ }, 404);
818
+ return c.json({
819
+ ok: true,
820
+ events: workItems.listEvents(item.id)
821
+ });
822
+ });
823
+ authenticated.get("/api/work-items/:id/update-suggestions", async (c) => {
824
+ const item = workItems.getWorkItem(c.req.param("id"));
825
+ if (!item) return c.json({
826
+ ok: false,
827
+ error: "Work item not found"
828
+ }, 404);
829
+ const status = parseEnumValue(c.req.query("status"), WORK_ITEM_SUGGESTION_STATUSES);
830
+ if (c.req.query("status") && !status) return c.json({
831
+ ok: false,
832
+ error: "Invalid suggestion status"
833
+ }, 400);
834
+ return c.json({
835
+ ok: true,
836
+ suggestions: workItems.listUpdateSuggestions(item.id, status)
837
+ });
838
+ });
839
+ authenticated.post("/api/work-items/:id/update-suggestions", async (c) => {
840
+ const item = workItems.getWorkItem(c.req.param("id"));
841
+ if (!item) return c.json({
842
+ ok: false,
843
+ error: "Work item not found"
844
+ }, 404);
845
+ const body = await c.req.json().catch(() => ({}));
846
+ const sourceKind = parseEnumValue(body.sourceKind, [
847
+ "chat",
848
+ "goal",
849
+ "workflow_run",
850
+ "automation"
851
+ ]);
852
+ const sourceId = textField(body, "sourceId")?.trim();
853
+ if (!sourceKind) return c.json({
854
+ ok: false,
855
+ error: "Invalid sourceKind"
856
+ }, 400);
857
+ if (!sourceId) return c.json({
858
+ ok: false,
859
+ error: "sourceId is required"
860
+ }, 400);
861
+ const patchBody = body.patch && typeof body.patch === "object" && !Array.isArray(body.patch) ? body.patch : {};
862
+ const status = Object.hasOwn(patchBody, "status") ? parseEnumValue(patchBody.status, WORK_ITEM_STATUSES) : void 0;
863
+ if (Object.hasOwn(patchBody, "status") && !status) return c.json({
864
+ ok: false,
865
+ error: "Invalid work item status"
866
+ }, 400);
867
+ const confidence = typeof body.confidence === "number" && Number.isFinite(body.confidence) ? Math.max(0, Math.min(1, body.confidence)) : void 0;
868
+ const suggestion = workItems.createUpdateSuggestion(item.id, {
869
+ sourceKind,
870
+ sourceId,
871
+ patch: {
872
+ ...Object.hasOwn(patchBody, "status") ? { status } : {},
873
+ ...Object.hasOwn(patchBody, "nextAction") ? { nextAction: optionalTextField(patchBody, "nextAction") } : {},
874
+ ...Object.hasOwn(patchBody, "blockedReason") ? { blockedReason: optionalTextField(patchBody, "blockedReason") } : {}
875
+ },
876
+ progressNote: optionalTextField(body, "progressNote") ?? void 0,
877
+ rationale: optionalTextField(body, "rationale") ?? void 0,
878
+ confidence
879
+ });
880
+ if (!suggestion) return c.json({
881
+ ok: false,
882
+ error: "Work item not found"
883
+ }, 404);
884
+ return c.json({
885
+ ok: true,
886
+ suggestion
887
+ }, 201);
888
+ });
889
+ authenticated.post("/api/work-item-update-suggestions/:id/apply", async (c) => {
890
+ const result = workItems.applyUpdateSuggestion(c.req.param("id"));
891
+ if (!result) return c.json({
892
+ ok: false,
893
+ error: "Suggestion not found or already resolved"
894
+ }, 404);
895
+ return c.json({
896
+ ok: true,
897
+ item: result.item,
898
+ suggestion: result.suggestion
899
+ });
900
+ });
901
+ authenticated.post("/api/work-item-update-suggestions/:id/dismiss", async (c) => {
902
+ const suggestion = workItems.dismissUpdateSuggestion(c.req.param("id"));
903
+ if (!suggestion) return c.json({
904
+ ok: false,
905
+ error: "Suggestion not found or already resolved"
906
+ }, 404);
907
+ return c.json({
908
+ ok: true,
909
+ suggestion
910
+ });
911
+ });
912
+ authenticated.post("/api/work-items/:id/start-chat", async (c) => {
913
+ const item = workItems.getWorkItem(c.req.param("id"));
914
+ if (!item) return c.json({
915
+ ok: false,
916
+ error: "Work item not found"
917
+ }, 404);
918
+ const project = service.projects.get(item.projectId);
919
+ if (!project) return c.json({
920
+ ok: false,
921
+ error: "Project not found"
922
+ }, 404);
923
+ const agentId = resolveProjectAgentId({
924
+ config: service.currentConfig,
925
+ projects: service.projects,
926
+ explicitAgentId: item.ownerAgentId,
927
+ projectId: project.id
928
+ });
929
+ const peerId = `work_item_${Date.now()}`;
930
+ const sessionKey = buildSessionKey({
931
+ agentId,
932
+ source: "webchat",
933
+ accountId: "default",
934
+ peerKind: "direct",
935
+ peerId
936
+ });
937
+ await service.sessionIndexInstance.saveMessages(sessionKey, [], { metadata: buildWorkItemChatSessionMetadata({
938
+ agentId,
939
+ accountId: "default",
940
+ peerId,
941
+ workItemId: item.id,
942
+ title: item.title,
943
+ updatedAt: item.updatedAt
944
+ }) });
945
+ service.projects.attachSession(sessionKey, project.id);
946
+ const session = await service.sessions.getSession(sessionKey);
947
+ workItems.addLink(item.id, {
948
+ kind: "chat",
949
+ targetId: sessionKey,
950
+ title: session?.name || item.title,
951
+ statusSnapshot: session?.status
952
+ }, "chat_started");
953
+ const updated = item.status === "todo" || item.status === "backlog" ? workItems.updateWorkItem(item.id, { status: "in_progress" }) : workItems.getWorkItem(item.id);
954
+ return c.json({
955
+ ok: true,
956
+ session,
957
+ item: updated
958
+ }, 201);
959
+ });
960
+ authenticated.post("/api/work-items/:id/create-goal", async (c) => {
961
+ const item = workItems.getWorkItem(c.req.param("id"));
962
+ if (!item) return c.json({
963
+ ok: false,
964
+ error: "Work item not found"
965
+ }, 404);
966
+ const project = service.projects.get(item.projectId);
967
+ if (!project) return c.json({
968
+ ok: false,
969
+ error: "Project not found"
970
+ }, 404);
971
+ const attachments = await workItems.snapshotAttachmentsForGoal(item.id);
972
+ if (!attachments) return c.json({
973
+ ok: false,
974
+ error: "Work item not found"
975
+ }, 404);
976
+ const context = await buildWorkItemAgentContext(item, {
977
+ attachments,
978
+ includeImages: false
979
+ });
980
+ const goal = goals.create({
981
+ title: item.title,
982
+ description: item.description || item.nextAction,
983
+ priority: item.priority === "urgent" ? "high" : item.priority,
984
+ agentId: item.ownerAgentId || project.defaultAgentId || void 0,
985
+ projectId: project.id,
986
+ source: "api",
987
+ config: service.currentConfig
988
+ });
989
+ const goalWithContext = goals.setContextMessage({
990
+ goalId: goal.id,
991
+ text: context.text,
992
+ attachments
993
+ }) ?? goal;
994
+ workItems.addLink(item.id, {
995
+ kind: "goal",
996
+ targetId: goal.id,
997
+ title: goal.title,
998
+ statusSnapshot: goal.status
999
+ }, "goal_created");
1000
+ const updated = item.status === "todo" || item.status === "backlog" ? workItems.updateWorkItem(item.id, { status: "in_progress" }) : workItems.getWorkItem(item.id);
1001
+ return c.json({
1002
+ ok: true,
1003
+ goal: goalWithContext,
1004
+ item: updated
1005
+ }, 201);
1006
+ });
301
1007
  authenticated.post("/api/projects/:id/digest-memory", async (c) => {
302
1008
  const project = service.projects.getWithDetails(c.req.param("id"));
303
1009
  if (!project) return c.json({
@@ -388,7 +1094,7 @@ function registerProjectsRoutes(authenticated, deps) {
388
1094
  }, 404);
389
1095
  return c.json({
390
1096
  ok: true,
391
- project
1097
+ project: enrichProjectWorkspace(service, project)
392
1098
  });
393
1099
  });
394
1100
  authenticated.patch("/api/projects/:id", async (c) => {
@@ -413,7 +1119,7 @@ function registerProjectsRoutes(authenticated, deps) {
413
1119
  });
414
1120
  return c.json({
415
1121
  ok: true,
416
- project
1122
+ project: enrichProjectWorkspace(service, project)
417
1123
  });
418
1124
  } catch (error) {
419
1125
  if (error instanceof ProjectWorkspaceConflictError) return c.json({
@@ -444,7 +1150,7 @@ function registerProjectsRoutes(authenticated, deps) {
444
1150
  const sessions = await Promise.all(keys.map((key) => service.sessions.getSession(key)));
445
1151
  return c.json({
446
1152
  ok: true,
447
- sessions: sessions.filter(Boolean)
1153
+ sessions: sessions.filter((session) => session && !isHiddenEmptyProjectChatShell(session))
448
1154
  });
449
1155
  } catch (error) {
450
1156
  return c.json({
@@ -468,39 +1174,12 @@ function registerProjectsRoutes(authenticated, deps) {
468
1174
  }
469
1175
  });
470
1176
  authenticated.get("/api/projects/:id/files", async (c) => {
471
- const project = service.projects.get(c.req.param("id"));
472
- if (!project) return c.json({
473
- ok: false,
474
- error: "Project not found"
475
- }, 404);
476
- if (!project.workspaceRoot?.trim()) return c.json({
477
- ok: false,
478
- error: "Project workspace root is not set"
479
- }, 400);
480
- let root;
481
- try {
482
- root = await realpath(project.workspaceRoot);
483
- if (!(await stat(root)).isDirectory()) return c.json({
484
- ok: false,
485
- error: "Project workspace root is not a directory"
486
- }, 400);
487
- } catch (err) {
488
- log.warn({
489
- err,
490
- projectId: project.id,
491
- path: project.workspaceRoot
492
- }, "project workspace root unavailable");
493
- return c.json({
494
- ok: false,
495
- error: "Project workspace root is unavailable"
496
- }, 404);
497
- }
498
- const requestedPath = normalizeRelativePath(c.req.query("path"));
499
- const candidate = path$1.resolve(root, requestedPath);
500
- if (!isWithinDirectory(root, candidate)) return c.json({
1177
+ const resolved = await resolveProjectWorkspacePath(service, c.req.param("id"), c.req.query("path"));
1178
+ if (resolved.ok === false) return c.json({
501
1179
  ok: false,
502
- error: "Path is outside project workspace"
503
- }, 400);
1180
+ error: resolved.error
1181
+ }, resolved.status);
1182
+ const { root, absolutePath: candidate } = resolved;
504
1183
  let currentPath;
505
1184
  try {
506
1185
  currentPath = await realpath(candidate);
@@ -515,7 +1194,7 @@ function registerProjectsRoutes(authenticated, deps) {
515
1194
  } catch (err) {
516
1195
  log.warn({
517
1196
  err,
518
- projectId: project.id,
1197
+ projectId: resolved.projectId,
519
1198
  path: candidate
520
1199
  }, "project file path unavailable");
521
1200
  return c.json({
@@ -525,19 +1204,23 @@ function registerProjectsRoutes(authenticated, deps) {
525
1204
  }
526
1205
  try {
527
1206
  const dirents = await readdir(currentPath, { withFileTypes: true });
528
- const entries = await Promise.all(dirents.filter((entry) => !SKIP_FILE_NAMES.has(entry.name)).map(async (entry) => {
529
- const absolutePath = path$1.join(currentPath, entry.name);
1207
+ const visibleEntries = (await Promise.all(dirents.filter((entry) => !SKIP_FILE_NAMES.has(entry.name)).map(async (entry) => {
1208
+ const displayPath = path$1.join(currentPath, entry.name);
1209
+ const absolutePath = await realpath(displayPath).catch(() => null);
1210
+ if (!absolutePath || !isWithinDirectory(root, absolutePath)) return null;
530
1211
  const entryStat = await stat(absolutePath).catch(() => null);
531
- const relativePath = path$1.relative(root, absolutePath).split(path$1.sep).join("/");
1212
+ if (!entryStat) return null;
1213
+ const relativePath = path$1.relative(root, displayPath).split(path$1.sep).join("/");
532
1214
  return {
533
1215
  name: entry.name,
534
1216
  path: relativePath,
535
- type: entry.isDirectory() ? "directory" : "file",
1217
+ absolutePath,
1218
+ type: entryStat.isDirectory() ? "directory" : "file",
536
1219
  size: entryStat?.isFile() ? entryStat.size : void 0,
537
1220
  updatedAt: entryStat?.mtime.toISOString()
538
1221
  };
539
- }));
540
- entries.sort((left, right) => {
1222
+ }))).filter((entry) => entry !== null);
1223
+ visibleEntries.sort((left, right) => {
541
1224
  if (left.type !== right.type) return left.type === "directory" ? -1 : 1;
542
1225
  return left.name.localeCompare(right.name);
543
1226
  });
@@ -548,12 +1231,12 @@ function registerProjectsRoutes(authenticated, deps) {
548
1231
  root,
549
1232
  path: relativeCurrentPath === "." ? "" : relativeCurrentPath,
550
1233
  parentPath: parentRelativePath === "." ? "" : parentRelativePath,
551
- entries
1234
+ entries: visibleEntries
552
1235
  });
553
1236
  } catch (err) {
554
1237
  log.warn({
555
1238
  err,
556
- projectId: project.id,
1239
+ projectId: resolved.projectId,
557
1240
  path: currentPath
558
1241
  }, "project file list failed");
559
1242
  if (err?.code === "EACCES") return c.json({
@@ -566,6 +1249,176 @@ function registerProjectsRoutes(authenticated, deps) {
566
1249
  }, 500);
567
1250
  }
568
1251
  });
1252
+ authenticated.get("/api/projects/:id/files/read", async (c) => {
1253
+ const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param("id"), c.req.query("path"));
1254
+ if (resolved.ok === false) return c.json({
1255
+ ok: false,
1256
+ error: { message: resolved.error }
1257
+ }, resolved.status);
1258
+ if (!resolved.stat.isFile()) return c.json({
1259
+ ok: false,
1260
+ error: { message: "Not a file" }
1261
+ }, 400);
1262
+ try {
1263
+ const content = await readFile(resolved.absolutePath, "utf-8");
1264
+ return c.json({
1265
+ ok: true,
1266
+ payload: {
1267
+ content,
1268
+ path: resolved.relativePath,
1269
+ absolutePath: resolved.absolutePath,
1270
+ mtimeMs: resolved.stat.mtimeMs
1271
+ }
1272
+ });
1273
+ } catch {
1274
+ return c.json({
1275
+ ok: false,
1276
+ error: { message: "Read failed" }
1277
+ }, 500);
1278
+ }
1279
+ });
1280
+ authenticated.get("/api/projects/:id/files/raw", async (c) => {
1281
+ const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param("id"), c.req.query("path"));
1282
+ if (resolved.ok === false) return c.json({
1283
+ ok: false,
1284
+ error: { message: resolved.error }
1285
+ }, resolved.status);
1286
+ if (!resolved.stat.isFile()) return c.json({
1287
+ ok: false,
1288
+ error: { message: "Not a file" }
1289
+ }, 400);
1290
+ const contentType = PROJECT_FILE_MIME_BY_EXT[resolved.relativePath.split(".").pop()?.toLowerCase() ?? ""] || "application/octet-stream";
1291
+ try {
1292
+ const buf = await readFile(resolved.absolutePath);
1293
+ return new Response(buf, { headers: {
1294
+ "Content-Type": contentType,
1295
+ "Cache-Control": "private, max-age=3600"
1296
+ } });
1297
+ } catch {
1298
+ return c.json({
1299
+ ok: false,
1300
+ error: { message: "Read failed" }
1301
+ }, 500);
1302
+ }
1303
+ });
1304
+ authenticated.get("/api/projects/:id/files/resolve-reference", async (c) => {
1305
+ const rawPath = typeof c.req.query("path") === "string" ? c.req.query("path").trim() : "";
1306
+ if (!rawPath) return c.json({
1307
+ ok: false,
1308
+ error: {
1309
+ code: "INVALID_PATH",
1310
+ message: "Missing path"
1311
+ }
1312
+ }, 400);
1313
+ const resolved = await resolveProjectWorkspacePath(service, c.req.param("id"), rawPath);
1314
+ if (resolved.ok === false) return c.json({
1315
+ ok: false,
1316
+ error: {
1317
+ code: "PROJECT_WORKSPACE_RESOLUTION_FAILED",
1318
+ message: resolved.error
1319
+ }
1320
+ }, resolved.status);
1321
+ let st = null;
1322
+ let absolutePath = resolved.absolutePath;
1323
+ try {
1324
+ absolutePath = await realpath(resolved.absolutePath);
1325
+ if (!isWithinDirectory(resolved.root, absolutePath)) return c.json({
1326
+ ok: false,
1327
+ error: {
1328
+ code: "PROJECT_WORKSPACE_RESOLUTION_FAILED",
1329
+ message: "Path is outside project workspace"
1330
+ }
1331
+ }, 400);
1332
+ st = await stat(absolutePath);
1333
+ } catch {
1334
+ st = null;
1335
+ }
1336
+ const displayName = path$1.basename(rawPath);
1337
+ if (!st) return c.json({
1338
+ ok: true,
1339
+ payload: {
1340
+ inputPath: rawPath,
1341
+ displayName,
1342
+ scope: "missing",
1343
+ exists: false,
1344
+ absolutePath: resolved.absolutePath,
1345
+ capabilities: ["copyPath"],
1346
+ errorCode: "FILE_NOT_FOUND"
1347
+ }
1348
+ });
1349
+ return c.json({
1350
+ ok: true,
1351
+ payload: {
1352
+ inputPath: rawPath,
1353
+ displayName,
1354
+ scope: "workspace",
1355
+ exists: true,
1356
+ isDirectory: st.isDirectory(),
1357
+ absolutePath,
1358
+ workspaceRelativePath: resolved.relativePath,
1359
+ capabilities: st.isDirectory() ? [
1360
+ "openExternal",
1361
+ "revealInFolder",
1362
+ "copyPath"
1363
+ ] : [
1364
+ "preview",
1365
+ "edit",
1366
+ "openExternal",
1367
+ "revealInFolder",
1368
+ "copyPath"
1369
+ ],
1370
+ mtimeMs: st.mtimeMs
1371
+ }
1372
+ });
1373
+ });
1374
+ authenticated.put("/api/projects/:id/files/write", async (c) => {
1375
+ let body;
1376
+ try {
1377
+ body = await c.req.json();
1378
+ } catch {
1379
+ return c.json({
1380
+ ok: false,
1381
+ error: { message: "Invalid JSON" }
1382
+ }, 400);
1383
+ }
1384
+ const bodyRecord = typeof body === "object" && body !== null ? body : {};
1385
+ const pathRel = typeof bodyRecord.path === "string" ? bodyRecord.path : "";
1386
+ const content = typeof bodyRecord.content === "string" ? bodyRecord.content : "";
1387
+ if (!pathRel.trim()) return c.json({
1388
+ ok: false,
1389
+ error: { message: "Missing path" }
1390
+ }, 400);
1391
+ const resolved = await resolveProjectWorkspaceWritePath(service, c.req.param("id"), pathRel);
1392
+ if (resolved.ok === false) return c.json({
1393
+ ok: false,
1394
+ error: { message: resolved.error }
1395
+ }, resolved.status);
1396
+ if (resolved.existingStat && !resolved.existingStat.isFile()) return c.json({
1397
+ ok: false,
1398
+ error: { message: "Not a file" }
1399
+ }, 400);
1400
+ try {
1401
+ await writeFile(resolved.absolutePath, content, "utf-8");
1402
+ const mtimeMs = (await stat(resolved.absolutePath).catch(() => ({ mtimeMs: Date.now() }))).mtimeMs;
1403
+ return c.json({
1404
+ ok: true,
1405
+ payload: {
1406
+ path: resolved.relativePath,
1407
+ mtimeMs
1408
+ }
1409
+ });
1410
+ } catch (err) {
1411
+ log.error({
1412
+ err,
1413
+ projectId: resolved.projectId,
1414
+ path: resolved.absolutePath
1415
+ }, "project file write failed");
1416
+ return c.json({
1417
+ ok: false,
1418
+ error: { message: "Write failed" }
1419
+ }, 500);
1420
+ }
1421
+ });
569
1422
  authenticated.post("/api/projects/:id/sessions/:sessionKey", async (c) => {
570
1423
  try {
571
1424
  service.projects.attachSession(c.req.param("sessionKey"), c.req.param("id"));