@xopcai/xopc 0.0.211 → 0.0.213

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 (212) 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-BzjFoSr0.js → activity-store-Xw-pOm9A.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DTfjhfVE.js → agent-avatar-dicebear-Ca1bciiK.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-DD3TqNrC.js +68 -0
  6. package/dist/gateway/static/root/assets/{api-D269PnU9.js → api-CZK-lRew.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-BFpfQDWc.js → app-management-settings-panel-BLFIG09j.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-DLxFdqhY.js → appearance-settings-BsTWUq1i.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-cJkDKn72.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-DPlH4dnc.js → archive-plugin-B9LsFfEx.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-xqfLLd0I.js → attachment-load-CsWiFfmN.js} +1 -1
  12. package/dist/gateway/static/root/assets/automations-page-CbjU2e75.js +1 -0
  13. package/dist/gateway/static/root/assets/automations-workspace-C4xyo0c4.js +6 -0
  14. package/dist/gateway/static/root/assets/{binary-plugins-C0tuoPXk.js → binary-plugins-DbqhT_JB.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-Deyphj1o.js → block-editor-BGpHwxZ5.js} +47 -47
  16. package/dist/gateway/static/root/assets/browser-settings-page-CrhpQl-e.js +8 -0
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-CYEbXyRF.js → browser-workflow-inputs-BXlon_hL.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-Bf0tPbGi.js → browser-workflows-page-B3BBDM_r.js} +2 -2
  19. package/dist/gateway/static/root/assets/capabilities-settings-panel-B9MoPW9u.js +7 -0
  20. package/dist/gateway/static/root/assets/{capability-presets-api-DPkFA_-R.js → capability-presets-api-BqvMm6UW.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BmwldV9R.js +3 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-DqKaAcnZ.js → channel-recipient-api-9uca5kDa.js} +1 -1
  23. package/dist/gateway/static/root/assets/channels-settings-CwLqWcy_.js +1 -0
  24. package/dist/gateway/static/root/assets/channels-status-swr-DeBw3du9.js +1 -0
  25. package/dist/gateway/static/root/assets/{chat-terminal-dock-CTDRZa7e.js → chat-terminal-dock-DJjYT3WX.js} +2 -2
  26. package/dist/gateway/static/root/assets/{chunk-KS7C4IRE-BMhrPKJC.js → chunk-KS7C4IRE-BaASWQor.js} +1 -1
  27. package/dist/gateway/static/root/assets/{connectors-api-Buu8fif8.js → connectors-api-XCLfuDrN.js} +1 -1
  28. package/dist/gateway/static/root/assets/connectors-page-CVkGtcMS.js +2 -0
  29. package/dist/gateway/static/root/assets/{cron-expression-DTLR82NB.js → cron-expression-DzQN7zBR.js} +1 -1
  30. package/dist/gateway/static/root/assets/{date-picker-DyNogHQH.js → date-picker-B-r5O5qd.js} +1 -1
  31. package/dist/gateway/static/root/assets/{dependency-picker-BpnCuo7B.js → dependency-picker-Ch2XBU2s.js} +1 -1
  32. package/dist/gateway/static/root/assets/{desktop-pet-CDKI4gVB.js → desktop-pet-BdjX8jde.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-settings-DjT5C2a3.js → desktop-pet-settings-CzjjgMMn.js} +1 -1
  34. package/dist/gateway/static/root/assets/directory-picker-path-field-BCTgGTk4.js +1 -0
  35. package/dist/gateway/static/root/assets/{extension-debug-page-DWf2z7q5.js → extension-debug-page-6OGgOucD.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-page-Dorx0kf9.js → extension-page-Cf6MUfCF.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-settings-page-B1wU9ZOB.js → extension-settings-page-pSY_ZvQZ.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-config-api-B1lG4dNr.js → gateway-config-api-CFJMng9v.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-swr-BIxuwPQi.js → gateway-config-swr-DpiY6aub.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-settings-DqIOqJjM.js → gateway-settings-aQYxNePf.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-startup-retry-BpZgd4U-.js → gateway-startup-retry-BZ_6ChP4.js} +1 -1
  42. package/dist/gateway/static/root/assets/{heartbeat-settings-DG4Kmgkc.js → heartbeat-settings-CI33q9i1.js} +1 -1
  43. package/dist/gateway/static/root/assets/home-page-CAIaWs6r.js +1 -0
  44. package/dist/gateway/static/root/assets/{image-generation-api-PkhYohDa.js → image-generation-api-DPndEWOU.js} +1 -1
  45. package/dist/gateway/static/root/assets/index-BhstAl5i.js +108 -0
  46. package/dist/gateway/static/root/assets/index-DQzjgIkQ.css +2 -0
  47. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-6OQT3gQF.js → keyboard-shortcuts-settings-CbLJRGXR.js} +1 -1
  48. package/dist/gateway/static/root/assets/local-app-workbench-page-BqFnCaKT.js +2 -0
  49. package/dist/gateway/static/root/assets/{local-apps-page-DfruRAmE.js → local-apps-page-Crf6c3SK.js} +1 -1
  50. package/dist/gateway/static/root/assets/{locale-store-C5MK9WcP.js → locale-store-BYSRjM6g.js} +1 -1
  51. package/dist/gateway/static/root/assets/logs-page-BpfLQWex.js +2 -0
  52. package/dist/gateway/static/root/assets/{management-settings-L1VYkywO.js → management-settings-mxyYWKgM.js} +1 -1
  53. package/dist/gateway/static/root/assets/{markdown-split-oqgHbqt-.js → markdown-split-kZaPrUTM.js} +1 -1
  54. package/dist/gateway/static/root/assets/{markdown-view-V4rcPPH0.js → markdown-view-DlsczsQ1.js} +1 -1
  55. package/dist/gateway/static/root/assets/{media-plugins-Bb6gSX2o.js → media-plugins-Dk67jaG6.js} +1 -1
  56. package/dist/gateway/static/root/assets/messages-DyM8OOVG.js +3 -0
  57. package/dist/gateway/static/root/assets/notes-api-DaeeQw8A.js +1 -0
  58. package/dist/gateway/static/root/assets/{notes-page-B1rOXjpT.js → notes-page-CQDzw8fX.js} +1 -1
  59. package/dist/gateway/static/root/assets/notes-workbench-BYiROmRJ.js +4 -0
  60. package/dist/gateway/static/root/assets/{page-tabs-CBuCKeyy.js → page-tabs-C4UkhX2U.js} +1 -1
  61. package/dist/gateway/static/root/assets/{preview-open-alternatives-BQ0tLfPO.js → preview-open-alternatives-nzcjh6y0.js} +1 -1
  62. package/dist/gateway/static/root/assets/{product-open-page-DPeFn7Hu.js → product-open-page-3FvW5cHm.js} +1 -1
  63. package/dist/gateway/static/root/assets/project-detail-page-p45i1sMj.js +1 -0
  64. package/dist/gateway/static/root/assets/projects-page-Y9yXB4DX.js +1 -0
  65. package/dist/gateway/static/root/assets/registry-api-Bu6OGEY2.js +2 -0
  66. package/dist/gateway/static/root/assets/remote-access-hub-CNsGY0VS.js +1 -0
  67. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BCfQNzjG.js → runtime-tools-settings-panel-CVqPSfUb.js} +2 -2
  68. package/dist/gateway/static/root/assets/{schema-form-Bo7YbHYN.js → schema-form-Dz6eZpqv.js} +1 -1
  69. package/dist/gateway/static/root/assets/sessions-page-BAtpgb1t.js +1 -0
  70. package/dist/gateway/static/root/assets/settings-advanced-gate-pgBQ21Oe.js +1 -0
  71. package/dist/gateway/static/root/assets/{settings-form-section-B9dnKr3M.js → settings-form-section-BaWFAZv4.js} +1 -1
  72. package/dist/gateway/static/root/assets/{settings-loading-skeleton-CYDV2JtY.js → settings-loading-skeleton-BWmdZfNg.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-page-DbrIYfS9.js → settings-page-Btcb-Dc8.js} +1 -1
  74. package/dist/gateway/static/root/assets/setup-status-panel-BNllZUFP.js +1 -0
  75. package/dist/gateway/static/root/assets/{share-preview-page-olgr7LLN.js → share-preview-page-CGzY3S0N.js} +1 -1
  76. package/dist/gateway/static/root/assets/shares-settings-CncwbTHY.js +1 -0
  77. package/dist/gateway/static/root/assets/skill-reload-api-CcW2dhSW.js +1 -0
  78. package/dist/gateway/static/root/assets/{skills-page-PE16CNw5.js → skills-page-Bi2IWpU0.js} +1 -1
  79. package/dist/gateway/static/root/assets/{skills-page.utils-nXmBcBxt.js → skills-page.utils-BancvwN2.js} +1 -1
  80. package/dist/gateway/static/root/assets/{system-settings-panel-C3qPwAdY.js → system-settings-panel-CihjIzWx.js} +1 -1
  81. package/dist/gateway/static/root/assets/task-detail-page-SSNFtY-d.js +1 -0
  82. package/dist/gateway/static/root/assets/{theme-store-KR5Otp5w.js → theme-store-D1_t_31B.js} +1 -1
  83. package/dist/gateway/static/root/assets/{typed-models-lib-lMZodtDF.js → typed-models-lib-C2LhiQq5.js} +1 -1
  84. package/dist/gateway/static/root/assets/{use-autosave-CKpatP3S.js → use-autosave-tf_8rxAK.js} +1 -1
  85. package/dist/gateway/static/root/assets/user-context-page-BnPTFEar.js +1 -0
  86. package/dist/gateway/static/root/assets/{voice-api-key-field-CDcv0Wbh.js → voice-api-key-field-DN-y7Zfe.js} +1 -1
  87. package/dist/gateway/static/root/assets/work-discovery-overlay-bqqH4aZ9.js +1 -0
  88. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BAHYNlQt.js → workflow-run-setup-panel-2H33iXOB.js} +2 -2
  89. package/dist/gateway/static/root/assets/workflows-page-BnfxRf1q.js +5 -0
  90. package/dist/gateway/static/root/index.html +12 -10
  91. package/dist/package.js +1 -1
  92. package/dist/src/auth/oauth/xopc-cloud.js +1 -1
  93. package/dist/src/cli/commands/connectors.js +1 -1
  94. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  95. package/dist/src/cli/commands/tunnel.js +3 -3
  96. package/dist/src/config/agent-profile.js +1 -1
  97. package/dist/src/connectors/composio-managed-client.d.ts +60 -0
  98. package/dist/src/connectors/composio-managed-client.js +135 -0
  99. package/dist/src/connectors/composio-managed-events.d.ts +41 -0
  100. package/dist/src/connectors/composio-managed-events.js +105 -0
  101. package/dist/src/connectors/composio-sessions.d.ts +2 -1
  102. package/dist/src/connectors/composio-sessions.js +13 -7
  103. package/dist/src/connectors/composio.js +2 -1
  104. package/dist/src/connectors/connected-source-ingestion.js +67 -25
  105. package/dist/src/connectors/health.js +1 -1
  106. package/dist/src/connectors/learning-recipes.js +2 -0
  107. package/dist/src/connectors/runtime-adapter-registry.js +2 -2
  108. package/dist/src/discussions/sealer.js +2 -2
  109. package/dist/src/discussions/service.js +6 -2
  110. package/dist/src/discussions/transcript.d.ts +2 -0
  111. package/dist/src/discussions/transcript.js +16 -3
  112. package/dist/src/extensions/install.d.ts +10 -0
  113. package/dist/src/extensions/install.js +111 -14
  114. package/dist/src/extensions/loader.js +22 -18
  115. package/dist/src/gateway/agents-admin.js +1 -1
  116. package/dist/src/gateway/heartbeat/service.js +1 -1
  117. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  118. package/dist/src/gateway/hono/middleware/auth.js +2 -2
  119. package/dist/src/gateway/hono/middleware/logger.js +1 -1
  120. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +1 -1
  121. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  122. package/dist/src/gateway/hono/routes/connectors.js +11 -4
  123. package/dist/src/gateway/hono/routes/exposure.js +1 -1
  124. package/dist/src/gateway/hono/routes/home.d.ts +1 -1
  125. package/dist/src/gateway/hono/routes/home.js +2 -2
  126. package/dist/src/gateway/hono/routes/mcp.js +1 -1
  127. package/dist/src/gateway/hono/routes/shares.js +1 -1
  128. package/dist/src/gateway/hono/routes/tunnel.js +3 -3
  129. package/dist/src/gateway/hono/routes/workflows.js +69 -0
  130. package/dist/src/gateway/index.js +2 -2
  131. package/dist/src/gateway/runtime-config.js +2 -2
  132. package/dist/src/gateway/security/audit.js +2 -2
  133. package/dist/src/gateway/service/config-coordinator.js +1 -1
  134. package/dist/src/gateway/service.d.ts +1 -0
  135. package/dist/src/gateway/service.js +25 -10
  136. package/dist/src/heartbeat/index.js +1 -1
  137. package/dist/src/notes/note-attachment-sync.js +1 -1
  138. package/dist/src/notes/service.d.ts +1 -0
  139. package/dist/src/notes/service.js +2 -1
  140. package/dist/src/notes/types.d.ts +2 -0
  141. package/dist/src/providers/model-catalog-persistence.d.ts +1 -1
  142. package/dist/src/providers/model-catalog-store.d.ts +2 -60
  143. package/dist/src/providers/model-catalog-types.d.ts +60 -0
  144. package/dist/src/providers/model-catalog-types.js +1 -0
  145. package/dist/src/providers/provider-disconnect-core.d.ts +11 -0
  146. package/dist/src/providers/provider-disconnect-core.js +35 -0
  147. package/dist/src/providers/provider-disconnect.d.ts +2 -10
  148. package/dist/src/providers/provider-disconnect.js +4 -26
  149. package/dist/src/providers/xopc-cloud-catalog-coordinator.js +2 -2
  150. package/dist/src/storage/sqlite/migrations/124_workflow_context_snapshots.sql +15 -0
  151. package/dist/src/storage/sqlite/migrations/125_project_workflow_presets.sql +12 -0
  152. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  153. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  154. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  155. package/dist/src/storage/sqlite/schema.js +1 -1
  156. package/dist/src/tasks/home-query-service.d.ts +12 -127
  157. package/dist/src/tasks/home-query-service.js +73 -271
  158. package/dist/src/tasks/index.js +2 -2
  159. package/dist/src/tui/tui-startup-resources.js +1 -1
  160. package/dist/src/tui/xopc-tui-keybindings.d.ts +2 -2
  161. package/dist/src/tunnel/index.js +2 -2
  162. package/dist/src/voice/audio/normalize.d.ts +1 -0
  163. package/dist/src/voice/audio/normalize.js +24 -4
  164. package/dist/src/voice/local/wav.d.ts +3 -0
  165. package/dist/src/voice/local/wav.js +10 -4
  166. package/dist/src/work-discovery/service.js +6 -8
  167. package/dist/src/work-discovery/types.d.ts +2 -0
  168. package/dist/src/workflows/context/workflow-context-snapshot-repository.d.ts +21 -0
  169. package/dist/src/workflows/context/workflow-context-snapshot-repository.js +40 -0
  170. package/dist/src/workflows/context/workflow-context.d.ts +18 -0
  171. package/dist/src/workflows/context/workflow-context.js +159 -0
  172. package/dist/src/workflows/domain/run.d.ts +10 -1
  173. package/dist/src/workflows/engine/workflow-engine.d.ts +1 -0
  174. package/dist/src/workflows/engine/workflow-engine.js +2 -0
  175. package/dist/src/workflows/project-presets/project-workflow-preset-repository.d.ts +20 -0
  176. package/dist/src/workflows/project-presets/project-workflow-preset-repository.js +38 -0
  177. package/dist/src/workflows/service/workflow-run-service.d.ts +1 -0
  178. package/dist/src/workflows/service/workflow-run-service.js +107 -22
  179. package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -0
  180. package/dist/src/workflows/service/workflow-writeback-service.d.ts +9 -0
  181. package/dist/src/workflows/service/workflow-writeback-service.js +106 -0
  182. package/package.json +6 -6
  183. package/dist/gateway/static/root/assets/agents-CjhgfuVJ.js +0 -68
  184. package/dist/gateway/static/root/assets/apps-page-CjmlGB5V.js +0 -1
  185. package/dist/gateway/static/root/assets/automations-page-4m6Ey6wG.js +0 -6
  186. package/dist/gateway/static/root/assets/browser-settings-page-CAGCYx8U.js +0 -8
  187. package/dist/gateway/static/root/assets/capabilities-settings-panel-CKfLsxTI.js +0 -7
  188. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CpipKNqX.js +0 -3
  189. package/dist/gateway/static/root/assets/channels-settings-Bvq-O4pt.js +0 -1
  190. package/dist/gateway/static/root/assets/channels-status-swr-CrMld2l7.js +0 -1
  191. package/dist/gateway/static/root/assets/connectors-page-CSQRzaVn.js +0 -2
  192. package/dist/gateway/static/root/assets/directory-picker-path-field-DlJY90TM.js +0 -1
  193. package/dist/gateway/static/root/assets/home-page-BhqItS_s.js +0 -1
  194. package/dist/gateway/static/root/assets/index-DLhvsU9B.css +0 -2
  195. package/dist/gateway/static/root/assets/index-_cuTcWjB.js +0 -107
  196. package/dist/gateway/static/root/assets/local-app-workbench-page-DWjTmzxw.js +0 -2
  197. package/dist/gateway/static/root/assets/logs-page-BA5efZ8B.js +0 -2
  198. package/dist/gateway/static/root/assets/messages-ctG2e-ix.js +0 -3
  199. package/dist/gateway/static/root/assets/notes-workbench-CkHXVmKP.js +0 -4
  200. package/dist/gateway/static/root/assets/project-detail-page-DCqet9-L.js +0 -1
  201. package/dist/gateway/static/root/assets/projects-page-D0t_AjzG.js +0 -1
  202. package/dist/gateway/static/root/assets/remote-access-hub-BUWPoBvw.js +0 -1
  203. package/dist/gateway/static/root/assets/sessions-page-vLhrrM3m.js +0 -1
  204. package/dist/gateway/static/root/assets/settings-advanced-gate-OP1y0Y8M.js +0 -1
  205. package/dist/gateway/static/root/assets/setup-status-panel-Cxc-Ejl5.js +0 -1
  206. package/dist/gateway/static/root/assets/shares-settings-ZOqC6-aA.js +0 -1
  207. package/dist/gateway/static/root/assets/skill-reload-api-DwvC3Iuf.js +0 -1
  208. package/dist/gateway/static/root/assets/task-detail-page-DCRB-5q-.js +0 -1
  209. package/dist/gateway/static/root/assets/user-context-page-CoiedRuA.js +0 -1
  210. package/dist/gateway/static/root/assets/work-discovery-overlay-CGdT22un.js +0 -1
  211. package/dist/gateway/static/root/assets/work-discovery-page-BwaU1RqI.js +0 -1
  212. package/dist/gateway/static/root/assets/workflows-page-DHYmh9G7.js +0 -5
