@xopcai/xopc 0.0.284 → 0.0.285

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-CwbIMGLY.js → activity-store-B0BTIk9j.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DjiOld-S.js → agent-avatar-dicebear-Dc-0QZTQ.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CcmqK1Sc.js +1 -0
  6. package/dist/gateway/static/root/assets/agents-B_7PVt7S.js +1 -0
  7. package/dist/gateway/static/root/assets/api-COG_Tzpv.js +1 -0
  8. package/dist/gateway/static/root/assets/{api-3lphBVuY.js → api-Coly9ab6.js} +1 -1
  9. package/dist/gateway/static/root/assets/{app-management-settings-panel-B2nwCXxE.js → app-management-settings-panel-TWBO-msg.js} +1 -1
  10. package/dist/gateway/static/root/assets/{appearance-settings-BXO4Ej88.js → appearance-settings-CpTZ2KuT.js} +1 -1
  11. package/dist/gateway/static/root/assets/apps-page-6qxxKFsK.js +1 -0
  12. package/dist/gateway/static/root/assets/{archive-plugin-6ZRqNjla.js → archive-plugin-z_u6alob.js} +1 -1
  13. package/dist/gateway/static/root/assets/{attachment-load-CmPZalcW.js → attachment-load-C2nS04TC.js} +1 -1
  14. package/dist/gateway/static/root/assets/{automations-page-Bc3WbK5n.js → automations-page-aIBsw9zR.js} +1 -1
  15. package/dist/gateway/static/root/assets/automations-workspace-BRQlU4qk.js +6 -0
  16. package/dist/gateway/static/root/assets/{binary-plugins-OWR6cxpc.js → binary-plugins-CGmXoZnl.js} +1 -1
  17. package/dist/gateway/static/root/assets/{block-editor-Ca-tDQXm.js → block-editor-CtvzCZhC.js} +3 -3
  18. package/dist/gateway/static/root/assets/{browser-automation-inputs-Dxy2_p3U.js → browser-automation-inputs-BOTU1isH.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-automations-page-CibQIxpi.js → browser-automations-page-BwU5V8J0.js} +2 -2
  20. package/dist/gateway/static/root/assets/browser-settings-page-DDjbDeHQ.js +8 -0
  21. package/dist/gateway/static/root/assets/capabilities-settings-panel-DM1Bcf1x.js +8 -0
  22. package/dist/gateway/static/root/assets/channels-settings-Bq36CUxL.js +1 -0
  23. package/dist/gateway/static/root/assets/{channels-status-swr-Bh-G9mdZ.js → channels-status-swr-Dfi0Desh.js} +1 -1
  24. package/dist/gateway/static/root/assets/{chat-terminal-dock-lbzbSpV3.js → chat-terminal-dock-B0MvcO6j.js} +2 -2
  25. package/dist/gateway/static/root/assets/connectors-page-L8JehrxF.js +2 -0
  26. package/dist/gateway/static/root/assets/{date-picker-tYvbTfZT.js → date-picker-DXOvbHCr.js} +1 -1
  27. package/dist/gateway/static/root/assets/{dependency-picker-B8yo7-7V.js → dependency-picker-BEnC-eS0.js} +1 -1
  28. package/dist/gateway/static/root/assets/{desktop-pet-BUGkGB4-.js → desktop-pet-DtPNvznL.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-settings-DNeVGZNp.js → desktop-pet-settings-CYyjcSn6.js} +1 -1
  30. package/dist/gateway/static/root/assets/device-pairing-wizard-BPMGvAKE.js +1 -0
  31. package/dist/gateway/static/root/assets/{extension-debug-page-CiK0QI2p.js → extension-debug-page-H_aPMGXW.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-CirPNHJd.js → extension-page-C1JnpeMt.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-Baua1_Le.js → extension-settings-page-C75kCOqe.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-config-swr-Co4hHe0i.js → gateway-config-swr-G2lQt7Ak.js} +1 -1
  35. package/dist/gateway/static/root/assets/gateway-settings-BCF732TU.js +1 -0
  36. package/dist/gateway/static/root/assets/{gateway-startup-retry-DBPNJG-e.js → gateway-startup-retry-GP31PUrG.js} +1 -1
  37. package/dist/gateway/static/root/assets/{heartbeat-settings-DTM_kYpE.js → heartbeat-settings-C7fjiowt.js} +1 -1
  38. package/dist/gateway/static/root/assets/home-page-DZXeXdUL.js +1 -0
  39. package/dist/gateway/static/root/assets/{image-generation-api-D0rMTumD.js → image-generation-api-CKFhfHSw.js} +1 -1
  40. package/dist/gateway/static/root/assets/imports-page-GROumhj8.js +1 -0
  41. package/dist/gateway/static/root/assets/{index-C9aQA4Dr.js → index-ChIrvv3t.js} +47 -47
  42. package/dist/gateway/static/root/assets/index-R1VNlHjj.css +2 -0
  43. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CMUaF61L.js → keyboard-shortcuts-settings-zcI822m_.js} +1 -1
  44. package/dist/gateway/static/root/assets/local-app-workbench-page-CAEKGTAg.js +2 -0
  45. package/dist/gateway/static/root/assets/{local-apps-page-CHxyT09t.js → local-apps-page-BtgDJ92Q.js} +1 -1
  46. package/dist/gateway/static/root/assets/{locale-store-DO6JJ1l2.js → locale-store-DlOv7896.js} +1 -1
  47. package/dist/gateway/static/root/assets/logs-page-DHZ4BEkG.js +2 -0
  48. package/dist/gateway/static/root/assets/{management-settings-jXbA2S54.js → management-settings-DasZxCyD.js} +1 -1
  49. package/dist/gateway/static/root/assets/{markdown-view-CKInRsDh.js → markdown-view-6oYdBahT.js} +1 -1
  50. package/dist/gateway/static/root/assets/{media-plugins-BaPkSvW7.js → media-plugins-CxthbBvk.js} +1 -1
  51. package/dist/gateway/static/root/assets/{messages-BgZRsCkG.js → messages-Ls1Aaiqd.js} +1 -1
  52. package/dist/gateway/static/root/assets/note-detail-panel-BcWq3ddw.js +5 -0
  53. package/dist/gateway/static/root/assets/notes-page-DfZ8QWyv.js +8 -0
  54. package/dist/gateway/static/root/assets/{page-tabs-CdYemUOu.js → page-tabs-BG39KidE.js} +1 -1
  55. package/dist/gateway/static/root/assets/{preview-open-alternatives-DzgF1yYO.js → preview-open-alternatives-Bevpbq9f.js} +1 -1
  56. package/dist/gateway/static/root/assets/proactive-page-D2U_xQaS.js +1 -0
  57. package/dist/gateway/static/root/assets/{product-open-page-iQ-eW6Aj.js → product-open-page-Bi1seZpM.js} +1 -1
  58. package/dist/gateway/static/root/assets/project-detail-page-CzlGTW4F.js +1 -0
  59. package/dist/gateway/static/root/assets/projects-page-mQsM-TsP.js +1 -0
  60. package/dist/gateway/static/root/assets/{registry-api-DMNudT60.js → registry-api-D0ddwBFj.js} +1 -1
  61. package/dist/gateway/static/root/assets/remote-access-hub-Cb56JcO1.js +1 -0
  62. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-u_wVepf7.js → runtime-tools-settings-panel-Wkru8_My.js} +2 -2
  63. package/dist/gateway/static/root/assets/{schema-form-YdZj2xdI.js → schema-form-CSMRzj9Y.js} +1 -1
  64. package/dist/gateway/static/root/assets/sessions-page-Hj9uFcIO.js +1 -0
  65. package/dist/gateway/static/root/assets/settings-advanced-gate-CV4-_EVA.js +1 -0
  66. package/dist/gateway/static/root/assets/{settings-form-section-Bw6xKOX5.js → settings-form-section-wcAdCkK8.js} +1 -1
  67. package/dist/gateway/static/root/assets/{settings-page-CV8kVdnE.js → settings-page-BcQGAnCs.js} +1 -1
  68. package/dist/gateway/static/root/assets/setup-status-panel-DzxmsaQG.js +1 -0
  69. package/dist/gateway/static/root/assets/{share-preview-page-BHwjHlrV.js → share-preview-page-DQocUl-1.js} +1 -1
  70. package/dist/gateway/static/root/assets/shares-settings-xlJh1ccG.js +1 -0
  71. package/dist/gateway/static/root/assets/skill-reload-api-wSXJRSxX.js +1 -0
  72. package/dist/gateway/static/root/assets/{skills-page-DRKdb6O5.js → skills-page-AmqtBJo7.js} +1 -1
  73. package/dist/gateway/static/root/assets/{skills-page.utils-DYfaLtts.js → skills-page.utils-DtlfCgJp.js} +1 -1
  74. package/dist/gateway/static/root/assets/{system-settings-panel-CWrWpKV-.js → system-settings-panel-Ct698Nf-.js} +1 -1
  75. package/dist/gateway/static/root/assets/task-detail-page-sQpwq5-c.js +1 -0
  76. package/dist/gateway/static/root/assets/{theme-store-CDc7Wqy5.js → theme-store-ng8KJsAT.js} +1 -1
  77. package/dist/gateway/static/root/assets/{tunnel-api-Bmsy-5Fs.js → tunnel-api-Boajol0M.js} +1 -1
  78. package/dist/gateway/static/root/assets/{use-autosave-D-FRib85.js → use-autosave-BSyxRHt2.js} +1 -1
  79. package/dist/gateway/static/root/assets/user-model-page-DIEHnAER.js +2 -0
  80. package/dist/gateway/static/root/assets/{voice-api-key-field-iQ7EBzII.js → voice-api-key-field-SE3OQI1s.js} +1 -1
  81. package/dist/gateway/static/root/assets/{voice-config-api-DNMWA2tx.js → voice-config-api-VNuCmdFe.js} +1 -1
  82. package/dist/gateway/static/root/assets/{work-discovery-overlay-BesuhDlH.js → work-discovery-overlay-Dn1vy2oq.js} +1 -1
  83. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Du81FoCy.js → workflow-run-setup-panel-BJEfGY-k.js} +2 -2
  84. package/dist/gateway/static/root/assets/workflows-page-DgRNIyr7.js +6 -0
  85. package/dist/gateway/static/root/index.html +10 -10
  86. package/dist/package.js +1 -1
  87. package/dist/packages/gateway-contract/src/proactive.js +13 -4
  88. package/dist/src/agent/coding/repository-instructions.js +1 -1
  89. package/dist/src/agent/coding/workspace-revision.js +1 -1
  90. package/dist/src/agent/commands/command-isolation.js +1 -1
  91. package/dist/src/agent/tools/factory.js +7 -3
  92. package/dist/src/agent/tools/review-workspace.js +1 -1
  93. package/dist/src/browser/providers/browser-ext-install.js +10 -2
  94. package/dist/src/cli/command-manifest.js +2 -2
  95. package/dist/src/cli/commands/agent.js +2 -2
  96. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  97. package/dist/src/cli/commands/gateway/lifecycle.js +2 -2
  98. package/dist/src/cli/commands/gateway/run-foreground.js +3 -0
  99. package/dist/src/cli/commands/import.js +54 -6
  100. package/dist/src/cli/commands/models.js +1 -1
  101. package/dist/src/cli/commands/onboard.js +1 -1
  102. package/dist/src/cli/commands/platform.js +1 -1
  103. package/dist/src/cli/commands/profile.js +1 -1
  104. package/dist/src/cli/commands/tunnel.js +1 -1
  105. package/dist/src/cli/commands/update.js +1 -1
  106. package/dist/src/cli/extension-cli-register.js +1 -1
  107. package/dist/src/config/index.js +1 -1
  108. package/dist/src/discussions/action-tasks.js +1 -1
  109. package/dist/src/discussions/edits.js +1 -1
  110. package/dist/src/discussions/index.js +1 -1
  111. package/dist/src/discussions/organizer.js +1 -1
  112. package/dist/src/discussions/recording.js +1 -1
  113. package/dist/src/discussions/sealer.js +1 -1
  114. package/dist/src/discussions/service.js +2 -2
  115. package/dist/src/endpoint-tools/invocation-service.d.ts +2 -0
  116. package/dist/src/endpoint-tools/invocation-service.js +48 -19
  117. package/dist/src/gateway/heartbeat/check-store.d.ts +18 -0
  118. package/dist/src/gateway/heartbeat/check-store.js +73 -0
  119. package/dist/src/gateway/heartbeat/service.d.ts +12 -3
  120. package/dist/src/gateway/heartbeat/service.js +62 -45
  121. package/dist/src/gateway/hono/routes/discussions.js +2 -2
  122. package/dist/src/gateway/hono/routes/imports.js +18 -6
  123. package/dist/src/gateway/hono/routes/proactive-control.js +2 -1
  124. package/dist/src/gateway/run-loop.js +1 -1
  125. package/dist/src/gateway/service.d.ts +7 -0
  126. package/dist/src/gateway/service.js +24 -9
  127. package/dist/src/heartbeat/index.js +1 -1
  128. package/dist/src/imports/importService.d.ts +17 -12
  129. package/dist/src/imports/importService.js +67 -70
  130. package/dist/src/imports/inventory.d.ts +11 -0
  131. package/dist/src/imports/inventory.js +202 -0
  132. package/dist/src/imports/productImport.d.ts +4 -4
  133. package/dist/src/imports/productImport.js +201 -108
  134. package/dist/src/imports/runtime.js +7 -2
  135. package/dist/src/imports/scanner.d.ts +1 -1
  136. package/dist/src/imports/scanner.js +4 -4
  137. package/dist/src/imports/types.d.ts +53 -0
  138. package/dist/src/infra/background-task.d.ts +2 -0
  139. package/dist/src/infra/background-task.js +25 -0
  140. package/dist/src/infra/process-diagnostics.d.ts +5 -0
  141. package/dist/src/infra/process-diagnostics.js +97 -0
  142. package/dist/src/infra/unhandled-rejections.js +6 -3
  143. package/dist/src/infra/update-restart.js +1 -1
  144. package/dist/src/knowledge/ingestion-service.js +1 -0
  145. package/dist/src/media-shared/http/ssrf-guard.js +1 -1
  146. package/dist/src/notifications/proactive-policy.js +7 -5
  147. package/dist/src/proactive/execution/authorization.d.ts +2 -0
  148. package/dist/src/proactive/execution/authorization.js +10 -1
  149. package/dist/src/proactive/execution/context.js +1 -0
  150. package/dist/src/proactive/execution/repository.d.ts +2 -0
  151. package/dist/src/proactive/execution/repository.js +19 -2
  152. package/dist/src/proactive/execution/worker.js +14 -4
  153. package/dist/src/proactive/experience.d.ts +4 -1
  154. package/dist/src/proactive/experience.js +3 -0
  155. package/dist/src/proactive/follow-ups.d.ts +5 -0
  156. package/dist/src/proactive/follow-ups.js +18 -7
  157. package/dist/src/proactive/inbox/cards.js +2 -1
  158. package/dist/src/proactive/inbox/delivery.js +6 -7
  159. package/dist/src/proactive/inbox/digest.d.ts +1 -1
  160. package/dist/src/proactive/inbox/digest.js +23 -13
  161. package/dist/src/proactive/inbox/notification-policy.d.ts +1 -1
  162. package/dist/src/proactive/inbox/notification-policy.js +9 -6
  163. package/dist/src/proactive/inbox/repository.js +3 -2
  164. package/dist/src/proactive/inbox/service.d.ts +6 -0
  165. package/dist/src/proactive/inbox/service.js +18 -0
  166. package/dist/src/proactive/inbox/types.d.ts +1 -0
  167. package/dist/src/proactive/policy/presence.d.ts +1 -1
  168. package/dist/src/proactive/policy/presence.js +7 -5
  169. package/dist/src/proactive/policy/service.d.ts +8 -5
  170. package/dist/src/proactive/policy/service.js +12 -12
  171. package/dist/src/proactive/scenarios/control.d.ts +3 -3
  172. package/dist/src/proactive/scenarios/control.js +12 -2
  173. package/dist/src/proactive/source-freshness.d.ts +8 -0
  174. package/dist/src/proactive/source-freshness.js +27 -0
  175. package/dist/src/proactive/status.d.ts +2 -0
  176. package/dist/src/proactive/status.js +21 -0
  177. package/dist/src/proactive/temporal/worker.js +2 -1
  178. package/dist/src/realtime/runtime.js +31 -5
  179. package/dist/src/realtime/writer.js +16 -9
  180. package/dist/src/storage/sqlite/import-repository.d.ts +2 -3
  181. package/dist/src/storage/sqlite/import-repository.js +3 -3
  182. package/dist/src/storage/sqlite/import-selection-repository.d.ts +15 -0
  183. package/dist/src/storage/sqlite/import-selection-repository.js +28 -0
  184. package/dist/src/storage/sqlite/knowledge-repository.d.ts +1 -0
  185. package/dist/src/storage/sqlite/knowledge-repository.js +2 -2
  186. package/dist/src/storage/sqlite/migrations/175_import_selections.sql +8 -0
  187. package/dist/src/storage/sqlite/migrations/176_proactive_quality.sql +5 -0
  188. package/dist/src/storage/sqlite/migrations/177_proactive_check_controls.sql +25 -0
  189. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  190. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  191. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  192. package/dist/src/storage/sqlite/schema.js +1 -1
  193. package/dist/src/work-discovery/candidate-discovery.js +1 -1
  194. package/dist/src/work-discovery/probe.js +1 -1
  195. package/package.json +2 -2
  196. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-D9qP10BK.js +0 -1
  197. package/dist/gateway/static/root/assets/agents-D-bkOuAl.js +0 -1
  198. package/dist/gateway/static/root/assets/apps-page-BKwBBwJN.js +0 -1
  199. package/dist/gateway/static/root/assets/automations-workspace-B2-f9qZu.js +0 -6
  200. package/dist/gateway/static/root/assets/browser-settings-page-Dtn4rMeq.js +0 -8
  201. package/dist/gateway/static/root/assets/capabilities-settings-panel-DiwtR9MD.js +0 -8
  202. package/dist/gateway/static/root/assets/channels-settings-pTdR1q1K.js +0 -1
  203. package/dist/gateway/static/root/assets/connectors-page-BSQ7Hs2w.js +0 -2
  204. package/dist/gateway/static/root/assets/device-pairing-wizard-CYkT7ecp.js +0 -1
  205. package/dist/gateway/static/root/assets/gateway-settings-CzpSYWex.js +0 -1
  206. package/dist/gateway/static/root/assets/home-page-CSSJvdd6.js +0 -1
  207. package/dist/gateway/static/root/assets/imports-page-XqVVYbAp.js +0 -1
  208. package/dist/gateway/static/root/assets/index-B_Sg5BKz.css +0 -2
  209. package/dist/gateway/static/root/assets/local-app-workbench-page-CZSgTYuI.js +0 -2
  210. package/dist/gateway/static/root/assets/logs-page-z5ktnEzX.js +0 -2
  211. package/dist/gateway/static/root/assets/note-detail-panel-DSaZfkna.js +0 -5
  212. package/dist/gateway/static/root/assets/notes-page-CePEyv_C.js +0 -8
  213. package/dist/gateway/static/root/assets/proactive-page-Cy2Gm2f8.js +0 -1
  214. package/dist/gateway/static/root/assets/project-detail-page-BliwYpns.js +0 -1
  215. package/dist/gateway/static/root/assets/projects-page-Dm-BqnQn.js +0 -1
  216. package/dist/gateway/static/root/assets/remote-access-hub-C_XuQ9XR.js +0 -1
  217. package/dist/gateway/static/root/assets/sessions-page-Drt1aS2G.js +0 -1
  218. package/dist/gateway/static/root/assets/settings-advanced-gate-BAUd06_9.js +0 -1
  219. package/dist/gateway/static/root/assets/setup-status-panel-BHI9e5Tw.js +0 -1
  220. package/dist/gateway/static/root/assets/shares-settings-DOAOjZBQ.js +0 -1
  221. package/dist/gateway/static/root/assets/skill-reload-api-DU0VQpHj.js +0 -1
  222. package/dist/gateway/static/root/assets/task-detail-page-DiPgMmBM.js +0 -1
  223. package/dist/gateway/static/root/assets/user-model-page-DxRaRdA0.js +0 -2
  224. package/dist/gateway/static/root/assets/workflows-page-CZikdgNw.js +0 -6
