@xopcai/xopc 0.0.168 → 0.0.169

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 (129) 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-DjEDu38T.js → activity-store-DumQD8EX.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DVuLzaJi.js → agent-avatar-dicebear-CNI1HQdV.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agents-tF_QTWxn.js → agents-DfpeWAnu.js} +2 -2
  6. package/dist/gateway/static/root/assets/{api-DwVCuPOb.js → api-D7eNcGmE.js} +1 -1
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-spzVBvAu.js → app-management-settings-panel-BPbnbnFn.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-CetimI47.js → appearance-settings-WWFCDver.js} +1 -1
  9. package/dist/gateway/static/root/assets/{apps-page-HDyN6Fjx.js → apps-page-B27faKqW.js} +1 -1
  10. package/dist/gateway/static/root/assets/{archive-plugin-TOmQ2XKc.js → archive-plugin-Cu2dsFtI.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-NFNEWVLJ.js → attachment-load-C9mycbtr.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automation-suggestion-card-B0FnLpSl.js → automation-suggestion-card-DtHqVViI.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-DVevVD6A.js → automations-page-BoH5grBX.js} +1 -1
  14. package/dist/gateway/static/root/assets/{binary-plugins-Csc4xkR9.js → binary-plugins-DqrPRyjm.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-C6Xgrbse.js → block-editor-B9dc3pqc.js} +1 -1
  16. package/dist/gateway/static/root/assets/{browser-settings-page-CyDDEKxB.js → browser-settings-page-CK2fnxHY.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-workflow-inputs-DaxyAai1.js → browser-workflow-inputs-70k5yvTc.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflows-page-CaX6iIJA.js → browser-workflows-page-DBNuaWwR.js} +1 -1
  19. package/dist/gateway/static/root/assets/{capabilities-settings-panel-EXZv96j1.js → capabilities-settings-panel-gg9GXU00.js} +6 -6
  20. package/dist/gateway/static/root/assets/{capability-presets-api-DdCHSzcA.js → capability-presets-api-CvV4M4Oe.js} +1 -1
  21. package/dist/gateway/static/root/assets/capability-presets-settings-panel-A1qGVyll.js +1 -0
  22. package/dist/gateway/static/root/assets/{channel-recipient-api-BOkLI89e.js → channel-recipient-api-BnLOBd7v.js} +1 -1
  23. package/dist/gateway/static/root/assets/{channels-settings-aCN05KdJ.js → channels-settings-H4vCzqiD.js} +1 -1
  24. package/dist/gateway/static/root/assets/channels-status-swr-DtswVkDX.js +1 -0
  25. package/dist/gateway/static/root/assets/{chunk-KS7C4IRE-uQ0fehio.js → chunk-KS7C4IRE-BMhrPKJC.js} +2 -2
  26. package/dist/gateway/static/root/assets/{connector-logo-Mp40HWsb.js → connector-logo-CYQPu4Nn.js} +1 -1
  27. package/dist/gateway/static/root/assets/{connectors-page-i0cu5rg5.js → connectors-page-DphVkloc.js} +1 -1
  28. package/dist/gateway/static/root/assets/{desktop-pet-BtzUJ0d7.js → desktop-pet-Deb8fsr-.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-settings-Dg0Duj8B.js → desktop-pet-settings-DHTY5Ku1.js} +1 -1
  30. package/dist/gateway/static/root/assets/{directory-picker-path-field-9f0k1wZq.js → directory-picker-path-field-cGL2aEB6.js} +1 -1
  31. package/dist/gateway/static/root/assets/{dreaming-settings-rdW7dsGP.js → dreaming-settings-C2XF2wL4.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-debug-page-C9zUnn-z.js → extension-debug-page-F8AzDx0d.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-page-Cy5rfU0h.js → extension-page-ZrX_Ge87.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-settings-page-BjIquAw6.js → extension-settings-page-VypAD6ok.js} +1 -1
  35. package/dist/gateway/static/root/assets/{gateway-config-api-AQQmI6SW.js → gateway-config-api-C-UsxEKi.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-settings-CYNmbqHj.js → gateway-settings-ChG26Coy.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-startup-retry-qnEmj-vL.js → gateway-startup-retry-D73V3EVy.js} +1 -1
  38. package/dist/gateway/static/root/assets/{goal-create-dialog-CkXaDfN3.js → goal-create-dialog-B6aBG2KK.js} +1 -1
  39. package/dist/gateway/static/root/assets/{goal-detail-page-FqDa5bfO.js → goal-detail-page-B_G9oVL1.js} +3 -3
  40. package/dist/gateway/static/root/assets/{goals-config-api-CaVGtM6n.js → goals-config-api-fv7JLhjy.js} +1 -1
  41. package/dist/gateway/static/root/assets/{goals-page-B-uBRGN6.js → goals-page-BQmg_7aD.js} +1 -1
  42. package/dist/gateway/static/root/assets/{goals-settings-C9J3MX0F.js → goals-settings-DlfyneMz.js} +1 -1
  43. package/dist/gateway/static/root/assets/{heartbeat-settings-C0qFLyew.js → heartbeat-settings-BPyFbSbh.js} +1 -1
  44. package/dist/gateway/static/root/assets/image-generation-api-CSKX7PsM.js +1 -0
  45. package/dist/gateway/static/root/assets/index-DJtuKve9.js +199 -0
  46. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BAZlRZMd.js → keyboard-shortcuts-settings-BUxrnWH_.js} +1 -1
  47. package/dist/gateway/static/root/assets/{local-app-workbench-page-DkJUQRyC.js → local-app-workbench-page-Dzlj4fH8.js} +1 -1
  48. package/dist/gateway/static/root/assets/{local-apps-page-PcQABi7F.js → local-apps-page-BsZMeDnS.js} +1 -1
  49. package/dist/gateway/static/root/assets/{locale-store-tnRLWdx2.js → locale-store-DXq-Y8Bi.js} +1 -1
  50. package/dist/gateway/static/root/assets/{logs-page-B-nXM29t.js → logs-page-Bg1B-cKU.js} +1 -1
  51. package/dist/gateway/static/root/assets/{markdown-split-B6W1H0Fj.js → markdown-split-Cmaw70yM.js} +1 -1
  52. package/dist/gateway/static/root/assets/{media-plugins-B-r9Tj74.js → media-plugins-Blqj_oJD.js} +1 -1
  53. package/dist/gateway/static/root/assets/{messages-B1EG4gdu.js → messages-Cj_n7gUv.js} +2 -2
  54. package/dist/gateway/static/root/assets/notes-page-B6Fdlf_s.js +1 -0
  55. package/dist/gateway/static/root/assets/{notes-workbench-Be97S0Im.js → notes-workbench-4HYPR6Hb.js} +2 -2
  56. package/dist/gateway/static/root/assets/{page-tabs-BmUWVWO9.js → page-tabs-D6zFoyJY.js} +1 -1
  57. package/dist/gateway/static/root/assets/{preview-open-alternatives-a76A8p5R.js → preview-open-alternatives-BLoo7Ad8.js} +1 -1
  58. package/dist/gateway/static/root/assets/{product-open-page-BWhYrt-U.js → product-open-page-0-tt2dp7.js} +1 -1
  59. package/dist/gateway/static/root/assets/{project-detail-page-md0ANZ-f.js → project-detail-page-CGa68F1d.js} +1 -1
  60. package/dist/gateway/static/root/assets/{projects-page-D1MNrLcy.js → projects-page-BXmIeErj.js} +1 -1
  61. package/dist/gateway/static/root/assets/{remote-access-hub-GTuiqlJO.js → remote-access-hub-bxrIHaRt.js} +1 -1
  62. package/dist/gateway/static/root/assets/{save-bar-controls-_ZMLDSUw.js → save-bar-controls-9ujl7LRy.js} +1 -1
  63. package/dist/gateway/static/root/assets/{schedule-field-D4ErObRc.js → schedule-field-e80Mj-0z.js} +1 -1
  64. package/dist/gateway/static/root/assets/{schema-form-PqNSGlcH.js → schema-form-DYZQD-PL.js} +1 -1
  65. package/dist/gateway/static/root/assets/{sessions-page-Ct0MVjNv.js → sessions-page-D_7ms_LG.js} +1 -1
  66. package/dist/gateway/static/root/assets/settings-advanced-gate-VLuu9WHc.js +1 -0
  67. package/dist/gateway/static/root/assets/{settings-form-section-BCKaoLhJ.js → settings-form-section-Clt3p-mk.js} +1 -1
  68. package/dist/gateway/static/root/assets/{settings-loading-skeleton-Dn95fked.js → settings-loading-skeleton-CTuS66nC.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-page-C8MPUl2Q.js → settings-page-CMP_owwc.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-layout-Bigc8-GR.js → settings-page-layout-BWUV_wx6.js} +1 -1
  71. package/dist/gateway/static/root/assets/{setup-status-panel-DFTcAHsd.js → setup-status-panel-CAClgrxi.js} +1 -1
  72. package/dist/gateway/static/root/assets/{share-preview-page-xAjqaV4y.js → share-preview-page-tISZJtRK.js} +1 -1
  73. package/dist/gateway/static/root/assets/{shares-settings-D2uvC_aM.js → shares-settings-t-hP0QDv.js} +1 -1
  74. package/dist/gateway/static/root/assets/skill-reload-api-CYRaxTqs.js +1 -0
  75. package/dist/gateway/static/root/assets/{skills-page-6dr3RRVW.js → skills-page-C6CXLWnN.js} +1 -1
  76. package/dist/gateway/static/root/assets/{system-settings-panel-BJJQulg9.js → system-settings-panel-6u0k0wJi.js} +1 -1
  77. package/dist/gateway/static/root/assets/{theme-store-H9T49Iar.js → theme-store-DSpAOJ9G.js} +1 -1
  78. package/dist/gateway/static/root/assets/{time-picker-DsuPUbRE.js → time-picker-BF3f8el1.js} +1 -1
  79. package/dist/gateway/static/root/assets/{typed-models-lib-Djk3F3EL.js → typed-models-lib-CyRCjjGS.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-channel-catalog-UACJTyH0.js → use-channel-catalog-B_Igd7ec.js} +1 -1
  81. package/dist/gateway/static/root/assets/{user-context-page-BC585kHK.js → user-context-page-B3zeQLeM.js} +1 -1
  82. package/dist/gateway/static/root/assets/{voice-api-key-field-CvocOFat.js → voice-api-key-field-BanJk_cf.js} +1 -1
  83. package/dist/gateway/static/root/assets/{work-discovery-page-DiMn6nrT.js → work-discovery-page-BCANmOUS.js} +1 -1
  84. package/dist/gateway/static/root/assets/{work-item-detail-page-CFBlQbPy.js → work-item-detail-page-t5xiIEFv.js} +1 -1
  85. package/dist/gateway/static/root/assets/{work-page-CLJLKqsf.js → work-page-CEI3zs-y.js} +1 -1
  86. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DbQwWPjv.js → workflow-run-setup-panel-DCXTQx7p.js} +1 -1
  87. package/dist/gateway/static/root/assets/{workflows-page-BJOhlABF.js → workflows-page-B8FRLCHp.js} +3 -3
  88. package/dist/gateway/static/root/index.html +7 -7
  89. package/dist/package.js +1 -1
  90. package/dist/src/agent/memory/dreaming/config.js +1 -1
  91. package/dist/src/agent-runtime/index.js +1 -1
  92. package/dist/src/agent-runtime/runtime-profile.js +1 -1
  93. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  94. package/dist/src/config/agent-profile.js +1 -1
  95. package/dist/src/gateway/agents-admin.js +1 -1
  96. package/dist/src/gateway/heartbeat/service.js +1 -1
  97. package/dist/src/gateway/hono/routes/composer-history.d.ts +3 -0
  98. package/dist/src/gateway/hono/routes/composer-history.js +28 -0
  99. package/dist/src/gateway/hono/routes/index.js +2 -0
  100. package/dist/src/heartbeat/index.js +1 -1
  101. package/dist/src/session/client-history.d.ts +2 -0
  102. package/dist/src/session/client-history.js +2 -0
  103. package/dist/src/storage/sqlite/composer-input-history-repository.d.ts +12 -0
  104. package/dist/src/storage/sqlite/composer-input-history-repository.js +42 -0
  105. package/dist/src/storage/sqlite/index.d.ts +1 -0
  106. package/dist/src/storage/sqlite/index.js +2 -1
  107. package/dist/src/storage/sqlite/migrations/059_composer_input_history.sql +8 -0
  108. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  109. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  110. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  111. package/dist/src/storage/sqlite/schema.js +1 -1
  112. package/dist/src/tui/backends/embedded-backend.d.ts +3 -1
  113. package/dist/src/tui/backends/embedded-backend.js +7 -0
  114. package/dist/src/tui/backends/gateway-sse-backend.d.ts +3 -1
  115. package/dist/src/tui/backends/gateway-sse-backend.js +13 -0
  116. package/dist/src/tui/components/custom-editor.d.ts +1 -0
  117. package/dist/src/tui/components/custom-editor.js +6 -0
  118. package/dist/src/tui/tui-backend.d.ts +9 -0
  119. package/dist/src/tui/tui-submit.d.ts +1 -0
  120. package/dist/src/tui/tui-submit.js +1 -1
  121. package/dist/src/tui/tui.js +58 -1
  122. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  123. package/package.json +1 -1
  124. package/dist/gateway/static/root/assets/capability-presets-settings-panel-o08SXqM4.js +0 -2
  125. package/dist/gateway/static/root/assets/channels-status-swr-ZrqadU60.js +0 -1
  126. package/dist/gateway/static/root/assets/index-DchbD-qM.js +0 -199
  127. package/dist/gateway/static/root/assets/notes-page-BNECY6Oy.js +0 -1
  128. package/dist/gateway/static/root/assets/settings-advanced-gate-QOUph2Oq.js +0 -1
  129. package/dist/gateway/static/root/assets/skill-reload-api-DYtfQXB-.js +0 -1
