@xopcai/xopc 0.0.125 → 0.0.127

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 (386) 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/{agent-avatar-dicebear-BKDKICZV.js → agent-avatar-dicebear-CgGgO4OV.js} +1 -1
  18. package/dist/gateway/static/root/assets/agents-k59l7NMb.js +2 -0
  19. package/dist/gateway/static/root/assets/{app-management-settings-panel-DI4BqHKW.js → app-management-settings-panel-DeQsTsyy.js} +1 -1
  20. package/dist/gateway/static/root/assets/{appearance-settings-6_ie3NQ4.js → appearance-settings-BnHQW7Hv.js} +1 -1
  21. package/dist/gateway/static/root/assets/apps-page-BG9b4abG.js +1 -0
  22. package/dist/gateway/static/root/assets/{archive-plugin-kUHEJ1HK.js → archive-plugin-5NXT7Zqv.js} +1 -1
  23. package/dist/gateway/static/root/assets/{attachment-load-Dm-9prpU.js → attachment-load-DghwhYe0.js} +1 -1
  24. package/dist/gateway/static/root/assets/{automation-suggestion-card-OTxQTPnC.js → automation-suggestion-card-DYmESgwl.js} +1 -1
  25. package/dist/gateway/static/root/assets/automations-page-De8mVutL.js +4 -0
  26. package/dist/gateway/static/root/assets/{binary-plugins-DllA_jQ0.js → binary-plugins-DSbPKdWX.js} +1 -1
  27. package/dist/gateway/static/root/assets/{block-editor-Cm6CWNj1.js → block-editor-CoZ-_np-.js} +28 -28
  28. package/dist/gateway/static/root/assets/browser-settings-page-C_ZRa4LF.js +8 -0
  29. package/dist/gateway/static/root/assets/{capability-presets-api-VJ89b6I2.js → capability-presets-api-hny224j-.js} +1 -1
  30. package/dist/gateway/static/root/assets/{capability-presets-settings-panel-BaPj8wC2.js → capability-presets-settings-panel-Drc0qLsw.js} +1 -1
  31. package/dist/gateway/static/root/assets/{channel-recipient-api-B5PwBEUx.js → channel-recipient-api-DAlOHxKJ.js} +1 -1
  32. package/dist/gateway/static/root/assets/channels-settings-CA20zBV9.js +1 -0
  33. package/dist/gateway/static/root/assets/connectors-page-qMyMB5te.js +2 -0
  34. package/dist/gateway/static/root/assets/desktop-pet-XG6Vb_fZ.js +1 -0
  35. package/dist/gateway/static/root/assets/desktop-pet-settings-npJ0Oh5p.js +1 -0
  36. package/dist/gateway/static/root/assets/desktop-pet-sprite-DqZ6fbIj.js +1 -0
  37. package/dist/gateway/static/root/assets/directory-picker-path-field-BR2ItBuf.js +1 -0
  38. package/dist/gateway/static/root/assets/dreaming-settings-CkUZ997f.js +3 -0
  39. package/dist/gateway/static/root/assets/{extension-debug-page-BaM0FpW7.js → extension-debug-page-Tl0f1rNv.js} +1 -1
  40. package/dist/gateway/static/root/assets/{extension-page-DuZWVOGA.js → extension-page-Ck7QuwE3.js} +1 -1
  41. package/dist/gateway/static/root/assets/{extension-settings-page-DarVtbmJ.js → extension-settings-page-3RMhQtZ3.js} +1 -1
  42. package/dist/gateway/static/root/assets/{fetch-NFKfkqrd.js → fetch-pg2ErdAk.js} +1 -1
  43. package/dist/gateway/static/root/assets/{gateway-config-api-CFEm9rgy.js → gateway-config-api-DbG97ia2.js} +1 -1
  44. package/dist/gateway/static/root/assets/gateway-settings-B8cyqKk-.js +1 -0
  45. package/dist/gateway/static/root/assets/{gateway-startup-retry-Dtwh_yGg.js → gateway-startup-retry-Yh8h3hkj.js} +1 -1
  46. package/dist/gateway/static/root/assets/{goal-create-dialog-BKP7ylcG.js → goal-create-dialog-DmeW7Zz3.js} +1 -1
  47. package/dist/gateway/static/root/assets/goal-detail-page-DrTyGbVD.js +1 -0
  48. package/dist/gateway/static/root/assets/{goals-config-api-DTWZNA_Y.js → goals-config-api-CxCWGIBB.js} +1 -1
  49. package/dist/gateway/static/root/assets/goals-page-DV1bJhIh.js +2 -0
  50. package/dist/gateway/static/root/assets/{goals-settings-Bhct0ZT-.js → goals-settings-9DrfOkP5.js} +1 -1
  51. package/dist/gateway/static/root/assets/{heartbeat-settings-C-UxSU4a.js → heartbeat-settings-KaDpZrv0.js} +1 -1
  52. package/dist/gateway/static/root/assets/index-C2F0Clvm.js +256 -0
  53. package/dist/gateway/static/root/assets/index-COQSX5d_.css +1 -0
  54. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DCjy2y4d.js → keyboard-shortcuts-settings-CfQrt_Rb.js} +1 -1
  55. package/dist/gateway/static/root/assets/logs-page-C9dpiNTF.js +2 -0
  56. package/dist/gateway/static/root/assets/{markdown-split-BaqxP-GQ.js → markdown-split-BwiMdCf_.js} +1 -1
  57. package/dist/gateway/static/root/assets/{media-plugins-DQ_EXloK.js → media-plugins-DhoizyZv.js} +1 -1
  58. package/dist/gateway/static/root/assets/messages-DmnbiNxU.js +3 -0
  59. package/dist/gateway/static/root/assets/models-hub-panel-zdCdmBmH.js +2 -0
  60. package/dist/gateway/static/root/assets/notes-page-MpGeFfPt.js +1 -0
  61. package/dist/gateway/static/root/assets/notes-workbench-DYCM3yd2.js +2 -0
  62. package/dist/gateway/static/root/assets/{page-tabs-EIZhLppK.js → page-tabs-DDC2t4Z8.js} +1 -1
  63. package/dist/gateway/static/root/assets/{preview-open-alternatives-r_uB4Epr.js → preview-open-alternatives-BTmk-XDM.js} +1 -1
  64. package/dist/gateway/static/root/assets/project-detail-page-Cu0ElRnS.js +1 -0
  65. package/dist/gateway/static/root/assets/projects-page-DakNaUjZ.js +1 -0
  66. package/dist/gateway/static/root/assets/remote-access-hub-DYKjt7L9.js +1 -0
  67. package/dist/gateway/static/root/assets/{save-bar-controls-B132Uf-2.js → save-bar-controls-DqU-yKIh.js} +1 -1
  68. package/dist/gateway/static/root/assets/{schedule-field-B5qshALm.js → schedule-field-CUttkoSB.js} +1 -1
  69. package/dist/gateway/static/root/assets/{schema-form-CvLmkdS9.js → schema-form-CVSQA9nI.js} +1 -1
  70. package/dist/gateway/static/root/assets/sessions-page-CcGHDsz1.js +1 -0
  71. package/dist/gateway/static/root/assets/settings-advanced-gate-CuFdeKNu.js +1 -0
  72. package/dist/gateway/static/root/assets/{settings-collapsible-section-pRlvqsAf.js → settings-collapsible-section-CK7ogS-P.js} +1 -1
  73. package/dist/gateway/static/root/assets/settings-form-section-Bugp38Fa.js +1 -0
  74. package/dist/gateway/static/root/assets/settings-page-0AJoUvxi.js +1 -0
  75. package/dist/gateway/static/root/assets/settings-page-layout-DBRWwdhh.js +1 -0
  76. package/dist/gateway/static/root/assets/setup-status-panel-D6a_hEk7.js +1 -0
  77. package/dist/gateway/static/root/assets/{share-preview-page-v6-IOp8t.js → share-preview-page-BtsuETKF.js} +1 -1
  78. package/dist/gateway/static/root/assets/shares-settings-CcEFT7S9.js +1 -0
  79. package/dist/gateway/static/root/assets/skill-reload-api-BcN_RuTD.js +1 -0
  80. package/dist/gateway/static/root/assets/skills-page-BbRZZZA5.js +2 -0
  81. package/dist/gateway/static/root/assets/{system-settings-panel-HUU2FFjM.js → system-settings-panel-DJ6YuLqR.js} +1 -1
  82. package/dist/gateway/static/root/assets/{typed-models-lib-AH160QHh.js → typed-models-lib-B0T7N8Km.js} +1 -1
  83. package/dist/gateway/static/root/assets/{use-channel-catalog-BXzDmjCQ.js → use-channel-catalog-C6vrxdzZ.js} +1 -1
  84. package/dist/gateway/static/root/assets/{user-profile-settings-panel-DxwnQvQ3.js → user-profile-settings-panel-DZ0nKMgj.js} +1 -1
  85. package/dist/gateway/static/root/assets/{utils-i5POEtqd.js → utils-CehXcWAY.js} +1 -1
  86. package/dist/gateway/static/root/assets/voice-api-key-field-2QKflCx8.js +1 -0
  87. package/dist/gateway/static/root/assets/work-item-detail-page-DfJnuWq1.js +1 -0
  88. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-ClVVMgN-.js → workflow-run-setup-panel-c4jeaohQ.js} +2 -2
  89. package/dist/gateway/static/root/assets/{workflow-start-dialog-Dv4ZA1T0.js → workflow-start-dialog-ENRHjoqa.js} +1 -1
  90. package/dist/gateway/static/root/assets/workflows-page-BJwwFTm_.js +18 -0
  91. package/dist/gateway/static/root/index.html +5 -5
  92. package/dist/package.js +1 -1
  93. package/dist/src/activity/context.d.ts +11 -0
  94. package/dist/src/activity/context.js +36 -0
  95. package/dist/src/activity/context.js.map +1 -0
  96. package/dist/src/activity/emitter.d.ts +6 -0
  97. package/dist/src/activity/emitter.js +43 -0
  98. package/dist/src/activity/emitter.js.map +1 -0
  99. package/dist/src/activity/index.d.ts +3 -0
  100. package/dist/src/activity/index.js +3 -0
  101. package/dist/src/activity/service.d.ts +12 -0
  102. package/dist/src/activity/service.js +59 -0
  103. package/dist/src/activity/service.js.map +1 -0
  104. package/dist/src/activity/types.d.ts +109 -0
  105. package/dist/src/activity/types.js +1 -0
  106. package/dist/src/agent/agent-instance-gateway.d.ts +5 -0
  107. package/dist/src/agent/agent-manager.d.ts +21 -0
  108. package/dist/src/agent/agent-manager.js +118 -6
  109. package/dist/src/agent/agent-manager.js.map +1 -1
  110. package/dist/src/agent/capabilities/definitions.d.ts +153 -0
  111. package/dist/src/agent/capabilities/definitions.js +156 -0
  112. package/dist/src/agent/capabilities/definitions.js.map +1 -0
  113. package/dist/src/agent/capabilities/index.d.ts +2 -0
  114. package/dist/src/agent/capabilities/index.js +3 -0
  115. package/dist/src/agent/capabilities/registry.d.ts +10 -0
  116. package/dist/src/agent/capabilities/registry.js +51 -0
  117. package/dist/src/agent/capabilities/registry.js.map +1 -0
  118. package/dist/src/agent/context/project-context.js +2 -2
  119. package/dist/src/agent/context/workspace-seed.js +2 -2
  120. package/dist/src/agent/embedded/run-for-session.js +1 -1
  121. package/dist/src/agent/goals/post-turn.js +2 -2
  122. package/dist/src/agent/ipc/bus.js +1 -1
  123. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  124. package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
  125. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  126. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  127. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  128. package/dist/src/agent/models/manager.js +1 -1
  129. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
  130. package/dist/src/agent/service/process-direct-one-shot.js +5 -3
  131. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  132. package/dist/src/agent/service/process-direct-streaming.js +4 -3
  133. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  134. package/dist/src/agent/service.d.ts +2 -0
  135. package/dist/src/agent/service.js +9 -3
  136. package/dist/src/agent/service.js.map +1 -1
  137. package/dist/src/agent/service.types.d.ts +7 -0
  138. package/dist/src/agent/session/session-inspector.js +1 -1
  139. package/dist/src/agent/skills/hub-pull.js +1 -1
  140. package/dist/src/agent/skills/parse-skill-metadata.js +9 -1
  141. package/dist/src/agent/skills/parse-skill-metadata.js.map +1 -1
  142. package/dist/src/agent/skills/skill-manager.d.ts +4 -0
  143. package/dist/src/agent/skills/skill-manager.js +17 -0
  144. package/dist/src/agent/skills/skill-manager.js.map +1 -1
  145. package/dist/src/agent/skills/types.d.ts +5 -0
  146. package/dist/src/agent/tool-manuals/index.js +15 -6
  147. package/dist/src/agent/tool-manuals/index.js.map +1 -1
  148. package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -0
  149. package/dist/src/agent/tool-manuals/xopc-use.js +204 -0
  150. package/dist/src/agent/tool-manuals/xopc-use.js.map +1 -0
  151. package/dist/src/agent/tools/desktop-pet-tool.d.ts +24 -0
  152. package/dist/src/agent/tools/desktop-pet-tool.js +90 -0
  153. package/dist/src/agent/tools/desktop-pet-tool.js.map +1 -0
  154. package/dist/src/agent/tools/factory.d.ts +9 -0
  155. package/dist/src/agent/tools/factory.js +26 -0
  156. package/dist/src/agent/tools/factory.js.map +1 -1
  157. package/dist/src/agent/tools/goal-tool.js +2 -2
  158. package/dist/src/agent/tools/index.d.ts +2 -0
  159. package/dist/src/agent/tools/index.js +3 -1
  160. package/dist/src/agent/tools/workflow-tool.js +1 -1
  161. package/dist/src/agent/tools/xopc-use-tool.d.ts +34 -0
  162. package/dist/src/agent/tools/xopc-use-tool.js +636 -0
  163. package/dist/src/agent/tools/xopc-use-tool.js.map +1 -0
  164. package/dist/src/agent-manifest/schema.d.ts +27 -27
  165. package/dist/src/automations/api/routes.js +1 -1
  166. package/dist/src/automations/domain/validation.d.ts +55 -55
  167. package/dist/src/automations/draft/automation-draft-service.js +1 -1
  168. package/dist/src/automations/draft/automation-draft-validator.d.ts +25 -25
  169. package/dist/src/automations/service/action-executor.js +2 -2
  170. package/dist/src/browser/cdp-local-launcher.js +1 -1
  171. package/dist/src/browser/providers/browser-ext-install.js +3 -3
  172. package/dist/src/browser/providers/cloakbrowser.js +2 -2
  173. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  174. package/dist/src/browser/stealth.js +1 -1
  175. package/dist/src/chat-commands/agent-edit.js +1 -1
  176. package/dist/src/chat-commands/builtins/config.js +1 -1
  177. package/dist/src/chat-commands/builtins/goal.js +2 -2
  178. package/dist/src/chat-commands/context.js +1 -1
  179. package/dist/src/cli/commands/agent.js +3 -3
  180. package/dist/src/cli/commands/doctor/checks/database-schema.js +2 -2
  181. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  182. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  183. package/dist/src/cli/commands/extension-pack.js +1 -1
  184. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  185. package/dist/src/cli/commands/goal.js +3 -3
  186. package/dist/src/cli/commands/init.js +1 -1
  187. package/dist/src/cli/commands/models.js +1 -1
  188. package/dist/src/cli/commands/onboard.js +1 -1
  189. package/dist/src/cli/commands/profile.js +1 -1
  190. package/dist/src/cli/commands/project.js +4 -4
  191. package/dist/src/cli/commands/tunnel.js +1 -1
  192. package/dist/src/cli/commands/update.js +1 -1
  193. package/dist/src/cli/extension-cli-register.js +1 -1
  194. package/dist/src/config/agent-profile.js +1 -1
  195. package/dist/src/config/gateway-bind.js +1 -1
  196. package/dist/src/config/index.js +2 -2
  197. package/dist/src/config/loader.js +1 -1
  198. package/dist/src/config/models-json.d.ts +14 -14
  199. package/dist/src/config/models-json.js +1 -1
  200. package/dist/src/config/schema.d.ts +60 -60
  201. package/dist/src/daemon/launchd.js +1 -1
  202. package/dist/src/daemon/systemd.js +1 -1
  203. package/dist/src/extensions/discover-extensions.js +1 -1
  204. package/dist/src/extensions/loader.js +2 -2
  205. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  206. package/dist/src/gateway/agent-builtin-tools.js +1 -0
  207. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  208. package/dist/src/gateway/agents-admin.js +1 -1
  209. package/dist/src/gateway/hono/lib/config-payload.d.ts +14 -14
  210. package/dist/src/gateway/hono/lib/static-ui.js +1 -1
  211. package/dist/src/gateway/hono/middleware/log-context.js +8 -1
  212. package/dist/src/gateway/hono/middleware/log-context.js.map +1 -1
  213. package/dist/src/gateway/hono/routes/activity.d.ts +14 -0
  214. package/dist/src/gateway/hono/routes/activity.js +72 -0
  215. package/dist/src/gateway/hono/routes/activity.js.map +1 -0
  216. package/dist/src/gateway/hono/routes/commands-skills.js +7 -0
  217. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  218. package/dist/src/gateway/hono/routes/goals.js +1 -1
  219. package/dist/src/gateway/hono/routes/index.js +2 -0
  220. package/dist/src/gateway/hono/routes/index.js.map +1 -1
  221. package/dist/src/gateway/hono/routes/lazy-bundles.js +2 -1
  222. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  223. package/dist/src/gateway/hono/routes/memory.js +2 -2
  224. package/dist/src/gateway/hono/routes/projects.js +93 -15
  225. package/dist/src/gateway/hono/routes/projects.js.map +1 -1
  226. package/dist/src/gateway/hono/routes/sessions.js +101 -2
  227. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  228. package/dist/src/gateway/hono/routes/workflows.js +2 -2
  229. package/dist/src/gateway/lock.js +1 -1
  230. package/dist/src/gateway/ports.js +1 -1
  231. package/dist/src/gateway/run-loop.js +1 -1
  232. package/dist/src/gateway/service/run-gateway-agent.js +6 -2
  233. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  234. package/dist/src/gateway/service/sessions-api.d.ts +10 -0
  235. package/dist/src/gateway/service/sessions-api.js +31 -0
  236. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  237. package/dist/src/gateway/service.js +12 -9
  238. package/dist/src/gateway/service.js.map +1 -1
  239. package/dist/src/goals/goal-store.js +1 -1
  240. package/dist/src/goals/goal-store.js.map +1 -1
  241. package/dist/src/goals/goal-workflow-judge.js +1 -1
  242. package/dist/src/infra/ports.js +1 -1
  243. package/dist/src/infra/ssh-tunnel.js +1 -1
  244. package/dist/src/infra/update-check.js +1 -1
  245. package/dist/src/infra/update-restart.js +1 -1
  246. package/dist/src/migrations/runner.js +1 -1
  247. package/dist/src/notes/service.js +65 -6
  248. package/dist/src/notes/service.js.map +1 -1
  249. package/dist/src/notes/store.js +1 -1
  250. package/dist/src/pets/factory.d.ts +25 -0
  251. package/dist/src/pets/factory.js +327 -0
  252. package/dist/src/pets/factory.js.map +1 -0
  253. package/dist/src/pets/manifest.d.ts +2 -0
  254. package/dist/src/pets/manifest.js +16 -0
  255. package/dist/src/pets/manifest.js.map +1 -0
  256. package/dist/src/pets/validator.d.ts +12 -0
  257. package/dist/src/pets/validator.js +175 -0
  258. package/dist/src/pets/validator.js.map +1 -0
  259. package/dist/src/projects/project-service.d.ts +4 -1
  260. package/dist/src/projects/project-service.js +65 -2
  261. package/dist/src/projects/project-service.js.map +1 -1
  262. package/dist/src/projects/project-store.d.ts +3 -1
  263. package/dist/src/projects/project-store.js +56 -6
  264. package/dist/src/projects/project-store.js.map +1 -1
  265. package/dist/src/projects/types.d.ts +12 -0
  266. package/dist/src/projects/workspace.js +1 -1
  267. package/dist/src/routing/agent-session-key.js +1 -1
  268. package/dist/src/routing/resolve-route.js +1 -1
  269. package/dist/src/routing/resolve-tui-session-key.js +1 -1
  270. package/dist/src/session/client-history.d.ts +3 -0
  271. package/dist/src/session/client-history.js +24 -9
  272. package/dist/src/session/client-history.js.map +1 -1
  273. package/dist/src/session/init-session-turn.js +1 -1
  274. package/dist/src/session/resolve-session.js +1 -1
  275. package/dist/src/session/session-title.js +24 -4
  276. package/dist/src/session/session-title.js.map +1 -1
  277. package/dist/src/session/store.js +1 -1
  278. package/dist/src/session/types.d.ts +4 -0
  279. package/dist/src/session/types.js.map +1 -1
  280. package/dist/src/storage/sqlite/activity-repository.d.ts +8 -0
  281. package/dist/src/storage/sqlite/activity-repository.js +208 -0
  282. package/dist/src/storage/sqlite/activity-repository.js.map +1 -0
  283. package/dist/src/storage/sqlite/connection.js +1 -1
  284. package/dist/src/storage/sqlite/index.d.ts +1 -0
  285. package/dist/src/storage/sqlite/index.js +2 -1
  286. package/dist/src/storage/sqlite/migrations/024_activity_events.sql +62 -0
  287. package/dist/src/storage/sqlite/migrations/025_project_pinned_at.sql +5 -0
  288. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  289. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  290. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  291. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  292. package/dist/src/storage/sqlite/row-mappers.js +1 -1
  293. package/dist/src/storage/sqlite/schema.js +1 -1
  294. package/dist/src/storage/sqlite/schema.sql +63 -0
  295. package/dist/src/storage/sqlite/session-repository.js +11 -0
  296. package/dist/src/storage/sqlite/session-repository.js.map +1 -1
  297. package/dist/src/tui/backends/embedded-backend.d.ts +13 -0
  298. package/dist/src/tui/backends/embedded-backend.js +76 -7
  299. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  300. package/dist/src/tui/backends/gateway-sse-backend.d.ts +13 -0
  301. package/dist/src/tui/backends/gateway-sse-backend.js +53 -0
  302. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  303. package/dist/src/tui/chat-history.js +16 -3
  304. package/dist/src/tui/chat-history.js.map +1 -1
  305. package/dist/src/tui/clipboard-image.js +1 -1
  306. package/dist/src/tui/components/chat-log.d.ts +23 -3
  307. package/dist/src/tui/components/chat-log.js +68 -9
  308. package/dist/src/tui/components/chat-log.js.map +1 -1
  309. package/dist/src/tui/components/tui-bottom-bar.js +9 -5
  310. package/dist/src/tui/components/tui-bottom-bar.js.map +1 -1
  311. package/dist/src/tui/tui-backend.d.ts +16 -0
  312. package/dist/src/tui/tui-command-formatters.js +2 -2
  313. package/dist/src/tui/tui-commands.d.ts +9 -0
  314. package/dist/src/tui/tui-commands.js +95 -6
  315. package/dist/src/tui/tui-commands.js.map +1 -1
  316. package/dist/src/tui/tui-picker-overlay.d.ts +1 -0
  317. package/dist/src/tui/tui-picker-overlay.js +36 -1
  318. package/dist/src/tui/tui-picker-overlay.js.map +1 -1
  319. package/dist/src/tui/tui-picker-services.d.ts +13 -0
  320. package/dist/src/tui/tui-run-state.js +11 -0
  321. package/dist/src/tui/tui-run-state.js.map +1 -1
  322. package/dist/src/tui/tui-run-status-format.d.ts +3 -0
  323. package/dist/src/tui/tui-run-status-format.js +33 -0
  324. package/dist/src/tui/tui-run-status-format.js.map +1 -0
  325. package/dist/src/tui/tui-session-actions.d.ts +5 -0
  326. package/dist/src/tui/tui-session-actions.js +24 -0
  327. package/dist/src/tui/tui-session-actions.js.map +1 -1
  328. package/dist/src/tui/tui-timeline-picker.d.ts +19 -0
  329. package/dist/src/tui/tui-timeline-picker.js +81 -0
  330. package/dist/src/tui/tui-timeline-picker.js.map +1 -0
  331. package/dist/src/tui/tui-timeline.d.ts +15 -0
  332. package/dist/src/tui/tui-timeline.js +65 -0
  333. package/dist/src/tui/tui-timeline.js.map +1 -0
  334. package/dist/src/tui/tui-types.d.ts +1 -0
  335. package/dist/src/tui/tui-types.js +1 -0
  336. package/dist/src/tui/tui-types.js.map +1 -1
  337. package/dist/src/tui/tui.js +31 -25
  338. package/dist/src/tui/tui.js.map +1 -1
  339. package/dist/src/utils/index.js +1 -1
  340. package/dist/src/utils/logger/index.js +1 -1
  341. package/dist/src/utils/logger/stats.d.ts +3 -3
  342. package/dist/src/utils/logger.js +1 -1
  343. package/dist/src/work-items/agent-context.d.ts +5 -1
  344. package/dist/src/work-items/agent-context.js +39 -3
  345. package/dist/src/work-items/agent-context.js.map +1 -1
  346. package/dist/src/work-items/work-item-service.d.ts +2 -0
  347. package/dist/src/work-items/work-item-service.js +97 -0
  348. package/dist/src/work-items/work-item-service.js.map +1 -1
  349. package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
  350. package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
  351. package/package.json +5 -5
  352. package/skills/creative/hatch-pet/SKILL.md +63 -0
  353. package/dist/gateway/static/root/assets/agents-BnTB7-c5.js +0 -2
  354. package/dist/gateway/static/root/assets/apps-page-B6bG65SW.js +0 -1
  355. package/dist/gateway/static/root/assets/automations-page-1lVbo0dS.js +0 -1
  356. package/dist/gateway/static/root/assets/browser-settings-page-CzDBlOK0.js +0 -8
  357. package/dist/gateway/static/root/assets/channels-settings-Df4m7p1k.js +0 -1
  358. package/dist/gateway/static/root/assets/connectors-page-BMTphmHS.js +0 -2
  359. package/dist/gateway/static/root/assets/directory-picker-path-field-DySMzOF6.js +0 -1
  360. package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +0 -1
  361. package/dist/gateway/static/root/assets/dreaming-settings-D_AjSnV_.js +0 -3
  362. package/dist/gateway/static/root/assets/gateway-settings-BMk2S5td.js +0 -1
  363. package/dist/gateway/static/root/assets/goal-detail-page-C2cTxf71.js +0 -1
  364. package/dist/gateway/static/root/assets/goals-page-CTmA3hWK.js +0 -2
  365. package/dist/gateway/static/root/assets/index-BNHDd2j1.css +0 -1
  366. package/dist/gateway/static/root/assets/index-BPXLPMuY.js +0 -193
  367. package/dist/gateway/static/root/assets/logs-page-CGc3_CQU.js +0 -2
  368. package/dist/gateway/static/root/assets/messages-CjuIJcZl.js +0 -3
  369. package/dist/gateway/static/root/assets/models-hub-panel-Drz4UQMb.js +0 -2
  370. package/dist/gateway/static/root/assets/notes-page-CY1ylng1.js +0 -1
  371. package/dist/gateway/static/root/assets/notes-workbench-X7IaD--t.js +0 -2
  372. package/dist/gateway/static/root/assets/project-detail-page-DE5adRBE.js +0 -1
  373. package/dist/gateway/static/root/assets/projects-page-CuOb1k6F.js +0 -1
  374. package/dist/gateway/static/root/assets/remote-access-hub-BOxNrUVA.js +0 -1
  375. package/dist/gateway/static/root/assets/sessions-page-CY0IQcGW.js +0 -1
  376. package/dist/gateway/static/root/assets/settings-advanced-gate-D4NBNVCB.js +0 -1
  377. package/dist/gateway/static/root/assets/settings-form-section-BBYUDLVd.js +0 -1
  378. package/dist/gateway/static/root/assets/settings-page-DaO7zYZM.js +0 -1
  379. package/dist/gateway/static/root/assets/settings-page-layout-D8g9PAek.js +0 -1
  380. package/dist/gateway/static/root/assets/setup-status-panel-Bks0CLLT.js +0 -1
  381. package/dist/gateway/static/root/assets/shares-settings-CEZsKm9r.js +0 -1
  382. package/dist/gateway/static/root/assets/skill-reload-api-oTkHbb9W.js +0 -1
  383. package/dist/gateway/static/root/assets/skills-page-DigsbZ6K.js +0 -2
  384. package/dist/gateway/static/root/assets/voice-api-key-field-CEJklEgb.js +0 -1
  385. package/dist/gateway/static/root/assets/work-item-detail-page-CD6FL_Rs.js +0 -1
  386. package/dist/gateway/static/root/assets/workflows-page-OLQiUpoW.js +0 -18
