@xopcai/xopc 0.0.124 → 0.0.125

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 (304) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/Combination-BzaXOLd9.js +41 -0
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B5uSVAyJ.js → agent-avatar-dicebear-BKDKICZV.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-BnTB7-c5.js +2 -0
  6. package/dist/gateway/static/root/assets/app-management-settings-panel-DI4BqHKW.js +1 -0
  7. package/dist/gateway/static/root/assets/appearance-settings-6_ie3NQ4.js +1 -0
  8. package/dist/gateway/static/root/assets/apps-page-B6bG65SW.js +1 -0
  9. package/dist/gateway/static/root/assets/{archive-plugin-CXUGRp2i.js → archive-plugin-kUHEJ1HK.js} +1 -1
  10. package/dist/gateway/static/root/assets/{attachment-load-Cmiub3Wg.js → attachment-load-Dm-9prpU.js} +1 -1
  11. package/dist/gateway/static/root/assets/automation-suggestion-card-OTxQTPnC.js +1 -0
  12. package/dist/gateway/static/root/assets/automations-page-1lVbo0dS.js +1 -0
  13. package/dist/gateway/static/root/assets/{binary-plugins-0Izz-N3p.js → binary-plugins-DllA_jQ0.js} +1 -1
  14. package/dist/gateway/static/root/assets/{block-editor-C1Kv0IkJ.js → block-editor-Cm6CWNj1.js} +6 -6
  15. package/dist/gateway/static/root/assets/browser-settings-page-CzDBlOK0.js +8 -0
  16. package/dist/gateway/static/root/assets/capability-presets-api-VJ89b6I2.js +1 -0
  17. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BaPj8wC2.js +1 -0
  18. package/dist/gateway/static/root/assets/{channel-recipient-api-BeA2aVor.js → channel-recipient-api-B5PwBEUx.js} +1 -1
  19. package/dist/gateway/static/root/assets/channels-settings-Df4m7p1k.js +1 -0
  20. package/dist/gateway/static/root/assets/code-editor-gbRgS14t.js +1 -0
  21. package/dist/gateway/static/root/assets/connectors-page-BMTphmHS.js +2 -0
  22. package/dist/gateway/static/root/assets/{directory-picker-path-field-2rjzUu57.js → directory-picker-path-field-DySMzOF6.js} +1 -1
  23. package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
  24. package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
  25. package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
  26. package/dist/gateway/static/root/assets/dreaming-settings-D_AjSnV_.js +3 -0
  27. package/dist/gateway/static/root/assets/extension-debug-page-BaM0FpW7.js +1 -0
  28. package/dist/gateway/static/root/assets/extension-page-DuZWVOGA.js +1 -0
  29. package/dist/gateway/static/root/assets/extension-settings-page-DarVtbmJ.js +1 -0
  30. package/dist/gateway/static/root/assets/{fetch-BU5S0Sn7.js → fetch-NFKfkqrd.js} +1 -1
  31. package/dist/gateway/static/root/assets/{gateway-config-api-BIPGwrl1.js → gateway-config-api-CFEm9rgy.js} +1 -1
  32. package/dist/gateway/static/root/assets/gateway-settings-BMk2S5td.js +1 -0
  33. package/dist/gateway/static/root/assets/{gateway-startup-retry-Cd0Zz30N.js → gateway-startup-retry-Dtwh_yGg.js} +1 -1
  34. package/dist/gateway/static/root/assets/goal-create-dialog-BKP7ylcG.js +1 -0
  35. package/dist/gateway/static/root/assets/goal-detail-page-C2cTxf71.js +1 -0
  36. package/dist/gateway/static/root/assets/{goals-config-api-B95KdGMj.js → goals-config-api-DTWZNA_Y.js} +1 -1
  37. package/dist/gateway/static/root/assets/goals-page-CTmA3hWK.js +2 -0
  38. package/dist/gateway/static/root/assets/goals-settings-Bhct0ZT-.js +1 -0
  39. package/dist/gateway/static/root/assets/heartbeat-settings-C-UxSU4a.js +1 -0
  40. package/dist/gateway/static/root/assets/{html-workspace-editor-CQLWDiwE.js → html-workspace-editor-DV90ddkE.js} +1 -1
  41. package/dist/gateway/static/root/assets/index-BNHDd2j1.css +1 -0
  42. package/dist/gateway/static/root/assets/index-BPXLPMuY.js +193 -0
  43. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-DCjy2y4d.js +1 -0
  44. package/dist/gateway/static/root/assets/logs-page-CGc3_CQU.js +2 -0
  45. package/dist/gateway/static/root/assets/{markdown-editor-AssmZFx4.js → markdown-editor-BFOjBBla.js} +2 -2
  46. package/dist/gateway/static/root/assets/markdown-split-BaqxP-GQ.js +1 -0
  47. package/dist/gateway/static/root/assets/{media-plugins-BhIQU5yS.js → media-plugins-DQ_EXloK.js} +1 -1
  48. package/dist/gateway/static/root/assets/messages-CjuIJcZl.js +3 -0
  49. package/dist/gateway/static/root/assets/models-hub-panel-Drz4UQMb.js +2 -0
  50. package/dist/gateway/static/root/assets/notes-page-CY1ylng1.js +1 -0
  51. package/dist/gateway/static/root/assets/notes-workbench-X7IaD--t.js +2 -0
  52. package/dist/gateway/static/root/assets/page-tabs-EIZhLppK.js +1 -0
  53. package/dist/gateway/static/root/assets/{preview-open-alternatives-DGzet1d7.js → preview-open-alternatives-r_uB4Epr.js} +1 -1
  54. package/dist/gateway/static/root/assets/project-detail-page-DE5adRBE.js +1 -0
  55. package/dist/gateway/static/root/assets/projects-page-CuOb1k6F.js +1 -0
  56. package/dist/gateway/static/root/assets/remote-access-hub-BOxNrUVA.js +1 -0
  57. package/dist/gateway/static/root/assets/{save-bar-controls-Cqgb-jqa.js → save-bar-controls-B132Uf-2.js} +1 -1
  58. package/dist/gateway/static/root/assets/{schedule-field-DVZcI8Yt.js → schedule-field-B5qshALm.js} +1 -1
  59. package/dist/gateway/static/root/assets/{schema-form-Bj7sOxC8.js → schema-form-CvLmkdS9.js} +1 -1
  60. package/dist/gateway/static/root/assets/sessions-page-CY0IQcGW.js +1 -0
  61. package/dist/gateway/static/root/assets/settings-advanced-gate-D4NBNVCB.js +1 -0
  62. package/dist/gateway/static/root/assets/{settings-collapsible-section-BmXn-8N6.js → settings-collapsible-section-pRlvqsAf.js} +1 -1
  63. package/dist/gateway/static/root/assets/{settings-form-section-BnqYMWHR.js → settings-form-section-BBYUDLVd.js} +1 -1
  64. package/dist/gateway/static/root/assets/settings-page-DaO7zYZM.js +1 -0
  65. package/dist/gateway/static/root/assets/{settings-page-layout-CdWZU1hd.js → settings-page-layout-D8g9PAek.js} +1 -1
  66. package/dist/gateway/static/root/assets/setup-status-panel-Bks0CLLT.js +1 -0
  67. package/dist/gateway/static/root/assets/{share-preview-page-IB1v8i86.js → share-preview-page-v6-IOp8t.js} +1 -1
  68. package/dist/gateway/static/root/assets/shares-settings-CEZsKm9r.js +1 -0
  69. package/dist/gateway/static/root/assets/skill-reload-api-oTkHbb9W.js +1 -0
  70. package/dist/gateway/static/root/assets/skills-page-DigsbZ6K.js +2 -0
  71. package/dist/gateway/static/root/assets/{system-settings-panel-BxQ384RC.js → system-settings-panel-HUU2FFjM.js} +1 -1
  72. package/dist/gateway/static/root/assets/{typed-models-lib-BkcpvFYO.js → typed-models-lib-AH160QHh.js} +1 -1
  73. package/dist/gateway/static/root/assets/{use-channel-catalog-Cd0FaEQ4.js → use-channel-catalog-BXzDmjCQ.js} +1 -1
  74. package/dist/gateway/static/root/assets/{user-profile-settings-panel-DQ7NnRSY.js → user-profile-settings-panel-DxwnQvQ3.js} +1 -1
  75. package/dist/gateway/static/root/assets/{utils-YKhVf7Ka.js → utils-i5POEtqd.js} +1 -1
  76. package/dist/gateway/static/root/assets/{vendor-codemirror-CNP1wPe7.js → vendor-codemirror-BvNgyE1Q.js} +1 -1
  77. package/dist/gateway/static/root/assets/voice-api-key-field-CEJklEgb.js +1 -0
  78. package/dist/gateway/static/root/assets/work-item-detail-page-CD6FL_Rs.js +1 -0
  79. package/dist/gateway/static/root/assets/workflow-run-setup-panel-ClVVMgN-.js +3 -0
  80. package/dist/gateway/static/root/assets/{workflow-start-dialog-BNJVCWoS.js → workflow-start-dialog-Dv4ZA1T0.js} +1 -1
  81. package/dist/gateway/static/root/assets/workflows-page-OLQiUpoW.js +18 -0
  82. package/dist/gateway/static/root/index.html +8 -7
  83. package/dist/package.js +1 -1
  84. package/dist/src/agent/agent-manager.js +6 -2
  85. package/dist/src/agent/agent-manager.js.map +1 -1
  86. package/dist/src/agent/child-agent-factory.d.ts +2 -0
  87. package/dist/src/agent/child-agent-factory.js +2 -0
  88. package/dist/src/agent/child-agent-factory.js.map +1 -1
  89. package/dist/src/agent/coding/index.d.ts +1 -0
  90. package/dist/src/agent/coding/index.js +2 -0
  91. package/dist/src/agent/coding/turn-diff-tracker.d.ts +67 -0
  92. package/dist/src/agent/coding/turn-diff-tracker.js +233 -0
  93. package/dist/src/agent/coding/turn-diff-tracker.js.map +1 -0
  94. package/dist/src/agent/memory/dreaming/config.d.ts +2 -2
  95. package/dist/src/agent/memory/dreaming/config.js +3 -3
  96. package/dist/src/agent/memory/dreaming/config.js.map +1 -1
  97. package/dist/src/agent/memory/dreaming/constants.d.ts +1 -1
  98. package/dist/src/agent/memory/dreaming/constants.js +1 -1
  99. package/dist/src/agent/memory/dreaming/constants.js.map +1 -1
  100. package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +1 -0
  101. package/dist/src/agent/memory/dreaming/deep-promotion.js +11 -20
  102. package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
  103. package/dist/src/agent/memory/dreaming/events.d.ts +3 -3
  104. package/dist/src/agent/memory/dreaming/events.js +6 -6
  105. package/dist/src/agent/memory/dreaming/events.js.map +1 -1
  106. package/dist/src/agent/memory/dreaming/last-run.d.ts +2 -2
  107. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  108. package/dist/src/agent/memory/dreaming/last-run.js.map +1 -1
  109. package/dist/src/agent/memory/dreaming/light-sweep.d.ts +1 -1
  110. package/dist/src/agent/memory/dreaming/light-sweep.js +3 -3
  111. package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
  112. package/dist/src/agent/memory/dreaming/preview.d.ts +1 -0
  113. package/dist/src/agent/memory/dreaming/preview.js +2 -2
  114. package/dist/src/agent/memory/dreaming/preview.js.map +1 -1
  115. package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +1 -1
  116. package/dist/src/agent/memory/dreaming/rem-patterns.js +13 -13
  117. package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
  118. package/dist/src/agent/memory/dreaming/scope.d.ts +14 -0
  119. package/dist/src/agent/memory/dreaming/scope.js +27 -0
  120. package/dist/src/agent/memory/dreaming/scope.js.map +1 -0
  121. package/dist/src/agent/memory/dreaming/short-term-store.d.ts +4 -4
  122. package/dist/src/agent/memory/dreaming/short-term-store.js +17 -17
  123. package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
  124. package/dist/src/agent/orchestration/agent-event-handler.d.ts +2 -0
  125. package/dist/src/agent/orchestration/agent-event-handler.js +13 -0
  126. package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
  127. package/dist/src/agent/orchestration/agent-orchestrator.js +22 -12
  128. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  129. package/dist/src/agent/sandbox/command-validator.js +12 -0
  130. package/dist/src/agent/sandbox/command-validator.js.map +1 -1
  131. package/dist/src/agent/service.d.ts +2 -1
  132. package/dist/src/agent/service.js +18 -6
  133. package/dist/src/agent/service.js.map +1 -1
  134. package/dist/src/agent/session/session-inspector.d.ts +5 -3
  135. package/dist/src/agent/session/session-inspector.js +16 -7
  136. package/dist/src/agent/session/session-inspector.js.map +1 -1
  137. package/dist/src/agent/source-context/types.d.ts +1 -1
  138. package/dist/src/agent/source-context/types.js +1 -1
  139. package/dist/src/agent/source-context/types.js.map +1 -1
  140. package/dist/src/agent/tools/apply-patch.js +116 -62
  141. package/dist/src/agent/tools/apply-patch.js.map +1 -1
  142. package/dist/src/agent/tools/concurrency.d.ts +8 -0
  143. package/dist/src/agent/tools/concurrency.js +31 -0
  144. package/dist/src/agent/tools/concurrency.js.map +1 -0
  145. package/dist/src/agent/tools/dreaming-tool.d.ts +2 -0
  146. package/dist/src/agent/tools/dreaming-tool.js +13 -10
  147. package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
  148. package/dist/src/agent/tools/exec-command.js +4 -0
  149. package/dist/src/agent/tools/exec-command.js.map +1 -1
  150. package/dist/src/agent/tools/executor.d.ts +6 -4
  151. package/dist/src/agent/tools/executor.js +7 -4
  152. package/dist/src/agent/tools/executor.js.map +1 -1
  153. package/dist/src/agent/tools/factory.d.ts +3 -0
  154. package/dist/src/agent/tools/factory.js +7 -1
  155. package/dist/src/agent/tools/factory.js.map +1 -1
  156. package/dist/src/agent/tools/find.js +2 -0
  157. package/dist/src/agent/tools/find.js.map +1 -1
  158. package/dist/src/agent/tools/grep.js +2 -0
  159. package/dist/src/agent/tools/grep.js.map +1 -1
  160. package/dist/src/agent/tools/index.d.ts +2 -0
  161. package/dist/src/agent/tools/index.js +3 -1
  162. package/dist/src/agent/tools/list-dir.js +2 -0
  163. package/dist/src/agent/tools/list-dir.js.map +1 -1
  164. package/dist/src/agent/tools/memory-tool.d.ts +1 -0
  165. package/dist/src/agent/tools/memory-tool.js +2 -2
  166. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  167. package/dist/src/agent/tools/metadata.d.ts +15 -0
  168. package/dist/src/agent/tools/metadata.js +26 -0
  169. package/dist/src/agent/tools/metadata.js.map +1 -0
  170. package/dist/src/agent/tools/read.js +2 -0
  171. package/dist/src/agent/tools/read.js.map +1 -1
  172. package/dist/src/agent/tools/write.js +6 -0
  173. package/dist/src/agent/tools/write.js.map +1 -1
  174. package/dist/src/agent/workflow/subagent-runner.d.ts +1 -0
  175. package/dist/src/agent/workflow/subagent-runner.js +5 -1
  176. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  177. package/dist/src/agent/workflow/workflow-child-tools.js +5 -0
  178. package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -1
  179. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  180. package/dist/src/connectors/health.d.ts +2 -1
  181. package/dist/src/connectors/health.js +59 -1
  182. package/dist/src/connectors/health.js.map +1 -1
  183. package/dist/src/connectors/install.d.ts +1 -0
  184. package/dist/src/connectors/install.js +28 -1
  185. package/dist/src/connectors/install.js.map +1 -1
  186. package/dist/src/connectors/instances.js +7 -0
  187. package/dist/src/connectors/instances.js.map +1 -1
  188. package/dist/src/connectors/materialize.js +2 -1
  189. package/dist/src/connectors/materialize.js.map +1 -1
  190. package/dist/src/connectors/registries/modelscope.js +38 -13
  191. package/dist/src/connectors/registries/modelscope.js.map +1 -1
  192. package/dist/src/connectors/types.d.ts +2 -0
  193. package/dist/src/gateway/dreaming-automation-reconciler.d.ts +1 -0
  194. package/dist/src/gateway/dreaming-automation-reconciler.js +62 -42
  195. package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -1
  196. package/dist/src/gateway/hono/app.js +7 -1
  197. package/dist/src/gateway/hono/app.js.map +1 -1
  198. package/dist/src/gateway/hono/routes/connectors.js +46 -2
  199. package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
  200. package/dist/src/gateway/hono/routes/dreaming.js +111 -66
  201. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
  202. package/dist/src/gateway/hono/routes/projects.js +846 -43
  203. package/dist/src/gateway/hono/routes/projects.js.map +1 -1
  204. package/dist/src/gateway/hono/routes/sessions.js +1 -0
  205. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  206. package/dist/src/gateway/service.js +17 -8
  207. package/dist/src/gateway/service.js.map +1 -1
  208. package/dist/src/media/store.js +1 -1
  209. package/dist/src/media/store.js.map +1 -1
  210. package/dist/src/media/types.d.ts +1 -1
  211. package/dist/src/media/uri.js +2 -1
  212. package/dist/src/media/uri.js.map +1 -1
  213. package/dist/src/session/session-context-for-llm.d.ts +2 -0
  214. package/dist/src/session/session-context-for-llm.js +14 -1
  215. package/dist/src/session/session-context-for-llm.js.map +1 -1
  216. package/dist/src/session/store.js +2 -2
  217. package/dist/src/session/store.js.map +1 -1
  218. package/dist/src/storage/sqlite/migrations/022_work_items.sql +61 -0
  219. package/dist/src/storage/sqlite/migrations/023_work_item_attachments.sql +15 -0
  220. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  221. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  222. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  223. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  224. package/dist/src/storage/sqlite/schema.js +1 -1
  225. package/dist/src/storage/sqlite/schema.sql +78 -0
  226. package/dist/src/tui/components/assistant-message.js +12 -2
  227. package/dist/src/tui/components/assistant-message.js.map +1 -1
  228. package/dist/src/tui/components/tool-execution.d.ts +8 -0
  229. package/dist/src/tui/components/tool-execution.js +87 -77
  230. package/dist/src/tui/components/tool-execution.js.map +1 -1
  231. package/dist/src/tui/components/visual-truncate.d.ts +1 -0
  232. package/dist/src/tui/components/visual-truncate.js +28 -1
  233. package/dist/src/tui/components/visual-truncate.js.map +1 -1
  234. package/dist/src/tui/tool-summary.d.ts +22 -0
  235. package/dist/src/tui/tool-summary.js +212 -0
  236. package/dist/src/tui/tool-summary.js.map +1 -0
  237. package/dist/src/tui/tui-tool-diff.d.ts +15 -0
  238. package/dist/src/tui/tui-tool-diff.js +178 -7
  239. package/dist/src/tui/tui-tool-diff.js.map +1 -1
  240. package/dist/src/work-items/agent-context.d.ts +3 -0
  241. package/dist/src/work-items/agent-context.js +39 -0
  242. package/dist/src/work-items/agent-context.js.map +1 -0
  243. package/dist/src/work-items/index.d.ts +4 -0
  244. package/dist/src/work-items/index.js +4 -0
  245. package/dist/src/work-items/types.d.ts +112 -0
  246. package/dist/src/work-items/types.js +1 -0
  247. package/dist/src/work-items/work-item-service.d.ts +33 -0
  248. package/dist/src/work-items/work-item-service.js +180 -0
  249. package/dist/src/work-items/work-item-service.js.map +1 -0
  250. package/dist/src/work-items/work-item-store.d.ts +21 -0
  251. package/dist/src/work-items/work-item-store.js +302 -0
  252. package/dist/src/work-items/work-item-store.js.map +1 -0
  253. package/dist/src/workflows/service/workflow-run-service.js +4 -3
  254. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  255. package/dist/src/workflows/service/workflow-session-bridge.js +3 -0
  256. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  257. package/package.json +1 -1
  258. package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
  259. package/dist/gateway/static/root/assets/agents-BjIxt67Z.js +0 -2
  260. package/dist/gateway/static/root/assets/app-management-settings-panel-CYCONLIL.js +0 -1
  261. package/dist/gateway/static/root/assets/appearance-settings-Clw3ryKg.js +0 -1
  262. package/dist/gateway/static/root/assets/apps-page-QICTeGjX.js +0 -1
  263. package/dist/gateway/static/root/assets/automation-suggestion-card-CU0-4nQ-.js +0 -1
  264. package/dist/gateway/static/root/assets/automations-page-Car-jtiz.js +0 -1
  265. package/dist/gateway/static/root/assets/browser-settings-page-CMeBJzlS.js +0 -8
  266. package/dist/gateway/static/root/assets/capability-presets-api-BmQTM9Il.js +0 -1
  267. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DZEJEoCF.js +0 -1
  268. package/dist/gateway/static/root/assets/channels-settings-kkW-xFau.js +0 -1
  269. package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +0 -1
  270. package/dist/gateway/static/root/assets/connectors-page-BvaQvO5F.js +0 -2
  271. package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +0 -1
  272. package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +0 -1
  273. package/dist/gateway/static/root/assets/dreaming-settings-DnHO686d.js +0 -1
  274. package/dist/gateway/static/root/assets/extension-debug-page-BGLRuWVN.js +0 -1
  275. package/dist/gateway/static/root/assets/extension-page-D978ePp9.js +0 -1
  276. package/dist/gateway/static/root/assets/extension-settings-page-B6Ih4Swx.js +0 -1
  277. package/dist/gateway/static/root/assets/gateway-settings-CMEA3r5u.js +0 -1
  278. package/dist/gateway/static/root/assets/goal-create-dialog-B-KHKeXN.js +0 -1
  279. package/dist/gateway/static/root/assets/goal-detail-page-BxrSoWdj.js +0 -1
  280. package/dist/gateway/static/root/assets/goals-page-BTJzIl28.js +0 -2
  281. package/dist/gateway/static/root/assets/goals-settings-BJyEuLLm.js +0 -1
  282. package/dist/gateway/static/root/assets/heartbeat-settings-wkOjYNQT.js +0 -1
  283. package/dist/gateway/static/root/assets/index-BLaXr6Ev.css +0 -1
  284. package/dist/gateway/static/root/assets/index-c_9TVr_C.js +0 -191
  285. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-BT8T4DyC.js +0 -1
  286. package/dist/gateway/static/root/assets/logs-page-CrxBJUgI.js +0 -2
  287. package/dist/gateway/static/root/assets/markdown-split-Dv66bO2b.js +0 -1
  288. package/dist/gateway/static/root/assets/messages-O6TAtdFC.js +0 -3
  289. package/dist/gateway/static/root/assets/models-hub-panel-DOOpz6y1.js +0 -2
  290. package/dist/gateway/static/root/assets/notes-page-Br16pK9v.js +0 -1
  291. package/dist/gateway/static/root/assets/notes-workbench-PSJAi0ZC.js +0 -2
  292. package/dist/gateway/static/root/assets/project-detail-page-CIGGgKuw.js +0 -1
  293. package/dist/gateway/static/root/assets/projects-page-B2grhsBt.js +0 -1
  294. package/dist/gateway/static/root/assets/remote-access-hub-CXMORxBD.js +0 -1
  295. package/dist/gateway/static/root/assets/sessions-page-Bi2wkBzU.js +0 -1
  296. package/dist/gateway/static/root/assets/settings-advanced-gate-B1L3G4IA.js +0 -1
  297. package/dist/gateway/static/root/assets/settings-page-BfRSHJmO.js +0 -1
  298. package/dist/gateway/static/root/assets/setup-status-panel-CWtPM7RK.js +0 -1
  299. package/dist/gateway/static/root/assets/shares-settings-ngbsBgij.js +0 -1
  300. package/dist/gateway/static/root/assets/skill-reload-api-BIe442Gv.js +0 -1
  301. package/dist/gateway/static/root/assets/skills-page-BfchZRVa.js +0 -2
  302. package/dist/gateway/static/root/assets/voice-api-key-field-C5Ov8Uk_.js +0 -1
  303. package/dist/gateway/static/root/assets/workflow-run-setup-panel-BYD9BtOq.js +0 -3
  304. package/dist/gateway/static/root/assets/workflows-page-BYF29ANm.js +0 -18