@@ -11,29 +11,29 @@
11
11
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=20260713-1" />
12
12
  <link rel="manifest" href="/site.webmanifest?v=20260713-1" />
13
13
  <title>XOPC — Turn goals into loops. Keep what matters moving.</title>
14
- <script type="module" crossorigin src="/assets/index-DchbD-qM.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-DJtuKve9.js"></script>
15
15
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-aKtaBQYM.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-zJ_50EbN.js">
17
17
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-BOUWij0V.js">
18
18
  <link rel="modulepreload" crossorigin href="/assets/dist-CxGUk8J-.js">
19
19
  <link rel="modulepreload" crossorigin href="/assets/Combination-14nmIgxH.js">
20
20
  <link rel="modulepreload" crossorigin href="/assets/dist-C230izr8.js">
21
- <link rel="modulepreload" crossorigin href="/assets/chunk-KS7C4IRE-uQ0fehio.js">
21
+ <link rel="modulepreload" crossorigin href="/assets/chunk-KS7C4IRE-BMhrPKJC.js">
22
22
  <link rel="modulepreload" crossorigin href="/assets/vendor-swr-BIWyz7Rc.js">
23
23
  <link rel="modulepreload" crossorigin href="/assets/createLucideIcon-DPHK1VkS.js">
24
24
  <link rel="modulepreload" crossorigin href="/assets/check-DUBLcKHA.js">