@@ -1,8 +1,8 @@
1
+ import { getAsyncLogContext, inboundCorrelationMetadataFromAsyncLogContext, runWithLogContext, updateAsyncLogContext } from "./logger/context.js";
1
2
  import { getLogDir, getLoggerConfig } from "./logger/config.js";
2
3
  import { getRuntimeLogStats } from "./logger/stats.js";
3
4
  import { flushAndClose, isLoggerShuttingDown, setShuttingDown } from "./logger/shutdown.js";
4
5
  import { cleanOldLogs, rotateLogs } from "./logger/rotation.js";
5
- import { getAsyncLogContext, inboundCorrelationMetadataFromAsyncLogContext, runWithLogContext, updateAsyncLogContext } from "./logger/context.js";
6
6
  import { isLogRedactionEnabled, redactObject, redactPemBlock, redactSecret, redactSensitiveInfo } from "./logger/redact.js";
7
7
  import { exportLog, flushExporters, getExporters, initializeExporters } from "./logger/exporters.js";
8
8
  import { configureAuditLog, getAuditConfig, logAuditEvent, logAuthEvent, logConfigChange, logDataAccess, logPermissionChange } from "./logger/audit.js";
@@ -1,11 +1,11 @@
1
1
  import { __esmMin } from "../../../_virtual/_rolldown/runtime.js";