@@ -1,3 +1,4 @@
1
+ import { buildSessionKey, init_session_key } from "../../../routing/session-key.js";
1
2
  import { getSqliteDatabase } from "../../../storage/sqlite/transaction.js";
2
3
  import { GoalService } from "../../../goals/goal-service.js";
3
4
  import "../../../goals/index.js";
@@ -11,10 +12,14 @@ import { inferProjectKind } from "../../../projects/project-kind.js";
11
12
  import { inferSuggestedProjectDefaultAgentId } from "../../../projects/project-agent-suggestion.js";
12
13
  import { buildProjectLoopOverview } from "../../../projects/project-loop.js";
13
14
  import "../../../projects/index.js";
15
+ import { WORK_ITEM_ATTACHMENT_MAX_BYTES, WorkItemService } from "../../../work-items/work-item-service.js";
16
+ import { buildWorkItemAgentContext } from "../../../work-items/agent-context.js";
17
+ import "../../../work-items/index.js";
14
18
  import { createGatewayRouteLogger } from "../lib/route-logger.js";
15
19
  import * as path$1 from "node:path";
16
- import { readdir, realpath, stat } from "node:fs/promises";
20
+ import { readFile, readdir, realpath, stat, writeFile } from "node:fs/promises";
17
21
  //#region src/gateway/hono/routes/projects.ts
