@xopcai/xopc 0.0.197 → 0.0.199

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 (224) 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/{activity-store-BwmdJ5pv.js → activity-store-DYVN1hRp.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-C5st7lt5.js → agent-avatar-dicebear-Bt70bZjv.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-D19uNmJf.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-BM1hNzjw.js → api-B8mzbAle.js} +1 -1
  7. package/dist/gateway/static/root/assets/app-management-settings-panel-B4x7JfL8.js +1 -0
  8. package/dist/gateway/static/root/assets/appearance-settings-Dwdagf-Q.js +1 -0
  9. package/dist/gateway/static/root/assets/apps-page-DkTiesxe.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-qL07mwnY.js → archive-plugin-Cv0VXKLm.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-CqSobpdi.js → attachment-load-CgidKrXn.js} +1 -1
  12. package/dist/gateway/static/root/assets/automations-page-BR6qMOVr.js +6 -0
  13. package/dist/gateway/static/root/assets/{binary-plugins-DBRPyLYE.js → binary-plugins-DN3CQgIq.js} +1 -1
  14. package/dist/gateway/static/root/assets/{block-editor-6wG1LU7t.js → block-editor-BwkSl1F_.js} +5 -5
  15. package/dist/gateway/static/root/assets/browser-settings-page-CDFQWAxI.js +8 -0
  16. package/dist/gateway/static/root/assets/browser-workflow-inputs-_ndaecsf.js +1 -0
  17. package/dist/gateway/static/root/assets/{browser-workflows-page-BEu3E0et.js → browser-workflows-page-C_I31wLm.js} +2 -2
  18. package/dist/gateway/static/root/assets/button-CSEbl4zT.js +1 -0
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-D41mssOq.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-BoOzFotX.js → capability-presets-api-Dy1jZJKs.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BXgCyuu2.js +3 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-_8IiTxRB.js → channel-recipient-api-D-9qiuio.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-DV5BhAeu.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-B4Rbh3bM.js +1 -0
  25. package/dist/gateway/static/root/assets/connectors-api-5FEBYguL.js +1 -0
  26. package/dist/gateway/static/root/assets/connectors-page-C_qkEN0T.js +2 -0
  27. package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
  28. package/dist/gateway/static/root/assets/cron-expression-SEFx5rnr.js +2 -0
  29. package/dist/gateway/static/root/assets/date-picker-D4zCUQJL.js +1 -0
  30. package/dist/gateway/static/root/assets/dependency-picker-DpQAxS2k.js +1 -0
  31. package/dist/gateway/static/root/assets/{desktop-pet-CsLR4pWB.js → desktop-pet-B_5G3lQl.js} +1 -1
  32. package/dist/gateway/static/root/assets/desktop-pet-settings-ClEyoUJe.js +1 -0
  33. package/dist/gateway/static/root/assets/directory-picker-path-field-AsFWmOjG.js +1 -0
  34. package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +1 -0
  35. package/dist/gateway/static/root/assets/dist-DY4Af0fY.js +1 -0
  36. package/dist/gateway/static/root/assets/{extension-debug-page-CD73euAM.js → extension-debug-page-C22Y2o5l.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-DAKjpNwd.js → extension-page-C61Ikawk.js} +1 -1
  38. package/dist/gateway/static/root/assets/extension-settings-page-WlWWcDFr.js +1 -0
  39. package/dist/gateway/static/root/assets/external-link-DjqjBmc3.js +1 -0
  40. package/dist/gateway/static/root/assets/form-field-width-DJw_jULe.js +1 -0
  41. package/dist/gateway/static/root/assets/gateway-config-api-ByIOMQdc.js +1 -0
  42. package/dist/gateway/static/root/assets/gateway-config-swr-jB0hAhWO.js +1 -0
  43. package/dist/gateway/static/root/assets/gateway-settings-CzzS9A17.js +1 -0
  44. package/dist/gateway/static/root/assets/{gateway-startup-retry--2njcDpC.js → gateway-startup-retry-C-fRlHCL.js} +1 -1
  45. package/dist/gateway/static/root/assets/globe-DSSGFWFn.js +1 -0
  46. package/dist/gateway/static/root/assets/heartbeat-settings-B4A_CXUL.js +1 -0
  47. package/dist/gateway/static/root/assets/home-page-FVGYYPWo.js +3 -0
  48. package/dist/gateway/static/root/assets/index-CGbKTCST.js +152 -0
  49. package/dist/gateway/static/root/assets/index-CR233S0Q.css +1 -0
  50. package/dist/gateway/static/root/assets/interaction-BmQogeqz.js +1 -0
  51. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-HMhxgOuD.js → keyboard-shortcuts-settings-BD_TFz0_.js} +1 -1
  52. package/dist/gateway/static/root/assets/loader-circle-CifKLtgG.js +1 -0
  53. package/dist/gateway/static/root/assets/local-app-workbench-page-BNpkigNb.js +2 -0
  54. package/dist/gateway/static/root/assets/local-apps-page-BwbUeLfm.js +1 -0
  55. package/dist/gateway/static/root/assets/{locale-store-Bjvw7jtg.js → locale-store-xULEcFVs.js} +1 -1
  56. package/dist/gateway/static/root/assets/logs-page-DXP9OQQt.js +2 -0
  57. package/dist/gateway/static/root/assets/management-settings-CW2VpqtT.js +1 -0
  58. package/dist/gateway/static/root/assets/{markdown-split-DvVBewS4.js → markdown-split-B1M9KO16.js} +1 -1
  59. package/dist/gateway/static/root/assets/{media-plugins-YVj7NVzD.js → media-plugins-B_QlNdqZ.js} +1 -1
  60. package/dist/gateway/static/root/assets/messages-3qRsLZuX.js +3 -0
  61. package/dist/gateway/static/root/assets/{notes-page-BDzuL2I9.js → notes-page-BTbD4GmH.js} +1 -1
  62. package/dist/gateway/static/root/assets/notes-workbench-JRiq7QDW.js +4 -0
  63. package/dist/gateway/static/root/assets/page-tabs-BaEQMYm_.js +1 -0
  64. package/dist/gateway/static/root/assets/popover-select-BzdnTy3h.js +1 -0
  65. package/dist/gateway/static/root/assets/preview-open-alternatives-CeqtArlZ.js +1 -0
  66. package/dist/gateway/static/root/assets/{product-open-page-Bwx_CQht.js → product-open-page-DnalBZZs.js} +1 -1
  67. package/dist/gateway/static/root/assets/project-detail-page-CjWA13aE.js +1 -0
  68. package/dist/gateway/static/root/assets/projects-page-jsCkScbG.js +1 -0
  69. package/dist/gateway/static/root/assets/remote-access-hub-CGPJTEkM.js +1 -0
  70. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-Fe05Nus6.js → runtime-tools-settings-panel-cGkBEfg4.js} +4 -4
  71. package/dist/gateway/static/root/assets/schema-form-CmsrLlxu.js +1 -0
  72. package/dist/gateway/static/root/assets/sessions-page-BBHzziMd.js +1 -0
  73. package/dist/gateway/static/root/assets/settings-advanced-gate-2cGg8-9h.js +1 -0
  74. package/dist/gateway/static/root/assets/settings-form-draft-Dy10ldo8.js +1 -0
  75. package/dist/gateway/static/root/assets/settings-form-section-DUWCbaMJ.js +1 -0
  76. package/dist/gateway/static/root/assets/{settings-loading-skeleton-BRE_-7Da.js → settings-loading-skeleton-Bvy5rdMY.js} +1 -1
  77. package/dist/gateway/static/root/assets/{settings-page-C1zxCpqB.js → settings-page-cZSAwsRR.js} +1 -1
  78. package/dist/gateway/static/root/assets/settings-page-layout-BRQNel6r.js +1 -0
  79. package/dist/gateway/static/root/assets/settings-shell-dialog-layer-BU3UuiJr.js +1 -0
  80. package/dist/gateway/static/root/assets/setup-status-panel-Cf06b66-.js +1 -0
  81. package/dist/gateway/static/root/assets/share-preview-page-BzA2NCAH.js +2 -0
  82. package/dist/gateway/static/root/assets/shares-settings-xlNKydYY.js +1 -0
  83. package/dist/gateway/static/root/assets/skill-reload-api-C5Xu93c_.js +1 -0
  84. package/dist/gateway/static/root/assets/skills-page-Bvde7_i5.js +2 -0
  85. package/dist/gateway/static/root/assets/{skills-page.utils-CYwFWTso.js → skills-page.utils-vXSqHR7g.js} +1 -1
  86. package/dist/gateway/static/root/assets/system-settings-panel-9cQGOGCK.js +1 -0
  87. package/dist/gateway/static/root/assets/task-detail-page-Bkno4tTe.js +1 -0
  88. package/dist/gateway/static/root/assets/{theme-store-DtxpMC5S.js → theme-store-CHQRiuCF.js} +1 -1
  89. package/dist/gateway/static/root/assets/tool-activity-R8V9l6nk.js +1 -0
  90. package/dist/gateway/static/root/assets/typed-models-lib-q5-Vfqd8.js +1 -0
  91. package/dist/gateway/static/root/assets/use-autosave-7XfKULPI.js +1 -0
  92. package/dist/gateway/static/root/assets/user-context-page-CZ9m9aC_.js +1 -0
  93. package/dist/gateway/static/root/assets/voice-api-key-field-DXr21v-3.js +1 -0
  94. package/dist/gateway/static/root/assets/work-discovery-overlay-CeG7g_DZ.js +1 -0
  95. package/dist/gateway/static/root/assets/work-discovery-page-CQWZD03N.js +1 -0
  96. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DqIb1oBB.js → workflow-run-setup-panel-DSQQZP9T.js} +2 -2
  97. package/dist/gateway/static/root/assets/workflows-page-Cs-MXFJ1.js +5 -0
  98. package/dist/gateway/static/root/assets/working-directory-picker-modal-D-IgcHPp.js +1 -0
  99. package/dist/gateway/static/root/index.html +23 -8
  100. package/dist/package.js +1 -1
  101. package/dist/packages/gateway-contract/src/tasks.js +54 -2
  102. package/dist/src/agent/agent-manager.d.ts +1 -0
  103. package/dist/src/agent/agent-manager.js +1 -0
  104. package/dist/src/agent/service.js +1 -0
  105. package/dist/src/agent/service.types.d.ts +1 -0
  106. package/dist/src/agent/tools/factory.d.ts +2 -0
  107. package/dist/src/agent/tools/factory.js +2 -1
  108. package/dist/src/agent/tools/xopc-use-tool.d.ts +1 -0
  109. package/dist/src/agent/tools/xopc-use-tool.js +56 -6
  110. package/dist/src/automations/domain/validation.d.ts +40 -0
  111. package/dist/src/automations/draft/automation-draft-validator.d.ts +4 -1
  112. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  113. package/dist/src/config/rules.js +2 -2
  114. package/dist/src/gateway/hono/app.d.ts +2 -0
  115. package/dist/src/gateway/hono/app.js +10 -3
  116. package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
  117. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +8 -1
  118. package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -1
  119. package/dist/src/gateway/hono/routes/config.js +9 -0
  120. package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
  121. package/dist/src/gateway/hono/routes/projects.js +55 -0
  122. package/dist/src/gateway/hono/routes/tasks.js +112 -19
  123. package/dist/src/gateway/host.d.ts +9 -1
  124. package/dist/src/gateway/host.js +22 -5
  125. package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
  126. package/dist/src/gateway/rate-limit/buckets.js +12 -0
  127. package/dist/src/gateway/runtime-config.js +6 -5
  128. package/dist/src/gateway/security/audit.js +0 -7
  129. package/dist/src/gateway/server.js +4 -1
  130. package/dist/src/gateway/service.d.ts +1 -0
  131. package/dist/src/gateway/service.js +5 -1
  132. package/dist/src/proactive/actions/service.d.ts +2 -0
  133. package/dist/src/proactive/actions/service.js +80 -0
  134. package/dist/src/proactive/execution/insight.js +20 -0
  135. package/dist/src/proactive/execution/repository.js +8 -2
  136. package/dist/src/proactive/execution/types.d.ts +14 -0
  137. package/dist/src/proactive/inbox/repository.js +59 -9
  138. package/dist/src/proactive/inbox/service.d.ts +2 -2
  139. package/dist/src/proactive/inbox/service.js +7 -2
  140. package/dist/src/proactive/inbox/types.d.ts +14 -0
  141. package/dist/src/proactive/inbox/worker.js +2 -0
  142. package/dist/src/proactive/scenarios/prompt-composer.js +2 -2
  143. package/dist/src/storage/sqlite/migrations/118_task_board_rank.sql +6 -0
  144. package/dist/src/storage/sqlite/migrations/119_proactive_disposition.sql +13 -0
  145. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  146. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  147. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  148. package/dist/src/storage/sqlite/schema.js +1 -1
  149. package/dist/src/tasks/home-query-service.d.ts +5 -0
  150. package/dist/src/tasks/home-query-service.js +7 -2
  151. package/dist/src/tasks/index.d.ts +1 -0
  152. package/dist/src/tasks/index.js +4 -3
  153. package/dist/src/tasks/project-monitoring-service.d.ts +9 -0
  154. package/dist/src/tasks/project-monitoring-service.js +41 -3
  155. package/dist/src/tasks/project-operating-view-service.d.ts +1 -2
  156. package/dist/src/tasks/project-operating-view-service.js +26 -23
  157. package/dist/src/tasks/task-application-service.js +99 -6
  158. package/dist/src/tasks/task-change-events.d.ts +13 -0
  159. package/dist/src/tasks/task-change-events.js +29 -0
  160. package/dist/src/tasks/task-read-model-projector.js +2 -1
  161. package/dist/src/tasks/task-repository.d.ts +7 -0
  162. package/dist/src/tasks/task-repository.js +29 -6
  163. package/dist/src/tunnel/enable-lan-pairing.js +15 -26
  164. package/dist/src/tunnel/pair-context.js +1 -1
  165. package/dist/src/tunnel/pair-url.js +1 -1
  166. package/dist/src/tunnel/tunnel-qr.d.ts +0 -7
  167. package/dist/src/tunnel/tunnel-qr.js +2 -19
  168. package/package.json +3 -1
  169. package/dist/gateway/static/root/assets/agents-Baxfj44y.js +0 -68
  170. package/dist/gateway/static/root/assets/app-management-settings-panel-S8LhoD6G.js +0 -1
  171. package/dist/gateway/static/root/assets/appearance-settings-D8Cd5vDP.js +0 -1
  172. package/dist/gateway/static/root/assets/apps-page-0uCxKyE5.js +0 -1
  173. package/dist/gateway/static/root/assets/automations-page-XyDat125.js +0 -6
  174. package/dist/gateway/static/root/assets/browser-settings-page-CrYNMR4w.js +0 -8
  175. package/dist/gateway/static/root/assets/browser-workflow-inputs-Abil4puY.js +0 -1
  176. package/dist/gateway/static/root/assets/capabilities-settings-panel-CvMcDhGf.js +0 -7
  177. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CHJDY-Ih.js +0 -3
  178. package/dist/gateway/static/root/assets/channels-settings-Ds9BJbcY.js +0 -1
  179. package/dist/gateway/static/root/assets/channels-status-swr-DPaJSYX_.js +0 -1
  180. package/dist/gateway/static/root/assets/connectors-api-CgWjgPSI.js +0 -1
  181. package/dist/gateway/static/root/assets/connectors-page-NUs-Zf7F.js +0 -2
  182. package/dist/gateway/static/root/assets/cron-expression-ZdDBAoqA.js +0 -2
  183. package/dist/gateway/static/root/assets/dependency-picker-BGeB1jpn.js +0 -1
  184. package/dist/gateway/static/root/assets/desktop-pet-settings-CCjT1bdo.js +0 -1
  185. package/dist/gateway/static/root/assets/directory-picker-path-field-C-Te1QN3.js +0 -1
  186. package/dist/gateway/static/root/assets/extension-settings-page-BLSNdlgd.js +0 -1
  187. package/dist/gateway/static/root/assets/gateway-config-api-CQrf0k3D.js +0 -1
  188. package/dist/gateway/static/root/assets/gateway-settings-CvgH8IJI.js +0 -1
  189. package/dist/gateway/static/root/assets/heartbeat-settings-SPpnqbjl.js +0 -1
  190. package/dist/gateway/static/root/assets/home-page-BFoD6047.js +0 -3
  191. package/dist/gateway/static/root/assets/index-84ys9u-K.js +0 -152
  192. package/dist/gateway/static/root/assets/index-D-srnucP.css +0 -1
  193. package/dist/gateway/static/root/assets/local-app-workbench-page-D5uL2_Fd.js +0 -2
  194. package/dist/gateway/static/root/assets/local-apps-page-DIWkFa3g.js +0 -1
  195. package/dist/gateway/static/root/assets/logs-page--6v8qq6y.js +0 -2
  196. package/dist/gateway/static/root/assets/management-settings-DtEuS-kR.js +0 -1
  197. package/dist/gateway/static/root/assets/messages-DQ5X6cXp.js +0 -3
  198. package/dist/gateway/static/root/assets/notes-workbench-IdjuNXvH.js +0 -4
  199. package/dist/gateway/static/root/assets/page-tabs-7bSEWfSX.js +0 -1
  200. package/dist/gateway/static/root/assets/preview-open-alternatives-tgLbHgcV.js +0 -1
  201. package/dist/gateway/static/root/assets/project-detail-page-DnJXSuM4.js +0 -1
  202. package/dist/gateway/static/root/assets/projects-page-DckZKlBI.js +0 -1
  203. package/dist/gateway/static/root/assets/remote-access-hub-CfbUHBUH.js +0 -1
  204. package/dist/gateway/static/root/assets/schema-form-CFfyC4CB.js +0 -1
  205. package/dist/gateway/static/root/assets/sessions-page-BCfCh4My.js +0 -1
  206. package/dist/gateway/static/root/assets/settings-advanced-gate-Cbi4FvzO.js +0 -1
  207. package/dist/gateway/static/root/assets/settings-form-section-gEnEYT_3.js +0 -1
  208. package/dist/gateway/static/root/assets/settings-page-layout-CRpXF_05.js +0 -1
  209. package/dist/gateway/static/root/assets/setup-status-panel-BcHdpmFf.js +0 -1
  210. package/dist/gateway/static/root/assets/share-preview-page-DU8L68A5.js +0 -2
  211. package/dist/gateway/static/root/assets/shares-settings-kjTqH9yY.js +0 -1
  212. package/dist/gateway/static/root/assets/skill-reload-api-QAGpwzIM.js +0 -1
  213. package/dist/gateway/static/root/assets/skills-page-lE1-YRdK.js +0 -2
  214. package/dist/gateway/static/root/assets/system-settings-panel-CVDsiPKn.js +0 -1
  215. package/dist/gateway/static/root/assets/task-detail-page-DsM13-cy.js +0 -1
  216. package/dist/gateway/static/root/assets/typed-models-lib-DelyYgoc.js +0 -1
  217. package/dist/gateway/static/root/assets/use-autosave-C50Mq5yQ.js +0 -1
  218. package/dist/gateway/static/root/assets/user-context-page-D-VEOt2A.js +0 -1
  219. package/dist/gateway/static/root/assets/voice-api-key-field-DYfgTe3Y.js +0 -1
  220. package/dist/gateway/static/root/assets/work-discovery-overlay-DPbujsp3.js +0 -1
  221. package/dist/gateway/static/root/assets/work-discovery-page-D77opady.js +0 -1
  222. package/dist/gateway/static/root/assets/workflows-page-B9-PLmlX.js +0 -5
  223. package/dist/src/gateway/ensure-network-cors.d.ts +0 -3
  224. package/dist/src/gateway/ensure-network-cors.js +0 -23