2
2
  import { PACKAGE_VERSION, init_package_version } from "../../package-version.js";
3
+ import { getAsyncLogContext, getAsyncLogCorrelationKeys, inboundCorrelationMetadataFromAsyncLogContext, init_context, mergeContext, runWithLogContext, updateAsyncLogContext } from "./context.js";
3
4
  import { config, getLogDir, getLoggerConfig, init_config } from "./config.js";
4
5
  import { init_streams, initializeStreams } from "./streams.js";
5
6
  import { getRuntimeLogStats, incrementStats, init_stats } from "./stats.js";
6
7
  import { flushAndClose, init_shutdown, isLoggerShuttingDown, setShuttingDown } from "./shutdown.js";
7
8
  import { cleanOldLogs, init_rotation, rotateLogs } from "./rotation.js";
8
- import { getAsyncLogContext, getAsyncLogCorrelationKeys, inboundCorrelationMetadataFromAsyncLogContext, init_context, mergeContext, runWithLogContext, updateAsyncLogContext } from "./context.js";
9
9
  import { init_redact, isLogRedactionEnabled, redactLogRecord, redactObject, redactPemBlock, redactSecret, redactSensitiveInfo } from "./redact.js";
10
10
  import { exportLog, flushExporters, getExporters, init_exporters, initializeExporters } from "./exporters.js";
