@xopcai/xopc 0.0.246 → 0.0.248

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 (199) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/src/update-offset-store.js +17 -54
  3. package/dist/extensions/telegram/xopc.extension.json +1 -1
  4. package/dist/extensions/weixin/src/auth/accounts.js +3 -5
  5. package/dist/extensions/weixin/src/monitor/monitor.js +3 -5
  6. package/dist/extensions/weixin/src/storage/sync-buf.d.ts +3 -6
  7. package/dist/extensions/weixin/src/storage/sync-buf.js +9 -22
  8. package/dist/gateway/static/root/assets/{activity-store-BlxqErph.js → activity-store-etpmyV7S.js} +1 -1
  9. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CJJzpYYS.js → agent-avatar-dicebear-BmKxSM1k.js} +1 -1
  10. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CUXApfcE.js +1 -0
  11. package/dist/gateway/static/root/assets/{agents-je3sRGmk.js → agents-DNq_GKuc.js} +1 -1
  12. package/dist/gateway/static/root/assets/{api-BbXzyQMj.js → api-B0-hLuZ1.js} +1 -1
  13. package/dist/gateway/static/root/assets/{app-management-settings-panel-Cnn3i00c.js → app-management-settings-panel-qfwAgyhQ.js} +1 -1
  14. package/dist/gateway/static/root/assets/{appearance-settings-BToQaw_v.js → appearance-settings-DqQVUpCC.js} +1 -1
  15. package/dist/gateway/static/root/assets/apps-page-dwIqYmXk.js +1 -0
  16. package/dist/gateway/static/root/assets/{archive-plugin-DD2SweEH.js → archive-plugin-BnMSgZvR.js} +1 -1
  17. package/dist/gateway/static/root/assets/{attachment-load-BFtcib5t.js → attachment-load-CejsQMev.js} +1 -1
  18. package/dist/gateway/static/root/assets/{automations-page-XS8wIl5o.js → automations-page-RC8EyoAf.js} +1 -1
  19. package/dist/gateway/static/root/assets/automations-workspace-SkdcSZ0i.js +6 -0
  20. package/dist/gateway/static/root/assets/{binary-plugins-Xs7pLHxR.js → binary-plugins-DGjppLSG.js} +1 -1
  21. package/dist/gateway/static/root/assets/{block-editor-BPdSzceB.js → block-editor-CWdP4bUc.js} +44 -44
  22. package/dist/gateway/static/root/assets/browser-settings-page-CKCa6TvG.js +8 -0
  23. package/dist/gateway/static/root/assets/{browser-workflow-inputs-BAAc151l.js → browser-workflow-inputs-BQ1Ilw_o.js} +1 -1
  24. package/dist/gateway/static/root/assets/{browser-workflows-page-DUPPvE30.js → browser-workflows-page-CJh4NyxT.js} +2 -2
  25. package/dist/gateway/static/root/assets/{capabilities-settings-panel-cl9kYilL.js → capabilities-settings-panel-DSp--zIZ.js} +5 -5
  26. package/dist/gateway/static/root/assets/channels-settings-CMd2dDrI.js +1 -0
  27. package/dist/gateway/static/root/assets/{channels-status-swr-CCBCtLDg.js → channels-status-swr-Ohhee4vm.js} +1 -1
  28. package/dist/gateway/static/root/assets/{chat-terminal-dock-DKW1M6aJ.js → chat-terminal-dock-BOtoKTK3.js} +2 -2
  29. package/dist/gateway/static/root/assets/connectors-page-udWs5Kdm.js +2 -0
  30. package/dist/gateway/static/root/assets/{cron-expression-Bijb0ZQu.js → cron-expression-DTj1V3Sw.js} +1 -1
  31. package/dist/gateway/static/root/assets/{date-picker-BZuHw-SY.js → date-picker-Yr6OCvGL.js} +1 -1
  32. package/dist/gateway/static/root/assets/{dependency-picker-BsBD2JFY.js → dependency-picker-DpN3XZg9.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-Ceuw3QKb.js → desktop-pet-DbGzggPF.js} +1 -1
  34. package/dist/gateway/static/root/assets/{desktop-pet-settings-DctOXexM.js → desktop-pet-settings-DinCToZh.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-debug-page-BNlMPATK.js → extension-debug-page-DgTtk4KC.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-page-CK4Uvzge.js → extension-page-DtQeiP6f.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-settings-page-CpnXXemw.js → extension-settings-page-DcguCgsH.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-config-api-C_mlpe-r.js → gateway-config-api-Br7lSf6H.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-swr-826dipyU.js → gateway-config-swr-DXuXtU1w.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-settings-DSSW17ed.js → gateway-settings-CdPoDMuj.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-startup-retry-DyvcAIMm.js → gateway-startup-retry-CzBzglzQ.js} +1 -1
  42. package/dist/gateway/static/root/assets/{heartbeat-settings-hbmIZTpg.js → heartbeat-settings-DHk1hawP.js} +1 -1
  43. package/dist/gateway/static/root/assets/home-page-YGipe_W6.js +1 -0
  44. package/dist/gateway/static/root/assets/{image-generation-api-D7cyfks6.js → image-generation-api-TIgsn04n.js} +1 -1
  45. package/dist/gateway/static/root/assets/{index-eZjksPvq.js → index-D5TQQpeb.js} +44 -44
  46. package/dist/gateway/static/root/assets/index-DReBaaTX.css +2 -0
  47. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BQrDwwgi.js → keyboard-shortcuts-settings-wsWuoa8p.js} +1 -1
  48. package/dist/gateway/static/root/assets/local-app-workbench-page-CpyvYyrb.js +2 -0
  49. package/dist/gateway/static/root/assets/{local-apps-page-D-YWD6LS.js → local-apps-page-CXrbrGo8.js} +1 -1
  50. package/dist/gateway/static/root/assets/local-context-graph-BjUf7fQ9.js +1 -0
  51. package/dist/gateway/static/root/assets/{locale-store-CBoCuIMx.js → locale-store-BJFLQY8O.js} +1 -1
  52. package/dist/gateway/static/root/assets/{logs-page-DvLc9l59.js → logs-page-CXKy6E_l.js} +2 -2
  53. package/dist/gateway/static/root/assets/{management-settings-DsULLUUv.js → management-settings-BdJZFR7U.js} +1 -1
  54. package/dist/gateway/static/root/assets/{markdown-split-CjqlP6IB.js → markdown-split-NK3ACVG2.js} +1 -1
  55. package/dist/gateway/static/root/assets/{markdown-view-BXsHghJd.js → markdown-view-DTF9v1gg.js} +1 -1
  56. package/dist/gateway/static/root/assets/{media-plugins-DQL029DU.js → media-plugins-F0jcUxyl.js} +1 -1
  57. package/dist/gateway/static/root/assets/messages-CHNYp8EQ.js +3 -0
  58. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-gauprAae.js → mobile-pairing-wizard-3NKCniSp.js} +1 -1
  59. package/dist/gateway/static/root/assets/models-hub-cache-nCfkBN8M.js +1 -0
  60. package/dist/gateway/static/root/assets/{notes-page-AsEfLZt9.js → notes-page-DuqLahi6.js} +1 -1
  61. package/dist/gateway/static/root/assets/notes-workbench-C7j9EdQk.js +5 -0
  62. package/dist/gateway/static/root/assets/{oauth-api-BjSUDIgq.js → oauth-api-8lP_qJpq.js} +1 -1
  63. package/dist/gateway/static/root/assets/{product-open-page-CAJeUXeU.js → product-open-page-CxGGlWA8.js} +1 -1
  64. package/dist/gateway/static/root/assets/project-detail-page-CfebYVX0.js +1 -0
  65. package/dist/gateway/static/root/assets/projects-page-48GvzSVa.js +1 -0
  66. package/dist/gateway/static/root/assets/{registry-api-BhGKnvLP.js → registry-api-CIsNlSBi.js} +1 -1
  67. package/dist/gateway/static/root/assets/remote-access-hub-64xj_s2m.js +1 -0
  68. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DH6EilMV.js → runtime-tools-settings-panel-YkjhiQfA.js} +2 -2
  69. package/dist/gateway/static/root/assets/{schema-form-DYHmEZeZ.js → schema-form-oFGf3G3s.js} +1 -1
  70. package/dist/gateway/static/root/assets/sessions-page-CcwcdRN8.js +1 -0
  71. package/dist/gateway/static/root/assets/settings-advanced-gate-BaN84CyW.js +1 -0
  72. package/dist/gateway/static/root/assets/{settings-page-BHwPd_M3.js → settings-page-C7VWs0IT.js} +1 -1
  73. package/dist/gateway/static/root/assets/setup-status-panel-DVVOCNbr.js +1 -0
  74. package/dist/gateway/static/root/assets/{share-preview-page-BjwrS03F.js → share-preview-page-t5oz18rh.js} +1 -1
  75. package/dist/gateway/static/root/assets/shares-settings-DUYbYLi7.js +1 -0
  76. package/dist/gateway/static/root/assets/skill-reload-api-BGyD0gB9.js +1 -0
  77. package/dist/gateway/static/root/assets/{skills-page-OHyK25op.js → skills-page-CjF8DTsN.js} +1 -1
  78. package/dist/gateway/static/root/assets/{skills-page.utils-DQx9ulmg.js → skills-page.utils-DEDTYs2W.js} +1 -1
  79. package/dist/gateway/static/root/assets/{system-settings-panel-wO7DWv4C.js → system-settings-panel-BSYuRgFI.js} +1 -1
  80. package/dist/gateway/static/root/assets/task-detail-page-YZYSTJH7.js +1 -0
  81. package/dist/gateway/static/root/assets/{theme-store-hybK3oC9.js → theme-store-O597U8q_.js} +1 -1
  82. package/dist/gateway/static/root/assets/{tunnel-api-CVC8BHZu.js → tunnel-api-FKUi9wDL.js} +1 -1
  83. package/dist/gateway/static/root/assets/{use-autosave-DMvRu2XZ.js → use-autosave-B5eUJ6Zq.js} +1 -1
  84. package/dist/gateway/static/root/assets/user-context-page-BCyiduKd.js +2 -0
  85. package/dist/gateway/static/root/assets/{voice-api-key-field-DuBK2NDG.js → voice-api-key-field-CMKSwz4C.js} +1 -1
  86. package/dist/gateway/static/root/assets/{voice-config-api-CBbiF1T3.js → voice-config-api-q7B6fOFB.js} +1 -1
  87. package/dist/gateway/static/root/assets/{work-discovery-overlay-B7VXWpDr.js → work-discovery-overlay-jhT2EzeH.js} +1 -1
  88. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BokVAsWN.js → workflow-run-setup-panel-DZmvLZjb.js} +2 -2
  89. package/dist/gateway/static/root/assets/workflows-page-DQC0TpMa.js +5 -0
  90. package/dist/gateway/static/root/index.html +12 -12
  91. package/dist/package.js +1 -1
  92. package/dist/src/agent/commands/command-registry.d.ts +1 -0
  93. package/dist/src/agent/commands/command-registry.js +12 -22
  94. package/dist/src/agent/ipc/inbox.d.ts +8 -31
  95. package/dist/src/agent/ipc/inbox.js +64 -133
  96. package/dist/src/agent/service/process-direct-one-shot.js +15 -10
  97. package/dist/src/agent/workflow/catalog.d.ts +1 -8
  98. package/dist/src/agent/workflow/catalog.js +44 -102
  99. package/dist/src/agent/workflow/index.d.ts +1 -1
  100. package/dist/src/agent/workflow/index.js +2 -2
  101. package/dist/src/automations/domain/types.d.ts +1 -0
  102. package/dist/src/automations/service/action-executor.js +2 -2
  103. package/dist/src/automations/service/automation-service.js +2 -2
  104. package/dist/src/channels/manager.d.ts +1 -1
  105. package/dist/src/channels/manager.js +2 -2
  106. package/dist/src/channels/outbound/persist-store.d.ts +2 -8
  107. package/dist/src/channels/outbound/persist-store.js +11 -38
  108. package/dist/src/channels/outbound-sender.d.ts +1 -1
  109. package/dist/src/channels/outbound-sender.js +2 -2
  110. package/dist/src/cli/commands/connectors.js +1 -1
  111. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  112. package/dist/src/config/schema.js +2 -2
  113. package/dist/src/connectors/auth-provider-registry.js +1 -1
  114. package/dist/src/connectors/composio-triggers.d.ts +2 -2
  115. package/dist/src/connectors/composio-triggers.js +8 -15
  116. package/dist/src/connectors/connected-source-ingestion.js +1 -1
  117. package/dist/src/connectors/health.js +1 -1
  118. package/dist/src/gateway/automation-agent-session.js +3 -0
  119. package/dist/src/gateway/heartbeat/service.js +1 -1
  120. package/dist/src/gateway/hono/lib/extension-store.js +8 -25
  121. package/dist/src/gateway/hono/routes/capabilities.js +1 -1
  122. package/dist/src/gateway/hono/routes/connectors.js +3 -3
  123. package/dist/src/gateway/hono/routes/mcp.js +1 -1
  124. package/dist/src/gateway/hono/routes/projects.js +1 -1
  125. package/dist/src/gateway/hono/routes/you.js +20 -4
  126. package/dist/src/gateway/service.js +4 -5
  127. package/dist/src/heartbeat/index.js +1 -1
  128. package/dist/src/notes/index.d.ts +1 -1
  129. package/dist/src/notes/index.js +2 -2
  130. package/dist/src/notes/paths.d.ts +0 -3
  131. package/dist/src/notes/paths.js +1 -10
  132. package/dist/src/notes/service.d.ts +0 -1
  133. package/dist/src/notes/service.js +0 -3
  134. package/dist/src/notes/store.d.ts +0 -2
  135. package/dist/src/notes/store.js +33 -80
  136. package/dist/src/share/hosted-session-share.d.ts +1 -4
  137. package/dist/src/share/hosted-session-share.js +14 -47
  138. package/dist/src/share/share-auto.d.ts +1 -1
  139. package/dist/src/share/share-auto.js +2 -2
  140. package/dist/src/share/share-store.d.ts +2 -7
  141. package/dist/src/share/share-store.js +153 -195
  142. package/dist/src/share/share-types.d.ts +0 -4
  143. package/dist/src/share/site-share-store.d.ts +3 -8
  144. package/dist/src/share/site-share-store.js +94 -153
  145. package/dist/src/share/site-share-types.d.ts +0 -4
  146. package/dist/src/storage/sqlite/connection.d.ts +1 -2
  147. package/dist/src/storage/sqlite/connection.js +50 -47
  148. package/dist/src/storage/sqlite/durable-queue.d.ts +16 -0
  149. package/dist/src/storage/sqlite/durable-queue.js +52 -0
  150. package/dist/src/storage/sqlite/durable-state.d.ts +16 -0
  151. package/dist/src/storage/sqlite/durable-state.js +43 -0
  152. package/dist/src/storage/sqlite/migrations/146_understanding_focus_exclusions.sql +9 -0
  153. package/dist/src/storage/sqlite/migrations/147_durable_application_state.sql +39 -0
  154. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  155. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  156. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  157. package/dist/src/storage/sqlite/schema.js +1 -1
  158. package/dist/src/storage/sqlite/understanding-focus-exclusions.d.ts +2 -0
  159. package/dist/src/storage/sqlite/understanding-focus-exclusions.js +24 -0
  160. package/dist/src/tui/tui-scoped-models.js +9 -6
  161. package/dist/src/tui/tui-startup-resources.js +1 -1
  162. package/dist/src/voice/dashscope/streaming-tts-stream.js +49 -0
  163. package/dist/src/voice/realtime/agentEngine.js +63 -18
  164. package/dist/src/voice/realtime/conversationTurn.d.ts +20 -0
  165. package/dist/src/voice/realtime/conversationTurn.js +83 -0
  166. package/dist/src/voice/realtime/omniEngine.js +72 -18
  167. package/dist/src/workflows/authoring/workflow-draft-store.d.ts +1 -5
  168. package/dist/src/workflows/authoring/workflow-draft-store.js +23 -43
  169. package/dist/src/workflows/index.js +2 -2
  170. package/dist/src/workflows/store/event-store.d.ts +1 -2
  171. package/dist/src/workflows/store/event-store.js +19 -64
  172. package/dist/src/workflows/store/paths.d.ts +0 -2
  173. package/dist/src/workflows/store/paths.js +1 -7
  174. package/dist/src/workflows/store/run-store.d.ts +0 -1
  175. package/dist/src/workflows/store/run-store.js +1 -24
  176. package/package.json +3 -3
  177. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-0dRjnL2s.js +0 -1
  178. package/dist/gateway/static/root/assets/apps-page-EpUZsl4h.js +0 -1
  179. package/dist/gateway/static/root/assets/automations-workspace-BGQdHrip.js +0 -6
  180. package/dist/gateway/static/root/assets/browser-settings-page-DJGcm7rH.js +0 -8
  181. package/dist/gateway/static/root/assets/channels-settings-BcIr-_GM.js +0 -1
  182. package/dist/gateway/static/root/assets/connectors-page-DNHqaZfX.js +0 -2
  183. package/dist/gateway/static/root/assets/home-page-CaVvW77l.js +0 -1
  184. package/dist/gateway/static/root/assets/index-Dbh5SXyV.css +0 -2
  185. package/dist/gateway/static/root/assets/local-app-workbench-page-D3K1XmOM.js +0 -2
  186. package/dist/gateway/static/root/assets/messages-BbdwoxVo.js +0 -3
  187. package/dist/gateway/static/root/assets/models-hub-cache-88f4fzYS.js +0 -1
  188. package/dist/gateway/static/root/assets/notes-workbench-CI30cDh3.js +0 -4
  189. package/dist/gateway/static/root/assets/project-detail-page-jO_4I5zN.js +0 -1
  190. package/dist/gateway/static/root/assets/projects-page-BrTGFME0.js +0 -1
  191. package/dist/gateway/static/root/assets/remote-access-hub-CH70D5SH.js +0 -1
  192. package/dist/gateway/static/root/assets/sessions-page-hbfUNtNs.js +0 -1
  193. package/dist/gateway/static/root/assets/settings-advanced-gate-Vg3_jua6.js +0 -1
  194. package/dist/gateway/static/root/assets/setup-status-panel-DkcpWSss.js +0 -1
  195. package/dist/gateway/static/root/assets/shares-settings-BL4DEt6p.js +0 -1
  196. package/dist/gateway/static/root/assets/skill-reload-api-CafhNktn.js +0 -1
  197. package/dist/gateway/static/root/assets/task-detail-page-anyomXsu.js +0 -1
  198. package/dist/gateway/static/root/assets/user-context-page-BBk9YdBn.js +0 -1
  199. package/dist/gateway/static/root/assets/workflows-page-RUTv0yvR.js +0 -5