@@ -3,6 +3,7 @@ import { TaskRepository } from "./task-repository.js";
3
3
  import { TaskRunRepository } from "./task-run-repository.js";
4
4
  import { TaskReadModelProjector } from "./task-read-model-projector.js";
5
5
  import { TaskContextRepository } from "./task-context-repository.js";
6
+ import { enqueueTaskChangedEvent } from "./task-change-events.js";
6
7
  import { TaskDependencyService } from "./task-dependency-service.js";
7
8
  import { createHash, randomUUID } from "node:crypto";
8
9
  //#region src/tasks/task-application-service.ts
@@ -24,6 +25,28 @@ function executorRef(executor) {
24
25
  };
25
26
  }
26
27
  }
28
+ function commandChangedFields(command) {
29
+ switch (command.type) {
30
+ case "move":
31
+ case "mark_ready":
32
+ case "request_review":
33
+ case "close":
34
+ case "reopen": return [
35
+ "phase",
36
+ "resolution",
37
+ "attention"
38
+ ];
39
+ case "start": return [
40
+ "phase",
41
+ "runs",
42
+ "attention"
43
+ ];
44
+ case "add_wait":
45
+ case "resolve_wait": return ["runs", "attention"];
46
+ case "delegate": return ["delegateAgentId"];
47
+ case "revise_contract": return ["contract"];
48
+ }
49
+ }
27
50
  var TaskApplicationService = class {
28
51
  #tasks = new TaskRepository();
29
52
  #runs = new TaskRunRepository();
@@ -86,16 +109,43 @@ var TaskApplicationService = class {
86
109
  phase: current.phase,
87
110
  projectId: current.projectId
88
111
  });