25
25
  <link rel="modulepreload" crossorigin href="/assets/circle-alert-BEjgurr2.js">
26
26
  <link rel="modulepreload" crossorigin href="/assets/middleware-Pd0e8Igk.js">
27
- <link rel="modulepreload" crossorigin href="/assets/messages-B1EG4gdu.js">
28
- <link rel="modulepreload" crossorigin href="/assets/locale-store-tnRLWdx2.js">
27
+ <link rel="modulepreload" crossorigin href="/assets/messages-Cj_n7gUv.js">
28
+ <link rel="modulepreload" crossorigin href="/assets/locale-store-DXq-Y8Bi.js">
29
29
  <link rel="modulepreload" crossorigin href="/assets/cn-JdwAhgNB.js">
30
30
  <link rel="modulepreload" crossorigin href="/assets/schemas-DgQq6Z5S.js">
31
31
  <link rel="modulepreload" crossorigin href="/assets/product-delivery-BTRT9kCS.js">
32
32
  <link rel="modulepreload" crossorigin href="/assets/config-reload-event-Bjh2zoKp.js">
33
33
  <link rel="modulepreload" crossorigin href="/assets/copy-to-clipboard-HOJ79TWv.js">
34
- <link rel="modulepreload" crossorigin href="/assets/gateway-startup-retry-qnEmj-vL.js">
35
- <link rel="modulepreload" crossorigin href="/assets/activity-store-DjEDu38T.js">
36
- <link rel="modulepreload" crossorigin href="/assets/theme-store-H9T49Iar.js">
34
+ <link rel="modulepreload" crossorigin href="/assets/gateway-startup-retry-D73V3EVy.js">
35
+ <link rel="modulepreload" crossorigin href="/assets/activity-store-DumQD8EX.js">
36
+ <link rel="modulepreload" crossorigin href="/assets/theme-store-DSpAOJ9G.js">
37
37
  <link rel="stylesheet" crossorigin href="/assets/index-DfE2j0g8.css">
38
38
  </head>
39
39
  <body>
package/dist/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.0.168";
2
+ var version = "0.0.169";
3
3
  //#endregion
4
4
  export { version };
@@ -1,5 +1,5 @@
1
- import { DEFAULT_DEEP_CRON, DEFAULT_LIGHT_CRON, DEFAULT_REM_CRON } from "./constants.js";
2
1
  import { buildMemoryRuntime } from "../../../agent-runtime/memory-runtime.js";
2
+ import { DEFAULT_DEEP_CRON, DEFAULT_LIGHT_CRON, DEFAULT_REM_CRON } from "./constants.js";
3
3
  //#region src/agent/memory/dreaming/config.ts