@@ -485,10 +485,18 @@ async function readInstalledExtensionDir(cacheDir) {
485
485
  return resolveInstalledExtensionPath(resolved, await readMeta(resolveMetaPath(resolved)));
486
486
  }
487
487
  function spawnDetached(command, args) {
488
- spawn(command, [...args], {
488
+ const child = spawn(command, [...args], {
489
489
  stdio: "ignore",
490
490
  detached: true
491
- }).unref();
491
+ });
492
+ child.on("error", (err) => {
493
+ log.error({
494
+ err,
495
+ command,
496
+ phase: "open_browser_install_ui"
497
+ }, `Unable to open browser setup: ${err.message}`);
498
+ });
499
+ child.unref();
492
500
  }
493
501
  function windowsExtensionManagerCandidates(env) {
494
502
  const programFiles = [
@@ -128,8 +128,8 @@ const ROOT_HELP_COMMANDS = [
128
128
  description: "Manage web-search providers (brave / tavily / bing / searxng)"
129
129
  },
130
130
  {
131
- name: "import [source]",
132
- description: "Import skills, context and projects from another AI app"
131
+ name: "import [options] [source]",
132
+ description: "Select skills, context and projects to import from another AI app"
133
133
  },
134
134
  {
135
135
  name: "skills",
@@ -8,10 +8,10 @@ import { MessageBus, MessageBusShutdownError } from "../../infra/bus/queue.js";
8
8
  import "../../infra/bus/index.js";
9
9
  import { AgentService } from "../../agent/service.js";
10
10
  import "../../agent/index.js";
11
- import { getWorkspacePath } from "../../config/workspace-path-helpers.js";
12
- import "../../config/index.js";
13
11
  import { formatExamples, register } from "../registry.js";
14
12
  import { getContextWithOpts } from "../context.js";
13
+ import { getWorkspacePath } from "../../config/workspace-path-helpers.js";
14
+ import "../../config/index.js";
15
15
  import { getXopcCloudCatalogCoordinator } from "../../providers/xopc-cloud-catalog-coordinator.js";
16
16
  import { listSessions } from "./agent/sessions.js";
17
17
  import { renderStreamToTerminal } from "./agent/stream-renderer.js";
@@ -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 v174).`,
55
+ message: `SQLite schema v${status.dbVersion} (current release v177).`,
56
56
  hints: []
57
57
  };
58
58
  }
@@ -1,10 +1,10 @@
1
1
  import { init_paths, resolveConfigPath } from "../../../config/paths.js";
2
2
  import { loadConfig } from "../../../config/loader.js";
3
- import { isRestartEnabled } from "../../../config/commands.flags.js";
4
3
  import "../../../config/index.js";
5
- import { resolveGatewayService } from "../../../daemon/service.js";
4
+ import { isRestartEnabled } from "../../../config/commands.flags.js";
6
5
  import { authorizeGatewaySigusr1Restart, writeGatewayRestartIntentSync } from "../../../infra/restart.js";
7
6
  import { findVerifiedGatewayListenerPidsOnPortSync, formatGatewayPidList, signalVerifiedGatewayPidSync } from "../../../infra/gateway-processes.js";
7
+ import { resolveGatewayService } from "../../../daemon/service.js";
8
8
  import { runServiceRestart, runServiceStop } from "./lifecycle-core.js";
9
9
  import { DEFAULT_RESTART_HEALTH_ATTEMPTS, renderGatewayPortHealthDiagnostics, waitForGatewayHealthyListener } from "./restart-health.js";
10
10
  import { parsePortFromArgs, renderGatewayServiceStartHints, resolveGatewayPortFromConfig } from "./shared.js";
@@ -1,3 +1,5 @@
1
+ import { installProcessDiagnostics } from "../../../infra/process-diagnostics.js";
2
+ import { dirname, join } from "node:path";
1
3
  //#region src/cli/commands/gateway/run-foreground.ts
2
4
  async function ensureGatewayReady(configPath, workspacePath, port) {
3
5
  const { initWorkspace } = await import("../../utils/init-workspace.js");
@@ -20,6 +22,7 @@ async function ensureGatewayReady(configPath, workspacePath, port) {
20
22
  }
21
23
  }
22
24
  async function runGatewayFromCliOptions(options, ctx) {
25
+ installProcessDiagnostics(process.env.XOPC_GATEWAY_DIAGNOSTIC_PATH ?? join(process.env.XOPC_LOG_DIR ?? join(dirname(ctx.configPath), "logs"), "gateway-process.log"));
23
26
  const tailscaleModes = new Set([
24
27
  "off",
25
28
  "serve",
@@ -1,19 +1,67 @@
1
1
  import { closeXopcDatabase, isXopcDatabaseOpen, openXopcDatabase } from "../../storage/sqlite/connection.js";
2
2
  import { register } from "../registry.js";
3
3
  import { isImportSource } from "../../imports/sources.js";
4
+ import { scanProduct } from "../../imports/inventory.js";
5
+ import { importSelection, listImportSources } from "../../imports/productImport.js";
4
6
  import { createRuntimeImportService, recoverCapabilityImports } from "../../imports/runtime.js";
5
- import { importProduct, listImportSources } from "../../imports/productImport.js";
7
+ import { randomUUID } from "node:crypto";
6
8
  import { Command } from "commander";
7
9
  //#region src/cli/commands/import.ts
8
10
  function createImportCommand() {
9
- return new Command("import").description("Import skills, context and projects from another AI app").argument("[source]", "codex or claude-code; omit to list detected apps").action(async (source) => {
10
- const selected = source && isImportSource(source) ? source : void 0;
11
- if (source && !selected) throw new Error("Unsupported import source");
11
+ return new Command("import").description("Select skills, context and projects to import from another AI app").argument("[source]", "codex or claude-code; omit to list detected apps").option("--inventory <id>", "Previously scanned inventory").option("--items <ids>", "Explicit comma-separated candidate IDs").option("--request-id <id>", "Unique request ID; reuse when retrying a network request").option("--retry-of <id>", "Retry failed items from this run").action(async (source, options) => {
12
+ const selectedSource = source && isImportSource(source) ? source : void 0;
13
+ if (source && !selectedSource) throw new Error("Unsupported import source");
14
+ if ((options.inventory || options.items || options.requestId || options.retryOf) && (!options.inventory || !options.items || !options.requestId)) throw new Error("--inventory, --items and --request-id must be provided together");
12
15
  const opened = !isXopcDatabaseOpen();
13
16
  if (opened) openXopcDatabase();
14
17
  try {
15
18
  await recoverCapabilityImports();
16
- console.log(JSON.stringify(selected ? await importProduct(createRuntimeImportService("gateway-owner"), selected) : listImportSources("gateway-owner"), null, 2));
19
+ const service = createRuntimeImportService("gateway-owner");
20
+ if (options.inventory) {
21
+ console.log(JSON.stringify(await importSelection(service, {
22
+ inventoryId: options.inventory,
23
+ candidateIds: options.items.split(",").map((s) => s.trim()),
24
+ requestId: options.requestId,
25
+ retryOf: options.retryOf
26
+ }), null, 2));
27
+ return;
28
+ }
29
+ if (!selectedSource) {
30
+ console.log(JSON.stringify(listImportSources("gateway-owner"), null, 2));
31
+ return;
32
+ }
33
+ const inventory = await scanProduct(service, selectedSource);
34
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
35
+ console.log(JSON.stringify(inventory, null, 2));
36
+ console.error("No content imported. Submit --inventory, --items and --request-id to import an explicit selection.");
37
+ return;
38
+ }
39
+ const { checkbox, confirm } = await import("@inquirer/prompts");
40
+ const ids = await checkbox({
41
+ message: "Select content to import (projects and rules are not selected by default)",
42
+ choices: inventory.candidates.map((item) => ({
43
+ name: `${item.kind}: ${item.name} — ${item.displayPath}${item.targetName && item.targetName !== item.name ? ` → ${item.targetName}` : ""}`,
44
+ value: item.id,
45
+ checked: item.scope === "user" && item.suggested,
46
+ disabled: item.status === "blocked" || item.status === "existing" && item.kind !== "project" ? item.reason ?? "Already available" : false
47
+ }))
48
+ });
49
+ const selected = new Set(ids);
50
+ for (const item of inventory.candidates) {
51
+ if (selected.has(item.id) && item.parentId) selected.add(item.parentId);
52
+ if (item.kind === "skill" && item.suggested && item.parentId && ids.includes(item.parentId)) selected.add(item.id);
53
+ }
54
+ if (!selected.size) return;
55
+ const summary = inventory.candidates.filter((i) => selected.has(i.id)).map((i) => `${i.kind}: ${i.name} — ${i.displayPath}`).join("\n");
56
+ if (!await confirm({
57
+ message: `Import these ${selected.size} items?\n${summary}`,
58
+ default: false
59
+ })) return;
60
+ console.log(JSON.stringify(await importSelection(service, {
61
+ inventoryId: inventory.id,
62
+ candidateIds: [...selected],
63
+ requestId: randomUUID()
64
+ }), null, 2));
17
65
  } finally {
18
66
  if (opened) closeXopcDatabase();
19
67
  }
@@ -22,7 +70,7 @@ function createImportCommand() {
22
70
  register({
23
71
  id: "import",
24
72
  name: "import",
25
- description: "Import from other AI apps",
73
+ description: "Select content from other AI apps",
26
74
  factory: createImportCommand,
27
75
  metadata: { category: "utility" }
28
76
  });
@@ -2,9 +2,9 @@ import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
2
2
  import { loadConfig, saveConfig } from "../../config/loader.js";
3
3
  import { CredentialResolver, init_credentials } from "../../auth/credentials.js";
4
4
  import { getAllModels, getAvailableModels, getConfiguredProviders, getProviderAuthState, getProviderDisplayName, init_providers, isProviderConfigured, providerSupportsApiKey, providerSupportsOAuth, resolveModel } from "../../providers/index.js";
5
- import "../../config/index.js";
6
5
  import { formatExamples, register } from "../registry.js";
7
6
  import { getContextWithOpts } from "../context.js";
7
+ import "../../config/index.js";
8
8
  import { prepareUpdateGlobalDefaults } from "../../gateway/global-defaults-admin.js";
9
9
  import { disconnectProvider } from "../../providers/provider-disconnect.js";
10
10
  import { colors } from "../utils/colors.js";
@@ -2,8 +2,8 @@ import { init_paths_state, resolveStateDir } from "../../config/paths-state.js";
2
2
  import { ConfigSchema, init_schema } from "../../config/schema.js";
3
3
  import { saveConfig } from "../../config/loader.js";
4
4
  import { resolveGatewayLocalClientHost } from "../../config/gateway-bind.js";
5
- import "../../config/index.js";
6
5
  import { formatExamples, register } from "../registry.js";
6
+ import "../../config/index.js";
7
7
  import { provisionEagerRuntimes } from "../../runtime-tools/bootstrap.js";
8
8
  import { colors } from "../utils/colors.js";
9
9
  import { initWorkspace } from "../utils/init-workspace.js";
@@ -1,6 +1,6 @@
1
1
  import { loadConfig, saveConfig } from "../../config/loader.js";
2
- import "../../config/index.js";
3
2
  import { formatExamples, register } from "../registry.js";
3
+ import "../../config/index.js";
4
4
  import { PLATFORM_RUNTIME_PROFILE, PLATFORM_RUNTIME_PROVIDER, PlatformRuntimeClient, discoverPlatform } from "../../platform/client.js";
5
5
  import "../../platform/index.js";
6
6
  import { getProfile, upsertAuthProfile } from "../../auth/profiles/profiles.js";
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { createProfile, deleteProfile, getCurrentProfile, getSwitchCommand, listProfiles, resolveProfileStateDir } from "../../config/profile.js";
4
3
  import { formatExamples, register } from "../registry.js";
4
+ import { createProfile, deleteProfile, getCurrentProfile, getSwitchCommand, listProfiles, resolveProfileStateDir } from "../../config/profile.js";
5
5
  import { colors } from "../utils/colors.js";
6
6
  import { Command } from "commander";
7
7
  import Table from "cli-table3";
@@ -7,8 +7,8 @@ import { ensureFrpcBinary } from "../../tunnel/frpc-binary.js";
7
7
  import { resolveTunnelBrokerUrl, resolveTunnelRegistrationSecret } from "../../tunnel/env.js";
8
8
  import { loadTunnelState } from "../../tunnel/tunnel-state.js";
9
9
  import { getTunnelService } from "../../tunnel/tunnel-service.js";
10
- import "../../config/index.js";
11
10
  import { formatExamples, register } from "../registry.js";
11
+ import "../../config/index.js";
12
12
  import { resolveGatewayAuth } from "../../gateway/auth.js";
13
13
  import { requireTunnelGatewayToken } from "../../tunnel/auth-policy.js";
14
14
  import { TUNNEL_RISK_SUMMARY_LINES, TunnelConsentError, assertTunnelMayStart, hasValidTunnelConsent } from "../../tunnel/consent.js";
@@ -1,7 +1,7 @@
1
1
  import { PACKAGE_VERSION, init_package_version } from "../../package-version.js";
2
2
  import { loadConfig } from "../../config/loader.js";
3
- import "../../config/index.js";
4
3
  import { formatExamples, register } from "../registry.js";
4
+ import "../../config/index.js";
5
5
  import { acquireUpdateLock } from "../../infra/update-lock.js";
6
6
  import { normalizeUpdateChannel } from "../../infra/update-channels.js";
7
7
  import { compareSemver, resolveNpmChannelTag } from "../../infra/update-check.js";
@@ -4,9 +4,9 @@ import { ExtensionLoader } from "../extensions/loader.js";
4
4
  import "../extensions/index.js";
5
5
  import { MessageBus } from "../infra/bus/queue.js";
6
6
  import "../infra/bus/index.js";
7
+ import { createDefaultContext } from "./registry.js";
7
8
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
8
9
  import "../config/index.js";
9
- import { createDefaultContext } from "./registry.js";
10
10
  import { registerExtensionCliProgram } from "../extensions/sdk/channel-helpers.js";
11
11
  import { join } from "path";
12
12
  //#region src/cli/extension-cli-register.ts
@@ -13,10 +13,10 @@ import { clearConfigValueCache, getAllowedCommands, getCacheStats, init_resolve_
13
13
  import { CustomModelSchema, ImageGenerationCapabilitiesSchema, ImageGenerationModelSchema, ImageGenerationProviderSchema, ModelOverrideSchema, ModelsJsonSchema, OpenAICompatSchema, OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema, OpenRouterRoutingSchema, ProviderConfigSchema, VercelGatewayRoutingSchema, getDefaultModelValues, init_models_json, loadModelsJson, modelsJsonExists, saveModelsJson, validateModelsConfig } from "./models-json.js";
14
14
  import { canonicalizeConfiguredMcpServer, isKnownCliMcpTypeAlias, normalizeConfiguredMcpServers, resolveXopcMcpTransportAlias } from "./mcp-config-normalize.js";
15
15
  import { formatThinkingLevels, listThinkingLevels, normalizeElevatedMode, normalizeReasoningLevel, normalizeThinkLevel, normalizeVerboseLevel, thinkLevelToNumber } from "../agent/transcript/thinking-types.js";
16
- import { diffConfigPaths } from "./diff.js";
17
16
  import { getWorkspacePath } from "./workspace-path-helpers.js";
18
17
  import { listAgentProfileMarkdownDirs, listAgentWorkspaceDirs } from "./workspace-dirs.js";
19
18
  import { ProfileManager, createProfile, deleteProfile, getCurrentProfile, getProfileManager, getProfileNameFromDir, getSwitchCommand, listProfiles, resolveProfileStateDir } from "./profile.js";
19
+ import { diffConfigPaths } from "./diff.js";
20
20
  import { BASE_RELOAD_RULES, buildReloadPlan, matchReloadRule } from "./rules.js";
21
21
  import { ConfigHotReloader } from "./reload.js";
22
22
  //#region src/config/index.ts
@@ -2,8 +2,8 @@ import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/
2
2
  import { TaskCreateRequestSchema } from "../../packages/gateway-contract/src/tasks.js";
3
3
  import { TaskRepository } from "../tasks/task-repository.js";
4
4
  import { TaskApplicationService } from "../tasks/task-application-service.js";
5
- import { DiscussionServiceError } from "./errors.js";
6
5
  import { getDiscussionCapture, getLatestDiscussionOrganization } from "./repository.js";
6
+ import { DiscussionServiceError } from "./errors.js";
7
7
  import { readTranscriptRevision } from "./revisions.js";
8
8
  //#region src/discussions/action-tasks.ts
9
9
  function meetingActionTasks(id) {
@@ -1,6 +1,6 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
2
- import { DiscussionServiceError } from "./errors.js";
3
2
  import { completeDiscussionOrganization, createDiscussionOrganization, getDiscussionCapture, getLatestDiscussionOrganization } from "./repository.js";
3
+ import { DiscussionServiceError } from "./errors.js";
4
4
  import { z } from "zod";
5
5
  const MeetingEditSchema = z.object({
6
6
  kind: z.enum([
@@ -1,7 +1,7 @@
1
1
  import { DISCUSSION_AUDIO_MAX_BYTES, DISCUSSION_MAX_DURATION_MS, DISCUSSION_STATUSES } from "../../packages/gateway-contract/src/discussions.js";
2
2
  import { DiscussionServiceError } from "./errors.js";
3
- import { analyzeDiscussion } from "./analyzer.js";
4
3
  import { DiscussionService } from "./service.js";
4
+ import { analyzeDiscussion } from "./analyzer.js";
5
5
  import { DiscussionOrganizer } from "./organizer.js";
6
6
  import { DiscussionLiveWorker } from "./live-worker.js";
7
7
  import { DiscussionOrganizerWorker } from "./organizer-worker.js";
@@ -1,9 +1,9 @@
1
1
  import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
2
2
  import { ObjectLinkService } from "../activity/service.js";
3
3
  import { completeDiscussionOrganization, createDiscussionOrganization, getDiscussionCapture, getLatestDiscussionOrganization, listDiscussionTranscriptSegments, renewDiscussionWorkLease, updateDiscussionCapture } from "./repository.js";
4
+ import { applyMeetingEdits } from "./edits.js";
4
5
  import { saveTranscriptRevision } from "./revisions.js";
5
6
  import { analyzeDiscussion } from "./analyzer.js";
6
- import { applyMeetingEdits } from "./edits.js";
7
7
  import { acceptRankedProject, findExactProjectMention } from "./project-inference.js";
8
8
  //#region src/discussions/organizer.ts
9
9
  const PROMPT_VERSION = "discussion-evidence-v2";
@@ -2,8 +2,8 @@ import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/
2
2
  import { DISCUSSION_MAX_DURATION_MS } from "../../packages/gateway-contract/src/discussions.js";
3
3
  import { decodeWavToMonoFloat32 } from "../voice/local/wav.js";
4
4
  import { forEachNormalizedAudioSegment } from "../voice/audio/normalize.js";
5
- import { DiscussionServiceError } from "./errors.js";
6
5
  import { getDiscussionCapture, updateDiscussionCapture } from "./repository.js";
6
+ import { DiscussionServiceError } from "./errors.js";
7
7
  import { resolveNoteMediaDir } from "../notes/paths.js";
8
8
  import { join } from "node:path";
9
9
  import { createReadStream } from "node:fs";
@@ -9,8 +9,8 @@ import "../voice/stt/index.js";
9
9
  import { getDiscussionCapture, listDiscussionCaptures, listDiscussionTranscriptSegments, updateDiscussionCapture } from "./repository.js";
10
10
  import { assembleDiscussionTranscript } from "./transcript.js";
11
11
  import { replaceTranscriptSegments, saveTranscriptRevision } from "./revisions.js";
12
- import { missingAudioRanges, slicePcmWav } from "./audio-repair.js";
13
12
  import { getRecordingJob } from "./recordingJobs.js";
13
+ import { missingAudioRanges, slicePcmWav } from "./audio-repair.js";
14
14
  import { createHash } from "node:crypto";
15
15
  //#region src/discussions/sealer.ts
16
16
  init_logger();
@@ -3,11 +3,11 @@ import { init_logger } from "../utils/logger.js";
3
3
  import { runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
4
4
  import { DISCUSSION_AUDIO_MAX_BYTES, DISCUSSION_MAX_DURATION_MS, DISCUSSION_SEGMENT_MAX_BYTES } from "../../packages/gateway-contract/src/discussions.js";
5
5
  import { ObjectLinkService } from "../activity/service.js";
6
- import { DiscussionServiceError } from "./errors.js";
7
6
  import { acknowledgeDiscussionCaptureConsent, correctDiscussionTranscriptSegment, createDiscussionCapture, createDiscussionTranscriptSegment, deleteDiscussionSegmentAudio, getDiscussionCapture, getDiscussionCaptureByClientRequestId, getDiscussionCaptureByNoteId, getDiscussionCaptureSettings, getDiscussionMetrics, getDiscussionTranscriptSegment, getLatestDiscussionOrganization, listDiscussionCaptures, listDiscussionTranscriptSegments, updateDiscussionCapture } from "./repository.js";
7
+ import { DiscussionServiceError } from "./errors.js";
8
+ import { editMeeting } from "./edits.js";
8
9
  import { assembleDiscussionTranscript } from "./transcript.js";
9
10
  import { readTranscriptRevision, refreshCanonicalTranscript, saveTranscriptRevision } from "./revisions.js";
10
- import { editMeeting } from "./edits.js";
11
11
  import { completeRecording, listRecordingChunks, removeRecordingChunks, saveRecordingChunk, validateRecordingManifest } from "./recording.js";
12
12
  import { cancelRecordingJob, claimRecordingJob, finishRecordingJob, getRecordingJob, getRecordingJobInput, renewRecordingJob, submitRecordingJob } from "./recordingJobs.js";
13
13
  import { createHash, randomUUID } from "node:crypto";
@@ -63,6 +63,8 @@ export declare class EndpointInvocationService {
63
63
  private cancel;
64
64
  private succeed;
65
65
  private fail;
66
+ private finishAudit;
67
+ private abortUploads;
66
68
  private take;
67
69
  private error;
68
70
  }
@@ -1,8 +1,12 @@
1
+ import { createLogger } from "../utils/logger/index.js";
2
+ import { init_logger } from "../utils/logger.js";
1
3
  import { ENDPOINT_INVOCATION_RECEIPT_TIMEOUT_MS, canonicalJson } from "../../packages/endpoint-tools-protocol/src/index.js";
2
4
  import { EndpointToolPolicy, EndpointToolPolicyError } from "./policy.js";
3
5
  import crypto from "node:crypto";
4
6
  import Ajv2020 from "ajv/dist/2020.js";
5
7
  //#region src/endpoint-tools/invocation-service.ts
8
+ init_logger();
9
+ const log = createLogger("EndpointInvocations");
6
10
  var EndpointToolExecutionError = class extends Error {
7
11
  constructor(code, message) {
8
12
  super(message);
@@ -55,7 +59,7 @@ var EndpointInvocationService = class {
55
59
  startedAt
56
60
  });
57
61
  } catch (error) {
58
- this.options.uploads?.abort(invocationId);
62
+ this.abortUploads(invocationId, params.endpointId, params.toolName);
59
63
  return Promise.reject(error);
60
64
  }
61
65
  return new Promise((resolve, reject) => {
@@ -155,30 +159,55 @@ var EndpointInvocationService = class {
155
159
  succeed(invocationId, result) {
156
160
  const pending = this.take(invocationId);
157
161
  if (!pending) return;
158
- try {
159
- this.options.audit?.finished({
160
- id: invocationId,
161
- status: "succeeded",
162
- completedAt: Date.now()
163
- });
164
- } finally {
165
- pending.resolve(result);
166
- }
162
+ this.finishAudit(pending, {
163
+ id: invocationId,
164
+ status: "succeeded",
165
+ completedAt: Date.now()
166
+ });
167
+ pending.resolve(result);
167
168
  }
168
169
  fail(invocationId, error) {
169
170
  const pending = this.take(invocationId);
170
171
  if (!pending) return;
172
+ this.abortUploads(invocationId, pending.endpointId, pending.toolName);
173
+ this.finishAudit(pending, {
174
+ id: invocationId,
175
+ status: "failed",
176
+ ...error instanceof EndpointToolExecutionError ? { errorCode: error.code } : {},
177
+ errorMessage: error.message,
178
+ completedAt: Date.now()
179
+ });
180
+ pending.reject(error);
181
+ }
182
+ finishAudit(pending, result) {
183
+ try {
184
+ this.options.audit?.finished(result);
185
+ } catch (err) {
186
+ const errorMessage = err instanceof Error ? err.message : String(err);
187
+ log.error({
188
+ err,
189
+ errorMessage,
190
+ invocationId: pending.id,
191
+ endpointId: pending.endpointId,
192
+ toolName: pending.toolName,
193
+ phase: "audit_finish",
194
+ status: result.status
195
+ }, `Endpoint invocation audit failed: ${errorMessage}`);
196
+ }
197
+ }
198
+ abortUploads(invocationId, endpointId, toolName) {
171
199
  try {
172
200
  this.options.uploads?.abort(invocationId);
173
- this.options.audit?.finished({
174
- id: invocationId,
175
- status: "failed",
176
- ...error instanceof EndpointToolExecutionError ? { errorCode: error.code } : {},
177
- errorMessage: error.message,
178
- completedAt: Date.now()
179
- });
180
- } finally {
181
- pending.reject(error);
201
+ } catch (err) {
202
+ const errorMessage = err instanceof Error ? err.message : String(err);
203
+ log.error({
204
+ err,
205
+ errorMessage,
206
+ invocationId,
207
+ endpointId,
208
+ toolName,
209
+ phase: "upload_abort"
210
+ }, `Endpoint upload cleanup failed: ${errorMessage}`);
182
211
  }
183
212
  }
184
213
  take(invocationId) {
@@ -0,0 +1,18 @@
1
+ import type { MessageBus } from '../../infra/bus/index.js';
2
+ export interface HeartbeatCheck {
3
+ id: string;
4
+ startedAt: string;
5
+ completedAt: string | null;
6
+ status: string;
7
+ detail: string | null;
8
+ content: string | null;
9
+ deliveryStatus: string;
10
+ target: string | null;
11
+ chatId: string | null;
12
+ }
13
+ export declare function beginHeartbeatCheck(workspace: string): string;
14
+ export declare function completeHeartbeatCheck(id: string, status: string, detail?: string, content?: string, target?: string, chatId?: string): void;
15
+ export declare function recentHeartbeatChecks(workspace: string): HeartbeatCheck[];
16
+ export declare function recoverHeartbeatChecks(workspace: string): void;
17
+ /** Claim before publishing: an ambiguous bus handoff is never blindly replayed. */
18
+ export declare function deliverHeartbeatChecks(workspace: string, bus: Pick<MessageBus, 'publishOutbound'>, target?: string, chatId?: string): Promise<void>;
@@ -0,0 +1,73 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "../../storage/sqlite/transaction.js";
2
+ import { proactiveChecksAllowed, proactivePreferences, quietHoursEnd } from "../../proactive/policy/service.js";
3
+ import { reserveWorkspaceAttention } from "../../proactive/inbox/digest.js";
4
+ import { createHash, randomUUID } from "node:crypto";
5
+ //#region src/gateway/heartbeat/check-store.ts
6
+ function beginHeartbeatCheck(workspace) {
7
+ const id = randomUUID();
8
+ const now = /* @__PURE__ */ new Date();
9
+ const db = getSqliteDatabase();
10
+ db.prepare("DELETE FROM heartbeat_checks WHERE workspace_id = ? AND started_at < ?").run(workspace, (/* @__PURE__ */ new Date(now.getTime() - 30 * 864e5)).toISOString());
11
+ db.prepare("INSERT INTO heartbeat_checks(id, workspace_id, started_at, status, expires_at) VALUES (?, ?, ?, ?, ?)").run(id, workspace, now.toISOString(), "running", new Date(now.getTime() + 864e5).toISOString());
12
+ return id;
13
+ }
14
+ function completeHeartbeatCheck(id, status, detail, content, target, chatId) {
15
+ runSqliteWriteTransaction((db) => {
16
+ const row = db.prepare("SELECT workspace_id FROM heartbeat_checks WHERE id = ?").get(id);
17
+ const fingerprint = content ? createHash("sha256").update(JSON.stringify([
18
+ target,
19
+ chatId,
20
+ content.trim()
21
+ ])).digest("hex") : null;
22
+ const delivery = fingerprint && db.prepare(`SELECT 1 FROM heartbeat_checks WHERE workspace_id = ? AND fingerprint = ?
23
+ AND delivery_status IN ('pending', 'sending', 'queued', 'unknown') AND expires_at > ? AND id <> ?`).get(row.workspace_id, fingerprint, (/* @__PURE__ */ new Date()).toISOString(), id) ? "duplicate" : status === "prepared" ? target && chatId ? "pending" : "no_target" : "none";
24
+ db.prepare(`UPDATE heartbeat_checks SET status = ?, detail = ?, content = ?, target = ?, chat_id = ?, fingerprint = ?,
25
+ delivery_status = ?, completed_at = ?, next_attempt_at = ? WHERE id = ? AND status = 'running'`).run(status, detail?.slice(0, 500) ?? null, content?.slice(0, 2e4) ?? null, target ?? null, chatId ?? null, fingerprint, delivery, (/* @__PURE__ */ new Date()).toISOString(), (/* @__PURE__ */ new Date()).toISOString(), id);
26
+ });
27
+ }
28
+ function recentHeartbeatChecks(workspace) {
29
+ return getSqliteDatabase().prepare(`SELECT id, started_at AS startedAt, completed_at AS completedAt, status, detail, content,
30
+ delivery_status AS deliveryStatus, target, chat_id AS chatId FROM heartbeat_checks WHERE workspace_id = ? ORDER BY started_at DESC, rowid DESC LIMIT 10`).all(workspace);
31
+ }
32
+ function recoverHeartbeatChecks(workspace) {
33
+ const db = getSqliteDatabase();
34
+ db.prepare("UPDATE heartbeat_checks SET delivery_status = 'unknown', detail = 'Delivery interrupted; verify before sending again' WHERE workspace_id = ? AND delivery_status = 'sending'").run(workspace);
35
+ db.prepare("UPDATE heartbeat_checks SET status = 'interrupted', completed_at = ? WHERE workspace_id = ? AND status = 'running'").run((/* @__PURE__ */ new Date()).toISOString(), workspace);
36
+ }
37
+ /** Claim before publishing: an ambiguous bus handoff is never blindly replayed. */
38
+ async function deliverHeartbeatChecks(workspace, bus, target, chatId) {
39
+ const claim = runSqliteWriteTransaction((db) => {
40
+ const now = /* @__PURE__ */ new Date();
41
+ db.prepare("UPDATE heartbeat_checks SET delivery_status = 'expired' WHERE workspace_id = ? AND delivery_status = 'pending' AND expires_at <= ?").run(workspace, now.toISOString());
42
+ const row = db.prepare("SELECT * FROM heartbeat_checks WHERE workspace_id = ? AND delivery_status = 'pending' AND next_attempt_at <= ? ORDER BY started_at LIMIT 1").get(workspace, now.toISOString());
43
+ if (!row) return null;
44
+ if (row.target !== target || row.chat_id !== chatId) {
45
+ db.prepare("UPDATE heartbeat_checks SET delivery_status = 'cancelled', detail = 'Delivery target changed' WHERE id = ?").run(row.id);
46
+ return null;
47
+ }
48
+ const preferences = proactivePreferences(workspace);
49
+ if (!proactiveChecksAllowed(preferences, now) || preferences.notificationsMuted || preferences.level === "quiet") return null;
50
+ const quietEnd = quietHoursEnd(preferences, now);
51
+ if (quietEnd) {
52
+ db.prepare("UPDATE heartbeat_checks SET next_attempt_at = ? WHERE id = ?").run(quietEnd.toISOString(), row.id);
53
+ return null;
54
+ }
55
+ if (!reserveWorkspaceAttention(workspace, `heartbeat:${row.id}`, now)) return null;
56
+ db.prepare("UPDATE heartbeat_checks SET delivery_status = 'sending' WHERE id = ? AND delivery_status = 'pending'").run(row.id);
57
+ return row;
58
+ });
59
+ if (!claim) return;
60
+ try {
61
+ await bus.publishOutbound({
62
+ channel: claim.target,
63
+ chat_id: claim.chat_id,
64
+ content: claim.content,
65
+ type: "message"
66
+ });
67
+ getSqliteDatabase().prepare("UPDATE heartbeat_checks SET delivery_status = 'queued' WHERE id = ? AND delivery_status = 'sending'").run(claim.id);
68
+ } catch {
69
+ getSqliteDatabase().prepare("UPDATE heartbeat_checks SET delivery_status = 'unknown', detail = 'Outbound handoff failed; verify before sending again' WHERE id = ?").run(claim.id);
70
+ }
71
+ }
72
+ //#endregion
73
+ export { beginHeartbeatCheck, completeHeartbeatCheck, deliverHeartbeatChecks, recentHeartbeatChecks, recoverHeartbeatChecks };
@@ -24,13 +24,16 @@ export interface HeartbeatServiceDeps {
24
24
  sessionStore: SessionStore;
25
25
  /** Current app config (for HEARTBEAT.md path under the default agent `profile/` directory). */
26
26
  getConfig: () => Config;
27
+ getWorkspace: () => string;
27
28
  }
28
29
  export declare class HeartbeatService {
29
30
  private deps;
30
31
  private intervalId;
31
32
  private wake;
32
- private lastHeartbeatText;
33
- private lastHeartbeatAt;
33
+ private nextCheckAt;
34
+ private deliveryTimer;
35
+ private delivering;
36
+ private recovered;
34
37
  private runnerConfig;
35
38
  constructor(deps: HeartbeatServiceDeps);
36
39
  start(config: HeartbeatRunnerConfig): void;
@@ -41,6 +44,12 @@ export declare class HeartbeatService {
41
44
  stop(): void;
42
45
  updateConfig(config: Config): void;
43
46
  isRunning(): boolean;
47
+ status(): {
48
+ enabled: boolean;
49
+ checksAllowed: boolean;
50
+ nextCheckAt: string;
51
+ recent: import("./check-store.js").HeartbeatCheck[];
52
+ };
53
+ private drainDeliveries;
44
54
  private runHeartbeatOnce;
45
- private isDuplicate;
46
55
  }