112
+ enqueueTaskChangedEvent(db, {
113
+ taskId: current.id,
114
+ projectId: current.projectId,
115
+ version: current.version,
116
+ changedFields: [
117
+ "title",
118
+ "body",
119
+ "phase",
120
+ "priority",
121
+ "contract",
122
+ "dependencies",
123
+ "context"
124
+ ],
125
+ actor
126
+ });
89
127
  if (input.activation.mode === "capture") return {
90
128
  ok: true,
91
129
  model: this.#projector.project(current)
92
130
  };
93
- return this.start(current.id, current.version, input.activation.executor, {
131
+ const started = this.start(current.id, current.version, input.activation.executor, {
94
132
  idempotencyKey: `${input.idempotencyKey}:start`,
95
133
  scheduleAt: input.activation.scheduleAt,
96
134
  actor,
97
135
  correlationId: input.idempotencyKey
98
136
  });
137
+ if (started.ok) enqueueTaskChangedEvent(db, {
138
+ taskId: started.model.task.id,
139
+ projectId: started.model.task.projectId,
140
+ version: started.model.task.version,
141
+ changedFields: [
142
+ "phase",
143
+ "runs",
144
+ "attention"
145
+ ],
146
+ actor
147
+ });
148
+ return started;
99
149
  });
100
150
  }