@@ -0,0 +1,39 @@
1
+ CREATE TABLE durable_state (
2
+ namespace TEXT NOT NULL,
3
+ scope TEXT NOT NULL,
4
+ key TEXT NOT NULL,
5
+ payload TEXT NOT NULL CHECK(json_valid(payload)),
6
+ UNIQUE(namespace, scope, key)
7
+ );
8
+ CREATE TABLE workflow_events (
9
+ agent_id TEXT NOT NULL,
10
+ run_id TEXT NOT NULL,
11
+ sequence INTEGER NOT NULL CHECK(sequence > 0),
12
+ id TEXT NOT NULL UNIQUE,
13
+ payload TEXT NOT NULL CHECK(json_valid(payload)),
14
+ PRIMARY KEY(agent_id, run_id, sequence)
15
+ );
16
+ CREATE TABLE note_snapshots (
17
+ note_id TEXT NOT NULL REFERENCES notes(note_id) ON DELETE CASCADE,
18
+ timestamp INTEGER NOT NULL,
19
+ payload TEXT NOT NULL CHECK(json_valid(payload)),
20
+ PRIMARY KEY(note_id, timestamp)
21
+ );
22
+ CREATE TABLE durable_messages (
23
+ sequence INTEGER PRIMARY KEY AUTOINCREMENT,
24
+ queue TEXT NOT NULL,
25
+ scope TEXT NOT NULL,
26
+ id TEXT NOT NULL,
27
+ payload TEXT NOT NULL CHECK(json_valid(payload)),
28
+ enqueued_at INTEGER NOT NULL,
29
+ processed_at INTEGER,
30
+ lease_token TEXT,
31
+ lease_until INTEGER,
32
+ UNIQUE(queue, scope, id)
33
+ );
34
+ CREATE INDEX durable_messages_pending ON durable_messages(queue, scope, processed_at, sequence);
35
+
36
+ CREATE UNIQUE INDEX durable_share_token ON durable_state(namespace, json_extract(payload, '$.token'))
37
+ WHERE namespace IN ('shares', 'site-shares');
38
+ CREATE UNIQUE INDEX durable_site_subdomain ON durable_state(json_extract(payload, '$.subdomain'))
39
+ WHERE namespace = 'site-shares' AND json_extract(payload, '$.subdomain') IS NOT NULL;
@@ -3,7 +3,7 @@ import type { ApplyMigrationsOptions } from './types.js';
3
3
  /** Baseline schema version applied from schema.sql on first open. */