4
4
  function clampScore(value, fallback) {
5
5
  if (!Number.isFinite(value)) return fallback;
@@ -1,7 +1,7 @@
1
- import { buildMemoryRuntime } from "./memory-runtime.js";
2
1
  import { checkBoundary } from "./boundary-guard.js";
3
2
  import { resolveModelRole } from "./model-router.js";
4
3
  import { buildRuntimeToolRegistry } from "./tool-registry.js";
4
+ import { buildMemoryRuntime } from "./memory-runtime.js";
5
5
  import { resolveWorkflow, validateWorkflowForRuntime } from "./workflow-runtime.js";
6
6
  import { buildAgentRuntimeProfile } from "./runtime-profile.js";
7
7
  import { appendAgentRunEvent, createAgentRunTrace, finishAgentRunTrace, hashEffectiveManifest } from "./run-trace.js";
@@ -1,9 +1,9 @@
1
1
  import { buildAgentManifestPromptSection } from "../agent-manifest/prompt.js";
2
2
  import "../agent-manifest/index.js";
3
- import { buildMemoryRuntime } from "./memory-runtime.js";
4
3
  import { checkBoundary } from "./boundary-guard.js";
5
4
  import { resolveModelRole } from "./model-router.js";
6
5
  import { buildRuntimeToolRegistry } from "./tool-registry.js";
6
+ import { buildMemoryRuntime } from "./memory-runtime.js";
7
7
  import { resolveWorkflow, validateWorkflowForRuntime } from "./workflow-runtime.js";
8
8
  //#region src/agent-runtime/runtime-profile.ts
9
9
  function buildAgentRuntimeProfile(params) {
@@ -52,7 +52,7 @@ async function checkDatabaseSchema(ctx) {
52
52
  id: "database-schema",
53
53
  label: "Database schema",
54
54
  status: "pass",
55
- message: `SQLite schema v${status.dbVersion} (current release v58).`,
55
+ message: `SQLite schema v${status.dbVersion} (current release v59).`,
56
56
  hints: []
57
57
  };
58
58
  }
@@ -1,6 +1,6 @@
1
- import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
2
1
  import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
3
2
  import "../agent-manifest/index.js";
3
+ import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
4
4
  import { init_session_key, parseSessionKey } from "../routing/session-key.js";
5
5
  import { agentExists, getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
6
6
  //#region src/config/agent-profile.ts
@@ -1,5 +1,5 @@
1
- import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
2
1
  import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
2
+ import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
3
3
  import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
4
4
  import { WORKSPACE_FILES, init_paths, resolveUserProfilePath } from "../config/paths.js";
5
5
  import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET } from "../agent/context/workspace.js";
@@ -1,9 +1,9 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { shouldSilence, stripHeartbeatToken } from "../../heartbeat/tokens.js";
4
+ import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
4
5
  import { isWithinActiveHours } from "../../heartbeat/active-hours.js";
5
6
  import { isHeartbeatContentEmpty } from "../../heartbeat/content-check.js";
6
- import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
7
7
  import { createHeartbeatWake } from "../../heartbeat/wake.js";
8
8
  import { resolveHeartbeatMdPath } from "../workspace-heartbeat-path.js";
9
9
  import { readFile } from "fs/promises";
@@ -0,0 +1,3 @@
1
+ import type { Hono } from 'hono';
2
+ import type { AuthenticatedRouteDeps } from './deps.js';
3
+ export declare function registerComposerHistoryRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void;
@@ -0,0 +1,28 @@
1
+ import { appendComposerInputHistory, clearComposerInputHistory, listComposerInputHistory } from "../../../storage/sqlite/composer-input-history-repository.js";
2
+ import "../../../storage/sqlite/index.js";
3
+ //#region src/gateway/hono/routes/composer-history.ts
4
+ const MAX_TEXT_LENGTH = 1e5;
5
+ function registerComposerHistoryRoutes(authenticated, deps) {
6
+ authenticated.get("/api/composer-history", (c) => {
7
+ return c.json({ items: listComposerInputHistory() });
8
+ });
9
+ authenticated.post("/api/composer-history", deps.strictRateLimitMiddleware, async (c) => {
10
+ const body = await c.req.json().catch(() => null);
11
+ const text = body && typeof body === "object" && typeof body.text === "string" ? body.text.trim() : "";
12
+ if (!text) return c.json({ error: "text is required" }, 400);
13
+ if (text.length > MAX_TEXT_LENGTH) return c.json({ error: "text is too long" }, 413);
14
+ const result = appendComposerInputHistory(text);
15
+ if (result.inserted) deps.service.emit("composer-history.appended", result.item);
16
+ return c.json(result);
17
+ });
18
+ authenticated.delete("/api/composer-history", deps.strictRateLimitMiddleware, (c) => {
19
+ const cleared = clearComposerInputHistory();
20
+ if (cleared > 0) deps.service.emit("composer-history.cleared", { cleared });
21
+ return c.json({
22
+ ok: true,
23
+ cleared
24
+ });
25
+ });
26
+ }
27
+ //#endregion
28
+ export { registerComposerHistoryRoutes };
@@ -8,6 +8,7 @@ import { registerSearchRoutes } from "./search.js";
8
8
  import { registerMobileRoutes } from "./mobile.js";
9
9
  import { registerTaskOutcomeRoutes } from "./task-outcomes.js";
10
10
  import { registerInteractionStateRoutes } from "./interaction-state.js";
11
+ import { registerComposerHistoryRoutes } from "./composer-history.js";
11
12
  import { registerLocalAppsRoutes } from "./local-apps.js";
12
13
  import { registerWorkDiscoveryRoutes } from "./work-discovery.js";
13
14
  import { mountAppLazyRoutePrefixes, registerAuthenticatedLazyRouteFallback } from "./lazy-fallback.js";
@@ -25,6 +26,7 @@ function registerCoreAuthenticatedRoutes(authenticated, deps) {
25
26
  registerMobileRoutes(authenticated, deps);
26
27
  registerTaskOutcomeRoutes(authenticated, deps);
27
28
  registerInteractionStateRoutes(authenticated, deps);
29
+ registerComposerHistoryRoutes(authenticated, deps);
28
30
  }
29
31
  function registerAuthenticatedRoutes(app, authenticated, deps) {
30
32
  registerCoreAuthenticatedRoutes(authenticated, deps);
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_ACK_MAX_CHARS, HEARTBEAT_OK, NO_REPLY, shouldSilence, stripHeartbeatToken } from "./tokens.js";
2
+ import { appendCronEventLines } from "./event-prompt.js";
2
3
  import { isWithinActiveHours } from "./active-hours.js";
3
4
  import { isHeartbeatContentEmpty } from "./content-check.js";
4
- import { appendCronEventLines } from "./event-prompt.js";
5
5
  import { createHeartbeatWake } from "./wake.js";
6
6
  export { DEFAULT_ACK_MAX_CHARS, HEARTBEAT_OK, NO_REPLY, appendCronEventLines, createHeartbeatWake, isHeartbeatContentEmpty, isWithinActiveHours, shouldSilence, stripHeartbeatToken };
@@ -7,6 +7,8 @@ export interface ClientHistoryMessage {
7
7
  content: string;
8
8
  displayIndex?: number;
9
9
  rawContent?: string | unknown[];
10
+ /** Persisted inbound attachment metadata used by chat clients to reload media. */
11
+ media?: Message['media'];
10
12
  timestamp?: number;
11
13
  kind?: 'message' | 'compaction' | 'context' | 'bash' | 'custom' | 'branch';
12
14
  tokensBefore?: number;
@@ -111,6 +111,7 @@ function messagesToClientHistory(messages, opts) {
111
111
  out.push({
112
112
  role: m.role,
113
113
  content: text,
114
+ ...m.media?.length ? { media: m.media } : {},
114
115
  timestamp: parseTimestamp(m.timestamp)
115
116
  });
116
117
  continue;
@@ -410,6 +411,7 @@ function transcriptRowsToClientHistory(rows, opts) {
410
411
  role: messageRow.role,
411
412
  kind: "message",
412
413
  content: flattenMessageContent(messageRow.content ?? ""),
414
+ ...messageRow.media?.length ? { media: messageRow.media } : {},
413
415
  ...displayIndex !== void 0 ? { displayIndex } : {},
414
416
  timestamp: parseTimestampValue(messageRow.timestamp)
415
417
  });
@@ -0,0 +1,12 @@
1
+ export declare const COMPOSER_INPUT_HISTORY_LIMIT = 100;
2
+ export interface ComposerInputHistoryItem {
3
+ id: number;
4
+ text: string;
5
+ createdAt: number;
6
+ }
7
+ export declare function listComposerInputHistory(limit?: number): ComposerInputHistoryItem[];
8
+ export declare function appendComposerInputHistory(text: string, now?: number): {
9
+ item: ComposerInputHistoryItem;
10
+ inserted: boolean;
11
+ };
12
+ export declare function clearComposerInputHistory(): number;
@@ -0,0 +1,42 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
+ //#region src/storage/sqlite/composer-input-history-repository.ts
3
+ const COMPOSER_INPUT_HISTORY_LIMIT = 100;
4
+ function fromRow(row) {
5
+ return {
6
+ id: row.id,
7
+ text: row.text,
8
+ createdAt: row.created_at
9
+ };
10
+ }
11
+ function listComposerInputHistory(limit = 100) {
12
+ const boundedLimit = Number.isFinite(limit) ? Math.min(100, Math.max(1, Math.trunc(limit))) : 100;
13
+ return getSqliteDatabase().prepare("SELECT id, text, created_at FROM composer_input_history ORDER BY id DESC LIMIT ?").all(boundedLimit).map(fromRow);
14
+ }
15
+ function appendComposerInputHistory(text, now = Date.now()) {
16
+ const normalized = text.trim();
17
+ if (!normalized) throw new Error("Composer history text is required");
18
+ return runSqliteWriteTransaction((db) => {
19
+ const latest = db.prepare("SELECT id, text, created_at FROM composer_input_history ORDER BY id DESC LIMIT 1").get();
20
+ if (latest?.text === normalized) return {
21
+ item: fromRow(latest),
22
+ inserted: false
23
+ };
24
+ const result = db.prepare("INSERT INTO composer_input_history (text, created_at) VALUES (?, ?)").run(normalized, now);
25
+ const id = Number(result.lastInsertRowid);
26
+ db.prepare(`DELETE FROM composer_input_history
27
+ WHERE id NOT IN (SELECT id FROM composer_input_history ORDER BY id DESC LIMIT ?)`).run(100);
28
+ return {
29
+ item: {
30
+ id,
31
+ text: normalized,
32
+ createdAt: now
33
+ },
34
+ inserted: true
35
+ };
36
+ });
37
+ }
38
+ function clearComposerInputHistory() {
39
+ return Number(runSqliteWriteTransaction((db) => db.prepare("DELETE FROM composer_input_history").run().changes));
40
+ }
41
+ //#endregion
42
+ export { COMPOSER_INPUT_HISTORY_LIMIT, appendComposerInputHistory, clearComposerInputHistory, listComposerInputHistory };
@@ -5,6 +5,7 @@ export { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, } from './m
5
5
  export { discoverSqlMigrations, listRegisteredMigrationTargets } from './migrations/discover.js';
6
6
  export { closeXopcDatabase, getXopcDatabase, isXopcDatabaseOpen, openXopcDatabase, requireXopcDatabase, resetXopcDatabaseSingletonForTest, type OpenXopcDatabaseOptions, type XopcDatabase, } from './connection.js';
7
7
  export { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';
8
+ export { appendComposerInputHistory, clearComposerInputHistory, listComposerInputHistory, COMPOSER_INPUT_HISTORY_LIMIT, type ComposerInputHistoryItem, } from './composer-input-history-repository.js';
8
9
  export { getInteractionState, setInteractionState, updateInteractionStateFromMessage, type InteractionState, } from './interaction-state-repository.js';
9
10
  export { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAllowed, updateRelationshipSettings, type RelationshipSettings, type SupportMode, } from './relationship-settings-repository.js';
10
11
  export { completeTaskOutcome, findTaskOutcomeForAssistant, getTaskOutcome, listTaskOutcomes, setTaskOutcomeFeedback, startTaskOutcome, summarizeTaskOutcomes, updateTaskOutcome, type TaskContract, type TaskEvidence, type TaskFeedbackOutcome, type TaskOutcome, type TaskOutcomeMetrics, type TaskOutcomeStatus, } from './task-outcome-repository.js';
@@ -6,6 +6,7 @@ import { XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_SCHEMA_VERSION, applyPendingMi
6
6
  import { ensureXopcDatabaseSchema } from "./schema.js";
7
7
  import { closeXopcDatabase, getXopcDatabase, isXopcDatabaseOpen, openXopcDatabase, requireXopcDatabase, resetXopcDatabaseSingletonForTest } from "./connection.js";
8
8
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
9
+ import { COMPOSER_INPUT_HISTORY_LIMIT, appendComposerInputHistory, clearComposerInputHistory, listComposerInputHistory } from "./composer-input-history-repository.js";
9
10
  import { getInteractionState, setInteractionState, updateInteractionStateFromMessage } from "./interaction-state-repository.js";
10
11
  import { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAllowed, updateRelationshipSettings } from "./relationship-settings-repository.js";
11
12
  import { completeTaskOutcome, findTaskOutcomeForAssistant, getTaskOutcome, listTaskOutcomes, setTaskOutcomeFeedback, startTaskOutcome, summarizeTaskOutcomes, updateTaskOutcome } from "./task-outcome-repository.js";
@@ -24,4 +25,4 @@ import { appendConnectorExecutionAudit, claimConnectorWebhookDelivery, completeC
24
25
  import { getUserTrustPolicy, setUserTrustPolicy } from "./user-trust-repository.js";
25
26
  import { consumeMemoryReferenceConsent, decideMemoryReferenceConsent, ensureMemoryReferenceConsentRequest, hasMemoryReferenceConsent, listMemoryReferenceConsents, revokeMemoryReferenceConsent } from "./memory-reference-consent-repository.js";
26
27
  import { getUserProfilePromptState, setUserProfilePromptState } from "./user-profile-setup-repository.js";
27
- export { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, USER_UNDERSTANDING_REMEDIATION_POLICY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRelationshipPrompt, captureCompactionCheckpoint, claimConnectorWebhookDelivery, claimKnowledgeSourceItems, classifyStoredRow, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, completeTaskOutcome, consumeConnectorApproval, consumeMemoryReferenceConsent, createConnectorApproval, createObjectLinkRecord, decideConnectorApproval, decideMemoryReferenceConsent, deleteConnectorConnection, deleteConnectorInstallation, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteNoteAgentContextRecord, deleteNoteRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, ensureMemoryReferenceConsentRequest, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findLatestMemoryInjectTrace, findSessionKeyBySessionId, findTaskOutcomeForAssistant, finishKnowledgeSyncRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCompactionCheckpointDetail, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getCurrentSessionId, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getNoteAgentContextRecord, getNoteRecord, getRelationshipSettings, getSessionConfig, getSessionMetadata, getSessionPersistedLevels, getSqliteDatabase, getTaskOutcome, getUserProfilePromptState, getUserTrustPolicy, getXopcDatabase, hasMemoryReferenceConsent, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, inspectSchemaMigrationStatus, isProactiveSupportAllowed, isXopcDatabaseOpen, listActivityRecords, listCachedConnectorCatalogEntries, listCompactionCheckpoints, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemoryReferenceConsents, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTaskOutcomes, loadCheckpointRows, loadLlmMessagesForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, metadataToSessionInsert, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, readSchemaVersion, readSchemaVersionForTest, recordActivityEvent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreCompactionCheckpoint, revokeMemoryReferenceConsent, runSqliteWriteTransaction, searchMemoryIndex, searchMemoryRecords, sessionConfigRowToConfig, sessionRowToMetadata, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setLatestMemoryInjectFeedback, setMemoryProviderState, setMemoryTraceFeedback, setSessionConfig, setTaskOutcomeFeedback, setUserProfilePromptState, setUserTrustPolicy, startKnowledgeSyncRun, startTaskOutcome, summarizeMemoryRecallFeedback, summarizeTaskOutcomes, summarizeUserUnderstandingQuality, syncMemoryIndex, transcriptEntryRowToStoredRow, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateTaskOutcome, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord };
28
+ export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, USER_UNDERSTANDING_REMEDIATION_POLICY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, appendComposerInputHistory, appendConnectorExecutionAudit, appendMemorySignal, appendMemoryTraceEvent, appendTranscriptEntry, applyPendingMigrations, attachMemoryEvidence, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRelationshipPrompt, captureCompactionCheckpoint, claimConnectorWebhookDelivery, claimKnowledgeSourceItems, classifyStoredRow, clearComposerInputHistory, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, completeTaskOutcome, consumeConnectorApproval, consumeMemoryReferenceConsent, createConnectorApproval, createObjectLinkRecord, decideConnectorApproval, decideMemoryReferenceConsent, deleteConnectorConnection, deleteConnectorInstallation, deleteMemoryEvidenceForRecord, deleteMemoryRecord, deleteNoteAgentContextRecord, deleteNoteRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, ensureMemoryReferenceConsentRequest, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findLatestMemoryInjectTrace, findSessionKeyBySessionId, findTaskOutcomeForAssistant, finishKnowledgeSyncRun, getActivityEventRecord, getCachedConnectorCatalogEntry, getCompactionCheckpointDetail, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getCurrentSessionId, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getMemoryProviderState, getMemoryRecord, getNoteAgentContextRecord, getNoteRecord, getRelationshipSettings, getSessionConfig, getSessionMetadata, getSessionPersistedLevels, getSqliteDatabase, getTaskOutcome, getUserProfilePromptState, getUserTrustPolicy, getXopcDatabase, hasMemoryReferenceConsent, hasSessionConfig, hasUnresolvedMemoryConflict, incrementSessionStatsOnAppend, inspectSchemaMigrationStatus, isProactiveSupportAllowed, isXopcDatabaseOpen, listActivityRecords, listCachedConnectorCatalogEntries, listCompactionCheckpoints, listComposerInputHistory, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listMemoryEvidence, listMemoryRecords, listMemoryReferenceConsents, listMemorySignals, listMemoryTraceEvents, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTaskOutcomes, loadCheckpointRows, loadLlmMessagesForSession, loadTranscriptRows, loadTranscriptRowsForSession, markMemoryRecordsConflicted, metadataToSessionInsert, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, readSchemaVersion, readSchemaVersionForTest, recordActivityEvent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreCompactionCheckpoint, revokeMemoryReferenceConsent, runSqliteWriteTransaction, searchMemoryIndex, searchMemoryRecords, sessionConfigRowToConfig, sessionRowToMetadata, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setLatestMemoryInjectFeedback, setMemoryProviderState, setMemoryTraceFeedback, setSessionConfig, setTaskOutcomeFeedback, setUserProfilePromptState, setUserTrustPolicy, startKnowledgeSyncRun, startTaskOutcome, summarizeMemoryRecallFeedback, summarizeTaskOutcomes, summarizeUserUnderstandingQuality, syncMemoryIndex, transcriptEntryRowToStoredRow, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateTaskOutcome, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertKnowledgeSourceItems, upsertMemoryRecord, upsertNoteAgentContextRecord, upsertNoteRecord };
@@ -0,0 +1,8 @@
1
+ CREATE TABLE composer_input_history (
2
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
3
+ text TEXT NOT NULL,
4
+ created_at INTEGER NOT NULL
5
+ );
6
+
7
+ CREATE INDEX idx_composer_input_history_recent
8
+ ON composer_input_history(id DESC);
@@ -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 = 58;
6
+ export declare const XOPC_DB_SCHEMA_VERSION = 59;
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 = 58;
15
+ const XOPC_DB_SCHEMA_VERSION = 59;
16
16
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
17
17
  function resolveMigrationsDir(override) {
18
18
  if (override) return override;
@@ -46,7 +46,7 @@ function applySingleMigration(db, migration) {
46
46
  * Each step runs in its own transaction and updates schema_meta on success.
47
47
  */
48
48
  function applyPendingMigrations(db, options = {}) {
49
- const targetVersion = options.targetVersion ?? 58;
49
+ const targetVersion = options.targetVersion ?? 59;
50
50
  let currentVersion = readSchemaVersion(db);
51
51
  if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
52
52
  if (currentVersion >= targetVersion) return currentVersion;
@@ -62,7 +62,7 @@ function applyPendingMigrations(db, options = {}) {
62
62
  }
63
63
  /** Inspect schema version without mutating the database. */
64
64
  function inspectSchemaMigrationStatus(db, options = {}) {
65
- const appVersion = options.targetVersion ?? 58;
65
+ const appVersion = options.targetVersion ?? 59;
66
66
  const dbVersion = readSchemaVersion(db);
67
67
  if (dbVersion > appVersion) return {
68
68
  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 = 58;
22
+ export const XOPC_DB_SCHEMA_VERSION = 59;
23
23
 
24
24
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
25
25
 
@@ -31,7 +31,7 @@ function ensureXopcDatabaseSchema(db) {
31
31
  bootstrapFreshDatabase(db);
32
32
  currentVersion = 11;
33
33
  }
34
- applyPendingMigrations(db, { targetVersion: 58 });
34
+ applyPendingMigrations(db, { targetVersion: 59 });
35
35
  }
36
36
  //#endregion
37
37
  export { SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_SCHEMA_VERSION, ensureSchemaMetaTable, ensureXopcDatabaseSchema, readSchemaVersion, readSchemaVersionForTest, setSchemaVersion };
@@ -2,7 +2,7 @@ import type { ExtensionRegistryImpl } from '../../extensions/loader.js';
2
2
  import { type SessionTimelineItem } from '../../session/transcript-outline.js';
3
3
  import { type Config } from '../../config/schema.js';
4
4
  import type { ExportFormat } from '../../session/types.js';
5
- import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
5
+ import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiComposerHistoryItem, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
6
6
  import type { SessionInfo } from '../tui-types.js';
7
7
  interface EmbeddedBackendOptions {
8
8
  config?: Config;
@@ -33,6 +33,8 @@ export declare class EmbeddedBackend implements TuiBackend {
33
33
  onDisconnected?: (reason: string) => void;
34
34
  constructor(opts?: EmbeddedBackendOptions);
35
35
  get connectionLabel(): string;
36
+ getComposerInputHistory(): Promise<TuiComposerHistoryItem[]>;
37
+ recordComposerInputHistory(text: string): Promise<TuiComposerHistoryItem>;
36
38
  start(): void;
37
39
  private ensureAgent;
38
40
  private createAgent;
@@ -1,6 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { openXopcDatabase } from "../../storage/sqlite/connection.js";
4
+ import { appendComposerInputHistory, listComposerInputHistory } from "../../storage/sqlite/composer-input-history-repository.js";
4
5
  import { init_agent_session_key, resolveAgentIdFromSessionKey } from "../../routing/agent-session-key.js";
5
6
  import { getSessionMetadata } from "../../storage/sqlite/session-repository.js";
6
7
  import "../../storage/sqlite/index.js";
@@ -77,6 +78,12 @@ var EmbeddedBackend = class {
77
78
  get connectionLabel() {
78
79
  return "local embedded";
79
80
  }
81
+ async getComposerInputHistory() {
82
+ return listComposerInputHistory();
83
+ }
84
+ async recordComposerInputHistory(text) {
85
+ return appendComposerInputHistory(text).item;
86
+ }
80
87
  start() {
81
88
  if (this.running) return;
82
89
  this.running = true;
@@ -1,6 +1,6 @@
1
1
  import type { ExportFormat } from '../../session/types.js';
2
2
  import type { SessionTimelineItem } from '../../session/transcript-outline.js';
3
- import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiStartupResources, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
3
+ import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiComposerHistoryItem, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiStartupResources, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
4
4
  import type { SessionInfo } from '../tui-types.js';
5
5
  import type { ReviewContext } from '../../review/review-git.js';
6
6
  import { type GatewayCredential } from '../../gateway/credential.js';
@@ -33,6 +33,8 @@ export declare class GatewaySseBackend implements TuiBackend {
33
33
  start(): void;
34
34
  stop(): void;
35
35
  getActiveSignal(): AbortSignal | undefined;
36
+ getComposerInputHistory(): Promise<TuiComposerHistoryItem[]>;
37
+ recordComposerInputHistory(text: string): Promise<TuiComposerHistoryItem>;
36
38
  sendChat(opts: ChatSendOptions): Promise<{
37
39
  runId: string;
38
40
  }>;
@@ -80,6 +80,19 @@ var GatewaySseBackend = class {
80
80
  const signal = this.chatAbort?.signal;
81
81
  return signal && !signal.aborted ? signal : void 0;
82
82
  }
83
+ async getComposerInputHistory() {
84
+ const res = await gatewayFetch(this.baseUrl, "/api/composer-history", this.credential);
85
+ if (!res.ok) throw new Error(`Failed to load composer history (${res.status})`);
86
+ return (await res.json()).items ?? [];
87
+ }
88
+ async recordComposerInputHistory(text) {
89
+ const res = await gatewayFetch(this.baseUrl, "/api/composer-history", this.credential, {
90
+ method: "POST",
91
+ body: JSON.stringify({ text })
92
+ });
93
+ if (!res.ok) throw new Error(`Failed to save composer history (${res.status})`);
94
+ return (await res.json()).item;
95
+ }
83
96
  async sendChat(opts) {
84
97
  this.chatAbort?.abort();
85
98
  this.chatAbort = new AbortController();
@@ -13,5 +13,6 @@ export declare class CustomEditor extends Editor {
13
13
  onExtensionShortcut?: (data: string) => boolean;
14
14
  constructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: EditorOptions);
15
15
  onAction(action: XopcTuiAppKeybinding, handler: () => void): void;
16
+ replaceHistory(itemsNewestFirst: string[]): void;
16
17
  handleInput(data: string): void;
17
18
  }
@@ -18,6 +18,12 @@ var CustomEditor = class extends Editor {
18
18
  onAction(action, handler) {
19
19
  this.actionHandlers.set(action, handler);
20
20
  }
21
+ replaceHistory(itemsNewestFirst) {
22
+ const internals = this;
23
+ internals.history = itemsNewestFirst.slice(0, 100);
24
+ internals.historyIndex = -1;
25
+ internals.historyDraft = "";
26
+ }
21
27
  handleInput(data) {
22
28
  if (this.onExtensionShortcut?.(data)) return;
23
29
  if (this.keybindings.matches(data, "app.clipboard.pasteImage")) {
@@ -25,6 +25,11 @@ export interface TuiEvent {
25
25
  data: unknown;
26
26
  source?: TuiEventSource;
27
27
  }
28
+ export interface TuiComposerHistoryItem {
29
+ id: number;
30
+ text: string;
31
+ createdAt: number;
32
+ }
28
33
  /** Minimal session list item. */
29
34
  export interface TuiSessionItem {
30
35
  key: string;
@@ -180,6 +185,10 @@ export interface TuiBackend {
180
185
  stop(): void;
181
186
  /** Current active chat abort signal, if a run is in progress. */
182
187
  getActiveSignal?(): AbortSignal | undefined;
188
+ /** Global composer history, shared across sessions and clients. */
189
+ getComposerInputHistory(): Promise<TuiComposerHistoryItem[]>;
190
+ /** Persist one submitted chat input. */
191
+ recordComposerInputHistory(text: string): Promise<TuiComposerHistoryItem>;
183
192
  /** Send a chat message, returns the run id. */
184
193
  sendChat(opts: ChatSendOptions): Promise<{
185
194
  runId: string;
@@ -7,6 +7,7 @@ export declare function createEditorSubmitHandler(params: {
7
7
  setText: (value: string) => void;
8
8
  addToHistory: (value: string) => void;
9
9
  };
10
+ recordChatHistory?: (value: string) => void;
10
11
  handleCommand: (value: string) => void | Promise<void>;
11
12
  sendMessage: (value: string) => void | Promise<void>;
12
13
  handleBangLine: (value: string) => void | Promise<void>;
@@ -36,7 +36,7 @@ function createEditorSubmitHandler(params) {
36
36
  params.handleBangLine(raw);
37
37
  return;
38
38
  }
39
- params.editor.addToHistory(value);
39
+ if (rawTrimmed) (params.recordChatHistory ?? params.editor.addToHistory)(rawTrimmed);
40
40
  if (value.startsWith("/")) {
41
41
  params.handleCommand(value);
42
42
  return;
@@ -360,6 +360,7 @@ async function runTui(opts) {
360
360
  paddingX: tuiSettings.editorPaddingX,
361
361
  autocompleteMaxVisible: tuiSettings.autocompleteMaxVisible
362
362
  });
363
+ let composerHistoryTexts = [];
363
364
  let editor = defaultEditor;
364
365
  let editorComponentFactory;
365
366
  const editorContainer = new Container();
@@ -421,6 +422,7 @@ async function runTui(opts) {
421
422
  nextEditor.setAutocompleteProvider?.(extensionRuntime.autocompleteProvider);
422
423
  copyDefaultEditorAppHandlers(nextEditor);
423
424
  editor = nextEditor;
425
+ for (const text of composerHistoryTexts.slice().reverse()) editor.addToHistory?.(text);
424
426
  } else {
425
427
  defaultEditor.setText(currentText);
426
428
  editor = defaultEditor;
@@ -1762,12 +1764,48 @@ async function runTui(opts) {
1762
1764
  updateFooter();
1763
1765
  tui.requestRender();
1764
1766
  };
1767
+ let composerHistory = [];
1768
+ let composerHistoryWriteQueue = Promise.resolve();
1769
+ const applyComposerHistory = (next) => {
1770
+ composerHistory = next.slice(0, 100);
1771
+ composerHistoryTexts = composerHistory.map((item) => item.text);
1772
+ if (editor === defaultEditor) {
1773
+ defaultEditor.replaceHistory(composerHistory.map((item) => item.text));
1774
+ return;
1775
+ }
1776
+ for (const item of composerHistory.slice().reverse()) editor.addToHistory?.(item.text);
1777
+ };
1778
+ const refreshComposerHistory = async () => {
1779
+ try {
1780
+ await composerHistoryWriteQueue;
1781
+ applyComposerHistory(await client.getComposerInputHistory());
1782
+ } catch {}
1783
+ };
1784
+ const recordChatHistory = (value) => {
1785
+ const text = value.trim();
1786
+ if (!text) return;
1787
+ editor.addToHistory?.(text);
1788
+ if (composerHistory[0]?.text !== text) {
1789
+ composerHistory = [{
1790
+ id: 0,
1791
+ text,
1792
+ createdAt: Date.now()
1793
+ }, ...composerHistory].slice(0, 100);
1794
+ composerHistoryTexts = composerHistory.map((item) => item.text);
1795
+ }
1796
+ composerHistoryWriteQueue = composerHistoryWriteQueue.then(async () => {
1797
+ const item = await client.recordComposerInputHistory(text);
1798
+ const optimisticIndex = composerHistory.findIndex((entry) => entry.id === 0 && entry.text === item.text);
1799
+ if (optimisticIndex >= 0) composerHistory[optimisticIndex] = item;
1800
+ }).catch(() => {});
1801
+ };
1765
1802
  const submitBurst = createSubmitBurstCoalescer({
1766
1803
  submit: createEditorSubmitHandler({
1767
1804
  editor: {
1768
1805
  setText: (value) => editor.setText(value),
1769
1806
  addToHistory: (value) => editor.addToHistory?.(value)
1770
1807
  },
1808
+ recordChatHistory: (value) => recordChatHistory(value),
1771
1809
  handleCommand,
1772
1810
  sendMessage,
1773
1811
  handleBangLine: runLocalShellLine,
@@ -1798,7 +1836,7 @@ async function runTui(opts) {
1798
1836
  tui.requestRender();
1799
1837
  return;
1800
1838
  }
1801
- editor.addToHistory(text);
1839
+ recordChatHistory(text);
1802
1840
  state.messageFollowUpQueue.push(text);
1803
1841
  editor.setText("");
1804
1842
  chatLog.addSystem(theme.dim(`Queued follow-up (${state.messageFollowUpQueue.length} in queue). ${tuiSettings.followUpMode === "all" ? "All queued messages send together when this reply finishes." : "Next sends when this reply finishes."}`));
@@ -2052,6 +2090,23 @@ async function runTui(opts) {
2052
2090
  };
2053
2091
  client.onEvent = (evt) => {
2054
2092
  const data = evt.data ?? {};
2093
+ if (evt.event === "composer-history.appended") {
2094
+ const item = data;
2095
+ if (typeof item.text === "string" && typeof item.id === "number") {
2096
+ const optimisticIndex = composerHistory.findIndex((entry) => entry.id === 0 && entry.text === item.text);
2097
+ if (optimisticIndex >= 0) composerHistory[optimisticIndex] = item;
2098
+ else if (composerHistory[0]?.text !== item.text) {
2099
+ composerHistory = [item, ...composerHistory].slice(0, 100);
2100
+ composerHistoryTexts = composerHistory.map((entry) => entry.text);
2101
+ editor.addToHistory?.(item.text);
2102
+ } else composerHistory[0] = item;
2103
+ }
2104
+ return;
2105
+ }
2106
+ if (evt.event === "composer-history.cleared") {
2107
+ applyComposerHistory([]);
2108
+ return;
2109
+ }
2055
2110
  if (evt.event === "workflow.run.updated" && handleWorkflowRunUpdated(data)) return;
2056
2111
  dispatchAgentEvent(evt.event, data, state, chatLog, tui, setActivityStatus, touchStreamingActivity, onAgentRunEnded, (message) => sessionSnapshot.appendMessage("assistant", assistantMessagePlainText(message)), evt.source);
2057
2112
  };
@@ -2061,6 +2116,7 @@ async function runTui(opts) {
2061
2116
  setConnectionStatus(isLocalMode ? "local ready" : "gateway connected");
2062
2117
  touchStreamingActivity();
2063
2118
  (async () => {
2119
+ await refreshComposerHistory();
2064
2120
  if (opts.openSessionPickerOnStart && !startupSessionPickerOpened) {
2065
2121
  startupSessionPickerOpened = true;
2066
2122
  await openSessionPickerOverlay(pickerSvc, {
@@ -2125,6 +2181,7 @@ async function runTui(opts) {
2125
2181
  setConnectionStatus(`event gap: expected ${info.expected}, got ${info.received}`);
2126
2182
  if (state.activeRunId) recoverActiveRunFromHistory("broadcast event gap");
2127
2183
  else loadSessionHistory({ merge: true });
2184
+ refreshComposerHistory();
2128
2185
  tui.requestRender();
2129
2186
  };
2130
2187
  const sigintHandler = () => handleCtrlC();