@@ -3,14 +3,11 @@ import { getRelationshipSettings } from "../storage/sqlite/relationship-settings
3
3
  import { listConnectorApprovals } from "../storage/sqlite/connector-repository.js";
4
4
  import "../storage/sqlite/index.js";
5
5
  import { TaskRepository } from "./task-repository.js";
6
- import { TaskRunRepository } from "./task-run-repository.js";
7
6
  import { TaskReadModelProjector } from "./task-read-model-projector.js";
8
7
  import "../automations/domain/defaults.js";
9
8
  import "../automations/index.js";
10
9
  import { AttentionGovernor } from "./attention-governor.js";
11
10
  import { listGatewayAgents } from "../gateway/agents-admin.js";
12
- import { getTunnelService } from "../tunnel/tunnel-service.js";
13
- import "../tunnel/index.js";
14
11
  //#region src/tasks/home-query-service.ts
15
12
  function toHomeWorkflowRun(run) {
16
13
  return {
@@ -51,21 +48,6 @@ function toHomeAutomation(automation) {
51
48
  nextRunAt: new Date(automation.state.nextRunAtMs).toISOString()
52
49
  };
53
50
  }
54
- function toHomeAutomationRun(run) {
55
- return {
56
- id: run.id,
57
- automationId: run.automationId,
58
- automationName: run.automationName,
59
- status: run.status,
60
- createdAtMs: run.createdAtMs,
61
- startedAtMs: run.startedAtMs,
62
- endedAtMs: run.endedAtMs,
63
- error: run.error,
64
- summary: run.summary,
65
- sessionKey: run.sessionKey,
66
- workflowRunId: run.workflowRunId
67
- };
68
- }
69
51
  function effectiveAutomationTimeoutSeconds(run, automation) {
70
52
  return ("timeoutSeconds" in run.actionSnapshot ? run.actionSnapshot.timeoutSeconds : void 0) ?? automation?.reliability?.timeoutSeconds ?? 1800;
71
53
  }
@@ -79,41 +61,46 @@ function attentionDetail(kind, status, locale, timeoutSeconds) {
79
61
  if (isChinese) return kind === "automation_run" ? "自动化未能完成,请查看详情后重试。" : "工作流未能完成,请查看详情后重试。";
80
62
  return kind === "automation_run" ? "The automation did not complete. Review the details and retry." : "The workflow did not complete. Review the details and retry.";
81
63
  }
82
- function decisionFromTask(model, projectName) {
83
- const item = model.attention[0];
84
- if (!item || !["input_required", "approval_required"].includes(item.kind)) return null;
64
+ function decisionFromTask(model, projectName, locale) {
85
65
  const task = model.task;
66
+ const isChinese = locale?.toLowerCase().startsWith("zh") ?? task.locale === "zh";
67
+ if (task.phase === "review") return {
68
+ id: `task:${task.id}:review`,
69
+ kind: "task",
70
+ title: task.title,
71
+ detail: isChinese ? "执行已经完成,正在等待你验收结果。" : "The work is complete and ready for your review.",
72
+ reason: "decision_needed",
73
+ urgency: "now",
74
+ href: `/tasks/${encodeURIComponent(task.id)}`,
75
+ projectId: task.projectId,
76
+ projectName,
77
+ dueAt: task.dueAt,
78
+ updatedAt: task.updatedAt
79
+ };
80
+ const item = model.attention.find((candidate) => [
81
+ "input_required",
82
+ "approval_required",
83
+ "run_failed",
84
+ "verification_failed",
85
+ "overdue"
86
+ ].includes(candidate.kind));
87
+ if (!item) return null;
88
+ const reason = item.kind === "input_required" ? "needs_input" : item.kind === "approval_required" ? "approval_required" : item.kind === "run_failed" || item.kind === "verification_failed" ? "retry" : item.kind === "overdue" ? "overdue" : void 0;
89
+ if (!reason) return null;
86
90
  return {
87
91
  id: `task:${task.id}`,
88
92
  kind: "task",
89
93
  title: task.title,
90
94
  detail: item.summary,
91
- reason: item.kind === "input_required" ? "needs_input" : "blocked",
95
+ reason,
92
96
  urgency: "now",
93
97
  href: `/tasks/${encodeURIComponent(task.id)}`,
94
98
  projectId: task.projectId,
95
99
  projectName,
100
+ dueAt: task.dueAt,
96
101
  updatedAt: task.updatedAt
97
102
  };
98
103
  }
99
- function buildHomeBriefing(input) {
100
- const isChinese = input.locale?.toLowerCase().startsWith("zh") ?? false;
101
- const movingCount = input.activeWorkflowCount + input.activeTaskCount;
102
- const attentionCount = input.decisions.length + input.attention.length;
103
- const summary = attentionCount > 0 ? isChinese ? movingCount > 0 ? `有 ${attentionCount} 件事需要你处理;我正在继续推进 ${movingCount} 件工作。` : `有 ${attentionCount} 件事需要你处理。` : movingCount > 0 ? `${attentionCount} ${attentionCount === 1 ? "item needs" : "items need"} your attention; I’m continuing ${movingCount} in the background.` : `${attentionCount} ${attentionCount === 1 ? "item needs" : "items need"} your attention.` : movingCount > 0 ? isChinese ? `目前没有事情需要你处理;我正在继续推进 ${movingCount} 件工作。` : `Nothing needs you right now; I’m continuing ${movingCount} ${movingCount === 1 ? "item" : "items"} in the background.` : isChinese ? "今天还没有正在推进的事项。把想要的结果交给我,我会从这里开始。" : "Nothing is moving yet today. Hand me an task and I’ll take it from here.";
104
- return {
105
- generatedAt: input.nowMs,
106
- summary,
107
- focus: input.decisions.slice(0, 3),
108
- progress: {
109
- activeWorkflowCount: input.activeWorkflowCount,
110
- activeTaskCount: input.activeTaskCount,
111
- movingCount
112
- },
113
- wins: input.wins.slice(0, 5),
114
- nextScheduled: input.nextScheduled
115
- };
116
- }
117
104
  function homeActionCopy(locale) {
118
105
  return locale?.toLowerCase().startsWith("zh") ?? false ? {
119
106
  approve: "允许并继续",
@@ -122,21 +109,14 @@ function homeActionCopy(locale) {
122
109
  retry: "重试",
123
110
  acknowledge: "暂时忽略",
124
111
  viewProgress: "查看进度",
125
- viewResult: "查看结果",
126
112
  viewSchedule: "查看计划",
127
- remaining: "项待继续",
128
- taskCompleted: "任务已完成",
129
- workflowCompleted: "工作流已完成",
130
- automationCompleted: "自动化已完成",
131
113
  runningTask: "任务正在推进",
132
114
  runningWorkflow: "工作流正在推进",
133
115
  scheduled: "下一项定时工作",
134
- organizeInbox: "整理收件箱",
135
- organizeInboxSummary: "把刚捕获的内容整理成笔记、任务或后续行动。",
136
- openInbox: "去整理",
137
- startSomething: "今天想推进什么?",
138
- startSomethingSummary: "把想要的结果交给我,我会从这里开始。",
139
- askAi: "交给 Agent"
116
+ inputRecommendation: "建议补充所需信息,让工作继续推进。",
117
+ approvalRecommendation: "建议先确认操作范围;符合预期后允许本次操作。",
118
+ reviewRecommendation: "建议查看结果,确认符合预期后完成验收。",
119
+ retryRecommendation: "建议先重试;如果再次失败,再检查执行详情。"
140
120
  } : {
141
121
  approve: "Allow and continue",
142
122
  deny: "Deny",
@@ -144,21 +124,14 @@ function homeActionCopy(locale) {
144
124
  retry: "Retry",
145
125
  acknowledge: "Dismiss",
146
126
  viewProgress: "View progress",
147
- viewResult: "View result",
148
127
  viewSchedule: "View schedule",
149
- remaining: "remaining",
150
- taskCompleted: "Task completed",
151
- workflowCompleted: "Workflow completed",
152
- automationCompleted: "Automation completed",
153
128
  runningTask: "Task in progress",
154
129
  runningWorkflow: "Workflow in progress",
155
130
  scheduled: "Next scheduled work",
156
- organizeInbox: "Organize your inbox",
157
- organizeInboxSummary: "Turn recent captures into notes, tasks, or next actions.",
158
- openInbox: "Organize",
159
- startSomething: "What would you like to move forward?",
160
- startSomethingSummary: "Hand me the outcome you want and I’ll take it from here.",
161
- askAi: "Ask an agent"
131
+ inputRecommendation: "Provide the missing information so the work can continue.",
132
+ approvalRecommendation: "Confirm the operation scope, then allow it if it matches your intent.",
133
+ reviewRecommendation: "Review the result and accept it if it meets your expectations.",
134
+ retryRecommendation: "Retry once; inspect the run details if it fails again."
162
135
  };
163
136
  }
164
137
  function formatScheduleDistance(value, nowMs, locale) {
@@ -170,7 +143,14 @@ function formatScheduleDistance(value, nowMs, locale) {
170
143
  if (hours < 48) return formatter.format(hours, "hour");
171
144
  return formatter.format(Math.ceil(distanceMs / 864e5), "day");
172
145
  }
173
- function buildHomeFocusItems(input) {
146
+ function decisionRecommendation(decision, copy) {
147
+ if (decision.judgment?.recommendation) return decision.judgment.recommendation;
148
+ if (decision.reason === "needs_input" || decision.reason === "user_input") return copy.inputRecommendation;
149
+ if (decision.reason === "approval_required" || decision.reason === "user_approval") return copy.approvalRecommendation;
150
+ if (decision.reason === "retry") return copy.retryRecommendation;
151
+ return copy.reviewRecommendation;
152
+ }
153
+ function buildHomeWorkbench(input) {
174
154
  const copy = homeActionCopy(input.locale);
175
155
  const decisions = input.decisions.map((decision) => {
176
156
  const openAction = decision.kind === "agent_judgment" && decision.judgment ? {
@@ -202,10 +182,10 @@ function buildHomeFocusItems(input) {
202
182
  return {
203
183
  id: decision.id,
204
184
  kind: "decision",
205
- priority: decision.urgency === "now" ? 100 : 90,
206
185
  title: decision.title,
207
186
  summary: decision.detail || copy.review,
208
- statusLabel: copy.review,
187
+ recommendation: decisionRecommendation(decision, copy),
188
+ dueAt: decision.dueAt,
209
189
  updatedAt: decision.updatedAt,
210
190
  openAction,
211
191
  ...connectorActions
@@ -214,9 +194,9 @@ function buildHomeFocusItems(input) {
214
194
  const failures = input.attention.map((item) => ({
215
195
  id: item.id,
216
196
  kind: "failure",
217
- priority: 80,
218
197
  title: item.title,
219
198
  summary: item.detail,
199
+ recommendation: copy.retryRecommendation,
220
200
  updatedAt: item.updatedAt,
221
201
  openAction: {
222
202
  type: "open",
@@ -245,13 +225,11 @@ function buildHomeFocusItems(input) {
245
225
  return {
246
226
  id: `workflow:${run.id}`,
247
227
  kind: "running",
248
- priority: 60,
249
228
  title: run.title,
250
229
  summary: copy.runningWorkflow,
251
230
  statusLabel: run.metrics.agentCount > 0 ? `${run.metrics.doneAgentCount}/${run.metrics.agentCount}` : void 0,
252
231
  updatedAt: run.startedAtMs ?? run.createdAtMs,
253
232
  openAction,
254
- primaryAction: openAction,
255
233
  secondaryActions: []
256
234
  };
257
235
  });
@@ -264,56 +242,16 @@ function buildHomeFocusItems(input) {
264
242
  return {
265
243
  id: `task:${task.id}`,
266
244
  kind: "running",
267
- priority: 55,
268
245
  title: task.title,
269
246
  summary: copy.runningTask,
270
247
  updatedAt: task.updatedAt,
271
248
  openAction,
272
- primaryAction: openAction,
273
- secondaryActions: []
274
- };
275
- });
276
- const results = input.wins.map((win) => {
277
- const openAction = {
278
- type: "open",
279
- label: copy.viewResult,
280
- href: win.href
281
- };
282
- return {
283
- id: win.id,
284
- kind: "result",
285
- priority: 40,
286
- title: win.title,
287
- summary: win.kind === "workflow_run" ? copy.workflowCompleted : win.kind === "automation_run" ? copy.automationCompleted : copy.taskCompleted,
288
- updatedAt: win.completedAt,
289
- openAction,
290
- primaryAction: openAction,
291
- secondaryActions: []
292
- };
293
- });
294
- const taskResults = input.recentTasks.map(({ taskId, taskTitle, receipt }) => {
295
- const openAction = {
296
- type: "open",
297
- label: copy.viewResult,
298
- href: `/tasks/${encodeURIComponent(taskId)}`
299
- };
300
- return {
301
- id: `task-result:${taskId}:${receipt.runId}`,
302
- kind: "result",
303
- priority: 40,
304
- title: taskTitle,
305
- summary: receipt.summary,
306
- statusLabel: receipt.remainingWork.length > 0 ? `${receipt.remainingWork.length} ${copy.remaining}` : void 0,
307
- updatedAt: receipt.finalizedAt,
308
- openAction,
309
- primaryAction: openAction,
310
249
  secondaryActions: []
311
250
  };
312
251
  });
313
252
  const scheduled = input.scheduled.map((automation) => ({
314
253
  id: `automation:${automation.id}:scheduled`,
315
254
  kind: "scheduled",
316
- priority: 30,
317
255
  title: automation.name || automation.id,
318
256
  summary: copy.scheduled,
319
257
  statusLabel: formatScheduleDistance(automation.nextRunAt, input.nowMs, input.locale),
@@ -323,63 +261,27 @@ function buildHomeFocusItems(input) {
323
261
  label: copy.viewSchedule,
324
262
  href: `/automations?automation=${encodeURIComponent(automation.id)}`
325
263
  },
326
- primaryAction: {
327
- type: "open",
328
- label: copy.viewSchedule,
329
- href: `/automations?automation=${encodeURIComponent(automation.id)}`
330
- },
331
264
  secondaryActions: []
332
265
  }));
333
- const items = [
334
- ...decisions,
335
- ...failures,
266
+ const urgencyById = new Map(input.decisions.map((decision) => [decision.id, decision.urgency]));
267
+ decisions.sort((left, right) => {
268
+ const leftUrgency = urgencyById.get(left.id) === "now" ? 1 : 0;
269
+ return (urgencyById.get(right.id) === "now" ? 1 : 0) - leftUrgency || right.updatedAt - left.updatedAt;
270
+ });
271
+ failures.sort((left, right) => right.updatedAt - left.updatedAt);
272
+ const needsUser = [...decisions, ...failures];
273
+ const allBackground = [
336
274
  ...workflows,
337
275
  ...tasks,
338
- ...results,
339
- ...taskResults,
340
276
  ...scheduled
341
- ].sort((left, right) => {
342
- const priorityDelta = right.priority - left.priority;
343
- if (priorityDelta !== 0) return priorityDelta;
344
- if (left.kind === "scheduled" && right.kind === "scheduled") return left.updatedAt - right.updatedAt;
345
- return right.updatedAt - left.updatedAt;
346
- });
347
- if (items.length > 0) return items;
348
- if (input.inboxCount > 0) return [{
349
- id: "suggestion:organize-inbox",
350
- kind: "suggestion",
351
- priority: 10,
352
- title: `${copy.organizeInbox} · ${input.inboxCount}`,
353
- summary: copy.organizeInboxSummary,
354
- updatedAt: input.nowMs,
355
- openAction: {
356
- type: "open",
357
- label: copy.openInbox,
358
- href: "/notes?status=inbox"
359
- },
360
- primaryAction: {
361
- type: "open",
362
- label: copy.openInbox,
363
- href: "/notes?status=inbox"
364
- },
365
- secondaryActions: []
366
- }];
367
- return [{
368
- id: "suggestion:ask-agent",
369
- kind: "suggestion",
370
- priority: 10,
371
- title: copy.startSomething,
372
- summary: copy.startSomethingSummary,
373
- updatedAt: input.nowMs,
374
- primaryAction: {
375
- type: "ask_ai",
376
- label: copy.askAi
377
- },
378
- secondaryActions: []
379
- }];
277
+ ];
278
+ return {
279
+ needsUser,
280
+ background: allBackground.slice(0, 3),
281
+ backgroundCount: allBackground.length
282
+ };
380
283
  }
381
284
  var HomeQueryService = class {
382
- #runs = new TaskRunRepository();
383
285
  #tasks = new TaskRepository();
384
286
  #projector = new TaskReadModelProjector();
385
287
  #attentionGovernor = new AttentionGovernor();
@@ -387,37 +289,12 @@ var HomeQueryService = class {
387
289
  this.service = service;
388
290
  }
389
291
  async getSnapshot(locale) {
390
- const notes = this.service.notesServiceInstance;
391
- const sessions = this.service.sessions;
392
292
  const agents = await listGatewayAgents(this.service.currentConfig);
393
293
  const defaultAgent = agents.agents.find((agent) => agent.id === agents.defaultId) ?? agents.agents[0];
394
294
  const workflowRunStore = this.service.createWorkflowRunService().createRunStore(defaultAgent?.id ?? agents.defaultId);
395
- const tunnel = getTunnelService().getStatus();
396
- const health = this.service.getHealth();
397
295
  const nowMs = Date.now();
398
296
  const tasks = this.#tasks.list({ limit: 60 });
399
- const [recentlyOpened, inbox, pendingTasks, recentSessions, workflowRuns, automations, automationRuns, projects, connectorApprovals] = await Promise.all([
400
- notes.listNotes({
401
- sortBy: "lastOpenedAt",
402
- sortOrder: "desc",
403
- limit: 10
404
- }),
405
- notes.listNotes({
406
- status: "inbox",
407
- limit: 0
408
- }),
409
- notes.listNotes({
410
- pendingTasksOnly: true,
411
- sortBy: "createdAt",
412
- sortOrder: "desc",
413
- limit: 10
414
- }),
415
- sessions.listSessions({
416
- channel: "webchat",
417
- sortBy: "updatedAt",
418
- sortOrder: "desc",
419
- limit: 50
420
- }),
297
+ const [workflowRuns, automations, automationRuns, projects, connectorApprovals] = await Promise.all([
421
298
  workflowRunStore.listRunSummaries(20),
422
299
  this.service.automationServiceInstance.list(),
423
300
  this.service.automationServiceInstance.listRuns({ limit: 10 }),
@@ -430,16 +307,9 @@ var HomeQueryService = class {
430
307
  ]);
431
308
  const activeTasks = tasks.filter((task) => task.phase !== "closed");
432
309
  const projectsById = new Map(projects.items.map((project) => [project.id, project]));
433
- const workChats = recentSessions.items.filter((session) => (session.messageCount ?? 0) > 0).map((session) => ({
434
- key: session.key,
435
- name: session.name || "Conversation",
436
- updatedAt: session.updatedAt,
437
- active: sessions.getActiveRun(session.key).active
438
- }));
439
- const activeWorkflowRuns = workflowRuns.filter((run) => run.status === "queued" || run.status === "running").slice(0, 5).map(toHomeWorkflowRun);
310
+ const activeWorkflowRuns = workflowRuns.filter((run) => run.status === "queued" || run.status === "running").map(toHomeWorkflowRun);
440
311
  const failedWorkflowRuns = workflowRuns.filter((run) => run.status === "failed" || run.status === "timeout").slice(0, 5).map(toHomeWorkflowRun);
441
- const recentWorkflowRuns = workflowRuns.slice(0, 5).map(toHomeWorkflowRun);
442
- const upcomingAutomations = automations.map(toHomeAutomation).filter((automation) => Boolean(automation)).sort((a, b) => Date.parse(a.nextRunAt) - Date.parse(b.nextRunAt)).slice(0, 5);
312
+ const upcomingAutomations = automations.filter((automation) => automation.notificationPolicy !== "none").map(toHomeAutomation).filter((automation) => Boolean(automation)).sort((a, b) => Date.parse(a.nextRunAt) - Date.parse(b.nextRunAt));
443
313
  const latestAutomationRuns = [...automationRuns].sort((left, right) => right.createdAtMs - left.createdAtMs).filter((run, index, all) => all.findIndex((candidate) => candidate.automationId === run.automationId) === index);
444
314
  const automationsById = new Map(automations.map((automation) => [automation.id, automation]));
445
315
  const decisionCandidates = [
@@ -468,7 +338,7 @@ var HomeQueryService = class {
468
338
  ...item.insight.decision && (!item.insight.proposedAction || item.insight.actionStatus === "approval_required") ? { decision: item.insight.decision } : {}
469
339
  }
470
340
  })),
471
- ...activeTasks.map((task) => decisionFromTask(this.#projector.project(task), task.projectId ? projectsById.get(task.projectId)?.name : void 0)).filter((item) => Boolean(item)),
341
+ ...activeTasks.map((task) => decisionFromTask(this.#projector.project(task), task.projectId ? projectsById.get(task.projectId)?.name : void 0, locale)).filter((item) => Boolean(item)),
472
342
  ...connectorApprovals.filter((approval) => Date.parse(approval.expiresAt) > nowMs).map((approval) => ({
473
343
  id: `connector-approval:${approval.id}`,
474
344
  kind: "connector_approval",
@@ -494,7 +364,7 @@ var HomeQueryService = class {
494
364
  href: `/workflows?runId=${encodeURIComponent(run.id)}`,
495
365
  updatedAt: run.completedAtMs ?? run.startedAtMs ?? run.createdAtMs,
496
366
  sessionKey: run.sessionKey
497
- })), ...latestAutomationRuns.filter((run) => run.status === "failed" || run.status === "timeout").filter((run) => !isHomeAttentionAcknowledged("automation_run", run.id)).map((run) => ({
367
+ })), ...latestAutomationRuns.filter((run) => run.status === "failed" || run.status === "timeout").filter((run) => automationsById.get(run.automationId)?.notificationPolicy !== "none").filter((run) => !isHomeAttentionAcknowledged("automation_run", run.id)).map((run) => ({
498
368
  id: `automation_run:${run.id}`,
499
369
  kind: "automation_run",
500
370
  runId: run.id,
@@ -512,91 +382,23 @@ var HomeQueryService = class {
512
382
  });
513
383
  const decisions = governed.decisions;
514
384
  const attention = governed.attention;
515
- const wins = [...workflowRuns.filter((run) => run.status === "succeeded").map((run) => ({
516
- id: `workflow:${run.id}`,
517
- kind: "workflow_run",
518
- title: run.title,
519
- href: `/workflows?runId=${encodeURIComponent(run.id)}`,
520
- completedAt: run.completedAtMs ?? run.createdAtMs
521
- })), ...latestAutomationRuns.filter((run) => run.status === "succeeded").map((run) => ({
522
- id: `automation:${run.id}`,
523
- kind: "automation_run",
524
- title: run.automationName || run.automationId,
525
- href: `/automations?automation=${encodeURIComponent(run.automationId)}&run=${encodeURIComponent(run.id)}`,
526
- completedAt: run.endedAtMs ?? run.createdAtMs
527
- }))].sort((left, right) => right.completedAt - left.completedAt);
528
- const runningTasks = tasks.filter((task) => {
529
- const state = this.#projector.project(task).operationalState;
530
- return state === "queued" || state === "running" || state === "verifying";
531
- }).slice(0, 20);
532
- const briefing = buildHomeBriefing({
533
- locale,
534
- decisions,
535
- attention,
536
- activeWorkflowCount: activeWorkflowRuns.length,
537
- activeTaskCount: activeTasks.length,
538
- wins,
539
- nextScheduled: upcomingAutomations[0],
540
- nowMs
541
- });
542
- const recentTasks = tasks.flatMap((task) => this.#runs.listReceipts(task.id, 3).map((receipt) => ({
543
- taskId: task.id,
544
- taskTitle: task.title,
545
- receipt
546
- }))).sort((a, b) => b.receipt.finalizedAt - a.receipt.finalizedAt).slice(0, 8);
547
385
  return {
548
- focusItems: buildHomeFocusItems({
386
+ ...buildHomeWorkbench({
549
387
  locale,
550
388
  decisions,
551
389
  attention,
552
390
  activeWorkflowRuns,
553
- runningTasks,
554
- wins,
555
- scheduled: upcomingAutomations.slice(0, 3),
556
- recentTasks: recentTasks.slice(0, 3),
557
- inboxCount: inbox.total,
391
+ runningTasks: tasks.filter((task) => {
392
+ const state = this.#projector.project(task).operationalState;
393
+ return state === "queued" || state === "running" || state === "verifying";
394
+ }),
395
+ scheduled: upcomingAutomations,
558
396
  nowMs
559
397
  }),
560
- recentlyOpened: recentlyOpened.items.filter((note) => note.lastOpenedAt),
561
- inboxCount: inbox.total,
562
- pendingTasks: pendingTasks.items,
563
- pendingTaskCount: pendingTasks.total,
564
- recentSessions: recentSessions.items.slice(0, 5),
565
- activeAgent: defaultAgent ? {
566
- id: defaultAgent.id,
567
- name: defaultAgent.name,
568
- description: defaultAgent.description
569
- } : { id: agents.defaultId },
570
- gateway: {
571
- status: health.status,
572
- ready: health.ready,
573
- httpListening: health.httpListening,
574
- version: health.version,
575
- uptime: health.uptime,
576
- tunnel: {
577
- state: tunnel.state,
578
- publicUrl: tunnel.publicUrl,
579
- connected: tunnel.state === "connected"
580
- }
581
- },
582
- workflowRuns: {
583
- active: activeWorkflowRuns,
584
- recent: recentWorkflowRuns
585
- },
586
- briefing,
587
398
  decisions,
588
- attention,
589
- attentionPolicy: governed.policy,
590
- chats: {
591
- running: workChats.filter((chat) => chat.active),
592
- recent: workChats.filter((chat) => !chat.active).slice(0, 8)
593
- },
594
- upcomingAutomations,
595
- tasks: { running: runningTasks },
596
- recentTasks,
597
- recentAutomationRuns: automationRuns.slice(0, 5).map(toHomeAutomationRun)
399
+ attentionPolicy: governed.policy
598
400
  };
599
401
  }
600
402
  };
601
403
  //#endregion
602
- export { HomeQueryService, buildHomeBriefing, buildHomeFocusItems, decisionFromTask };
404
+ export { HomeQueryService, buildHomeWorkbench, decisionFromTask };
@@ -4,7 +4,7 @@ import { TaskRunRepository } from "./task-run-repository.js";
4
4
  import { TaskReadModelProjector } from "./task-read-model-projector.js";
5
5
  import { resolveExecutionContext } from "./execution-context.js";
6
6
  import { AttentionGovernor } from "./attention-governor.js";
7
- import { HomeQueryService, buildHomeBriefing, buildHomeFocusItems, decisionFromTask } from "./home-query-service.js";
7
+ import { HomeQueryService, buildHomeWorkbench, decisionFromTask } from "./home-query-service.js";
8
8
  import { TaskContextRepository } from "./task-context-repository.js";
9
9
  import { enqueueTaskChanged, enqueueTaskChangedEvent } from "./task-change-events.js";
10
10
  import { TaskDependencyError, TaskDependencyService } from "./task-dependency-service.js";
@@ -21,4 +21,4 @@ import { TaskHandoffService } from "./task-handoff-service.js";
21
21
  import { TaskOutboxDispatcher } from "./task-outbox-dispatcher.js";
22
22
  import { TaskRunDispatcher } from "./task-run-dispatcher.js";
23
23
  import { TaskSignalService } from "./task-signal-service.js";
24
- export { AttentionGovernor, HomeQueryService, ModelTaskContractPlanner, ProjectMonitoringService, ProjectOperatingViewService, TaskApplicationService, TaskContextRepository, TaskConversationConflictError, TaskConversationRepository, TaskDependencyError, TaskDependencyService, TaskHandoffService, TaskOutboxDispatcher, TaskReadModelProjector, TaskRepository, TaskRunCoordinator, TaskRunDispatcher, TaskRunRepository, TaskSignalService, TaskValueMetricsService, TaskWorkflowCoordinator, assembleTaskContext, buildHomeBriefing, buildHomeFocusItems, buildTaskExecutionDirective, decideProactiveDisposition, decisionFromTask, defineTaskContract, enqueueTaskChanged, enqueueTaskChangedEvent, getTaskContextManifest, getTaskExecutionBrief, isInQuietHours, nextQuietHoursEnd, parseTaskContractResponse, proactiveDispositionReason, resolveExecutionContext, summarizeProjectOperatingView };
24
+ export { AttentionGovernor, HomeQueryService, ModelTaskContractPlanner, ProjectMonitoringService, ProjectOperatingViewService, TaskApplicationService, TaskContextRepository, TaskConversationConflictError, TaskConversationRepository, TaskDependencyError, TaskDependencyService, TaskHandoffService, TaskOutboxDispatcher, TaskReadModelProjector, TaskRepository, TaskRunCoordinator, TaskRunDispatcher, TaskRunRepository, TaskSignalService, TaskValueMetricsService, TaskWorkflowCoordinator, assembleTaskContext, buildHomeWorkbench, buildTaskExecutionDirective, decideProactiveDisposition, decisionFromTask, defineTaskContract, enqueueTaskChanged, enqueueTaskChangedEvent, getTaskContextManifest, getTaskExecutionBrief, isInQuietHours, nextQuietHoursEnd, parseTaskContractResponse, proactiveDispositionReason, resolveExecutionContext, summarizeProjectOperatingView };
@@ -5,9 +5,9 @@ import { resolveBootstrapFilesSync } from "../agent/bootstrap/bootstrap-files.js
5
5
  import { createSkillConfigManager, isSkillEnabled } from "../agent/skills/config.js";
6
6
  import { loadSkills } from "../agent/skills/index.js";
7
7
  import { createWorkflowCatalog } from "../agent/workflow/catalog.js";
8
+ import { listConnectorInstances } from "../connectors/instances.js";
8
9
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
9
10
  import "../config/index.js";
10
- import { listConnectorInstances } from "../connectors/instances.js";
11
11
  import { basename } from "node:path";
12
12
  //#region src/tui/tui-startup-resources.ts
13
13
  init_paths();
@@ -357,11 +357,11 @@ export declare const XOPC_TUI_KEYBINDINGS: {
357
357
  readonly description: "Scroll viewport down one line";
358
358
  };
359
359
  readonly "tui.altScreen.previousPrompt": {
360
- readonly defaultKeys: "ctrl+shift+up";
360
+ readonly defaultKeys: ["ctrl+shift+up", "ctrl+up"];
361
361
  readonly description: "Jump to previous semantic prompt";
362
362
  };
363
363
  readonly "tui.altScreen.nextPrompt": {
364
- readonly defaultKeys: "ctrl+shift+down";
364
+ readonly defaultKeys: ["ctrl+shift+down", "ctrl+down"];
365
365
  readonly description: "Jump to next semantic prompt";
366
366
  };
367
367
  readonly "tui.altScreen.search": {
@@ -1,9 +1,8 @@
1
1
  import { loadTunnelState, resolveTunnelStatePath, saveTunnelState } from "./tunnel-state.js";
2
2
  import { buildMobileConnectQrPayload, resolveLanGatewayUrl } from "./tunnel-qr.js";
3
3
  import { CURRENT_TUNNEL_CONSENT_VERSION, TUNNEL_CONSENT_REQUIRED_CODE, TUNNEL_RISK_SUMMARY_LINES, TunnelConsentError, assertTunnelMayStart, getTunnelConsentState, hasValidTunnelConsent } from "./consent.js";
4
- import { TunnelBrokerClient, resolveBrokerApiBase } from "./broker-client.js";
5
4
  import { getTunnelRegistrationSecretMeta, isMaskedTunnelSecretPatchValue, isProductionTunnelBroker, resolveTunnelBrokerUrl, resolveTunnelRegistrationSecret } from "./env.js";
6
- import { applyTunnelConsentToConfig, mergeTunnelConfigPatch, sanitizeTunnelConfig, setTunnelEnabledInConfig } from "./tunnel-config.js";
5
+ import { TunnelBrokerClient, resolveBrokerApiBase } from "./broker-client.js";
7
6
  import { FRPC_VERSION, clearFrpcPathForProcess, ensureFrpcBinary, publishFrpcPathForProcess } from "./frpc-binary.js";
8
7
  import { consumePairingSecret, createPairingSecret, resetPairingSessionsForTests } from "./pairing.js";
9
8
  import { logTunnelAudit } from "./tunnel-audit.js";
@@ -11,5 +10,6 @@ import { TunnelService, getTunnelService, hashGatewayToken } from "./tunnel-serv
11
10
  import { resolveFrpSubdomainHost } from "./frp-subdomain-host.js";
12
11
  import { clearTunnelWellKnownCache, fetchTunnelWellKnown } from "./well-known.js";
13
12
  import { configureTunnelFromGatewayConfig, maybeAutoStartTunnelFromConfig, wireTunnelEventsToGateway } from "./gateway-lifecycle.js";
13
+ import { applyTunnelConsentToConfig, mergeTunnelConfigPatch, sanitizeTunnelConfig, setTunnelEnabledInConfig } from "./tunnel-config.js";
14
14
  import { consumeTunnelMutationLimit, resetTunnelMutationLimitsForTests } from "./tunnel-rate-limit.js";
15
15
  export { CURRENT_TUNNEL_CONSENT_VERSION, FRPC_VERSION, TUNNEL_CONSENT_REQUIRED_CODE, TUNNEL_RISK_SUMMARY_LINES, TunnelBrokerClient, TunnelConsentError, TunnelService, applyTunnelConsentToConfig, assertTunnelMayStart, buildMobileConnectQrPayload, clearFrpcPathForProcess, clearTunnelWellKnownCache, configureTunnelFromGatewayConfig, consumePairingSecret, consumeTunnelMutationLimit, createPairingSecret, ensureFrpcBinary, fetchTunnelWellKnown, getTunnelConsentState, getTunnelRegistrationSecretMeta, getTunnelService, hasValidTunnelConsent, hashGatewayToken, isMaskedTunnelSecretPatchValue, isProductionTunnelBroker, loadTunnelState, logTunnelAudit, maybeAutoStartTunnelFromConfig, mergeTunnelConfigPatch, publishFrpcPathForProcess, resetPairingSessionsForTests, resetTunnelMutationLimitsForTests, resolveBrokerApiBase, resolveFrpSubdomainHost, resolveLanGatewayUrl, resolveTunnelBrokerUrl, resolveTunnelRegistrationSecret, resolveTunnelStatePath, sanitizeTunnelConfig, saveTunnelState, setTunnelEnabledInConfig, wireTunnelEventsToGateway };
@@ -13,5 +13,6 @@ export declare function decodeAudioToMonoFloat32(input: {
13
13
  export declare function forEachNormalizedAudioSegment(input: {
14
14
  filePath: string;
15
15
  segmentSeconds?: number;
16
+ maxDurationSeconds?: number;
16
17
  signal?: AbortSignal;
17
18
  }, consume: (buffer: Buffer, index: number) => Promise<void>): Promise<number>;
@@ -1,11 +1,13 @@
1
- import { decodeWavToMonoFloat32 } from "../local/wav.js";
1
+ import { UnsupportedWavEncodingError, decodeWavToMonoFloat32 } from "../local/wav.js";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { spawn } from "node:child_process";
5
5
  import { mkdtemp, readFile, readdir, rm } from "node:fs/promises";
6
6
  //#region src/voice/audio/normalize.ts
7
7
  const TARGET_SAMPLE_RATE = 16e3;
8
- const MAX_DECODED_BYTES = TARGET_SAMPLE_RATE * 4 * 15 * 60;
8
+ const MAX_DECODED_DURATION_SECONDS = 900;
9
+ const MAX_DECODED_BYTES = TARGET_SAMPLE_RATE * 4 * MAX_DECODED_DURATION_SECONDS;
10
+ const MAX_SEGMENTED_DURATION_SECONDS = 1800;
9
11
  var AudioNormalizationError = class extends Error {
10
12
  code = "unsupported_audio_codec";
11
13
  constructor(message, options) {
@@ -87,7 +89,13 @@ function runFfmpeg(args, options = {}) {
87
89
  });
88
90
  }
89
91
  async function decodeAudioToMonoFloat32(input) {
90
- if (detectAudioFormat(input.buffer) === "wav") return decodeWavToMonoFloat32(input.buffer);
92
+ if (detectAudioFormat(input.buffer) === "wav") try {
93
+ const decoded = decodeWavToMonoFloat32(input.buffer);
94
+ if (decoded.durationSeconds > MAX_DECODED_DURATION_SECONDS) throw new AudioNormalizationError("Decoded audio exceeds the supported duration");
95
+ return decoded;
96
+ } catch (error) {
97
+ if (!(error instanceof UnsupportedWavEncodingError)) throw error;
98
+ }
91
99
  const bytes = await runFfmpeg([
92
100
  "-i",
93
101
  "pipe:0",
@@ -117,6 +125,10 @@ async function decodeAudioToMonoFloat32(input) {
117
125
  }
118
126
  /** Decodes a recording into bounded PCM WAV files and removes all temporary files afterwards. */
119
127
  async function forEachNormalizedAudioSegment(input, consume) {
128
+ const segmentSeconds = input.segmentSeconds ?? 20;
129
+ const maxDurationSeconds = input.maxDurationSeconds ?? MAX_SEGMENTED_DURATION_SECONDS;
130
+ if (!Number.isFinite(segmentSeconds) || segmentSeconds <= 0) throw new AudioNormalizationError("Audio segment duration must be positive");
131
+ if (!Number.isFinite(maxDurationSeconds) || maxDurationSeconds <= 0) throw new AudioNormalizationError("Maximum audio duration must be positive");
120
132
  const directory = await mkdtemp(join(tmpdir(), "xopc-audio-"));
121
133
  const outputPattern = join(directory, "segment-%05d.wav");
122
134
  try {
@@ -130,18 +142,26 @@ async function forEachNormalizedAudioSegment(input, consume) {
130
142
  "1",
131
143
  "-ar",
132
144
  String(TARGET_SAMPLE_RATE),
145
+ "-t",
146
+ String(maxDurationSeconds + segmentSeconds),
133
147
  "-c:a",
134
148
  "pcm_s16le",
135
149
  "-f",
136
150
  "segment",
137
151
  "-segment_time",
138
- String(input.segmentSeconds ?? 20),
152
+ String(segmentSeconds),
139
153
  "-reset_timestamps",
140
154
  "1",
141
155
  outputPattern
142
156
  ], { signal: input.signal });
143
157
  const files = (await readdir(directory)).filter((name) => name.endsWith(".wav")).sort();
144
158
  if (files.length === 0) throw new AudioNormalizationError("Audio decoder produced no segments");
159
+ let decodedDurationSeconds = 0;
160
+ for (const file of files) {
161
+ const decoded = decodeWavToMonoFloat32(await readFile(join(directory, file)));
162
+ decodedDurationSeconds += decoded.durationSeconds;
163
+ if (decodedDurationSeconds > maxDurationSeconds + .05) throw new AudioNormalizationError(`Decoded audio exceeds the ${Math.round(maxDurationSeconds)} second limit`);
164
+ }
145
165
  for (let index = 0; index < files.length; index += 1) await consume(await readFile(join(directory, files[index])), index);
146
166
  return files.length;
147
167
  } finally {