4
4
  export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
5
5
  /** Latest schema version this release supports (increment when adding migrations). */
6
- export declare const XOPC_DB_SCHEMA_VERSION = 145;
6
+ export declare const XOPC_DB_SCHEMA_VERSION = 147;
7
7
  export declare function resolveMigrationsDir(override?: string): string;
8
8
  /**
9
9
  * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
@@ -12,7 +12,7 @@ const log = createLogger("Sqlite:Migrations");
12
12
  /** Baseline schema version applied from schema.sql on first open. */
13
13
  const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
14
14
  /** Latest schema version this release supports (increment when adding migrations). */
15
- const XOPC_DB_SCHEMA_VERSION = 145;
15
+ const XOPC_DB_SCHEMA_VERSION = 147;
16
16
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
17
17
  function backupBeforeTaskCutover(db, databasePath) {
18
18
  db.exec("PRAGMA wal_checkpoint(FULL)");
@@ -57,7 +57,7 @@ function applySingleMigration(db, migration) {
57
57
  * Each step runs in its own transaction and updates schema_meta on success.
58
58
  */
59
59
  function applyPendingMigrations(db, options = {}) {
60
- const targetVersion = options.targetVersion ?? 145;
60
+ const targetVersion = options.targetVersion ?? 147;
61
61
  let currentVersion = readSchemaVersion(db);
62
62
  if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
63
63
  if (currentVersion >= targetVersion) return currentVersion;
@@ -94,7 +94,7 @@ function applyPendingMigrations(db, options = {}) {
94
94
  }
95
95
  /** Inspect schema version without mutating the database. */
96
96
  function inspectSchemaMigrationStatus(db, options = {}) {
97
- const appVersion = options.targetVersion ?? 145;
97
+ const appVersion = options.targetVersion ?? 147;
98
98
  const dbVersion = readSchemaVersion(db);
99
99
  if (dbVersion > appVersion) return {
100
100
  dbVersion,
@@ -19,7 +19,7 @@ const log = createLogger('Sqlite:Migrations');
19
19
  export const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
20
20
 
21
21
  /** Latest schema version this release supports (increment when adding migrations). */
22
- export const XOPC_DB_SCHEMA_VERSION = 145;
22
+ export const XOPC_DB_SCHEMA_VERSION = 147;
23
23
 
24
24
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
25
25
 
@@ -32,7 +32,7 @@ function ensureXopcDatabaseSchema(db, options = {}) {
32
32
  currentVersion = 11;
33
33
  }
34
34
  applyPendingMigrations(db, {
35
- targetVersion: 145,
35
+ targetVersion: 147,
36
36
  databasePath: options.databasePath
37
37
  });
38
38
  }
@@ -0,0 +1,2 @@
1
+ export declare function listUnderstandingFocusExclusions(): Map<string, string[]>;
2
+ export declare function setUnderstandingFocusExclusion(understandingId: string, focusId: string, excluded: boolean): void;
@@ -0,0 +1,24 @@
1
+ import { getSqliteDatabase } from "./transaction.js";
2
+ import { notifyUserContextChange } from "../../user-context/changes.js";
3
+ //#region src/storage/sqlite/understanding-focus-exclusions.ts
4
+ function listUnderstandingFocusExclusions() {
5
+ const rows = getSqliteDatabase().prepare("SELECT understanding_id, focus_id FROM understanding_focus_exclusions").all();
6
+ const result = /* @__PURE__ */ new Map();
7
+ for (const row of rows) {
8
+ const ids = result.get(row.understanding_id) ?? [];
9
+ ids.push(row.focus_id);
10
+ result.set(row.understanding_id, ids);
11
+ }
12
+ return result;
13
+ }
14
+ function setUnderstandingFocusExclusion(understandingId, focusId, excluded) {
15
+ const db = getSqliteDatabase();
16
+ if (excluded) db.prepare("INSERT OR IGNORE INTO understanding_focus_exclusions (understanding_id, focus_id, created_at) VALUES (?, ?, ?)").run(understandingId, focusId, Date.now());
17
+ else db.prepare("DELETE FROM understanding_focus_exclusions WHERE understanding_id = ? AND focus_id = ?").run(understandingId, focusId);
18
+ notifyUserContextChange({
19
+ kind: "understanding",
20
+ id: understandingId
21
+ });
22
+ }
23
+ //#endregion
24
+ export { listUnderstandingFocusExclusions, setUnderstandingFocusExclusion };
@@ -1,15 +1,18 @@
1
- import { homedir } from "node:os";
1
+ import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
2
2
  import { join } from "node:path";
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
4
  //#region src/tui/tui-scoped-models.ts
5
- const STORE_PATH = join(homedir(), ".xopc", "tui-scoped-models.json");
5
+ init_paths_state();
6
+ function storePath() {
7
+ return join(resolveStateDir(), "tui-scoped-models.json");
8
+ }
6
9
  function normalizeWorkspaceKey(cwd) {
7
10
  return cwd.replace(/\\/g, "/").replace(/\/+$/, "") || "/";
8
11
  }
9
12
  function readStore() {
10
13
  try {
11
- if (!existsSync(STORE_PATH)) return {};
12
- const raw = readFileSync(STORE_PATH, "utf8");
14
+ if (!existsSync(storePath())) return {};
15
+ const raw = readFileSync(storePath(), "utf8");
13
16
  const parsed = JSON.parse(raw);
14
17
  return parsed && typeof parsed === "object" ? parsed : {};
15
18
  } catch {
@@ -17,9 +20,9 @@ function readStore() {
17
20
  }
18
21
  }
19
22
  function writeStore(data) {
20
- const dir = join(homedir(), ".xopc");
23
+ const dir = resolveStateDir();
21
24
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
22
- writeFileSync(STORE_PATH, `${JSON.stringify(data, null, 2)}\n`, "utf8");
25
+ writeFileSync(storePath(), `${JSON.stringify(data, null, 2)}\n`, "utf8");
23
26
  }
24
27
  /** Load scoped model refs for Ctrl+P cycling (`null` = all models). */
25
28
  function loadScopedModelRefs(cwd = process.cwd()) {
@@ -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";
9
8
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
10
9
  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();
@@ -1,8 +1,28 @@
1
+ import { createLogger } from "../../utils/logger/index.js";
2
+ import { init_logger } from "../../utils/logger.js";
1
3
  import { createRequire } from "node:module";
2
4
  import crypto from "node:crypto";
5
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
3
6
  //#region src/voice/dashscope/streaming-tts-stream.ts
7
+ init_logger();
4
8
  const { WebSocket } = createRequire(import.meta.url)("ws");
5
9
  const DEFAULT_REALTIME_URL = "wss://dashscope.aliyuncs.com/api-ws/v1/realtime";
10
+ const log = createLogger("TTS:DashScope");
11
+ var TtsHandshakeError = class extends Error {
12
+ constructor(statusCode, retryAfterMs) {
13
+ super(`Realtime TTS WebSocket handshake failed (HTTP ${statusCode})${retryAfterMs === void 0 ? "" : `; retry after ${retryAfterMs} ms`}`);
14
+ this.statusCode = statusCode;
15
+ this.retryAfterMs = retryAfterMs;
16
+ this.name = "TtsHandshakeError";
17
+ }
18
+ };
19
+ function parseRetryAfter(value) {
20
+ if (!value?.trim()) return void 0;
21
+ const seconds = Number(value);
22
+ if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
23
+ const timestamp = Date.parse(value);
24
+ return Number.isFinite(timestamp) ? Math.max(0, timestamp - Date.now()) : void 0;
25
+ }
6
26
  function realtimeUrl(baseUrl, model) {
7
27
  const configured = baseUrl ? new URL(baseUrl) : new URL(DEFAULT_REALTIME_URL);
8
28
  const wasWebSocket = configured.protocol === "ws:" || configured.protocol === "wss:";
@@ -26,6 +46,31 @@ function event(type, extra = {}) {
26
46
  });
27
47
  }
28
48
  async function openDashScopeStreamingTts(request) {
49
+ const deadline = Date.now() + request.timeoutMs;
50
+ for (let attempt = 1;; attempt += 1) {
51
+ request.signal.throwIfAborted();
52
+ try {
53
+ return await openStreamingTtsAttempt({
54
+ ...request,
55
+ timeoutMs: Math.max(1, deadline - Date.now())
56
+ });
57
+ } catch (error) {
58
+ if (request.signal.aborted) throw error;
59
+ if (!(error instanceof TtsHandshakeError) || error.statusCode !== 429 || attempt >= 3) throw error;
60
+ const delayMs = Math.max(error.retryAfterMs ?? 0, 500 * 2 ** (attempt - 1) + Math.floor(Math.random() * 250));
61
+ if (delayMs > 5e3 || Date.now() + delayMs >= deadline) throw error;
62
+ log.warn({
63
+ model: request.model,
64
+ statusCode: error.statusCode,
65
+ attempt,
66
+ delayMs
67
+ }, "Realtime TTS handshake rate limited; retrying");
68
+ await setTimeout$1(delayMs, void 0, { signal: request.signal });
69
+ if (Date.now() >= deadline) throw error;
70
+ }
71
+ }
72
+ }
73
+ async function openStreamingTtsAttempt(request) {
29
74
  if (!request.apiKey) throw new Error("DashScope TTS API key is unavailable");
30
75
  if (request.signal.aborted) throw request.signal.reason;
31
76
  const socket = new WebSocket(realtimeUrl(request.baseUrl, request.model), {
@@ -72,6 +117,10 @@ async function openDashScopeStreamingTts(request) {
72
117
  else if (socket.readyState === WebSocket.CONNECTING) socket.terminate();
73
118
  };
74
119
  request.signal.addEventListener("abort", onAbort, { once: true });
120
+ socket.on("unexpected-response", (_request, response) => {
121
+ fail(new TtsHandshakeError(response.statusCode ?? 0, parseRetryAfter(response.headers["retry-after"])));
122
+ response.destroy();
123
+ });
75
124
  socket.on("message", (data, isBinary) => {
76
125
  if (streamClosed || request.signal.aborted) return;
77
126
  if (isBinary) return;
@@ -2,6 +2,7 @@ import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { speakStream } from "../tts/speak-core.js";
4
4
  import { AudioPlaybackWindow } from "./audio-playback-window.js";
5
+ import { ConversationTurn } from "./conversationTurn.js";
5
6
  import { SpeakableSegmenter } from "./speakable-segmenter.js";
6
7
  import crypto from "node:crypto";
7
8
  //#region src/voice/realtime/agentEngine.ts
@@ -29,6 +30,32 @@ function createAgentVoiceEngine(options) {
29
30
  let finalCount = 0;
30
31
  let committing = false;
31
32
  const finalizedUtterances = /* @__PURE__ */ new Set();
33
+ let pendingTurn;
34
+ const turn = new ConversationTurn(claim.silenceDurationMs, (text) => {
35
+ if (closed || muted) return;
36
+ if (queuedTurns >= 8) {
37
+ send("session.error", {
38
+ code: "INPUT_BACKPRESSURE",
39
+ message: "Too many queued voice turns",
40
+ recoverable: false
41
+ });
42
+ options.onClose("input_backpressure", true);
43
+ return;
44
+ }
45
+ queuedTurns += 1;
46
+ const generation = inputGeneration;
47
+ const pending = {
48
+ text,
49
+ cancelled: false
50
+ };
51
+ pendingTurn = pending;
52
+ conversationTail = conversationTail.then(() => {
53
+ if (pendingTurn === pending) pendingTurn = void 0;
54
+ if (generation === inputGeneration && !pending.cancelled) return runConversationTurn(text);
55
+ }).finally(() => {
56
+ if (generation === inputGeneration) queuedTurns -= 1;
57
+ });
58
+ });
32
59
  function cancelActiveResponse(reason) {
33
60
  const response = activeResponse;
34
61
  if (!response) return false;
@@ -238,10 +265,23 @@ function createAgentVoiceEngine(options) {
238
265
  }
239
266
  });
240
267
  }
268
+ function bufferFinal(utteranceId, text) {
269
+ try {
270
+ turn.final(utteranceId, text);
271
+ } catch {
272
+ send("session.error", {
273
+ code: "INPUT_BACKPRESSURE",
274
+ message: "Voice turn input limit reached",
275
+ recoverable: false
276
+ });
277
+ options.onClose("input_backpressure", true);
278
+ }
279
+ }
241
280
  function onSttEvent(event) {
242
281
  if (closed) return;
243
282
  if (event.type === "ready" || event.type === "usage") return;
244
283
  if (event.type === "error") {
284
+ turn.reset();
245
285
  log.warn({
246
286
  err: event.error,
247
287
  sessionId: claim.sessionId,
@@ -257,10 +297,21 @@ function createAgentVoiceEngine(options) {
257
297
  }
258
298
  if (muted || finalizedUtterances.has(event.utteranceId)) return;
259
299
  if (event.type === "speech_started") {
300
+ if (claim.request.purpose === "conversation") {
301
+ if (pendingTurn) {
302
+ pendingTurn.cancelled = true;
303
+ turn.restore(pendingTurn.text);
304
+ pendingTurn = void 0;
305
+ }
306
+ turn.start(event.utteranceId);
307
+ }
260
308
  if (claim.request.purpose === "conversation" && claim.config.voice?.realtime?.bargeIn && !activeResponse?.awaitingClarification) cancelActiveResponse("barge_in");
261
309
  send("input.speech_started", { utteranceId: event.utteranceId });
262
310
  }
263
- if (event.type === "speech_stopped") send("input.speech_stopped", { utteranceId: event.utteranceId });
311
+ if (event.type === "speech_stopped") {
312
+ if (claim.request.purpose === "conversation") turn.stop(event.utteranceId);
313
+ send("input.speech_stopped", { utteranceId: event.utteranceId });
314
+ }
264
315
  if (event.type === "transcript_delta") send("input.transcript.delta", {
265
316
  utteranceId: event.utteranceId,
266
317
  revision: event.revision,
@@ -268,7 +319,10 @@ function createAgentVoiceEngine(options) {
268
319
  });
269
320
  if (event.type === "transcript_final") {
270
321
  const text = event.text.trim();
271
- if (!text) return;
322
+ if (!text) {
323
+ if (claim.request.purpose === "conversation") bufferFinal(event.utteranceId, "");
324
+ return;
325
+ }
272
326
  if (finalizedUtterances.size >= 1e4) {
273
327
  options.onClose("utterance_limit", true);
274
328
  return;
@@ -282,28 +336,18 @@ function createAgentVoiceEngine(options) {
282
336
  ...event.language === "zh" || event.language === "en" ? { language: event.language } : {}
283
337
  });
284
338
  if (claim.request.purpose === "conversation") {
285
- if (activeResponse?.awaitingClarification) return;
286
- if (claim.config.voice?.realtime?.bargeIn) cancelActiveResponse("barge_in");
287
- if (queuedTurns >= 8) {
288
- send("session.error", {
289
- code: "INPUT_BACKPRESSURE",
290
- message: "Too many queued voice turns",
291
- recoverable: false
292
- });
293
- options.onClose("input_backpressure", true);
339
+ if (activeResponse?.awaitingClarification) {
340
+ turn.reset();
294
341
  return;
295
342
  }
296
- queuedTurns += 1;
297
- const generation = inputGeneration;
298
- conversationTail = conversationTail.then(() => {
299
- if (generation === inputGeneration) return runConversationTurn(text);
300
- }).finally(() => {
301
- if (generation === inputGeneration) queuedTurns -= 1;
302
- });
343
+ if (claim.config.voice?.realtime?.bargeIn) cancelActiveResponse("barge_in");
344
+ bufferFinal(event.utteranceId, text);
303
345
  }
304
346
  }
305
347
  }
306
348
  function discardInput() {
349
+ turn.reset();
350
+ pendingTurn = void 0;
307
351
  inputGeneration += 1;
308
352
  queuedTurns = 0;
309
353
  bufferedAudio = [];
@@ -387,6 +431,7 @@ function createAgentVoiceEngine(options) {
387
431
  close() {
388
432
  if (closing) return closing;
389
433
  closed = true;
434
+ turn.reset();
390
435
  cancelActiveResponse("session_closed");
391
436
  sttAbort.abort("session_closed");
392
437
  sttSession?.abort("session_closed");
@@ -0,0 +1,20 @@
1
+ /** Conservative continuation hints, not a semantic model or punctuation-based endpoint detector. */
2
+ export declare function needsContinuation(text: string): boolean;
3
+ /** Joins provider utterances until both transcription and the continuation window have settled. */
4
+ export declare class ConversationTurn {
5
+ private readonly silenceDurationMs;
6
+ private readonly onTurn;
7
+ private readonly parts;
8
+ private timer;
9
+ private stoppedAt;
10
+ constructor(silenceDurationMs: number, onTurn: (text: string) => void);
11
+ start(id: string): void;
12
+ stop(id: string): void;
13
+ final(id: string, text: string): void;
14
+ reset(): void;
15
+ /** Restore a settled turn if generation was still queued when the user resumed. */
16
+ restore(text: string): void;
17
+ private text;
18
+ private clearTimer;
19
+ private schedule;
20
+ }
@@ -0,0 +1,83 @@
1
+ //#region src/voice/realtime/conversationTurn.ts
2
+ const MIN_TURN_SILENCE_MS = 1200;
3
+ const FINAL_SETTLE_MS = 350;
4
+ const INCOMPLETE_HOLD_MS = 1800;
5
+ /** Conservative continuation hints, not a semantic model or punctuation-based endpoint detector. */
6
+ function needsContinuation(text) {
7
+ const tail = text.trim().replace(/[\s,。!?、;:,.!?;:]+$/u, "");
8
+ return /(?:…|\.\.\.)[\s,。!?,.!?]*$/u.test(text) || /(?:因为|但是|然后|而且|如果|所以|比如|或者|还有|我想|我要|我觉得|帮我|帮我查一下|帮我查查|请帮我|就是说|那个|这个|呃|嗯)$/u.test(tail) || /\b(?:because|but|and|or|if|so|then|um|uh|i want to|i would like to|can you|could you|let me)\s*$/iu.test(tail);
9
+ }
10
+ /** Joins provider utterances until both transcription and the continuation window have settled. */
11
+ var ConversationTurn = class {
12
+ parts = /* @__PURE__ */ new Map();
13
+ timer;
14
+ stoppedAt = 0;
15
+ constructor(silenceDurationMs, onTurn) {
16
+ this.silenceDurationMs = silenceDurationMs;
17
+ this.onTurn = onTurn;
18
+ }
19
+ start(id) {
20
+ if (this.parts.has(id)) return;
21
+ this.clearTimer();
22
+ this.parts.set(id, { stopped: false });
23
+ }
24
+ stop(id) {
25
+ const part = this.parts.get(id);
26
+ if (part?.stopped) return;
27
+ this.parts.set(id, {
28
+ ...part,
29
+ stopped: true
30
+ });
31
+ this.stoppedAt = Date.now();
32
+ this.schedule();
33
+ }
34
+ final(id, text) {
35
+ const part = this.parts.get(id);
36
+ if (part?.text !== void 0) return;
37
+ if (!part?.stopped) this.stoppedAt = Date.now();
38
+ this.parts.set(id, {
39
+ text: text.trim(),
40
+ stopped: true
41
+ });
42
+ if (this.parts.size > 256 || this.text().length > 32e3) {
43
+ this.reset();
44
+ throw new Error("Voice turn input limit reached");
45
+ }
46
+ this.schedule();
47
+ }
48
+ reset() {
49
+ this.clearTimer();
50
+ this.parts.clear();
51
+ }
52
+ /** Restore a settled turn if generation was still queued when the user resumed. */
53
+ restore(text) {
54
+ this.parts.set("queued-turn", {
55
+ text,
56
+ stopped: true
57
+ });
58
+ this.clearTimer();
59
+ }
60
+ text() {
61
+ return [...this.parts.values()].map((part) => part.text ?? "").filter(Boolean).join(" ");
62
+ }
63
+ clearTimer() {
64
+ clearTimeout(this.timer);
65
+ this.timer = void 0;
66
+ }
67
+ schedule() {
68
+ this.clearTimer();
69
+ if ([...this.parts.values()].some((part) => !part.stopped || part.text === void 0)) return;
70
+ const text = this.text();
71
+ if (!text) {
72
+ this.reset();
73
+ return;
74
+ }
75
+ const holdMs = Math.max(FINAL_SETTLE_MS, MIN_TURN_SILENCE_MS - this.silenceDurationMs, needsContinuation(text) ? INCOMPLETE_HOLD_MS : 0);
76
+ this.timer = setTimeout(() => {
77
+ this.reset();
78
+ this.onTurn(text);
79
+ }, Math.max(FINAL_SETTLE_MS, this.stoppedAt + holdMs - Date.now()));
80
+ }
81
+ };
82
+ //#endregion
83
+ export { ConversationTurn, needsContinuation };