11
11
  import { configureAuditLog, getAuditConfig, init_audit, logAuditEvent, logAuthEvent, logConfigChange, logDataAccess, logPermissionChange } from "./audit.js";
@@ -12,13 +12,13 @@ export declare function incrementStats(level: LogLevel, module?: string): void;
12
12
  */
13
13
  export declare function getRuntimeLogStats(): {
14
14
  byLevel: {
15
- error: number;
16
- debug: number;
17
- silent: number;
18
15
  trace: number;
16
+ debug: number;
19
17
  info: number;
20
18
  warn: number;
19
+ error: number;
21
20
  fatal: number;
21
+ silent: number;
22
22
  };
23
23
  byModule: {
24
24
  [k: string]: number;
@@ -1,9 +1,9 @@
1
1
  import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
2
+ import { getAsyncLogContext, inboundCorrelationMetadataFromAsyncLogContext, runWithLogContext, updateAsyncLogContext } from "./logger/context.js";
2
3
  import { getLogDir, getLoggerConfig } from "./logger/config.js";
3
4
  import { getRuntimeLogStats } from "./logger/stats.js";
4
5
  import { flushAndClose, isLoggerShuttingDown, setShuttingDown } from "./logger/shutdown.js";
5
6
  import { cleanOldLogs, rotateLogs } from "./logger/rotation.js";
6
- import { getAsyncLogContext, inboundCorrelationMetadataFromAsyncLogContext, runWithLogContext, updateAsyncLogContext } from "./logger/context.js";
7
7
  import { isLogRedactionEnabled, redactObject, redactPemBlock, redactSecret, redactSensitiveInfo } from "./logger/redact.js";
8
8
  import { exportLog, flushExporters, getExporters, initializeExporters } from "./logger/exporters.js";
9
9
  import { configureAuditLog, getAuditConfig, logAuditEvent, logAuthEvent, logConfigChange, logDataAccess, logPermissionChange } from "./logger/audit.js";
@@ -1,3 +1,7 @@
1
1
  import type { AgentSourceContext } from '../agent/source-context/types.js';
2
+ import type { MediaRef } from '../media/types.js';
2
3
  import type { WorkItem } from './types.js';
3
- export declare function buildWorkItemAgentContext(item: WorkItem): AgentSourceContext;
4
+ export declare function buildWorkItemAgentContext(item: WorkItem, opts?: {
5
+ attachments?: readonly MediaRef[];
6
+ includeImages?: boolean;
7
+ }): Promise<AgentSourceContext>;
@@ -1,12 +1,47 @@
1
+ import { readMediaReferenceBase64 } from "../media/media-reference.js";
1
2
  //#region src/work-items/agent-context.ts
3
+ const MAX_NATIVE_VISION_IMAGES = 6;
4
+ const MAX_NATIVE_VISION_IMAGE_BYTES = 2 * 1024 * 1024;
2
5
  function contextLine(label, value) {
3
6
  if (value === void 0 || value === null) return null;
4
7
  const text = String(value).trim();
5
8
  return text ? `${label}: ${text}` : null;
6
9
  }
7
- function buildWorkItemAgentContext(item) {
10
+ async function loadWorkItemNativeVisionImages(item) {
11
+ const images = [];
12
+ for (const attachment of item.attachments ?? []) {
13
+ if (attachment.type !== "image") continue;
14
+ if (!attachment.mimeType.toLowerCase().startsWith("image/")) continue;
15
+ if (attachment.size > MAX_NATIVE_VISION_IMAGE_BYTES) continue;
16
+ try {
17
+ const loaded = await readMediaReferenceBase64(attachment.mediaUri, MAX_NATIVE_VISION_IMAGE_BYTES);
18
+ images.push({
19
+ type: "image",
20
+ data: loaded.data,
21
+ mimeType: attachment.mimeType || loaded.mimeType
22
+ });
23
+ if (images.length >= MAX_NATIVE_VISION_IMAGES) break;
24
+ } catch {
25
+ continue;
26
+ }
27
+ }
28
+ return images;
29
+ }
30
+ function renderAttachmentLines(item, refs) {
31
+ if (!item.attachments?.length) return "";
32
+ return item.attachments.slice(0, 12).map((attachment, index) => {
33
+ const ref = refs?.[index];
34
+ return [
35
+ `- ${ref?.name ?? attachment.fileName} (${ref?.mimeType ?? attachment.mimeType}, ${ref?.size ?? attachment.size} bytes)`,
36
+ ` xopc-media-uri:${ref?.uri ?? attachment.mediaUri}`,
37
+ " Use the read_media tool with the xopc-media-uri value when you need to inspect this attachment."
38
+ ].join("\n");
39
+ }).join("\n");
40
+ }
41
+ async function buildWorkItemAgentContext(item, opts = {}) {
8
42
  const links = item.links?.length ? item.links.slice(0, 12).map((link) => `- ${link.kind}: ${link.title || link.targetId}${link.statusSnapshot ? ` (${link.statusSnapshot})` : ""}`).join("\n") : "";
9
- const attachments = item.attachments?.length ? item.attachments.slice(0, 12).map((attachment) => `- ${attachment.fileName} (${attachment.mimeType}, ${attachment.size} bytes)`).join("\n") : "";
43
+ const attachments = renderAttachmentLines(item, opts.attachments);
44
+ const images = opts.includeImages === false ? [] : await loadWorkItemNativeVisionImages(item);
10
45
  const text = [
11
46
  "You are working inside a project work item. Treat this as the active task context, not as a new user message.",
12
47
  "",
@@ -30,7 +65,8 @@ function buildWorkItemAgentContext(item) {
30
65
  sourceId: item.id,
31
66
  version: String(item.updatedAt),
32
67
  title: item.title,
33
- text
68
+ text,
69
+ ...images.length ? { images } : {}
34
70
  };
35
71
  }
36
72
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"agent-context.js","names":[],"sources":["../../../src/work-items/agent-context.ts"],"sourcesContent":["import type { AgentSourceContext } from '../agent/source-context/types.js';\n\nimport type { WorkItem } from './types.js';\n\nfunction contextLine(label: string, value: string | number | undefined | null): string | null {\n if (value === undefined || value === null) return null;\n const text = String(value).trim();\n return text ? `${label}: ${text}` : null;\n}\n\nexport function buildWorkItemAgentContext(item: WorkItem): AgentSourceContext {\n const links = item.links?.length\n ? item.links\n .slice(0, 12)\n .map((link) => `- ${link.kind}: ${link.title || link.targetId}${link.statusSnapshot ? ` (${link.statusSnapshot})` : ''}`)\n .join('\\n')\n : '';\n const attachments = item.attachments?.length\n ? item.attachments\n .slice(0, 12)\n .map((attachment) => `- ${attachment.fileName} (${attachment.mimeType}, ${attachment.size} bytes)`)\n .join('\\n')\n : '';\n const text = [\n 'You are working inside a project work item. Treat this as the active task context, not as a new user message.',\n '',\n contextLine('Work item id', item.id),\n contextLine('Project id', item.projectId),\n contextLine('Title', item.title),\n contextLine('Status', item.status),\n contextLine('Priority', item.priority),\n contextLine('Owner agent', item.ownerAgentId),\n contextLine('Description', item.description),\n contextLine('Next action', item.nextAction),\n contextLine('Blocked reason', item.blockedReason),\n item.dueAt ? contextLine('Due at', new Date(item.dueAt).toISOString()) : null,\n links ? `Linked executions:\\n${links}` : null,\n attachments ? `Attachments:\\n${attachments}` : null,\n '',\n 'When you answer, keep the work item moving. If the discussion changes scope, call out the suggested work item update explicitly.',\n ].filter(Boolean).join('\\n');\n\n return {\n kind: 'work_item',\n sourceId: item.id,\n version: String(item.updatedAt),\n title: item.title,\n text,\n };\n}\n"],"mappings":";AAIA,SAAS,YAAY,OAAe,OAA0D;AAC5F,KAAI,UAAU,KAAA,KAAa,UAAU,KAAM,QAAO;CAClD,MAAM,OAAO,OAAO,MAAM,CAAC,MAAM;AACjC,QAAO,OAAO,GAAG,MAAM,IAAI,SAAS;;AAGtC,SAAgB,0BAA0B,MAAoC;CAC5E,MAAM,QAAQ,KAAK,OAAO,SACtB,KAAK,MACJ,MAAM,GAAG,GAAG,CACZ,KAAK,SAAS,KAAK,KAAK,KAAK,IAAI,KAAK,SAAS,KAAK,WAAW,KAAK,iBAAiB,KAAK,KAAK,eAAe,KAAK,KAAK,CACxH,KAAK,KAAK,GACX;CACJ,MAAM,cAAc,KAAK,aAAa,SAClC,KAAK,YACJ,MAAM,GAAG,GAAG,CACZ,KAAK,eAAe,KAAK,WAAW,SAAS,IAAI,WAAW,SAAS,IAAI,WAAW,KAAK,SAAS,CAClG,KAAK,KAAK,GACX;CACJ,MAAM,OAAO;EACX;EACA;EACA,YAAY,gBAAgB,KAAK,GAAG;EACpC,YAAY,cAAc,KAAK,UAAU;EACzC,YAAY,SAAS,KAAK,MAAM;EAChC,YAAY,UAAU,KAAK,OAAO;EAClC,YAAY,YAAY,KAAK,SAAS;EACtC,YAAY,eAAe,KAAK,aAAa;EAC7C,YAAY,eAAe,KAAK,YAAY;EAC5C,YAAY,eAAe,KAAK,WAAW;EAC3C,YAAY,kBAAkB,KAAK,cAAc;EACjD,KAAK,QAAQ,YAAY,UAAU,IAAI,KAAK,KAAK,MAAM,CAAC,aAAa,CAAC,GAAG;EACzE,QAAQ,uBAAuB,UAAU;EACzC,cAAc,iBAAiB,gBAAgB;EAC/C;EACA;EACD,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;AAE5B,QAAO;EACL,MAAM;EACN,UAAU,KAAK;EACf,SAAS,OAAO,KAAK,UAAU;EAC/B,OAAO,KAAK;EACZ;EACD"}
1
+ {"version":3,"file":"agent-context.js","names":[],"sources":["../../../src/work-items/agent-context.ts"],"sourcesContent":["import type { ImageContent } from '@earendil-works/pi-ai';\n\nimport type { AgentSourceContext } from '../agent/source-context/types.js';\nimport { readMediaReferenceBase64 } from '../media/media-reference.js';\nimport type { MediaRef } from '../media/types.js';\n\nimport type { WorkItem } from './types.js';\n\nconst MAX_NATIVE_VISION_IMAGES = 6;\nconst MAX_NATIVE_VISION_IMAGE_BYTES = 2 * 1024 * 1024;\n\nfunction contextLine(label: string, value: string | number | undefined | null): string | null {\n if (value === undefined || value === null) return null;\n const text = String(value).trim();\n return text ? `${label}: ${text}` : null;\n}\n\nasync function loadWorkItemNativeVisionImages(item: WorkItem): Promise<ImageContent[]> {\n const images: ImageContent[] = [];\n for (const attachment of item.attachments ?? []) {\n if (attachment.type !== 'image') continue;\n if (!attachment.mimeType.toLowerCase().startsWith('image/')) continue;\n if (attachment.size > MAX_NATIVE_VISION_IMAGE_BYTES) continue;\n try {\n const loaded = await readMediaReferenceBase64(attachment.mediaUri, MAX_NATIVE_VISION_IMAGE_BYTES);\n images.push({ type: 'image', data: loaded.data, mimeType: attachment.mimeType || loaded.mimeType });\n if (images.length >= MAX_NATIVE_VISION_IMAGES) break;\n } catch {\n continue;\n }\n }\n return images;\n}\n\nfunction renderAttachmentLines(item: WorkItem, refs?: readonly MediaRef[]): string {\n if (!item.attachments?.length) return '';\n return item.attachments\n .slice(0, 12)\n .map((attachment, index) => {\n const ref = refs?.[index];\n return [\n `- ${ref?.name ?? attachment.fileName} (${ref?.mimeType ?? attachment.mimeType}, ${ref?.size ?? attachment.size} bytes)`,\n ` xopc-media-uri:${ref?.uri ?? attachment.mediaUri}`,\n ' Use the read_media tool with the xopc-media-uri value when you need to inspect this attachment.',\n ].join('\\n');\n })\n .join('\\n');\n}\n\nexport async function buildWorkItemAgentContext(\n item: WorkItem,\n opts: { attachments?: readonly MediaRef[]; includeImages?: boolean } = {},\n): Promise<AgentSourceContext> {\n const links = item.links?.length\n ? item.links\n .slice(0, 12)\n .map((link) => `- ${link.kind}: ${link.title || link.targetId}${link.statusSnapshot ? ` (${link.statusSnapshot})` : ''}`)\n .join('\\n')\n : '';\n const attachments = renderAttachmentLines(item, opts.attachments);\n const images = opts.includeImages === false ? [] : await loadWorkItemNativeVisionImages(item);\n const text = [\n 'You are working inside a project work item. Treat this as the active task context, not as a new user message.',\n '',\n contextLine('Work item id', item.id),\n contextLine('Project id', item.projectId),\n contextLine('Title', item.title),\n contextLine('Status', item.status),\n contextLine('Priority', item.priority),\n contextLine('Owner agent', item.ownerAgentId),\n contextLine('Description', item.description),\n contextLine('Next action', item.nextAction),\n contextLine('Blocked reason', item.blockedReason),\n item.dueAt ? contextLine('Due at', new Date(item.dueAt).toISOString()) : null,\n links ? `Linked executions:\\n${links}` : null,\n attachments ? `Attachments:\\n${attachments}` : null,\n '',\n 'When you answer, keep the work item moving. If the discussion changes scope, call out the suggested work item update explicitly.',\n ].filter(Boolean).join('\\n');\n\n return {\n kind: 'work_item',\n sourceId: item.id,\n version: String(item.updatedAt),\n title: item.title,\n text,\n ...(images.length ? { images } : {}),\n };\n}\n"],"mappings":";;AAQA,MAAM,2BAA2B;AACjC,MAAM,gCAAgC,IAAI,OAAO;AAEjD,SAAS,YAAY,OAAe,OAA0D;AAC5F,KAAI,UAAU,KAAA,KAAa,UAAU,KAAM,QAAO;CAClD,MAAM,OAAO,OAAO,MAAM,CAAC,MAAM;AACjC,QAAO,OAAO,GAAG,MAAM,IAAI,SAAS;;AAGtC,eAAe,+BAA+B,MAAyC;CACrF,MAAM,SAAyB,EAAE;AACjC,MAAK,MAAM,cAAc,KAAK,eAAe,EAAE,EAAE;AAC/C,MAAI,WAAW,SAAS,QAAS;AACjC,MAAI,CAAC,WAAW,SAAS,aAAa,CAAC,WAAW,SAAS,CAAE;AAC7D,MAAI,WAAW,OAAO,8BAA+B;AACrD,MAAI;GACF,MAAM,SAAS,MAAM,yBAAyB,WAAW,UAAU,8BAA8B;AACjG,UAAO,KAAK;IAAE,MAAM;IAAS,MAAM,OAAO;IAAM,UAAU,WAAW,YAAY,OAAO;IAAU,CAAC;AACnG,OAAI,OAAO,UAAU,yBAA0B;UACzC;AACN;;;AAGJ,QAAO;;AAGT,SAAS,sBAAsB,MAAgB,MAAoC;AACjF,KAAI,CAAC,KAAK,aAAa,OAAQ,QAAO;AACtC,QAAO,KAAK,YACT,MAAM,GAAG,GAAG,CACZ,KAAK,YAAY,UAAU;EAC1B,MAAM,MAAM,OAAO;AACnB,SAAO;GACL,KAAK,KAAK,QAAQ,WAAW,SAAS,IAAI,KAAK,YAAY,WAAW,SAAS,IAAI,KAAK,QAAQ,WAAW,KAAK;GAChH,oBAAoB,KAAK,OAAO,WAAW;GAC3C;GACD,CAAC,KAAK,KAAK;GACZ,CACD,KAAK,KAAK;;AAGf,eAAsB,0BACpB,MACA,OAAuE,EAAE,EAC5C;CAC7B,MAAM,QAAQ,KAAK,OAAO,SACtB,KAAK,MACJ,MAAM,GAAG,GAAG,CACZ,KAAK,SAAS,KAAK,KAAK,KAAK,IAAI,KAAK,SAAS,KAAK,WAAW,KAAK,iBAAiB,KAAK,KAAK,eAAe,KAAK,KAAK,CACxH,KAAK,KAAK,GACX;CACJ,MAAM,cAAc,sBAAsB,MAAM,KAAK,YAAY;CACjE,MAAM,SAAS,KAAK,kBAAkB,QAAQ,EAAE,GAAG,MAAM,+BAA+B,KAAK;CAC7F,MAAM,OAAO;EACX;EACA;EACA,YAAY,gBAAgB,KAAK,GAAG;EACpC,YAAY,cAAc,KAAK,UAAU;EACzC,YAAY,SAAS,KAAK,MAAM;EAChC,YAAY,UAAU,KAAK,OAAO;EAClC,YAAY,YAAY,KAAK,SAAS;EACtC,YAAY,eAAe,KAAK,aAAa;EAC7C,YAAY,eAAe,KAAK,YAAY;EAC5C,YAAY,eAAe,KAAK,WAAW;EAC3C,YAAY,kBAAkB,KAAK,cAAc;EACjD,KAAK,QAAQ,YAAY,UAAU,IAAI,KAAK,KAAK,MAAM,CAAC,aAAa,CAAC,GAAG;EACzE,QAAQ,uBAAuB,UAAU;EACzC,cAAc,iBAAiB,gBAAgB;EAC/C;EACA;EACD,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;AAE5B,QAAO;EACL,MAAM;EACN,UAAU,KAAK;EACf,SAAS,OAAO,KAAK,UAAU;EAC/B,OAAO,KAAK;EACZ;EACA,GAAI,OAAO,SAAS,EAAE,QAAQ,GAAG,EAAE;EACpC"}
@@ -1,3 +1,4 @@
1
+ import type { MediaRef } from '../media/types.js';
1
2
  import { WorkItemStore } from './work-item-store.js';
2
3
  import type { CreateWorkItemUpdateSuggestionInput, CreateWorkItemInput, UpdateWorkItemInput, WorkItem, WorkItemAttachment, WorkItemEvent, WorkItemLink, WorkItemListQuery, WorkItemListResult, WorkItemUpdateSuggestion, WorkItemUpdateSuggestionStatus } from './types.js';
3
4
  export declare const WORK_ITEM_ATTACHMENT_MAX_BYTES: number;
@@ -23,6 +24,7 @@ export declare class WorkItemService {
23
24
  buffer: Buffer;
24
25
  } | null>;
25
26
  removeAttachment(workItemId: string, attachmentId: string): Promise<WorkItemAttachment | null>;
27
+ snapshotAttachmentsForGoal(workItemId: string): Promise<MediaRef[] | null>;
26
28
  createUpdateSuggestion(workItemId: string, input: CreateWorkItemUpdateSuggestionInput): WorkItemUpdateSuggestion | null;
27
29
  listUpdateSuggestions(workItemId: string, status?: WorkItemUpdateSuggestionStatus): WorkItemUpdateSuggestion[];
28
30
  applyUpdateSuggestion(id: string): {
@@ -1,3 +1,4 @@
1
+ import { changedFieldsFromPatch, emitActivity, systemActivityActor, systemActivitySource } from "../activity/emitter.js";
1
2
  import { deleteMediaBuffer, mimeTypeFromMediaPath, saveMediaBuffer } from "../media/store.js";
2
3
  import { readMediaReference } from "../media/media-reference.js";
3
4
  import { WorkItemStore } from "./work-item-store.js";
@@ -11,6 +12,9 @@ function inferAttachmentType(mimeType) {
11
12
  if (mimeType.startsWith("video/")) return "video";
12
13
  return "file";
13
14
  }
15
+ function attachmentTypeForMediaRef(attachment) {
16
+ return attachment.type === "file" ? "document" : attachment.type;
17
+ }
14
18
  var WorkItemService = class {
15
19
  constructor(store = new WorkItemStore()) {
16
20
  this.store = store;
@@ -25,6 +29,27 @@ var WorkItemService = class {
25
29
  status: item.status,
26
30
  priority: item.priority
27
31
  });
32
+ emitActivity({
33
+ type: "work_item.created",
34
+ primaryObject: {
35
+ kind: "work_item",
36
+ id: item.id,
37
+ title: item.title
38
+ },
39
+ actor: systemActivityActor(),
40
+ source: systemActivitySource(),
41
+ payload: {
42
+ title: item.title,
43
+ status: item.status,
44
+ priority: item.priority
45
+ },
46
+ scopes: [{
47
+ scopeKind: "project",
48
+ scopeId: projectId,
49
+ reason: "object_owner"
50
+ }],
51
+ nowMs: item.createdAt
52
+ });
28
53
  return {
29
54
  ...item,
30
55
  links: []
@@ -44,6 +69,31 @@ var WorkItemService = class {
44
69
  });
45
70
  else this.store.addEvent(id, "updated", patch);
46
71
  if (!before.archivedAt && after.archivedAt) this.store.addEvent(id, "archived", { archivedAt: after.archivedAt });
72
+ const type = !before.archivedAt && after.archivedAt ? "work_item.archived" : before.status !== after.status ? "work_item.status_changed" : "work_item.updated";
73
+ emitActivity({
74
+ type,
75
+ primaryObject: {
76
+ kind: "work_item",
77
+ id: after.id,
78
+ title: after.title
79
+ },
80
+ actor: systemActivityActor(),
81
+ source: systemActivitySource(),
82
+ payload: {
83
+ changes: changedFieldsFromPatch(patch),
84
+ ...type === "work_item.status_changed" ? {
85
+ from: before.status,
86
+ to: after.status
87
+ } : {},
88
+ ...type === "work_item.archived" ? { archivedAt: after.archivedAt } : {}
89
+ },
90
+ scopes: [{
91
+ scopeKind: "project",
92
+ scopeId: after.projectId,
93
+ reason: "object_owner"
94
+ }],
95
+ nowMs: after.updatedAt
96
+ });
47
97
  return after;
48
98
  }
49
99
  addLink(workItemId, input, eventType = "link_added") {
@@ -58,6 +108,28 @@ var WorkItemService = class {
58
108
  title: link.title,
59
109
  statusSnapshot: link.statusSnapshot
60
110
  });
111
+ const item = this.store.get(workItemId);
112
+ if (item) emitActivity({
113
+ type: "work_item.link_added",
114
+ primaryObject: {
115
+ kind: "work_item",
116
+ id: item.id,
117
+ title: item.title
118
+ },
119
+ actor: systemActivityActor(),
120
+ source: systemActivitySource(),
121
+ payload: { target: {
122
+ kind: link.kind,
123
+ id: link.targetId,
124
+ title: link.title
125
+ } },
126
+ scopes: [{
127
+ scopeKind: "project",
128
+ scopeId: item.projectId,
129
+ reason: "object_owner"
130
+ }],
131
+ nowMs: link.createdAt
132
+ });
61
133
  return link;
62
134
  }
63
135
  listEvents(workItemId) {
@@ -115,6 +187,31 @@ var WorkItemService = class {
115
187
  });
116
188
  return attachment;
117
189
  }
190
+ async snapshotAttachmentsForGoal(workItemId) {
191
+ const item = this.store.get(workItemId);
192
+ if (!item) return null;
193
+ const refs = [];
194
+ for (const attachment of item.attachments ?? []) {
195
+ const { buffer } = await readMediaReference(attachment.mediaUri, WORK_ITEM_ATTACHMENT_MAX_BYTES);
196
+ const saved = await saveMediaBuffer(buffer, {
197
+ bucket: "inbound",
198
+ contentType: attachment.mimeType,
199
+ maxBytes: WORK_ITEM_ATTACHMENT_MAX_BYTES,
200
+ originalFilename: attachment.fileName
201
+ });
202
+ refs.push({
203
+ id: saved.id,
204
+ bucket: saved.bucket,
205
+ type: attachmentTypeForMediaRef(attachment),
206
+ mimeType: saved.contentType || attachment.mimeType,
207
+ name: attachment.fileName,
208
+ size: saved.size,
209
+ uri: saved.uri,
210
+ path: saved.path
211
+ });
212
+ }
213
+ return refs;
214
+ }
118
215
  createUpdateSuggestion(workItemId, input) {
119
216
  const suggestion = this.store.createUpdateSuggestion(workItemId, input);
120
217
  if (!suggestion) return null;
@@ -1 +1 @@
1
- {"version":3,"file":"work-item-service.js","names":[],"sources":["../../../src/work-items/work-item-service.ts"],"sourcesContent":["import { deleteMediaBuffer, mimeTypeFromMediaPath, saveMediaBuffer } from '../media/store.js';\nimport { readMediaReference } from '../media/media-reference.js';\nimport { WorkItemStore } from './work-item-store.js';\nimport type {\n CreateWorkItemUpdateSuggestionInput,\n CreateWorkItemInput,\n UpdateWorkItemInput,\n WorkItem,\n WorkItemAttachment,\n WorkItemEvent,\n WorkItemLink,\n WorkItemListQuery,\n WorkItemListResult,\n WorkItemUpdateSuggestion,\n WorkItemUpdateSuggestionStatus,\n} from './types.js';\n\nexport const WORK_ITEM_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;\nexport const WORK_ITEM_ATTACHMENT_MAX_COUNT = 10;\nexport const WORK_ITEM_ATTACHMENT_UPLOAD_BODY_MAX_BYTES =\n WORK_ITEM_ATTACHMENT_MAX_BYTES * WORK_ITEM_ATTACHMENT_MAX_COUNT + 1024 * 1024;\n\nfunction inferAttachmentType(mimeType: string): WorkItemAttachment['type'] {\n if (mimeType.startsWith('image/')) return 'image';\n if (mimeType.startsWith('audio/')) return 'audio';\n if (mimeType.startsWith('video/')) return 'video';\n return 'file';\n}\n\nexport class WorkItemService {\n constructor(private readonly store = new WorkItemStore()) {}\n\n listProjectWorkItems(projectId: string, query: WorkItemListQuery = {}): WorkItemListResult {\n return this.store.list(projectId, query);\n }\n\n createProjectWorkItem(projectId: string, input: CreateWorkItemInput): WorkItem {\n const item = this.store.create(projectId, input);\n this.store.addEvent(item.id, 'created', { title: item.title, status: item.status, priority: item.priority });\n return { ...item, links: [] };\n }\n\n getWorkItem(id: string): WorkItem | null {\n return this.store.get(id);\n }\n\n updateWorkItem(id: string, patch: UpdateWorkItemInput): WorkItem | null {\n const before = this.store.get(id);\n if (!before) return null;\n const after = this.store.update(id, patch);\n if (!after) return null;\n if (before.status !== after.status) {\n this.store.addEvent(id, 'status_changed', { from: before.status, to: after.status });\n } else {\n this.store.addEvent(id, 'updated', patch);\n }\n if (!before.archivedAt && after.archivedAt) {\n this.store.addEvent(id, 'archived', { archivedAt: after.archivedAt });\n }\n return after;\n }\n\n addLink(workItemId: string, input: Omit<WorkItemLink, 'id' | 'workItemId' | 'createdAt'>, eventType: Parameters<WorkItemStore['addEvent']>[1] = 'link_added'): WorkItemLink | null {\n if (!this.store.get(workItemId)) return null;\n const link = this.store.addLink({ ...input, workItemId });\n this.store.addEvent(workItemId, eventType, { kind: link.kind, targetId: link.targetId, title: link.title, statusSnapshot: link.statusSnapshot });\n return link;\n }\n\n listEvents(workItemId: string): WorkItemEvent[] {\n return this.store.listEvents(workItemId);\n }\n\n listAttachments(workItemId: string): WorkItemAttachment[] | null {\n if (!this.store.get(workItemId)) return null;\n return this.store.listAttachments(workItemId);\n }\n\n async addAttachment(\n workItemId: string,\n file: { name: string; buffer: Buffer; mimeType: string },\n ): Promise<WorkItemAttachment | null> {\n if (!this.store.get(workItemId)) return null;\n const saved = await saveMediaBuffer(file.buffer, {\n bucket: 'work-item',\n contentType: file.mimeType,\n maxBytes: WORK_ITEM_ATTACHMENT_MAX_BYTES,\n originalFilename: file.name,\n });\n const mimeType = saved.contentType || file.mimeType || mimeTypeFromMediaPath(saved.path);\n const attachment = this.store.addAttachment({\n workItemId,\n mediaUri: saved.uri,\n mediaId: saved.id,\n bucket: saved.bucket,\n type: inferAttachmentType(mimeType),\n mimeType,\n fileName: file.name.trim() || saved.id,\n size: saved.size,\n });\n this.store.addEvent(workItemId, 'attachment_added', {\n attachmentId: attachment.id,\n fileName: attachment.fileName,\n mimeType: attachment.mimeType,\n size: attachment.size,\n });\n return attachment;\n }\n\n async readAttachment(\n workItemId: string,\n attachmentId: string,\n ): Promise<{ attachment: WorkItemAttachment; buffer: Buffer } | null> {\n const attachment = this.store.getAttachment(workItemId, attachmentId);\n if (!attachment) return null;\n const { buffer } = await readMediaReference(attachment.mediaUri, WORK_ITEM_ATTACHMENT_MAX_BYTES);\n return { attachment, buffer };\n }\n\n async removeAttachment(workItemId: string, attachmentId: string): Promise<WorkItemAttachment | null> {\n const attachment = this.store.removeAttachment(workItemId, attachmentId);\n if (!attachment) return null;\n await deleteMediaBuffer(attachment.mediaId, 'work-item');\n this.store.addEvent(workItemId, 'attachment_removed', {\n attachmentId: attachment.id,\n fileName: attachment.fileName,\n mimeType: attachment.mimeType,\n size: attachment.size,\n });\n return attachment;\n }\n\n createUpdateSuggestion(workItemId: string, input: CreateWorkItemUpdateSuggestionInput): WorkItemUpdateSuggestion | null {\n const suggestion = this.store.createUpdateSuggestion(workItemId, input);\n if (!suggestion) return null;\n this.store.addEvent(workItemId, 'update_suggestion_created', {\n suggestionId: suggestion.id,\n sourceKind: suggestion.sourceKind,\n sourceId: suggestion.sourceId,\n patch: suggestion.patch,\n hasProgressNote: Boolean(suggestion.progressNote),\n });\n return suggestion;\n }\n\n listUpdateSuggestions(workItemId: string, status?: WorkItemUpdateSuggestionStatus): WorkItemUpdateSuggestion[] {\n return this.store.listUpdateSuggestions(workItemId, status);\n }\n\n applyUpdateSuggestion(id: string): { item: WorkItem; suggestion: WorkItemUpdateSuggestion } | null {\n const suggestion = this.store.getUpdateSuggestion(id);\n if (!suggestion || suggestion.status !== 'pending') return null;\n const before = this.store.get(suggestion.workItemId);\n if (!before) return null;\n const patch: UpdateWorkItemInput = {};\n if (suggestion.patch.status !== undefined) patch.status = suggestion.patch.status;\n if (suggestion.patch.nextAction !== undefined) patch.nextAction = suggestion.patch.nextAction;\n if (suggestion.patch.blockedReason !== undefined) patch.blockedReason = suggestion.patch.blockedReason;\n const item = Object.keys(patch).length > 0\n ? this.updateWorkItem(suggestion.workItemId, patch)\n : before;\n if (!item) return null;\n if (suggestion.progressNote) {\n this.store.addEvent(suggestion.workItemId, 'progress_note_added', {\n sourceKind: suggestion.sourceKind,\n sourceId: suggestion.sourceId,\n suggestionId: suggestion.id,\n text: suggestion.progressNote,\n });\n }\n const marked = this.store.markUpdateSuggestion(id, 'applied');\n if (!marked) return null;\n this.store.addEvent(suggestion.workItemId, 'update_suggestion_applied', {\n suggestionId: suggestion.id,\n sourceKind: suggestion.sourceKind,\n sourceId: suggestion.sourceId,\n patch,\n previousStatus: before.status,\n nextStatus: item.status,\n });\n return { item, suggestion: marked };\n }\n\n dismissUpdateSuggestion(id: string): WorkItemUpdateSuggestion | null {\n const suggestion = this.store.getUpdateSuggestion(id);\n if (!suggestion || suggestion.status !== 'pending') return null;\n const marked = this.store.markUpdateSuggestion(id, 'dismissed');\n if (marked) {\n this.store.addEvent(marked.workItemId, 'update_suggestion_dismissed', {\n suggestionId: marked.id,\n sourceKind: marked.sourceKind,\n sourceId: marked.sourceId,\n });\n }\n return marked;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"work-item-service.js","names":[],"sources":["../../../src/work-items/work-item-service.ts"],"sourcesContent":["import { changedFieldsFromPatch, emitActivity, systemActivityActor, systemActivitySource } from '../activity/emitter.js';\nimport { deleteMediaBuffer, mimeTypeFromMediaPath, saveMediaBuffer } from '../media/store.js';\nimport { readMediaReference } from '../media/media-reference.js';\nimport type { MediaRef } from '../media/types.js';\nimport { WorkItemStore } from './work-item-store.js';\nimport type {\n CreateWorkItemUpdateSuggestionInput,\n CreateWorkItemInput,\n UpdateWorkItemInput,\n WorkItem,\n WorkItemAttachment,\n WorkItemEvent,\n WorkItemLink,\n WorkItemListQuery,\n WorkItemListResult,\n WorkItemUpdateSuggestion,\n WorkItemUpdateSuggestionStatus,\n} from './types.js';\n\nexport const WORK_ITEM_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;\nexport const WORK_ITEM_ATTACHMENT_MAX_COUNT = 10;\nexport const WORK_ITEM_ATTACHMENT_UPLOAD_BODY_MAX_BYTES =\n WORK_ITEM_ATTACHMENT_MAX_BYTES * WORK_ITEM_ATTACHMENT_MAX_COUNT + 1024 * 1024;\n\nfunction inferAttachmentType(mimeType: string): WorkItemAttachment['type'] {\n if (mimeType.startsWith('image/')) return 'image';\n if (mimeType.startsWith('audio/')) return 'audio';\n if (mimeType.startsWith('video/')) return 'video';\n return 'file';\n}\n\nfunction attachmentTypeForMediaRef(attachment: WorkItemAttachment): string {\n return attachment.type === 'file' ? 'document' : attachment.type;\n}\n\nexport class WorkItemService {\n constructor(private readonly store = new WorkItemStore()) {}\n\n listProjectWorkItems(projectId: string, query: WorkItemListQuery = {}): WorkItemListResult {\n return this.store.list(projectId, query);\n }\n\n createProjectWorkItem(projectId: string, input: CreateWorkItemInput): WorkItem {\n const item = this.store.create(projectId, input);\n this.store.addEvent(item.id, 'created', { title: item.title, status: item.status, priority: item.priority });\n emitActivity({\n type: 'work_item.created',\n primaryObject: { kind: 'work_item', id: item.id, title: item.title },\n actor: systemActivityActor(),\n source: systemActivitySource(),\n payload: { title: item.title, status: item.status, priority: item.priority },\n scopes: [{ scopeKind: 'project', scopeId: projectId, reason: 'object_owner' }],\n nowMs: item.createdAt,\n });\n return { ...item, links: [] };\n }\n\n getWorkItem(id: string): WorkItem | null {\n return this.store.get(id);\n }\n\n updateWorkItem(id: string, patch: UpdateWorkItemInput): WorkItem | null {\n const before = this.store.get(id);\n if (!before) return null;\n const after = this.store.update(id, patch);\n if (!after) return null;\n if (before.status !== after.status) {\n this.store.addEvent(id, 'status_changed', { from: before.status, to: after.status });\n } else {\n this.store.addEvent(id, 'updated', patch);\n }\n if (!before.archivedAt && after.archivedAt) {\n this.store.addEvent(id, 'archived', { archivedAt: after.archivedAt });\n }\n const type = !before.archivedAt && after.archivedAt\n ? 'work_item.archived'\n : before.status !== after.status\n ? 'work_item.status_changed'\n : 'work_item.updated';\n emitActivity({\n type,\n primaryObject: { kind: 'work_item', id: after.id, title: after.title },\n actor: systemActivityActor(),\n source: systemActivitySource(),\n payload: {\n changes: changedFieldsFromPatch(patch as Record<string, unknown>),\n ...(type === 'work_item.status_changed' ? { from: before.status, to: after.status } : {}),\n ...(type === 'work_item.archived' ? { archivedAt: after.archivedAt } : {}),\n },\n scopes: [{ scopeKind: 'project', scopeId: after.projectId, reason: 'object_owner' }],\n nowMs: after.updatedAt,\n });\n return after;\n }\n\n addLink(workItemId: string, input: Omit<WorkItemLink, 'id' | 'workItemId' | 'createdAt'>, eventType: Parameters<WorkItemStore['addEvent']>[1] = 'link_added'): WorkItemLink | null {\n if (!this.store.get(workItemId)) return null;\n const link = this.store.addLink({ ...input, workItemId });\n this.store.addEvent(workItemId, eventType, { kind: link.kind, targetId: link.targetId, title: link.title, statusSnapshot: link.statusSnapshot });\n const item = this.store.get(workItemId);\n if (item) {\n emitActivity({\n type: 'work_item.link_added',\n primaryObject: { kind: 'work_item', id: item.id, title: item.title },\n actor: systemActivityActor(),\n source: systemActivitySource(),\n payload: { target: { kind: link.kind, id: link.targetId, title: link.title } },\n scopes: [{ scopeKind: 'project', scopeId: item.projectId, reason: 'object_owner' }],\n nowMs: link.createdAt,\n });\n }\n return link;\n }\n\n listEvents(workItemId: string): WorkItemEvent[] {\n return this.store.listEvents(workItemId);\n }\n\n listAttachments(workItemId: string): WorkItemAttachment[] | null {\n if (!this.store.get(workItemId)) return null;\n return this.store.listAttachments(workItemId);\n }\n\n async addAttachment(\n workItemId: string,\n file: { name: string; buffer: Buffer; mimeType: string },\n ): Promise<WorkItemAttachment | null> {\n if (!this.store.get(workItemId)) return null;\n const saved = await saveMediaBuffer(file.buffer, {\n bucket: 'work-item',\n contentType: file.mimeType,\n maxBytes: WORK_ITEM_ATTACHMENT_MAX_BYTES,\n originalFilename: file.name,\n });\n const mimeType = saved.contentType || file.mimeType || mimeTypeFromMediaPath(saved.path);\n const attachment = this.store.addAttachment({\n workItemId,\n mediaUri: saved.uri,\n mediaId: saved.id,\n bucket: saved.bucket,\n type: inferAttachmentType(mimeType),\n mimeType,\n fileName: file.name.trim() || saved.id,\n size: saved.size,\n });\n this.store.addEvent(workItemId, 'attachment_added', {\n attachmentId: attachment.id,\n fileName: attachment.fileName,\n mimeType: attachment.mimeType,\n size: attachment.size,\n });\n return attachment;\n }\n\n async readAttachment(\n workItemId: string,\n attachmentId: string,\n ): Promise<{ attachment: WorkItemAttachment; buffer: Buffer } | null> {\n const attachment = this.store.getAttachment(workItemId, attachmentId);\n if (!attachment) return null;\n const { buffer } = await readMediaReference(attachment.mediaUri, WORK_ITEM_ATTACHMENT_MAX_BYTES);\n return { attachment, buffer };\n }\n\n async removeAttachment(workItemId: string, attachmentId: string): Promise<WorkItemAttachment | null> {\n const attachment = this.store.removeAttachment(workItemId, attachmentId);\n if (!attachment) return null;\n await deleteMediaBuffer(attachment.mediaId, 'work-item');\n this.store.addEvent(workItemId, 'attachment_removed', {\n attachmentId: attachment.id,\n fileName: attachment.fileName,\n mimeType: attachment.mimeType,\n size: attachment.size,\n });\n return attachment;\n }\n\n async snapshotAttachmentsForGoal(workItemId: string): Promise<MediaRef[] | null> {\n const item = this.store.get(workItemId);\n if (!item) return null;\n const refs: MediaRef[] = [];\n for (const attachment of item.attachments ?? []) {\n const { buffer } = await readMediaReference(attachment.mediaUri, WORK_ITEM_ATTACHMENT_MAX_BYTES);\n const saved = await saveMediaBuffer(buffer, {\n bucket: 'inbound',\n contentType: attachment.mimeType,\n maxBytes: WORK_ITEM_ATTACHMENT_MAX_BYTES,\n originalFilename: attachment.fileName,\n });\n refs.push({\n id: saved.id,\n bucket: saved.bucket,\n type: attachmentTypeForMediaRef(attachment),\n mimeType: saved.contentType || attachment.mimeType,\n name: attachment.fileName,\n size: saved.size,\n uri: saved.uri,\n path: saved.path,\n });\n }\n return refs;\n }\n\n createUpdateSuggestion(workItemId: string, input: CreateWorkItemUpdateSuggestionInput): WorkItemUpdateSuggestion | null {\n const suggestion = this.store.createUpdateSuggestion(workItemId, input);\n if (!suggestion) return null;\n this.store.addEvent(workItemId, 'update_suggestion_created', {\n suggestionId: suggestion.id,\n sourceKind: suggestion.sourceKind,\n sourceId: suggestion.sourceId,\n patch: suggestion.patch,\n hasProgressNote: Boolean(suggestion.progressNote),\n });\n return suggestion;\n }\n\n listUpdateSuggestions(workItemId: string, status?: WorkItemUpdateSuggestionStatus): WorkItemUpdateSuggestion[] {\n return this.store.listUpdateSuggestions(workItemId, status);\n }\n\n applyUpdateSuggestion(id: string): { item: WorkItem; suggestion: WorkItemUpdateSuggestion } | null {\n const suggestion = this.store.getUpdateSuggestion(id);\n if (!suggestion || suggestion.status !== 'pending') return null;\n const before = this.store.get(suggestion.workItemId);\n if (!before) return null;\n const patch: UpdateWorkItemInput = {};\n if (suggestion.patch.status !== undefined) patch.status = suggestion.patch.status;\n if (suggestion.patch.nextAction !== undefined) patch.nextAction = suggestion.patch.nextAction;\n if (suggestion.patch.blockedReason !== undefined) patch.blockedReason = suggestion.patch.blockedReason;\n const item = Object.keys(patch).length > 0\n ? this.updateWorkItem(suggestion.workItemId, patch)\n : before;\n if (!item) return null;\n if (suggestion.progressNote) {\n this.store.addEvent(suggestion.workItemId, 'progress_note_added', {\n sourceKind: suggestion.sourceKind,\n sourceId: suggestion.sourceId,\n suggestionId: suggestion.id,\n text: suggestion.progressNote,\n });\n }\n const marked = this.store.markUpdateSuggestion(id, 'applied');\n if (!marked) return null;\n this.store.addEvent(suggestion.workItemId, 'update_suggestion_applied', {\n suggestionId: suggestion.id,\n sourceKind: suggestion.sourceKind,\n sourceId: suggestion.sourceId,\n patch,\n previousStatus: before.status,\n nextStatus: item.status,\n });\n return { item, suggestion: marked };\n }\n\n dismissUpdateSuggestion(id: string): WorkItemUpdateSuggestion | null {\n const suggestion = this.store.getUpdateSuggestion(id);\n if (!suggestion || suggestion.status !== 'pending') return null;\n const marked = this.store.markUpdateSuggestion(id, 'dismissed');\n if (marked) {\n this.store.addEvent(marked.workItemId, 'update_suggestion_dismissed', {\n suggestionId: marked.id,\n sourceKind: marked.sourceKind,\n sourceId: marked.sourceId,\n });\n }\n return marked;\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
4
4
  import { getDefaultModelSync, init_providers, resolveModel } from "../../providers/index.js";
5
5
  import { resolveModelRef } from "../../config/agent-typed-models.js";
6
6
  import { buildWorkflowDraftPrompt, buildWorkflowDraftRepairPrompt } from "./workflow-draft-prompt.js";
@@ -1,8 +1,8 @@
1
+ import "../../session/types.js";
1
2
  import { renderWorkflowText } from "../../agent/workflow/snapshot.js";
2
3
  import { runViewToSnapshot } from "./run-view-to-snapshot.js";
3
4
  import { GoalWorkflowJudge } from "../../goals/goal-workflow-judge.js";
4
5
  import "../../goals/index.js";
5
- import "../../session/types.js";
6
6
  import { isTerminalWorkflowRunStatus } from "../domain/run.js";
7
7
  import "../domain/index.js";
8
8
  import { buildWorkflowRunSessionKey } from "./workflow-session-key.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xopcai/xopc",
3
- "version": "0.0.125",
3
+ "version": "0.0.127",
4
4
  "description": "Local-first AI system that remembers context, coordinates AI, and sustains long-term progress.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -65,10 +65,10 @@
65
65
  "node": ">=22.19.0"
66
66
  },
67
67
  "dependencies": {
68
- "@earendil-works/pi-agent-core": "^0.80.3",
69
- "@earendil-works/pi-ai": "^0.80.3",
70
- "@earendil-works/pi-coding-agent": "^0.80.3",
71
- "@earendil-works/pi-tui": "^0.80.3",
68
+ "@earendil-works/pi-agent-core": "^0.80.6",
69
+ "@earendil-works/pi-ai": "^0.80.6",
70
+ "@earendil-works/pi-coding-agent": "^0.80.6",
71
+ "@earendil-works/pi-tui": "^0.80.6",
72
72
  "@grammyjs/runner": "^2.0.3",
73
73
  "@hono/node-server": "^2.0.4",
74
74
  "@inquirer/prompts": "^8.5.0",
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: hatch-pet
3
+ description: Create and install a custom animated xopc desktop pet from a user description.
4
+ metadata:
5
+ xopc:
6
+ activates_capabilities:
7
+ - desktop-pet-authoring
8
+ ---
9
+
10
+ # Hatch Pet
11
+
12
+ Use this skill when the user wants to create, customize, refine, or install an xopc desktop pet.
13
+
14
+ ## Conversation flow
15
+
16
+ Do not jump straight to `create_desktop_pet` when the pet idea is vague. First guide the user with `clarify` so the final pet has a clear visual identity, personality, and action set.
17
+
18
+ Use at most 3 concise `clarify` calls before creating or updating the pet. Each call should ask one short question. Provide `choices` when useful, set a sensible `default`, and write the question so the user knows they can type their own custom answer instead of picking a listed option.
19
+
20
+ Recommended questions for a new pet:
21
+
22
+ 1. Base character: ask what kind of pet it should be.
23
+ - Choices: `Tiny robot companion`, `Cute animal mascot`, `Plant or object spirit`, `Describe my own`
24
+ - Default: `Tiny robot companion`
25
+ 2. Visual mood: ask what style or vibe it should have.
26
+ - Choices: `Soft and cute`, `Techy and energetic`, `Calm and focused`, `Describe my own`
27
+ - Default: `Soft and cute`
28
+ 3. Signature work behavior: ask which behavior should be most recognizable.
29
+ - Choices: `Typing at a laptop`, `Searching a toolbox`, `Celebrating completed work`, `Describe my own`
30
+ - Default: `Typing at a laptop`
31
+
32
+ For an existing pet update, ask only what is missing for the requested refinement:
33
+
34
+ 1. Refinement target: ask what should change.
35
+ - Choices: `Appearance`, `Personality and dialogue`, `Animations and work actions`, `Everything`
36
+ - Default: `Animations and work actions`
37
+ 2. Update behavior: overwrite the same custom pet by default. Ask about renaming or creating a variant only if the user explicitly requests a separate version.
38
+
39
+ Skip clarification when the user already supplied enough detail, or when they explicitly asked you to choose. In that case, choose a coherent cute desktop-helper design and proceed.
40
+
41
+ ## Prompt assembly
42
+
43
+ After clarification, synthesize one complete `prompt` for `create_desktop_pet`. Include:
44
+
45
+ - The pet's base form, silhouette, colors, face/expression, and visual style.
46
+ - Personality and short dialogue tone.
47
+ - Required desktop-helper animation ideas: idle, greeting, thinking, typing at a laptop, searching through a toolbox, reading/searching, file or terminal work, success celebration, and error/blocked reaction.
48
+ - Any user-requested refinements, constraints, or brand cues.
49
+ - A note that the pet should read clearly at small desktop size and feel cute, lively, and polished.
50
+
51
+ Do not expose implementation details to the user unless they ask.
52
+
53
+ ## Tool call
54
+
55
+ Once the pet concept is clear, call `create_desktop_pet` with:
56
+
57
+ - `mode`: use `create` for a new pet; use `update` when the user is refining an existing custom pet.
58
+ - `petId`: required for `update`; pass the id from Settings, including the `custom:` prefix if present.
59
+ - `name`: a short display name when the user provides or implies one.
60
+ - `prompt`: the full visual and personality description, including all requested refinements.
61
+ - `description`: a concise one-line description for Settings.
62
+
63
+ When updating an existing pet, keep the same name unless the user explicitly asks to rename it. After the tool succeeds, tell the user the pet was installed under `~/.xopc/pets` and can be selected from Settings > Pet.