101
151
  execute(input) {
@@ -118,6 +168,13 @@ var TaskApplicationService = class {
118
168
  return runSqliteWriteTransaction((db) => {
119
169
  let result;
120
170
  switch (input.command.type) {
171
+ case "move":
172
+ result = task.phase !== "closed" && task.phase !== input.command.phase && !this.#runs.getActiveRoot(task.id) && this.#runs.listActiveWaits(task.id).length === 0 ? this.lifecycle(task.id, task.version, input.command.phase) : {
173
+ ok: false,
174
+ reason: "invalid_transition",
175
+ model
176
+ };
177
+ break;
121
178
  case "mark_ready":
122
179
  result = task.phase === "backlog" ? this.lifecycle(task.id, task.version, "ready") : {
123
180
  ok: false,
@@ -257,11 +314,18 @@ var TaskApplicationService = class {
257
314
  resolution: result.model.task.resolution,
258
315
  projectId: result.model.task.projectId
259
316
  });
317
+ enqueueTaskChangedEvent(db, {
318
+ taskId: result.model.task.id,
319
+ projectId: result.model.task.projectId,
320
+ version: result.model.task.version,
321
+ changedFields: commandChangedFields(input.command),
322
+ actor
323
+ });
260
324
  return result;
261
325
  });
262
326
  }
263
327
  completeRun(input) {
264
- return runSqliteWriteTransaction(() => {
328
+ return runSqliteWriteTransaction((db) => {
265
329
  const run = this.#runs.get(input.runId);
266
330
  if (!run) return {
267
331
  ok: false,
@@ -285,10 +349,25 @@ var TaskApplicationService = class {
285
349
  model: this.#projector.get(run.taskId)
286
350
  };
287
351
  const task = this.#tasks.require(run.taskId);
288
- if (input.receipt.status !== "succeeded") return {
289
- ok: true,
290
- model: this.#projector.project(task)
291
- };
352
+ if (input.receipt.status !== "succeeded") {
353
+ const model = this.#projector.project(task);
354
+ enqueueTaskChangedEvent(db, {
355
+ taskId: task.id,
356
+ projectId: task.projectId,
357
+ version: task.version,
358
+ changedFields: [
359
+ "runs",
360
+ "receipts",
361
+ "attention"
362
+ ],
363
+ actor: input.actor,
364
+ source: input.actor ? void 0 : "runtime"
365
+ });
366
+ return {
367
+ ok: true,
368
+ model
369
+ };
370
+ }
292
371
  const verified = input.receipt.verification.status === "passed";
293
372
  const phase = task.contract?.acceptancePolicy === "verified_auto" && verified ? "closed" : "review";
294
373
  const updated = this.#tasks.setLifecycle({
@@ -298,6 +377,20 @@ var TaskApplicationService = class {
298
377
  ...phase === "closed" ? { resolution: "done" } : {}
299
378
  });
300
379
  if (!updated) throw new Error("Task changed while its run was being finalized");
380
+ enqueueTaskChangedEvent(db, {
381
+ taskId: updated.id,
382
+ projectId: updated.projectId,
383
+ version: updated.version,
384
+ changedFields: [
385
+ "phase",
386
+ "resolution",
387
+ "runs",
388
+ "receipts",
389
+ "attention"
390
+ ],
391
+ actor: input.actor,
392
+ source: input.actor ? void 0 : "runtime"
393
+ });
301
394
  return {
302
395
  ok: true,
303
396
  model: this.#projector.project(updated)
@@ -0,0 +1,13 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { ActorRef, TaskChangedField } from '@xopcai/gateway-contract';
3
+ export type TaskChangeInput = {
4
+ taskId: string;
5
+ projectId?: string;
6
+ version: number;
7
+ changedFields: TaskChangedField[];
8
+ actor?: ActorRef;
9
+ source?: 'user' | 'agent' | 'runtime';
10
+ occurredAt?: number;
11
+ };
12
+ export declare function enqueueTaskChangedEvent(db: DatabaseSync, input: TaskChangeInput): void;
13
+ export declare function enqueueTaskChanged(input: TaskChangeInput): void;
@@ -0,0 +1,29 @@
1
+ import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
2
+ import { randomUUID } from "node:crypto";
3
+ //#region src/tasks/task-change-events.ts
4
+ function eventSource(input) {
5
+ if (input.source) return input.source;
6
+ return input.actor?.kind === "user" || input.actor?.kind === "agent" ? input.actor.kind : "runtime";
7
+ }
8
+ function enqueueTaskChangedEvent(db, input) {
9
+ const occurredAt = input.occurredAt ?? Date.now();
10
+ const changedFields = [...new Set(input.changedFields)];
11
+ if (changedFields.length === 0) return;
12
+ db.prepare(`INSERT INTO domain_outbox (
13
+ event_id, event_type, subject_kind, subject_id, correlation_id,
14
+ payload_json, created_at
15
+ ) VALUES (?, 'task.changed.v2', 'task', ?, ?, ?, ?)`).run(randomUUID(), input.taskId, randomUUID(), JSON.stringify({
16
+ taskId: input.taskId,
17
+ ...input.projectId ? { projectId: input.projectId } : {},
18
+ version: input.version,
19
+ changedFields,
20
+ source: eventSource(input),
21
+ ...input.actor?.id ? { actorId: input.actor.id } : {},
22
+ occurredAt
23
+ }), occurredAt);
24
+ }
25
+ function enqueueTaskChanged(input) {
26
+ runSqliteWriteTransaction((db) => enqueueTaskChangedEvent(db, input));
27
+ }
28
+ //#endregion
29
+ export { enqueueTaskChanged, enqueueTaskChangedEvent };
@@ -81,11 +81,12 @@ var TaskReadModelProjector = class {
81
81
  "delegate",
82
82
  "close"
83
83
  ];
84
+ if (!activeRunStatus && !hasWaits) commands.unshift("move");
84
85
  if (hasWaits) commands.unshift("resolve_wait");
85
86
  else if (activeRunStatus === "running" || activeRunStatus === "verifying") commands.unshift("add_wait");
86
87
  if (task.phase === "backlog") commands.unshift("mark_ready");
87
88
  if (!activeRunStatus && !hasWaits && task.phase !== "backlog") commands.unshift("start");
88
- if (task.phase === "active") commands.push("request_review");
89
+ if (task.phase === "active" && !activeRunStatus) commands.push("request_review");
89
90
  return commands;
90
91
  }
91
92
  };
@@ -39,6 +39,7 @@ export declare class TaskRepository {
39
39
  phase?: TaskPhase;
40
40
  projectId?: string;
41
41
  limit?: number;
42
+ order?: 'recent' | 'board';
42
43
  }): TaskAggregate[];
43
44
  listByProject(projectId: string, limit?: number): TaskAggregate[];
44
45
  getContract(taskId: string, version?: number): TaskContract | undefined;
@@ -62,6 +63,12 @@ export declare class TaskRepository {
62
63
  resolution?: TaskResolution;
63
64
  now?: number;
64
65
  }): TaskAggregate | undefined;
66
+ reorder(input: {
67
+ taskId: string;
68
+ expectedVersion: number;
69
+ beforeTaskId?: string | null;
70
+ now?: number;
71
+ }): TaskAggregate | undefined;
65
72
  reviseContract(input: {
66
73
  taskId: string;
67
74
  objective: string;
@@ -38,6 +38,7 @@ function taskFromRow(row, contract) {
38
38
  source: row.source,
39
39
  ...row.locale ? { locale: row.locale } : {},
40
40
  latestContractVersion: row.latest_contract_version,
41
+ boardRank: row.board_rank,
41
42
  version: row.version,
42
43
  ...contract ? { contract } : {},
43
44
  createdAt: row.created_at,
@@ -54,11 +55,13 @@ var TaskRepository = class {
54
55
  const id = input.id ?? randomUUID();
55
56
  const now = input.now ?? Date.now();
56
57
  runSqliteWriteTransaction((db) => {
58
+ const phase = input.phase ?? "backlog";
59
+ const boardRank = Number(db.prepare("SELECT COALESCE(MAX(board_rank), 0) + 1024 AS board_rank FROM tasks WHERE project_id IS ? AND phase = ?").get(input.projectId ?? null, phase).board_rank);
57
60
  db.prepare(`INSERT INTO tasks (
58
61
  task_id, creation_idempotency_key, project_id, milestone_id, parent_task_id,
59
62
  title, body, phase, priority, due_at, owner_id, delegate_agent_id,
60
- source, locale, latest_contract_version, version, created_at, updated_at
61
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 1, ?, ?)`).run(id, input.idempotencyKey ?? null, input.projectId ?? null, input.milestoneId ?? null, input.parentTaskId ?? null, title, input.body?.trim() || null, input.phase ?? "backlog", input.priority ?? "normal", input.dueAt ?? null, input.ownerId ?? null, input.delegateAgentId ?? null, input.source ?? "api", input.locale ?? null, now, now);
63
+ source, locale, latest_contract_version, board_rank, version, created_at, updated_at
64
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, 1, ?, ?)`).run(id, input.idempotencyKey ?? null, input.projectId ?? null, input.milestoneId ?? null, input.parentTaskId ?? null, title, input.body?.trim() || null, phase, input.priority ?? "normal", input.dueAt ?? null, input.ownerId ?? null, input.delegateAgentId ?? null, input.source ?? "api", input.locale ?? null, boardRank, now, now);
62
65
  this.insertContract(db, {
63
66
  taskId: id,
64
67
  version: 1,
@@ -111,12 +114,13 @@ var TaskRepository = class {
111
114
  const limit = Math.max(1, Math.min(200, Math.floor(input.limit ?? 50)));
112
115
  params.push(limit);
113
116
  return getSqliteDatabase().prepare(`SELECT * FROM tasks${clauses.length ? ` WHERE ${clauses.join(" AND ")}` : ""}
114
- ORDER BY updated_at DESC LIMIT ?`).all(...params).map((row) => taskFromRow(row, this.getContract(row.task_id, row.latest_contract_version)));
117
+ ORDER BY ${input.order === "board" ? "board_rank ASC, created_at ASC, task_id ASC" : "updated_at DESC"} LIMIT ?`).all(...params).map((row) => taskFromRow(row, this.getContract(row.task_id, row.latest_contract_version)));
115
118
  }
116
119
  listByProject(projectId, limit = 50) {
117
120
  return this.list({
118
121
  projectId,
119
- limit
122
+ limit,
123
+ order: "board"
120
124
  });
121
125
  }
122
126
  getContract(taskId, version) {
@@ -139,9 +143,28 @@ var TaskRepository = class {
139
143
  const current = this.get(input.taskId);
140
144
  if (!current || current.version !== input.expectedVersion) return void 0;
141
145
  const now = Math.max(input.now ?? Date.now(), current.updatedAt + 1);
146
+ const boardRank = current.phase === input.phase ? current.boardRank : Number(getSqliteDatabase().prepare("SELECT COALESCE(MAX(board_rank), 0) + 1024 AS board_rank FROM tasks WHERE project_id IS ? AND phase = ?").get(current.projectId ?? null, input.phase).board_rank);
142
147
  return getSqliteDatabase().prepare(`UPDATE tasks SET phase = ?, resolution = ?, closed_at = ?,
143
- version = version + 1, updated_at = ?
144
- WHERE task_id = ? AND version = ?`).run(input.phase, input.resolution ?? null, input.phase === "closed" ? now : null, now, input.taskId, input.expectedVersion).changes === 0 ? void 0 : this.get(input.taskId);
148
+ board_rank = ?, version = version + 1, updated_at = ?
149
+ WHERE task_id = ? AND version = ?`).run(input.phase, input.resolution ?? null, input.phase === "closed" ? now : null, boardRank, now, input.taskId, input.expectedVersion).changes === 0 ? void 0 : this.get(input.taskId);
150
+ }
151
+ reorder(input) {
152
+ const current = this.get(input.taskId);
153
+ if (!current || current.version !== input.expectedVersion) return void 0;
154
+ const before = input.beforeTaskId ? this.get(input.beforeTaskId) : void 0;
155
+ if (input.beforeTaskId && (!before || before.id === current.id || before.projectId !== current.projectId || before.phase !== current.phase)) throw new Error("Board position target must be another task in the same project phase");
156
+ const now = Math.max(input.now ?? Date.now(), current.updatedAt + 1);
157
+ return runSqliteWriteTransaction((db) => {
158
+ const ids = db.prepare(`SELECT task_id FROM tasks
159
+ WHERE project_id IS ? AND phase = ? AND task_id <> ?
160
+ ORDER BY board_rank ASC, created_at ASC, task_id ASC`).all(current.projectId ?? null, current.phase, current.id).map((row) => row.task_id);
161
+ const insertAt = before ? ids.indexOf(before.id) : ids.length;
162
+ ids.splice(insertAt, 0, current.id);
163
+ const updateRank = db.prepare("UPDATE tasks SET board_rank = ? WHERE task_id = ?");
164
+ ids.forEach((id, index) => updateRank.run((index + 1) * 1024, id));
165
+ return db.prepare(`UPDATE tasks SET version = version + 1, updated_at = ?
166
+ WHERE task_id = ? AND version = ?`).run(now, current.id, current.version).changes === 0 ? void 0 : this.get(current.id);
167
+ });
145
168
  }
146
169
  reviseContract(input) {
147
170
  const current = this.get(input.taskId);
@@ -1,39 +1,27 @@
1
- import { buildDefaultCorsOrigins } from "../gateway/host.js";
2
- import { isNetworkAccessibleBindHost, resolveGatewayBindMode, resolveGatewayEffectiveHost } from "../config/gateway-bind.js";
3
- import { enumerateLanGatewayCandidates } from "./tunnel-qr.js";
4
1
  import { assertGatewayAuthConfigured, resolveGatewayAuth } from "../gateway/auth.js";
5
2
  import { assertGatewayRuntimeConfig } from "../gateway/runtime-config.js";
6
3
  //#region src/tunnel/enable-lan-pairing.ts
7
- function mergeCorsOriginsForLan(config, port, bindHost) {
8
- if (!config.gateway) return;
9
- const existing = new Set((config.gateway.corsOrigins ?? []).map((o) => o.trim()).filter(Boolean));
10
- for (const origin of buildDefaultCorsOrigins({
11
- port,
12
- bindHost
13
- })) existing.add(origin);
14
- for (const candidate of enumerateLanGatewayCandidates(port)) existing.add(candidate.url);
15
- config.gateway.corsOrigins = [...existing];
16
- }
17
4
  function applyLanPairingGatewayPatch(config) {
18
- const bindMode = resolveGatewayBindMode(config);
19
- const listenHost = resolveGatewayEffectiveHost(config);
20
- if (bindMode === "lan" && isNetworkAccessibleBindHost(listenHost)) return {
21
- ok: true,
22
- changed: false
23
- };
24
5
  if (!config.gateway) return {
25
6
  ok: false,
26
7
  message: "Gateway section missing from config"
27
8
  };
28
- config.gateway.bind = "lan";
29
- delete config.gateway.customBindHost;
30
- const port = config.gateway.port ?? 18790;
31
- mergeCorsOriginsForLan(config, port, resolveGatewayEffectiveHost(config));
9
+ const previousGateway = JSON.stringify(config.gateway);
10
+ const nextGateway = {
11
+ ...config.gateway,
12
+ bind: "lan"
13
+ };
14
+ delete nextGateway.customBindHost;
15
+ const candidate = {
16
+ ...config,
17
+ gateway: nextGateway
18
+ };
19
+ const port = nextGateway.port ?? 18790;
32
20
  try {
33
- const auth = resolveGatewayAuth({ authConfig: config.gateway.auth });
21
+ const auth = resolveGatewayAuth({ authConfig: candidate.gateway.auth });
34
22
  assertGatewayAuthConfigured(auth);
35
23
  assertGatewayRuntimeConfig({
36
- cfg: config,
24
+ cfg: candidate,
37
25
  auth,
38
26
  port
39
27
  });
@@ -43,9 +31,10 @@ function applyLanPairingGatewayPatch(config) {
43
31
  message: err instanceof Error ? err.message : String(err)
44
32
  };
45
33
  }
34
+ config.gateway = candidate.gateway;
46
35
  return {
47
36
  ok: true,
48
- changed: true
37
+ changed: previousGateway !== JSON.stringify(config.gateway)
49
38
  };
50
39
  }
51
40
  //#endregion
@@ -1,6 +1,6 @@
1
1
  import { init_public_url, normalizePublicUrlOrNull } from "../config/public-url.js";
2
+ import { enumerateLanGatewayCandidates } from "../gateway/host.js";
2
3
  import { isNetworkAccessibleBindHost, resolveGatewayBindMode, resolveGatewayEffectiveHost } from "../config/gateway-bind.js";
3
- import { enumerateLanGatewayCandidates } from "./tunnel-qr.js";
4
4
  import { buildMobileConnectUrlOrder } from "./pair-url.js";
5
5
  //#region src/tunnel/pair-context.ts
6
6
  init_public_url();
@@ -1,5 +1,5 @@
1
+ import { enumerateLanGatewayCandidates } from "../gateway/host.js";
1
2
  import { isNetworkAccessibleBindHost, resolveGatewayEffectiveHost } from "../config/gateway-bind.js";
2
- import { enumerateLanGatewayCandidates } from "./tunnel-qr.js";
3
3
  import net from "node:net";
4
4
  //#region src/tunnel/pair-url.ts
5
5
  /** Normalize a gateway root URL (no trailing slash, no path). */
@@ -1,11 +1,4 @@
1
1
  import type { TunnelQrPayload } from './tunnel-types.js';
2
- export type LanGatewayCandidate = {
3
- url: string;
4
- address: string;
5
- interfaceName: string;
6
- };
7
- /** Non-internal IPv4 addresses on this machine (independent of gateway bind mode). */
8
- export declare function enumerateLanGatewayCandidates(port: number): LanGatewayCandidate[];
9
2
  /** First non-internal IPv4 suitable for LAN QR (when gateway listens on 0.0.0.0). */
10
3
  export declare function resolveLanGatewayUrl(gatewayHost: string, gatewayPort: number): string | null;
11
4
  export declare function buildMobileConnectQrPayload(input: {
@@ -1,25 +1,8 @@
1
- import { networkInterfaces } from "node:os";
1
+ import { enumerateLanGatewayCandidates } from "../gateway/host.js";
2
2
  //#region src/tunnel/tunnel-qr.ts
3
3
  function trimBase(raw) {
4
4
  return raw.trim().replace(/\/+$/, "");
5
5
  }
6
- /** Non-internal IPv4 addresses on this machine (independent of gateway bind mode). */
7
- function enumerateLanGatewayCandidates(port) {
8
- const nets = networkInterfaces();
9
- const seen = /* @__PURE__ */ new Set();
10
- const out = [];
11
- for (const [interfaceName, addrs] of Object.entries(nets)) for (const addr of addrs ?? []) {
12
- if (addr.family !== "IPv4" || addr.internal) continue;
13
- if (seen.has(addr.address)) continue;
14
- seen.add(addr.address);
15
- out.push({
16
- address: addr.address,
17
- interfaceName,
18
- url: trimBase(`http://${addr.address}:${port}`)
19
- });
20
- }
21
- return out;
22
- }
23
6
  /** First non-internal IPv4 suitable for LAN QR (when gateway listens on 0.0.0.0). */
24
7
  function resolveLanGatewayUrl(gatewayHost, gatewayPort) {
25
8
  const host = gatewayHost.trim().toLowerCase();
@@ -43,4 +26,4 @@ function buildMobileConnectQrPayload(input) {
43
26
  };
44
27
  }
45
28
  //#endregion
46
- export { buildMobileConnectQrPayload, enumerateLanGatewayCandidates, resolveLanGatewayUrl };
29
+ export { buildMobileConnectQrPayload, resolveLanGatewayUrl };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xopcai/xopc",
3
- "version": "0.0.197",
3
+ "version": "0.0.199",
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",
@@ -190,6 +190,8 @@
190
190
  "mobile:test": "pnpm -C apps/mobile-expo test",
191
191
  "mobile:test:stream": "pnpm --filter @xopcai/agent-stream-client test",
192
192
  "mobile:release:patch": "bash scripts/apps/mobile-expo/release-patch.sh",
193
+ "mobile:configure:ios:github": "bash scripts/apps/mobile-expo/configure-ios-github-secrets.sh",
194
+ "mobile:release:ios:testflight": "bash scripts/apps/mobile-expo/release-ios-testflight.sh",
193
195
  "dev": "tsx src/cli/bin.ts",
194
196
  "dev:init": "sh -c 'mkdir -p \"$HOME/.xopc-dev\" && XOPC_STATE_DIR=\"$HOME/.xopc-dev\" XOPC_CONFIG_PATH=\"$HOME/.xopc-dev/xopc.json\" XOPC_CONFIG=\"$HOME/.xopc-dev/xopc.json\" XOPC_LOG_DIR=\"$HOME/.xopc-dev/logs\" XOPC_LOG_LEVEL=info tsx src/cli/bin.ts init \"$@\"' --",
195
197
  "dev:gateway": "sh -c 'mkdir -p \"$HOME/.xopc-dev\" && XOPC_STATE_DIR=\"$HOME/.xopc-dev\" XOPC_CONFIG_PATH=\"$HOME/.xopc-dev/xopc.json\" XOPC_CONFIG=\"$HOME/.xopc-dev/xopc.json\" XOPC_LOG_DIR=\"$HOME/.xopc-dev/logs\" XOPC_LOG_LEVEL=info tsx src/cli/bin.ts gateway \"$@\"' --",