22
+ init_session_key();
18
23
  const log = createGatewayRouteLogger("Projects");
19
24
  function parseProjectStatus(raw) {
20
25
  return raw === "active" || raw === "paused" || raw === "archived" ? raw : void 0;
@@ -24,6 +29,9 @@ function parseLimit(raw, fallback = 50) {
24
29
  const n = Number.parseInt(raw, 10);
25
30
  return Number.isFinite(n) ? Math.min(500, Math.max(1, n)) : fallback;
26
31
  }
32
+ function isHiddenEmptyProjectChatShell(session) {
33
+ return session.hiddenFromSessionList === true && session.messageCount === 0 && session.customData?.genericNewChatShell !== false && Boolean(session.routing?.peerId?.startsWith("chat_"));
34
+ }
27
35
  function textField(body, key) {
28
36
  const value = body[key];
29
37
  return typeof value === "string" ? value : void 0;
@@ -33,7 +41,87 @@ function optionalTextField(body, key) {
33
41
  const value = body[key];
34
42
  return typeof value === "string" ? value : null;
35
43
  }
44
+ function finiteNumberField(value) {
45
+ if (typeof value === "number" && Number.isFinite(value)) return value;
46
+ if (typeof value === "string" && value.trim()) {
47
+ const parsed = Number(value);
48
+ return Number.isFinite(parsed) ? parsed : void 0;
49
+ }
50
+ }
51
+ function collectUploadedFiles(body) {
52
+ const raw = body.file ?? body.files ?? body.attachments;
53
+ return (Array.isArray(raw) ? raw : raw ? [raw] : []).filter((value) => value instanceof File);
54
+ }
55
+ function validateUploadedWorkItemFiles(files) {
56
+ if (files.length > 10) return `Too many attachments (max 10)`;
57
+ 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`;
58
+ return null;
59
+ }
60
+ async function uploadedFileToBuffer(file) {
61
+ return {
62
+ name: file.name || "upload",
63
+ buffer: Buffer.from(await file.arrayBuffer()),
64
+ mimeType: file.type || "application/octet-stream"
65
+ };
66
+ }
67
+ function parseCsvEnum(raw, values) {
68
+ if (!raw) return void 0;
69
+ const allowed = new Set(values);
70
+ const parsed = raw.split(",").map((item) => item.trim()).filter((item) => allowed.has(item));
71
+ return parsed.length > 0 ? [...new Set(parsed)] : void 0;
72
+ }
73
+ function parseEnumValue(raw, values) {
74
+ if (typeof raw !== "string") return void 0;
75
+ return values.includes(raw) ? raw : void 0;
76
+ }
77
+ const WORK_ITEM_STATUSES = [
78
+ "backlog",
79
+ "todo",
80
+ "in_progress",
81
+ "blocked",
82
+ "needs_input",
83
+ "in_review",
84
+ "done",
85
+ "cancelled"
86
+ ];
87
+ const WORK_ITEM_PRIORITIES = [
88
+ "urgent",
89
+ "high",
90
+ "normal",
91
+ "low"
92
+ ];
93
+ const WORK_ITEM_SUGGESTION_STATUSES = [
94
+ "pending",
95
+ "applied",
96
+ "dismissed"
97
+ ];
36
98
  const SKIP_FILE_NAMES = new Set([".git", "node_modules"]);
99
+ const PROJECT_FILE_MIME_BY_EXT = {
100
+ png: "image/png",
101
+ jpg: "image/jpeg",
102
+ jpeg: "image/jpeg",
103
+ gif: "image/gif",
104
+ webp: "image/webp",
105
+ bmp: "image/bmp",
106
+ svg: "image/svg+xml",
107
+ pdf: "application/pdf",
108
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
109
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
110
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
111
+ txt: "text/plain",
112
+ md: "text/markdown",
113
+ json: "application/json",
114
+ html: "text/html",
115
+ css: "text/css",
116
+ js: "text/javascript",
117
+ ts: "text/typescript",
118
+ mp3: "audio/mpeg",
119
+ wav: "audio/wav",
120
+ ogg: "audio/ogg",
121
+ webm: "video/webm",
122
+ mp4: "video/mp4",
123
+ mov: "video/quicktime"
124
+ };
37
125
  function normalizeRelativePath(raw) {
38
126
  return (raw ?? "").trim().replaceAll("\\", "/").replace(/^\/+/, "");
39
127
  }
@@ -41,6 +129,136 @@ function isWithinDirectory(root, target) {
41
129
  const relativePath = path$1.relative(root, target);
42
130
  return relativePath === "" || !relativePath.startsWith("..") && !path$1.isAbsolute(relativePath);
43
131
  }
132
+ async function resolveProjectWorkspaceRoot(service, projectId) {
133
+ const project = service.projects.get(projectId);
134
+ if (!project) return {
135
+ ok: false,
136
+ status: 404,
137
+ error: "Project not found"
138
+ };
139
+ if (!project.workspaceRoot?.trim()) return {
140
+ ok: false,
141
+ status: 400,
142
+ error: "Project workspace root is not set"
143
+ };
144
+ try {
145
+ const root = await realpath(project.workspaceRoot);
146
+ if (!(await stat(root)).isDirectory()) return {
147
+ ok: false,
148
+ status: 400,
149
+ error: "Project workspace root is not a directory"
150
+ };
151
+ return {
152
+ ok: true,
153
+ projectId: project.id,
154
+ root
155
+ };
156
+ } catch (err) {
157
+ log.warn({
158
+ err,
159
+ projectId: project.id,
160
+ path: project.workspaceRoot
161
+ }, "project workspace root unavailable");
162
+ return {
163
+ ok: false,
164
+ status: 404,
165
+ error: "Project workspace root is unavailable"
166
+ };
167
+ }
168
+ }
169
+ async function resolveProjectWorkspacePath(service, projectId, rawPath) {
170
+ const rootResult = await resolveProjectWorkspaceRoot(service, projectId);
171
+ if (rootResult.ok === false) return {
172
+ ok: false,
173
+ status: rootResult.status,
174
+ error: rootResult.error
175
+ };
176
+ const requestedPath = normalizeRelativePath(rawPath);
177
+ const candidate = path$1.resolve(rootResult.root, requestedPath);
178
+ if (!isWithinDirectory(rootResult.root, candidate)) return {
179
+ ok: false,
180
+ status: 400,
181
+ error: "Path is outside project workspace"
182
+ };
183
+ const relativePath = path$1.relative(rootResult.root, candidate).split(path$1.sep).join("/");
184
+ return {
185
+ ok: true,
186
+ projectId: rootResult.projectId,
187
+ root: rootResult.root,
188
+ requestedPath,
189
+ absolutePath: candidate,
190
+ relativePath: relativePath === "." ? "" : relativePath
191
+ };
192
+ }
193
+ async function resolveExistingProjectWorkspacePath(service, projectId, rawPath) {
194
+ const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);
195
+ if (resolved.ok === false) return resolved;
196
+ if (!resolved.requestedPath.trim()) return {
197
+ ok: false,
198
+ status: 400,
199
+ error: "Missing path"
200
+ };
201
+ let realTarget;
202
+ try {
203
+ realTarget = await realpath(resolved.absolutePath);
204
+ } catch {
205
+ return {
206
+ ok: false,
207
+ status: 404,
208
+ error: "Not found"
209
+ };
210
+ }
211
+ if (!isWithinDirectory(resolved.root, realTarget)) return {
212
+ ok: false,
213
+ status: 400,
214
+ error: "Path is outside project workspace"
215
+ };
216
+ const targetStat = await stat(realTarget);
217
+ return {
218
+ ...resolved,
219
+ absolutePath: realTarget,
220
+ stat: targetStat
221
+ };
222
+ }
223
+ async function resolveProjectWorkspaceWritePath(service, projectId, rawPath) {
224
+ const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);
225
+ if (resolved.ok === false) return resolved;
226
+ if (!resolved.requestedPath.trim()) return {
227
+ ok: false,
228
+ status: 400,
229
+ error: "Missing path"
230
+ };
231
+ try {
232
+ const realTarget = await realpath(resolved.absolutePath);
233
+ if (!isWithinDirectory(resolved.root, realTarget)) return {
234
+ ok: false,
235
+ status: 400,
236
+ error: "Path is outside project workspace"
237
+ };
238
+ return {
239
+ ...resolved,
240
+ absolutePath: realTarget,
241
+ existingStat: await stat(realTarget)
242
+ };
243
+ } catch {
244
+ const parentPath = path$1.dirname(resolved.absolutePath);
245
+ try {
246
+ const realParent = await realpath(parentPath);
247
+ if (!isWithinDirectory(resolved.root, realParent)) return {
248
+ ok: false,
249
+ status: 400,
250
+ error: "Path is outside project workspace"
251
+ };
252
+ } catch {
253
+ return {
254
+ ok: false,
255
+ status: 404,
256
+ error: "Parent directory not found"
257
+ };
258
+ }
259
+ return resolved;
260
+ }
261
+ }
44
262
  function textFromTranscriptContent(content) {
45
263
  if (typeof content === "string") return content;
46
264
  if (!Array.isArray(content)) return "";
@@ -66,6 +284,36 @@ function buildSessionSummaryMemoryContent(sessionKey, explicitSummary) {
66
284
  }).filter(Boolean);
67
285
  return lines.length > 0 ? [`Session summary for ${sessionKey}:`, ...lines].join("\n") : `Session summary for ${sessionKey}: no transcript content available.`;
68
286
  }
287
+ function buildWorkItemChatSessionMetadata(params) {
288
+ return {
289
+ name: params.title,
290
+ tags: ["work-item"],
291
+ sourceChannel: "webchat",
292
+ sourceChatId: [
293
+ params.accountId,
294
+ "direct",
295
+ params.peerId
296
+ ].join(":"),
297
+ sessionType: "chat",
298
+ hiddenFromSessionList: true,
299
+ routing: {
300
+ agentId: params.agentId,
301
+ source: "webchat",
302
+ accountId: params.accountId,
303
+ peerKind: "direct",
304
+ peerId: params.peerId
305
+ },
306
+ customData: {
307
+ genericNewChatShell: false,
308
+ sourceBinding: {
309
+ kind: "work_item",
310
+ sourceId: params.workItemId,
311
+ version: String(params.updatedAt),
312
+ attachedAt: Date.now()
313
+ }
314
+ }
315
+ };
316
+ }
69
317
  function listFailedProjectWorkflowRuns(projectId, limit = 5) {
70
318
  return getSqliteDatabase().prepare(`SELECT run_id, definition_id, status, created_at_ms, error_message
71
319
  FROM workflow_runs
@@ -101,6 +349,7 @@ function projectDigestMemoryRecordId(projectId) {
101
349
  function registerProjectsRoutes(authenticated, deps) {
102
350
  const { service } = deps;
103
351
  const goals = new GoalService();
352
+ const workItems = new WorkItemService();
104
353
  authenticated.post("/api/projects", async (c) => {
105
354
  const body = await c.req.json().catch(() => ({}));
106
355
  const name = textField(body, "name")?.trim();
@@ -298,6 +547,413 @@ function registerProjectsRoutes(authenticated, deps) {
298
547
  }
299
548
  });
300
549
  });
550
+ authenticated.get("/api/projects/:id/work-items", async (c) => {
551
+ const project = service.projects.get(c.req.param("id"));
552
+ if (!project) return c.json({
553
+ ok: false,
554
+ error: "Project not found"
555
+ }, 404);
556
+ const result = workItems.listProjectWorkItems(project.id, {
557
+ status: parseCsvEnum(c.req.query("status"), WORK_ITEM_STATUSES),
558
+ priority: parseCsvEnum(c.req.query("priority"), WORK_ITEM_PRIORITIES),
559
+ includeArchived: c.req.query("includeArchived") === "true",
560
+ search: c.req.query("search"),
561
+ sortBy: c.req.query("sortBy"),
562
+ sortOrder: c.req.query("sortOrder"),
563
+ limit: parseLimit(c.req.query("limit")),
564
+ offset: c.req.query("offset") ? Math.max(0, Number.parseInt(c.req.query("offset"), 10) || 0) : void 0
565
+ });
566
+ return c.json({
567
+ ok: true,
568
+ ...result
569
+ });
570
+ });
571
+ authenticated.post("/api/projects/:id/work-items", async (c) => {
572
+ const project = service.projects.get(c.req.param("id"));
573
+ if (!project) return c.json({
574
+ ok: false,
575
+ error: "Project not found"
576
+ }, 404);
577
+ const contentType = c.req.header("content-type") || "";
578
+ let body;
579
+ let files = [];
580
+ if (contentType.includes("multipart/form-data")) {
581
+ try {
582
+ body = await c.req.parseBody({ all: true });
583
+ } catch {
584
+ return c.json({
585
+ ok: false,
586
+ error: "Invalid multipart body"
587
+ }, 400);
588
+ }
589
+ files = collectUploadedFiles(body);
590
+ } else body = await c.req.json().catch(() => ({}));
591
+ const attachmentError = validateUploadedWorkItemFiles(files);
592
+ if (attachmentError) return c.json({
593
+ ok: false,
594
+ error: attachmentError
595
+ }, 413);
596
+ const title = textField(body, "title")?.trim();
597
+ if (!title) return c.json({
598
+ ok: false,
599
+ error: "Work item title is required"
600
+ }, 400);
601
+ const status = parseEnumValue(body.status, WORK_ITEM_STATUSES);
602
+ const priority = parseEnumValue(body.priority, WORK_ITEM_PRIORITIES);
603
+ const dueAt = finiteNumberField(body.dueAt);
604
+ if (Object.hasOwn(body, "status") && !status) return c.json({
605
+ ok: false,
606
+ error: "Invalid work item status"
607
+ }, 400);
608
+ if (Object.hasOwn(body, "priority") && !priority) return c.json({
609
+ ok: false,
610
+ error: "Invalid work item priority"
611
+ }, 400);
612
+ if (Object.hasOwn(body, "dueAt") && dueAt === void 0 && body.dueAt !== null) return c.json({
613
+ ok: false,
614
+ error: "Invalid dueAt"
615
+ }, 400);
616
+ const uploads = [];
617
+ for (const file of files) uploads.push(await uploadedFileToBuffer(file));
618
+ const item = workItems.createProjectWorkItem(project.id, {
619
+ title,
620
+ description: textField(body, "description"),
621
+ status,
622
+ priority,
623
+ ownerAgentId: textField(body, "ownerAgentId") || project.defaultAgentId || void 0,
624
+ nextAction: textField(body, "nextAction"),
625
+ blockedReason: textField(body, "blockedReason"),
626
+ dueAt
627
+ });
628
+ for (const upload of uploads) await workItems.addAttachment(item.id, upload);
629
+ const created = files.length > 0 ? workItems.getWorkItem(item.id) ?? item : item;
630
+ return c.json({
631
+ ok: true,
632
+ item: created
633
+ }, 201);
634
+ });
635
+ authenticated.get("/api/work-items/:id", async (c) => {
636
+ const item = workItems.getWorkItem(c.req.param("id"));
637
+ if (!item) return c.json({
638
+ ok: false,
639
+ error: "Work item not found"
640
+ }, 404);
641
+ return c.json({
642
+ ok: true,
643
+ item
644
+ });
645
+ });
646
+ authenticated.get("/api/work-items/:id/attachments", async (c) => {
647
+ const attachments = workItems.listAttachments(c.req.param("id"));
648
+ if (!attachments) return c.json({
649
+ ok: false,
650
+ error: "Work item not found"
651
+ }, 404);
652
+ return c.json({
653
+ ok: true,
654
+ attachments
655
+ });
656
+ });
657
+ authenticated.post("/api/work-items/:id/attachments", async (c) => {
658
+ const item = workItems.getWorkItem(c.req.param("id"));
659
+ if (!item) return c.json({
660
+ ok: false,
661
+ error: "Work item not found"
662
+ }, 404);
663
+ let body;
664
+ try {
665
+ body = await c.req.parseBody({ all: true });
666
+ } catch {
667
+ return c.json({
668
+ ok: false,
669
+ error: "Invalid multipart body"
670
+ }, 400);
671
+ }
672
+ const files = collectUploadedFiles(body);
673
+ if (!files.length) return c.json({
674
+ ok: false,
675
+ error: "Missing file field"
676
+ }, 400);
677
+ const attachmentError = validateUploadedWorkItemFiles(files);
678
+ if (attachmentError) return c.json({
679
+ ok: false,
680
+ error: attachmentError
681
+ }, 413);
682
+ const attachments = [];
683
+ for (const file of files) {
684
+ const upload = await uploadedFileToBuffer(file);
685
+ const attachment = await workItems.addAttachment(item.id, upload);
686
+ if (attachment) attachments.push(attachment);
687
+ }
688
+ return c.json({
689
+ ok: true,
690
+ attachments,
691
+ item: workItems.getWorkItem(item.id)
692
+ }, 201);
693
+ });
694
+ authenticated.get("/api/work-items/:id/attachments/:attachmentId/content", async (c) => {
695
+ const result = await workItems.readAttachment(c.req.param("id"), c.req.param("attachmentId"));
696
+ if (!result) return c.json({
697
+ ok: false,
698
+ error: "Attachment not found"
699
+ }, 404);
700
+ return new Response(result.buffer, { headers: {
701
+ "Content-Type": result.attachment.mimeType,
702
+ "Content-Length": String(result.attachment.size),
703
+ "Content-Disposition": `inline; filename="${encodeURIComponent(result.attachment.fileName)}"`,
704
+ "Cache-Control": "private, max-age=31536000, immutable"
705
+ } });
706
+ });
707
+ authenticated.delete("/api/work-items/:id/attachments/:attachmentId", async (c) => {
708
+ const attachment = await workItems.removeAttachment(c.req.param("id"), c.req.param("attachmentId"));
709
+ if (!attachment) return c.json({
710
+ ok: false,
711
+ error: "Attachment not found"
712
+ }, 404);
713
+ return c.json({
714
+ ok: true,
715
+ attachment,
716
+ item: workItems.getWorkItem(c.req.param("id"))
717
+ });
718
+ });
719
+ authenticated.patch("/api/work-items/:id", async (c) => {
720
+ const body = await c.req.json().catch(() => ({}));
721
+ const status = Object.hasOwn(body, "status") ? parseEnumValue(body.status, WORK_ITEM_STATUSES) : void 0;
722
+ const priority = Object.hasOwn(body, "priority") ? parseEnumValue(body.priority, WORK_ITEM_PRIORITIES) : void 0;
723
+ const dueAt = Object.hasOwn(body, "dueAt") ? body.dueAt === null ? null : typeof body.dueAt === "number" && Number.isFinite(body.dueAt) ? body.dueAt : void 0 : void 0;
724
+ const archivedAt = Object.hasOwn(body, "archivedAt") ? body.archivedAt === null ? null : typeof body.archivedAt === "number" && Number.isFinite(body.archivedAt) ? body.archivedAt : void 0 : void 0;
725
+ if (status === void 0 && Object.hasOwn(body, "status")) return c.json({
726
+ ok: false,
727
+ error: "Invalid work item status"
728
+ }, 400);
729
+ if (priority === void 0 && Object.hasOwn(body, "priority")) return c.json({
730
+ ok: false,
731
+ error: "Invalid work item priority"
732
+ }, 400);
733
+ if (dueAt === void 0 && Object.hasOwn(body, "dueAt")) return c.json({
734
+ ok: false,
735
+ error: "Invalid dueAt"
736
+ }, 400);
737
+ if (archivedAt === void 0 && Object.hasOwn(body, "archivedAt")) return c.json({
738
+ ok: false,
739
+ error: "Invalid archivedAt"
740
+ }, 400);
741
+ const item = workItems.updateWorkItem(c.req.param("id"), {
742
+ ...Object.hasOwn(body, "title") ? { title: textField(body, "title") ?? "" } : {},
743
+ ...Object.hasOwn(body, "description") ? { description: optionalTextField(body, "description") } : {},
744
+ ...Object.hasOwn(body, "status") ? { status } : {},
745
+ ...Object.hasOwn(body, "priority") ? { priority } : {},
746
+ ...Object.hasOwn(body, "ownerAgentId") ? { ownerAgentId: optionalTextField(body, "ownerAgentId") } : {},
747
+ ...Object.hasOwn(body, "nextAction") ? { nextAction: optionalTextField(body, "nextAction") } : {},
748
+ ...Object.hasOwn(body, "blockedReason") ? { blockedReason: optionalTextField(body, "blockedReason") } : {},
749
+ ...Object.hasOwn(body, "dueAt") ? { dueAt } : {},
750
+ ...Object.hasOwn(body, "archivedAt") ? { archivedAt } : {}
751
+ });
752
+ if (!item) return c.json({
753
+ ok: false,
754
+ error: "Work item not found"
755
+ }, 404);
756
+ return c.json({
757
+ ok: true,
758
+ item
759
+ });
760
+ });
761
+ authenticated.delete("/api/work-items/:id", async (c) => {
762
+ const item = workItems.updateWorkItem(c.req.param("id"), { archivedAt: Date.now() });
763
+ if (!item) return c.json({
764
+ ok: false,
765
+ error: "Work item not found"
766
+ }, 404);
767
+ return c.json({
768
+ ok: true,
769
+ item
770
+ });
771
+ });
772
+ authenticated.get("/api/work-items/:id/events", async (c) => {
773
+ const item = workItems.getWorkItem(c.req.param("id"));
774
+ if (!item) return c.json({
775
+ ok: false,
776
+ error: "Work item not found"
777
+ }, 404);
778
+ return c.json({
779
+ ok: true,
780
+ events: workItems.listEvents(item.id)
781
+ });
782
+ });
783
+ authenticated.get("/api/work-items/:id/update-suggestions", async (c) => {
784
+ const item = workItems.getWorkItem(c.req.param("id"));
785
+ if (!item) return c.json({
786
+ ok: false,
787
+ error: "Work item not found"
788
+ }, 404);
789
+ const status = parseEnumValue(c.req.query("status"), WORK_ITEM_SUGGESTION_STATUSES);
790
+ if (c.req.query("status") && !status) return c.json({
791
+ ok: false,
792
+ error: "Invalid suggestion status"
793
+ }, 400);
794
+ return c.json({
795
+ ok: true,
796
+ suggestions: workItems.listUpdateSuggestions(item.id, status)
797
+ });
798
+ });
799
+ authenticated.post("/api/work-items/:id/update-suggestions", async (c) => {
800
+ const item = workItems.getWorkItem(c.req.param("id"));
801
+ if (!item) return c.json({
802
+ ok: false,
803
+ error: "Work item not found"
804
+ }, 404);
805
+ const body = await c.req.json().catch(() => ({}));
806
+ const sourceKind = parseEnumValue(body.sourceKind, [
807
+ "chat",
808
+ "goal",
809
+ "workflow_run",
810
+ "automation"
811
+ ]);
812
+ const sourceId = textField(body, "sourceId")?.trim();
813
+ if (!sourceKind) return c.json({
814
+ ok: false,
815
+ error: "Invalid sourceKind"
816
+ }, 400);
817
+ if (!sourceId) return c.json({
818
+ ok: false,
819
+ error: "sourceId is required"
820
+ }, 400);
821
+ const patchBody = body.patch && typeof body.patch === "object" && !Array.isArray(body.patch) ? body.patch : {};
822
+ const status = Object.hasOwn(patchBody, "status") ? parseEnumValue(patchBody.status, WORK_ITEM_STATUSES) : void 0;
823
+ if (Object.hasOwn(patchBody, "status") && !status) return c.json({
824
+ ok: false,
825
+ error: "Invalid work item status"
826
+ }, 400);
827
+ const confidence = typeof body.confidence === "number" && Number.isFinite(body.confidence) ? Math.max(0, Math.min(1, body.confidence)) : void 0;
828
+ const suggestion = workItems.createUpdateSuggestion(item.id, {
829
+ sourceKind,
830
+ sourceId,
831
+ patch: {
832
+ ...Object.hasOwn(patchBody, "status") ? { status } : {},
833
+ ...Object.hasOwn(patchBody, "nextAction") ? { nextAction: optionalTextField(patchBody, "nextAction") } : {},
834
+ ...Object.hasOwn(patchBody, "blockedReason") ? { blockedReason: optionalTextField(patchBody, "blockedReason") } : {}
835
+ },
836
+ progressNote: optionalTextField(body, "progressNote") ?? void 0,
837
+ rationale: optionalTextField(body, "rationale") ?? void 0,
838
+ confidence
839
+ });
840
+ if (!suggestion) return c.json({
841
+ ok: false,
842
+ error: "Work item not found"
843
+ }, 404);
844
+ return c.json({
845
+ ok: true,
846
+ suggestion
847
+ }, 201);
848
+ });
849
+ authenticated.post("/api/work-item-update-suggestions/:id/apply", async (c) => {
850
+ const result = workItems.applyUpdateSuggestion(c.req.param("id"));
851
+ if (!result) return c.json({
852
+ ok: false,
853
+ error: "Suggestion not found or already resolved"
854
+ }, 404);
855
+ return c.json({
856
+ ok: true,
857
+ item: result.item,
858
+ suggestion: result.suggestion
859
+ });
860
+ });
861
+ authenticated.post("/api/work-item-update-suggestions/:id/dismiss", async (c) => {
862
+ const suggestion = workItems.dismissUpdateSuggestion(c.req.param("id"));
863
+ if (!suggestion) return c.json({
864
+ ok: false,
865
+ error: "Suggestion not found or already resolved"
866
+ }, 404);
867
+ return c.json({
868
+ ok: true,
869
+ suggestion
870
+ });
871
+ });
872
+ authenticated.post("/api/work-items/:id/start-chat", async (c) => {
873
+ const item = workItems.getWorkItem(c.req.param("id"));
874
+ if (!item) return c.json({
875
+ ok: false,
876
+ error: "Work item not found"
877
+ }, 404);
878
+ const project = service.projects.get(item.projectId);
879
+ if (!project) return c.json({
880
+ ok: false,
881
+ error: "Project not found"
882
+ }, 404);
883
+ const agentId = resolveProjectAgentId({
884
+ config: service.currentConfig,
885
+ projects: service.projects,
886
+ explicitAgentId: item.ownerAgentId,
887
+ projectId: project.id
888
+ });
889
+ const peerId = `work_item_${Date.now()}`;
890
+ const sessionKey = buildSessionKey({
891
+ agentId,
892
+ source: "webchat",
893
+ accountId: "default",
894
+ peerKind: "direct",
895
+ peerId
896
+ });
897
+ await service.sessionIndexInstance.saveMessages(sessionKey, [], { metadata: buildWorkItemChatSessionMetadata({
898
+ agentId,
899
+ accountId: "default",
900
+ peerId,
901
+ workItemId: item.id,
902
+ title: item.title,
903
+ updatedAt: item.updatedAt
904
+ }) });
905
+ service.projects.attachSession(sessionKey, project.id);
906
+ const session = await service.sessions.getSession(sessionKey);
907
+ workItems.addLink(item.id, {
908
+ kind: "chat",
909
+ targetId: sessionKey,
910
+ title: session?.name || item.title,
911
+ statusSnapshot: session?.status
912
+ }, "chat_started");
913
+ const updated = item.status === "todo" || item.status === "backlog" ? workItems.updateWorkItem(item.id, { status: "in_progress" }) : workItems.getWorkItem(item.id);
914
+ return c.json({
915
+ ok: true,
916
+ session,
917
+ item: updated
918
+ }, 201);
919
+ });
920
+ authenticated.post("/api/work-items/:id/create-goal", async (c) => {
921
+ const item = workItems.getWorkItem(c.req.param("id"));
922
+ if (!item) return c.json({
923
+ ok: false,
924
+ error: "Work item not found"
925
+ }, 404);
926
+ const project = service.projects.get(item.projectId);
927
+ if (!project) return c.json({
928
+ ok: false,
929
+ error: "Project not found"
930
+ }, 404);
931
+ const goal = goals.create({
932
+ title: item.title,
933
+ description: item.description || item.nextAction,
934
+ priority: item.priority === "urgent" ? "high" : item.priority,
935
+ agentId: item.ownerAgentId || project.defaultAgentId || void 0,
936
+ projectId: project.id,
937
+ source: "api",
938
+ config: service.currentConfig
939
+ });
940
+ goals.setContextMessage({
941
+ goalId: goal.id,
942
+ text: buildWorkItemAgentContext(item).text
943
+ });
944
+ workItems.addLink(item.id, {
945
+ kind: "goal",
946
+ targetId: goal.id,
947
+ title: goal.title,
948
+ statusSnapshot: goal.status
949
+ }, "goal_created");
950
+ const updated = item.status === "todo" || item.status === "backlog" ? workItems.updateWorkItem(item.id, { status: "in_progress" }) : workItems.getWorkItem(item.id);
951
+ return c.json({
952
+ ok: true,
953
+ goal,
954
+ item: updated
955
+ }, 201);
956
+ });
301
957
  authenticated.post("/api/projects/:id/digest-memory", async (c) => {
302
958
  const project = service.projects.getWithDetails(c.req.param("id"));
303
959
  if (!project) return c.json({
@@ -444,7 +1100,7 @@ function registerProjectsRoutes(authenticated, deps) {
444
1100
  const sessions = await Promise.all(keys.map((key) => service.sessions.getSession(key)));
445
1101
  return c.json({
446
1102
  ok: true,
447
- sessions: sessions.filter(Boolean)
1103
+ sessions: sessions.filter((session) => session && !isHiddenEmptyProjectChatShell(session))
448
1104
  });
449
1105
  } catch (error) {
450
1106
  return c.json({
@@ -468,39 +1124,12 @@ function registerProjectsRoutes(authenticated, deps) {
468
1124
  }
469
1125
  });
470
1126
  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({
1127
+ const resolved = await resolveProjectWorkspacePath(service, c.req.param("id"), c.req.query("path"));
1128
+ if (resolved.ok === false) return c.json({
477
1129
  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({
501
- ok: false,
502
- error: "Path is outside project workspace"
503
- }, 400);
1130
+ error: resolved.error
1131
+ }, resolved.status);
1132
+ const { root, absolutePath: candidate } = resolved;
504
1133
  let currentPath;
505
1134
  try {
506
1135
  currentPath = await realpath(candidate);
@@ -515,7 +1144,7 @@ function registerProjectsRoutes(authenticated, deps) {
515
1144
  } catch (err) {
516
1145
  log.warn({
517
1146
  err,
518
- projectId: project.id,
1147
+ projectId: resolved.projectId,
519
1148
  path: candidate
520
1149
  }, "project file path unavailable");
521
1150
  return c.json({
@@ -525,19 +1154,23 @@ function registerProjectsRoutes(authenticated, deps) {
525
1154
  }
526
1155
  try {
527
1156
  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);
1157
+ const visibleEntries = (await Promise.all(dirents.filter((entry) => !SKIP_FILE_NAMES.has(entry.name)).map(async (entry) => {
1158
+ const displayPath = path$1.join(currentPath, entry.name);
1159
+ const absolutePath = await realpath(displayPath).catch(() => null);
1160
+ if (!absolutePath || !isWithinDirectory(root, absolutePath)) return null;
530
1161
  const entryStat = await stat(absolutePath).catch(() => null);
531
- const relativePath = path$1.relative(root, absolutePath).split(path$1.sep).join("/");
1162
+ if (!entryStat) return null;
1163
+ const relativePath = path$1.relative(root, displayPath).split(path$1.sep).join("/");
532
1164
  return {
533
1165
  name: entry.name,
534
1166
  path: relativePath,
535
- type: entry.isDirectory() ? "directory" : "file",
1167
+ absolutePath,
1168
+ type: entryStat.isDirectory() ? "directory" : "file",
536
1169
  size: entryStat?.isFile() ? entryStat.size : void 0,
537
1170
  updatedAt: entryStat?.mtime.toISOString()
538
1171
  };
539
- }));
540
- entries.sort((left, right) => {
1172
+ }))).filter((entry) => entry !== null);
1173
+ visibleEntries.sort((left, right) => {
541
1174
  if (left.type !== right.type) return left.type === "directory" ? -1 : 1;
542
1175
  return left.name.localeCompare(right.name);
543
1176
  });
@@ -548,12 +1181,12 @@ function registerProjectsRoutes(authenticated, deps) {
548
1181
  root,
549
1182
  path: relativeCurrentPath === "." ? "" : relativeCurrentPath,
550
1183
  parentPath: parentRelativePath === "." ? "" : parentRelativePath,
551
- entries
1184
+ entries: visibleEntries
552
1185
  });
553
1186
  } catch (err) {
554
1187
  log.warn({
555
1188
  err,
556
- projectId: project.id,
1189
+ projectId: resolved.projectId,
557
1190
  path: currentPath
558
1191
  }, "project file list failed");
559
1192
  if (err?.code === "EACCES") return c.json({
@@ -566,6 +1199,176 @@ function registerProjectsRoutes(authenticated, deps) {
566
1199
  }, 500);
567
1200
  }
568
1201
  });
1202
+ authenticated.get("/api/projects/:id/files/read", async (c) => {
1203
+ const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param("id"), c.req.query("path"));
1204
+ if (resolved.ok === false) return c.json({
1205
+ ok: false,
1206
+ error: { message: resolved.error }
1207
+ }, resolved.status);
1208
+ if (!resolved.stat.isFile()) return c.json({
1209
+ ok: false,
1210
+ error: { message: "Not a file" }
1211
+ }, 400);
1212
+ try {
1213
+ const content = await readFile(resolved.absolutePath, "utf-8");
1214
+ return c.json({
1215
+ ok: true,
1216
+ payload: {
1217
+ content,
1218
+ path: resolved.relativePath,
1219
+ absolutePath: resolved.absolutePath,
1220
+ mtimeMs: resolved.stat.mtimeMs
1221
+ }
1222
+ });
1223
+ } catch {
1224
+ return c.json({
1225
+ ok: false,
1226
+ error: { message: "Read failed" }
1227
+ }, 500);
1228
+ }
1229
+ });
1230
+ authenticated.get("/api/projects/:id/files/raw", async (c) => {
1231
+ const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param("id"), c.req.query("path"));
1232
+ if (resolved.ok === false) return c.json({
1233
+ ok: false,
1234
+ error: { message: resolved.error }
1235
+ }, resolved.status);
1236
+ if (!resolved.stat.isFile()) return c.json({
1237
+ ok: false,
1238
+ error: { message: "Not a file" }
1239
+ }, 400);
1240
+ const contentType = PROJECT_FILE_MIME_BY_EXT[resolved.relativePath.split(".").pop()?.toLowerCase() ?? ""] || "application/octet-stream";
1241
+ try {
1242
+ const buf = await readFile(resolved.absolutePath);
1243
+ return new Response(buf, { headers: {
1244
+ "Content-Type": contentType,
1245
+ "Cache-Control": "private, max-age=3600"
1246
+ } });
1247
+ } catch {
1248
+ return c.json({
1249
+ ok: false,
1250
+ error: { message: "Read failed" }
1251
+ }, 500);
1252
+ }
1253
+ });
1254
+ authenticated.get("/api/projects/:id/files/resolve-reference", async (c) => {
1255
+ const rawPath = typeof c.req.query("path") === "string" ? c.req.query("path").trim() : "";
1256
+ if (!rawPath) return c.json({
1257
+ ok: false,
1258
+ error: {
1259
+ code: "INVALID_PATH",
1260
+ message: "Missing path"
1261
+ }
1262
+ }, 400);
1263
+ const resolved = await resolveProjectWorkspacePath(service, c.req.param("id"), rawPath);
1264
+ if (resolved.ok === false) return c.json({
1265
+ ok: false,
1266
+ error: {
1267
+ code: "PROJECT_WORKSPACE_RESOLUTION_FAILED",
1268
+ message: resolved.error
1269
+ }
1270
+ }, resolved.status);
1271
+ let st = null;
1272
+ let absolutePath = resolved.absolutePath;
1273
+ try {
1274
+ absolutePath = await realpath(resolved.absolutePath);
1275
+ if (!isWithinDirectory(resolved.root, absolutePath)) return c.json({
1276
+ ok: false,
1277
+ error: {
1278
+ code: "PROJECT_WORKSPACE_RESOLUTION_FAILED",
1279
+ message: "Path is outside project workspace"
1280
+ }
1281
+ }, 400);
1282
+ st = await stat(absolutePath);
1283
+ } catch {
1284
+ st = null;
1285
+ }
1286
+ const displayName = path$1.basename(rawPath);
1287
+ if (!st) return c.json({
1288
+ ok: true,
1289
+ payload: {
1290
+ inputPath: rawPath,
1291
+ displayName,
1292
+ scope: "missing",
1293
+ exists: false,
1294
+ absolutePath: resolved.absolutePath,
1295
+ capabilities: ["copyPath"],
1296
+ errorCode: "FILE_NOT_FOUND"
1297
+ }
1298
+ });
1299
+ return c.json({
1300
+ ok: true,
1301
+ payload: {
1302
+ inputPath: rawPath,
1303
+ displayName,
1304
+ scope: "workspace",
1305
+ exists: true,
1306
+ isDirectory: st.isDirectory(),
1307
+ absolutePath,
1308
+ workspaceRelativePath: resolved.relativePath,
1309
+ capabilities: st.isDirectory() ? [
1310
+ "openExternal",
1311
+ "revealInFolder",
1312
+ "copyPath"
1313
+ ] : [
1314
+ "preview",
1315
+ "edit",
1316
+ "openExternal",
1317
+ "revealInFolder",
1318
+ "copyPath"
1319
+ ],
1320
+ mtimeMs: st.mtimeMs
1321
+ }
1322
+ });
1323
+ });
1324
+ authenticated.put("/api/projects/:id/files/write", async (c) => {
1325
+ let body;
1326
+ try {
1327
+ body = await c.req.json();
1328
+ } catch {
1329
+ return c.json({
1330
+ ok: false,
1331
+ error: { message: "Invalid JSON" }
1332
+ }, 400);
1333
+ }
1334
+ const bodyRecord = typeof body === "object" && body !== null ? body : {};
1335
+ const pathRel = typeof bodyRecord.path === "string" ? bodyRecord.path : "";
1336
+ const content = typeof bodyRecord.content === "string" ? bodyRecord.content : "";
1337
+ if (!pathRel.trim()) return c.json({
1338
+ ok: false,
1339
+ error: { message: "Missing path" }
1340
+ }, 400);
1341
+ const resolved = await resolveProjectWorkspaceWritePath(service, c.req.param("id"), pathRel);
1342
+ if (resolved.ok === false) return c.json({
1343
+ ok: false,
1344
+ error: { message: resolved.error }
1345
+ }, resolved.status);
1346
+ if (resolved.existingStat && !resolved.existingStat.isFile()) return c.json({
1347
+ ok: false,
1348
+ error: { message: "Not a file" }
1349
+ }, 400);
1350
+ try {
1351
+ await writeFile(resolved.absolutePath, content, "utf-8");
1352
+ const mtimeMs = (await stat(resolved.absolutePath).catch(() => ({ mtimeMs: Date.now() }))).mtimeMs;
1353
+ return c.json({
1354
+ ok: true,
1355
+ payload: {
1356
+ path: resolved.relativePath,
1357
+ mtimeMs
1358
+ }
1359
+ });
1360
+ } catch (err) {
1361
+ log.error({
1362
+ err,
1363
+ projectId: resolved.projectId,
1364
+ path: resolved.absolutePath
1365
+ }, "project file write failed");
1366
+ return c.json({
1367
+ ok: false,
1368
+ error: { message: "Write failed" }
1369
+ }, 500);
1370
+ }
1371
+ });
569
1372
  authenticated.post("/api/projects/:id/sessions/:sessionKey", async (c) => {
570
1373
  try {
571
1374
  service.projects.attachSession(c.req.param("sessionKey"), c.req.param("id"));