@xopcai/xopc 0.0.302 → 0.0.306

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 (364) hide show
  1. package/README.md +4 -4
  2. package/README.zh-CN.md +4 -4
  3. package/dist/browser-ext/dist/assets/{auth-B_9ZuGDx.js → auth-C3yV1y_l.js} +67 -22
  4. package/dist/browser-ext/dist/background.js +4 -4
  5. package/dist/browser-ext/dist/sidepanel.html +1 -1
  6. package/dist/browser-ext/dist/sidepanel.js +3 -3
  7. package/dist/browser-ext/manifest.json +1 -1
  8. package/dist/extensions/feishu/xopc.extension.json +0 -3
  9. package/dist/extensions/telegram/xopc.extension.json +1 -4
  10. package/dist/extensions/weixin/xopc.extension.json +0 -3
  11. package/dist/gateway/static/root/assets/{activity-store-DCi5rh4e.js → activity-store-DLtim-_I.js} +1 -1
  12. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-C0zP6W2B.js → agent-avatar-dicebear-iQXtiilH.js} +1 -1
  13. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CxOv4ivK.js +1 -0
  14. package/dist/gateway/static/root/assets/agents-DzKx7z3k.js +1 -0
  15. package/dist/gateway/static/root/assets/{api-CAV9PN9i.js → api-DfSU0-lD.js} +1 -1
  16. package/dist/gateway/static/root/assets/api-gpHh07OL.js +1 -0
  17. package/dist/gateway/static/root/assets/app-management-settings-panel-BpYFKz7B.js +1 -0
  18. package/dist/gateway/static/root/assets/{appearance-settings-ZFjV_opr.js → appearance-settings-BQfR5vrq.js} +1 -1
  19. package/dist/gateway/static/root/assets/apps-page-BceB7JHZ.js +1 -0
  20. package/dist/gateway/static/root/assets/{archive-plugin-MaKWrpgC.js → archive-plugin-BxOvZ-ZX.js} +1 -1
  21. package/dist/gateway/static/root/assets/{attachment-load-IfqbP2BN.js → attachment-load-B0FzTMAJ.js} +1 -1
  22. package/dist/gateway/static/root/assets/{automations-page-CeI2NGSO.js → automations-page-BpXuPaPg.js} +1 -1
  23. package/dist/gateway/static/root/assets/automations-workspace-Cn_p8zY_.js +6 -0
  24. package/dist/gateway/static/root/assets/{binary-plugins-jvQ6FaBZ.js → binary-plugins-BP7wfpqy.js} +1 -1
  25. package/dist/gateway/static/root/assets/{block-editor-D4ZIVQbk.css → block-editor-BdOTO0Yo.css} +1 -1
  26. package/dist/gateway/static/root/assets/{block-editor-B7U3qlB3.js → block-editor-oMLvdnOQ.js} +3 -3
  27. package/dist/gateway/static/root/assets/{browser-automation-inputs-BGT0xoTv.js → browser-automation-inputs-DTxSZ00u.js} +1 -1
  28. package/dist/gateway/static/root/assets/{browser-automations-page-DvLAwoiQ.js → browser-automations-page-IbJnwEY4.js} +2 -2
  29. package/dist/gateway/static/root/assets/browser-settings-page-CCUO3G23.js +3 -0
  30. package/dist/gateway/static/root/assets/button-CS04eWY9.js +1 -0
  31. package/dist/gateway/static/root/assets/capabilities-settings-panel-BjMb5H2_.js +8 -0
  32. package/dist/gateway/static/root/assets/channels-settings-P22-_i13.js +1 -0
  33. package/dist/gateway/static/root/assets/{channels-status-swr-C_icwbWj.js → channels-status-swr-D2AmAoty.js} +1 -1
  34. package/dist/gateway/static/root/assets/{chat-terminal-dock-BtL71IOs.js → chat-terminal-dock-B-yI3Mi1.js} +2 -2
  35. package/dist/gateway/static/root/assets/{computer-settings-page-Bu6ZJtmS.js → computer-settings-page-CWx_jnng.js} +1 -1
  36. package/dist/gateway/static/root/assets/connectors-page-BLgPORmH.js +2 -0
  37. package/dist/gateway/static/root/assets/cron-expression-DMRRL4Zg.js +2 -0
  38. package/dist/gateway/static/root/assets/date-picker-BSwL0e6E.js +1 -0
  39. package/dist/gateway/static/root/assets/{dependency-picker-BNugauiZ.js → dependency-picker-BQTspLzC.js} +1 -1
  40. package/dist/gateway/static/root/assets/{desktop-pet-DTy_3-OY.js → desktop-pet-C3lFxDF6.js} +1 -1
  41. package/dist/gateway/static/root/assets/desktop-pet-settings-Y8pjpXFE.js +1 -0
  42. package/dist/gateway/static/root/assets/device-pairing-wizard-DM4_GMzo.js +1 -0
  43. package/dist/gateway/static/root/assets/{extension-debug-page-C3F7RiGW.js → extension-debug-page-CVGiGVcR.js} +1 -1
  44. package/dist/gateway/static/root/assets/{extension-page-C0jhcCT_.js → extension-page-g3JtCP_y.js} +1 -1
  45. package/dist/gateway/static/root/assets/{extension-settings-page-CNvJQkrr.js → extension-settings-page-CjpoKV1f.js} +1 -1
  46. package/dist/gateway/static/root/assets/{gateway-config-swr-D5AM8cyQ.js → gateway-config-swr-BSvXXpKM.js} +1 -1
  47. package/dist/gateway/static/root/assets/gateway-realtime-BDCpS7U1.js +1 -0
  48. package/dist/gateway/static/root/assets/gateway-realtime-store-BGmP1obI.js +1 -0
  49. package/dist/gateway/static/root/assets/gateway-settings-CYG9WCZn.js +1 -0
  50. package/dist/gateway/static/root/assets/{gateway-startup-retry-CSJWdnFs.js → gateway-startup-retry-Caf8g3sC.js} +1 -1
  51. package/dist/gateway/static/root/assets/{heartbeat-settings-Cd1VJsHe.js → heartbeat-settings-Cl834-SS.js} +1 -1
  52. package/dist/gateway/static/root/assets/home-page-CB_XVtIM.js +1 -0
  53. package/dist/gateway/static/root/assets/{image-generation-api-BNh604hw.js → image-generation-api-BwEWBUVC.js} +1 -1
  54. package/dist/gateway/static/root/assets/imports-page-CoMlgSIA.js +1 -0
  55. package/dist/gateway/static/root/assets/index-CI37dTAn.css +1 -0
  56. package/dist/gateway/static/root/assets/index-Do9MltC4.js +79 -0
  57. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-CNq5D4pe.js +1 -0
  58. package/dist/gateway/static/root/assets/local-app-workbench-page-BxQlEje6.js +2 -0
  59. package/dist/gateway/static/root/assets/{local-apps-page-DyrFxW3G.js → local-apps-page-DQnRA598.js} +1 -1
  60. package/dist/gateway/static/root/assets/{locale-store-DLK05Y1a.js → locale-store-D16nmbaN.js} +1 -1
  61. package/dist/gateway/static/root/assets/logs-page-CT5GrcMs.js +2 -0
  62. package/dist/gateway/static/root/assets/management-settings-DKcO5fQ-.js +1 -0
  63. package/dist/gateway/static/root/assets/{markdown-view-B8maDRWh.js → markdown-view-DCp4BlZP.js} +2 -2
  64. package/dist/gateway/static/root/assets/{media-plugins-5DakFba_.js → media-plugins-Cy64sn_C.js} +1 -1
  65. package/dist/gateway/static/root/assets/messages-C-9oo69N.js +3 -0
  66. package/dist/gateway/static/root/assets/note-detail-panel-5dc3LKTL.js +5 -0
  67. package/dist/gateway/static/root/assets/notes-page-AbwxgXuG.js +8 -0
  68. package/dist/gateway/static/root/assets/{page-tabs-DzJpglJJ.js → page-tabs-CgEoHSVT.js} +1 -1
  69. package/dist/gateway/static/root/assets/{popover-select-DldSX8GX.js → popover-select-9i-ZtHXL.js} +1 -1
  70. package/dist/gateway/static/root/assets/{preview-open-alternatives-Dj6LJsuQ.js → preview-open-alternatives-Ck2uKTbf.js} +1 -1
  71. package/dist/gateway/static/root/assets/{proactive-page-CwudBdrQ.js → proactive-page-Dr1mCJhZ.js} +1 -1
  72. package/dist/gateway/static/root/assets/{product-open-page-CujZXOea.js → product-open-page-DbZvJ5GE.js} +1 -1
  73. package/dist/gateway/static/root/assets/project-detail-page-DnE1zI1c.js +1 -0
  74. package/dist/gateway/static/root/assets/projects-page-BD0nLYxk.js +1 -0
  75. package/dist/gateway/static/root/assets/{registry-api-BMFL4vis.js → registry-api-DcQdwpPu.js} +1 -1
  76. package/dist/gateway/static/root/assets/remote-access-hub-TYuE6A3S.js +1 -0
  77. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DV554qyN.js → runtime-tools-settings-panel-CPwdgWKo.js} +2 -2
  78. package/dist/gateway/static/root/assets/{schema-form-Bh2Er67B.js → schema-form-8psK4cFO.js} +1 -1
  79. package/dist/gateway/static/root/assets/sessions-page-BcWDQQFX.js +1 -0
  80. package/dist/gateway/static/root/assets/settings-advanced-gate-DzGQX6Hq.js +1 -0
  81. package/dist/gateway/static/root/assets/{settings-form-section-BsdM7P1d.js → settings-form-section-D_Gsz5rl.js} +1 -1
  82. package/dist/gateway/static/root/assets/{settings-page-3yEAqoME.js → settings-page-C_Tj_mkZ.js} +1 -1
  83. package/dist/gateway/static/root/assets/setup-status-panel-CE2X89qN.js +1 -0
  84. package/dist/gateway/static/root/assets/share-preview-page-B_M_oPsT.js +2 -0
  85. package/dist/gateway/static/root/assets/shares-settings-BL4H9Iym.js +1 -0
  86. package/dist/gateway/static/root/assets/skill-reload-api-WMKIgUOp.js +1 -0
  87. package/dist/gateway/static/root/assets/skills-page-DYgwzl5B.js +2 -0
  88. package/dist/gateway/static/root/assets/{skills-page.utils-dHBD7YqU.js → skills-page.utils-Cuh6s2HM.js} +1 -1
  89. package/dist/gateway/static/root/assets/{system-settings-panel-lItR5Kah.js → system-settings-panel-aassGyNb.js} +1 -1
  90. package/dist/gateway/static/root/assets/task-detail-page-BjeRslap.js +1 -0
  91. package/dist/gateway/static/root/assets/theme-store-RUBQBsFP.js +1 -0
  92. package/dist/gateway/static/root/assets/tunnel-api-DJYcPWIV.js +1 -0
  93. package/dist/gateway/static/root/assets/{use-autosave-DO50_g_S.js → use-autosave-QGYG7oMZ.js} +1 -1
  94. package/dist/gateway/static/root/assets/user-model-page-PrRsd4go.js +2 -0
  95. package/dist/gateway/static/root/assets/{voice-api-key-field-k7tWLXzM.js → voice-api-key-field-D1s0gIRW.js} +1 -1
  96. package/dist/gateway/static/root/assets/{voice-config-api-bZqN8-UF.js → voice-config-api-D2goEn5e.js} +1 -1
  97. package/dist/gateway/static/root/assets/{work-discovery-overlay-BHI6gO_u.js → work-discovery-overlay-DkFW9aJ6.js} +1 -1
  98. package/dist/gateway/static/root/assets/workflow-run-setup-panel-BYToUPUY.js +3 -0
  99. package/dist/gateway/static/root/assets/workflows-page-Z8iZe9YP.js +6 -0
  100. package/dist/gateway/static/root/index.html +14 -12
  101. package/dist/package.js +1 -1
  102. package/dist/packages/gateway-contract/src/device-pairing.js +100 -7
  103. package/dist/packages/gateway-contract/src/gateway-scopes.js +53 -0
  104. package/dist/packages/gateway-contract/src/index.js +2 -0
  105. package/dist/packages/realtime-client/src/index.js +14 -2
  106. package/dist/packages/realtime-protocol/src/index.js +18 -14
  107. package/dist/src/agent/agent-instance-gateway.d.ts +2 -0
  108. package/dist/src/agent/agent-manager.d.ts +2 -0
  109. package/dist/src/agent/agent-manager.js +40 -12
  110. package/dist/src/agent/agent-scope.d.ts +4 -1
  111. package/dist/src/agent/agent-scope.js +19 -3
  112. package/dist/src/agent/commands/command-isolation.js +11 -9
  113. package/dist/src/agent/commands/command-registry.js +18 -33
  114. package/dist/src/agent/context/audit.js +12 -2
  115. package/dist/src/agent/context/coordinator.d.ts +13 -3
  116. package/dist/src/agent/context/coordinator.js +27 -11
  117. package/dist/src/agent/context/execution-context.js +42 -22
  118. package/dist/src/agent/context/execution-context.types.d.ts +4 -2
  119. package/dist/src/agent/context/execution-scope.d.ts +2 -2
  120. package/dist/src/agent/context/execution-scope.js +1 -1
  121. package/dist/src/agent/context/project-context.d.ts +2 -2
  122. package/dist/src/agent/context/project-context.js +3 -3
  123. package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
  124. package/dist/src/agent/embedded/run-for-session.js +7 -1
  125. package/dist/src/agent/inbound/attachment-pipeline.d.ts +2 -0
  126. package/dist/src/agent/inbound/attachment-pipeline.js +3 -3
  127. package/dist/src/agent/inbound/inbound-loop.js +1 -0
  128. package/dist/src/agent/inbound/turn-dispatcher.js +3 -3
  129. package/dist/src/agent/mcp/mcp-stdio-transport.js +5 -2
  130. package/dist/src/agent/memory/compaction-promotion.js +7 -2
  131. package/dist/src/agent/memory/create-memory-manager.js +1 -0
  132. package/dist/src/agent/memory/manager.d.ts +6 -0
  133. package/dist/src/agent/memory/manager.js +74 -39
  134. package/dist/src/agent/memory/runtime.d.ts +3 -3
  135. package/dist/src/agent/memory/runtime.js +11 -4
  136. package/dist/src/agent/orchestration/agent-orchestrator.js +4 -1
  137. package/dist/src/agent/prompt/cache-boundary.d.ts +2 -0
  138. package/dist/src/agent/prompt/cache-boundary.js +10 -1
  139. package/dist/src/agent/service/build-direct-message-content.d.ts +1 -0
  140. package/dist/src/agent/service/build-direct-message-content.js +2 -1
  141. package/dist/src/agent/service/direct-turn-helpers.js +3 -2
  142. package/dist/src/agent/service/process-direct-streaming.d.ts +3 -1
  143. package/dist/src/agent/service/process-direct-streaming.js +3 -2
  144. package/dist/src/agent/service/webchat-tts.d.ts +0 -4
  145. package/dist/src/agent/service/webchat-tts.js +20 -19
  146. package/dist/src/agent/tools/factory.js +3 -3
  147. package/dist/src/agent/tools/knowledge-memory-tool.d.ts +2 -2
  148. package/dist/src/agent/tools/knowledge-memory-tool.js +7 -7
  149. package/dist/src/browser/native-messaging-host.js +2 -2
  150. package/dist/src/channels/attachments/voice-stt-webchat.d.ts +3 -0
  151. package/dist/src/channels/attachments/voice-stt-webchat.js +22 -9
  152. package/dist/src/cli/commands/agent.js +2 -0
  153. package/dist/src/cli/commands/config.js +8 -9
  154. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  155. package/dist/src/cli/commands/extension-marketplace.js +69 -44
  156. package/dist/src/cli/commands/extension-pack.js +0 -2
  157. package/dist/src/cli/commands/extension.js +4 -25
  158. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  159. package/dist/src/cli/commands/onboard/gateway.js +2 -1
  160. package/dist/src/cli/commands/update.js +1 -1
  161. package/dist/src/cli/utils/init-workspace-core.js +5 -2
  162. package/dist/src/config/index.js +2 -2
  163. package/dist/src/config/loader.d.ts +1 -0
  164. package/dist/src/config/loader.js +14 -1
  165. package/dist/src/config/schema.d.ts +10 -3
  166. package/dist/src/config/schema.js +10 -2
  167. package/dist/src/execution-environments/local-worktree-manager.js +17 -15
  168. package/dist/src/execution-environments/store.js +4 -2
  169. package/dist/src/execution-environments/types.d.ts +3 -0
  170. package/dist/src/execution-environments/types.js +2 -1
  171. package/dist/src/execution-environments/worktree-safety.d.ts +8 -0
  172. package/dist/src/execution-environments/worktree-safety.js +43 -0
  173. package/dist/src/extensions/activation-planner.d.ts +1 -1
  174. package/dist/src/extensions/activation-planner.js +1 -1
  175. package/dist/src/extensions/api-version.d.ts +4 -0
  176. package/dist/src/extensions/api-version.js +15 -0
  177. package/dist/src/extensions/api.d.ts +3 -9
  178. package/dist/src/extensions/api.js +26 -32
  179. package/dist/src/extensions/config-validation.d.ts +8 -0
  180. package/dist/src/extensions/config-validation.js +25 -0
  181. package/dist/src/extensions/extension-registry-impl.d.ts +20 -9
  182. package/dist/src/extensions/extension-registry-impl.js +79 -11
  183. package/dist/src/extensions/hooks.d.ts +1 -1
  184. package/dist/src/extensions/index.d.ts +2 -1
  185. package/dist/src/extensions/install-transaction.d.ts +2 -0
  186. package/dist/src/extensions/install-transaction.js +32 -21
  187. package/dist/src/extensions/install.js +18 -1
  188. package/dist/src/extensions/loader.d.ts +5 -5
  189. package/dist/src/extensions/loader.js +109 -47
  190. package/dist/src/extensions/lockfile.d.ts +3 -5
  191. package/dist/src/extensions/lockfile.js +41 -14
  192. package/dist/src/extensions/normalize-manifest.js +6 -60
  193. package/dist/src/extensions/sdk/index.d.ts +3 -2
  194. package/dist/src/extensions/sdk/index.js +2 -2
  195. package/dist/src/extensions/sdk/testing.js +0 -4
  196. package/dist/src/extensions/security.js +5 -7
  197. package/dist/src/extensions/types/core.d.ts +0 -5
  198. package/dist/src/extensions/types/index.d.ts +1 -1
  199. package/dist/src/extensions/types/manifest.d.ts +1 -25
  200. package/dist/src/extensions/types/providers.d.ts +1 -1
  201. package/dist/src/extensions/types/registration.d.ts +0 -12
  202. package/dist/src/extensions/update.js +71 -30
  203. package/dist/src/gateway/heartbeat/service.js +2 -2
  204. package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -1
  205. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +47 -10
  206. package/dist/src/gateway/hono/routes/devices.js +10 -7
  207. package/dist/src/gateway/hono/routes/endpoint-compatibility.js +6 -0
  208. package/dist/src/gateway/hono/routes/extension-gateway.js +0 -33
  209. package/dist/src/gateway/hono/routes/imports.js +1 -1
  210. package/dist/src/gateway/hono/routes/lazy-bundles.js +0 -1
  211. package/dist/src/gateway/hono/routes/local-apps.js +1 -1
  212. package/dist/src/gateway/hono/routes/realtime.js +30 -8
  213. package/dist/src/gateway/hono/routes/update.js +2 -2
  214. package/dist/src/gateway/hono/routes/user-model.js +25 -6
  215. package/dist/src/gateway/index.js +5 -2
  216. package/dist/src/gateway/lock.d.ts +2 -0
  217. package/dist/src/gateway/lock.js +31 -14
  218. package/dist/src/gateway/run-loop.js +3 -2
  219. package/dist/src/gateway/security/gateway-scopes.d.ts +2 -5
  220. package/dist/src/gateway/security/gateway-scopes.js +3 -45
  221. package/dist/src/gateway/security/index.js +2 -1
  222. package/dist/src/gateway/service/config-coordinator.js +1 -1
  223. package/dist/src/gateway/service.js +11 -7
  224. package/dist/src/heartbeat/index.js +1 -1
  225. package/dist/src/imports/importService.d.ts +1 -1
  226. package/dist/src/imports/inventory.js +16 -2
  227. package/dist/src/imports/productImport.js +5 -5
  228. package/dist/src/imports/types.d.ts +3 -3
  229. package/dist/src/infra/exec.d.ts +2 -2
  230. package/dist/src/infra/exec.js +32 -27
  231. package/dist/src/infra/gateway-processes.js +1 -1
  232. package/dist/src/infra/run-command.js +15 -50
  233. package/dist/src/infra/update-restart.js +1 -1
  234. package/dist/src/infra/update-runner.js +2 -2
  235. package/dist/src/infra/update-startup.js +1 -1
  236. package/dist/src/knowledge/connected-knowledge-pipeline.js +13 -3
  237. package/dist/src/knowledge-memory/domain.d.ts +17 -1
  238. package/dist/src/knowledge-memory/index.js +2 -2
  239. package/dist/src/knowledge-memory/repository.d.ts +26 -4
  240. package/dist/src/knowledge-memory/repository.js +171 -36
  241. package/dist/src/mcp/channel-bridge.js +7 -3
  242. package/dist/src/media-understanding/registry.js +6 -1
  243. package/dist/src/migrations/knowledge-memory-read-policy-config.d.ts +2 -0
  244. package/dist/src/migrations/knowledge-memory-read-policy-config.js +48 -0
  245. package/dist/src/migrations/runner.js +2 -1
  246. package/dist/src/process/bounded-output.d.ts +10 -0
  247. package/dist/src/process/bounded-output.js +41 -0
  248. package/dist/src/process/kill-tree.d.ts +6 -17
  249. package/dist/src/process/kill-tree.js +43 -75
  250. package/dist/src/process/process-spec.d.ts +39 -0
  251. package/dist/src/process/process-spec.js +13 -0
  252. package/dist/src/process/run-process.d.ts +4 -0
  253. package/dist/src/process/run-process.js +97 -0
  254. package/dist/src/providers/plugin-registry.d.ts +1 -1
  255. package/dist/src/providers/plugin-registry.js +6 -0
  256. package/dist/src/realtime/runtime.js +3 -1
  257. package/dist/src/session/store.js +1 -1
  258. package/dist/src/storage/sqlite/device-pairing-approval.js +1 -1
  259. package/dist/src/storage/sqlite/index.d.ts +1 -1
  260. package/dist/src/storage/sqlite/index.js +2 -2
  261. package/dist/src/storage/sqlite/migrations/180_execution_environment_ownership.sql +7 -0
  262. package/dist/src/storage/sqlite/migrations/181_knowledge_item_status_events.sql +12 -0
  263. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  264. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  265. package/dist/src/storage/sqlite/schema.js +1 -1
  266. package/dist/src/storage/sqlite/schema.sql +13 -0
  267. package/dist/src/storage/sqlite/transcript-repository.d.ts +4 -0
  268. package/dist/src/storage/sqlite/transcript-repository.js +36 -1
  269. package/dist/src/tui/backends/embedded-backend.d.ts +24 -8
  270. package/dist/src/tui/backends/embedded-backend.js +114 -10
  271. package/dist/src/tui/backends/gateway-realtime-backend.d.ts +18 -0
  272. package/dist/src/tui/backends/gateway-realtime-backend.js +32 -5
  273. package/dist/src/tui/components/assistant-message.d.ts +4 -1
  274. package/dist/src/tui/components/assistant-message.js +10 -2
  275. package/dist/src/tui/components/cell-render-mode.d.ts +4 -0
  276. package/dist/src/tui/components/cell-render-mode.js +1 -0
  277. package/dist/src/tui/components/chat-log.d.ts +17 -4
  278. package/dist/src/tui/components/chat-log.js +68 -50
  279. package/dist/src/tui/components/custom-editor.d.ts +2 -2
  280. package/dist/src/tui/components/custom-editor.js +5 -1
  281. package/dist/src/tui/components/pending-input-preview.d.ts +9 -0
  282. package/dist/src/tui/components/pending-input-preview.js +33 -0
  283. package/dist/src/tui/components/semantic-cell.d.ts +17 -0
  284. package/dist/src/tui/components/semantic-cell.js +29 -0
  285. package/dist/src/tui/components/tool-execution.d.ts +5 -1
  286. package/dist/src/tui/components/tool-execution.js +33 -10
  287. package/dist/src/tui/components/transcript-overlay.d.ts +29 -0
  288. package/dist/src/tui/components/transcript-overlay.js +114 -0
  289. package/dist/src/tui/components/tui-bottom-bar.js +3 -1
  290. package/dist/src/tui/components/user-message.d.ts +5 -1
  291. package/dist/src/tui/components/user-message.js +12 -1
  292. package/dist/src/tui/extension-host/load-extensions.d.ts +1 -1
  293. package/dist/src/tui/extension-host/runtime-context.js +2 -1
  294. package/dist/src/tui/extension-host/runtime.d.ts +1 -1
  295. package/dist/src/tui/format-tui-hotkeys.js +8 -1
  296. package/dist/src/tui/tui-agent-events.js +31 -0
  297. package/dist/src/tui/tui-backend.d.ts +23 -11
  298. package/dist/src/tui/tui-backend.js +1 -9
  299. package/dist/src/tui/tui-chat-input-state.d.ts +25 -0
  300. package/dist/src/tui/tui-chat-input-state.js +36 -0
  301. package/dist/src/tui/tui-command-formatters.js +2 -1
  302. package/dist/src/tui/tui-commands.js +1 -1
  303. package/dist/src/tui/tui-types.d.ts +2 -1
  304. package/dist/src/tui/tui-types.js +2 -1
  305. package/dist/src/tui/tui.js +122 -30
  306. package/dist/src/tui/xopc-tui-keybindings.d.ts +23 -3
  307. package/dist/src/tui/xopc-tui-keybindings.js +22 -2
  308. package/dist/src/user-context/access-policy.d.ts +2 -2
  309. package/dist/src/user-context/access-policy.js +10 -2
  310. package/dist/src/user-context/config.d.ts +23 -6
  311. package/dist/src/user-context/config.js +54 -7
  312. package/dist/src/voice/platform-streams.js +11 -1
  313. package/dist/src/voice/realtime/omniEngine.js +13 -1
  314. package/dist/src/voice/realtime/runtime.js +2 -1
  315. package/dist/src/voice/tts/audio.js +1 -1
  316. package/dist/src/voice/tts/speech-registry.js +6 -1
  317. package/package.json +9 -7
  318. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-D0ITeUFb.js +0 -1
  319. package/dist/gateway/static/root/assets/agents-DcfWhk2S.js +0 -1
  320. package/dist/gateway/static/root/assets/api-fPapljyb.js +0 -1
  321. package/dist/gateway/static/root/assets/app-management-settings-panel-U3yDRzKF.js +0 -1
  322. package/dist/gateway/static/root/assets/apps-page-FgMHY1Pr.js +0 -1
  323. package/dist/gateway/static/root/assets/automations-workspace-DxaiBwrD.js +0 -6
  324. package/dist/gateway/static/root/assets/browser-settings-page-CHrfg3BX.js +0 -3
  325. package/dist/gateway/static/root/assets/button-CGlRPNzi.js +0 -1
  326. package/dist/gateway/static/root/assets/capabilities-settings-panel-DpYDPk_o.js +0 -8
  327. package/dist/gateway/static/root/assets/channels-settings-DMq-NBUQ.js +0 -1
  328. package/dist/gateway/static/root/assets/connectors-page-LsEiI9L5.js +0 -2
  329. package/dist/gateway/static/root/assets/cron-expression-B25FHn4w.js +0 -2
  330. package/dist/gateway/static/root/assets/date-picker-CzVHO7z9.js +0 -1
  331. package/dist/gateway/static/root/assets/desktop-pet-settings-CXfnejTb.js +0 -1
  332. package/dist/gateway/static/root/assets/device-pairing-wizard-CxKwfncn.js +0 -1
  333. package/dist/gateway/static/root/assets/gateway-settings-CQTcIvlZ.js +0 -1
  334. package/dist/gateway/static/root/assets/home-page-B_uyfCGq.js +0 -1
  335. package/dist/gateway/static/root/assets/imports-page-DXNfRmk9.js +0 -1
  336. package/dist/gateway/static/root/assets/index-BAqVpc1H.css +0 -1
  337. package/dist/gateway/static/root/assets/index-hlU8MUEz.js +0 -79
  338. package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-CgW5_XVP.js +0 -1
  339. package/dist/gateway/static/root/assets/local-app-workbench-page-C4h3qDRL.js +0 -2
  340. package/dist/gateway/static/root/assets/logs-page-Goy_QHfL.js +0 -2
  341. package/dist/gateway/static/root/assets/management-settings-DgQyGEpR.js +0 -1
  342. package/dist/gateway/static/root/assets/messages-C9h8SImu.js +0 -3
  343. package/dist/gateway/static/root/assets/note-detail-panel-lcZby9NY.js +0 -5
  344. package/dist/gateway/static/root/assets/notes-page-CDGPPI-W.js +0 -8
  345. package/dist/gateway/static/root/assets/project-detail-page-CyAf_sK-.js +0 -1
  346. package/dist/gateway/static/root/assets/projects-page-BW5m_HhZ.js +0 -1
  347. package/dist/gateway/static/root/assets/remote-access-hub-B4JgwB0s.js +0 -1
  348. package/dist/gateway/static/root/assets/sessions-page-D5SmvlQ1.js +0 -1
  349. package/dist/gateway/static/root/assets/settings-advanced-gate-DDALROy_.js +0 -1
  350. package/dist/gateway/static/root/assets/setup-status-panel-BOHNZ-S3.js +0 -1
  351. package/dist/gateway/static/root/assets/share-preview-page-wV056nz2.js +0 -2
  352. package/dist/gateway/static/root/assets/shares-settings-io4NzfJL.js +0 -1
  353. package/dist/gateway/static/root/assets/skill-reload-api-CERFaxLj.js +0 -1
  354. package/dist/gateway/static/root/assets/skills-page-CtwUqvsE.js +0 -2
  355. package/dist/gateway/static/root/assets/task-detail-page-CCKc67a-.js +0 -1
  356. package/dist/gateway/static/root/assets/theme-store-KfFEGMlp.js +0 -1
  357. package/dist/gateway/static/root/assets/tunnel-api-DPyLgmWw.js +0 -1
  358. package/dist/gateway/static/root/assets/user-model-page-CcnGgH1n.js +0 -2
  359. package/dist/gateway/static/root/assets/workflow-run-setup-panel-jEMtNIG8.js +0 -3
  360. package/dist/gateway/static/root/assets/workflows-page-CX4bcAD-.js +0 -6
  361. package/dist/src/extensions/when-context.d.ts +0 -6
  362. package/dist/src/extensions/when-context.js +0 -26
  363. package/dist/src/extensions/when-expression.d.ts +0 -11
  364. package/dist/src/extensions/when-expression.js +0 -213
@@ -12,6 +12,13 @@ var ExtensionRegistryImpl = class {
12
12
  gatewayMethods = /* @__PURE__ */ new Map();
13
13
  tools = /* @__PURE__ */ new Map();
14
14
  toolExtensionIds = /* @__PURE__ */ new Map();
15
+ hookOwners = /* @__PURE__ */ new Map();
16
+ hookPriorities = /* @__PURE__ */ new Map();
17
+ channelOwners = /* @__PURE__ */ new Map();
18
+ httpRouteOwners = /* @__PURE__ */ new Map();
19
+ commandOwners = /* @__PURE__ */ new Map();
20
+ serviceOwners = /* @__PURE__ */ new Map();
21
+ gatewayMethodOwners = /* @__PURE__ */ new Map();
15
22
  channelPlugins = [];
16
23
  cliRegistrations = [];
17
24
  reloadRegistrations = [];
@@ -26,45 +33,106 @@ var ExtensionRegistryImpl = class {
26
33
  getEnabledExtensions() {
27
34
  return Array.from(this.extensions.values()).filter((p) => p.enabled);
28
35
  }
29
- addHook(event, handler, _extensionId, _priority = 0) {
36
+ addHook(event, handler, extensionId, priority = 0) {
30
37
  if (!this.hooks.has(event)) this.hooks.set(event, []);
31
- this.hooks.get(event).push(handler);
38
+ const owners = this.hookOwners.get(event) ?? /* @__PURE__ */ new Map();
39
+ const priorities = this.hookPriorities.get(event) ?? /* @__PURE__ */ new Map();
40
+ owners.set(handler, extensionId);
41
+ priorities.set(handler, priority);
42
+ this.hookOwners.set(event, owners);
43
+ this.hookPriorities.set(event, priorities);
44
+ const handlers = this.hooks.get(event);
45
+ handlers.push(handler);
46
+ handlers.sort((left, right) => (priorities.get(right) ?? 0) - (priorities.get(left) ?? 0));
47
+ }
48
+ removeHook(event, handler) {
49
+ const handlers = this.hooks.get(event);
50
+ if (!handlers) return;
51
+ const next = handlers.filter((candidate) => candidate !== handler);
52
+ if (next.length > 0) this.hooks.set(event, next);
53
+ else this.hooks.delete(event);
54
+ const owners = this.hookOwners.get(event);
55
+ const priorities = this.hookPriorities.get(event);
56
+ owners?.delete(handler);
57
+ priorities?.delete(handler);
58
+ if (owners?.size === 0) this.hookOwners.delete(event);
59
+ if (priorities?.size === 0) this.hookPriorities.delete(event);
32
60
  }
33
61
  getHooks(event) {
34
62
  return this.hooks.get(event) || [];
35
63
  }
36
- addChannelPlugin(plugin) {
64
+ addChannelPlugin(plugin, extensionId = "") {
37
65
  this.channelPlugins = this.channelPlugins.filter((p) => p.id !== plugin.id);
38
66
  this.channelPlugins.push(plugin);
67
+ this.channelOwners.set(plugin.id, extensionId);
39
68
  }
40
- addHttpRoute(path, handler) {
41
- if (this.httpRoutes.has(path)) log.warn({ path }, `HTTP route already registered, overwriting`);
42
- this.httpRoutes.set(path, handler);
69
+ addHttpRoute(path, handler, extensionId = "") {
70
+ const key = this.httpRouteKey(extensionId, path);
71
+ if (this.httpRoutes.has(key)) log.warn({
72
+ extensionId,
73
+ path
74
+ }, `HTTP route already registered, overwriting`);
75
+ this.httpRoutes.set(key, handler);
76
+ this.httpRouteOwners.set(key, extensionId);
43
77
  }
44
- getHttpRoute(path) {
45
- return this.httpRoutes.get(path);
78
+ getHttpRoute(extensionId, path) {
79
+ return this.httpRoutes.get(this.httpRouteKey(extensionId, path));
46
80
  }
47
- addCommand(command) {
81
+ addCommand(command, extensionId = "") {
48
82
  if (this.commands.has(command.name)) log.warn({ command: command.name }, `Command already registered, overwriting`);
49
83
  this.commands.set(command.name, command);
84
+ this.commandOwners.set(command.name, extensionId);
50
85
  }
51
86
  getCommand(name) {
52
87
  return this.commands.get(name);
53
88
  }
54
- addService(service) {
89
+ addService(service, extensionId = "") {
55
90
  if (this.services.has(service.id)) log.warn({ service: service.id }, `Service already registered, overwriting`);
56
91
  this.services.set(service.id, service);
92
+ this.serviceOwners.set(service.id, extensionId);
57
93
  }
58
94
  getService(id) {
59
95
  return this.services.get(id);
60
96
  }
61
- addGatewayMethod(method, handler) {
97
+ addGatewayMethod(method, handler, extensionId = "") {
62
98
  if (this.gatewayMethods.has(method)) log.warn({ method }, `Gateway method already registered, overwriting`);
63
99
  this.gatewayMethods.set(method, handler);
100
+ this.gatewayMethodOwners.set(method, extensionId);
64
101
  }
65
102
  getGatewayMethod(method) {
66
103
  return this.gatewayMethods.get(method);
67
104
  }
105
+ getServicesForExtension(extensionId) {
106
+ return [...this.services.entries()].filter(([id]) => this.serviceOwners.get(id) === extensionId).map(([, service]) => service);
107
+ }
108
+ removeExtensionContributions(extensionId) {
109
+ for (const [event, handlers] of this.hooks) for (const handler of [...handlers]) if (this.hookOwners.get(event)?.get(handler) === extensionId) this.removeHook(event, handler);
110
+ for (const [name, owner] of this.toolExtensionIds) if (owner === extensionId) this.removeTool(name);
111
+ this.channelPlugins = this.channelPlugins.filter((plugin) => {
112
+ const owned = this.channelOwners.get(plugin.id) === extensionId;
113
+ if (owned) this.channelOwners.delete(plugin.id);
114
+ return !owned;
115
+ });
116
+ this.removeOwnedEntries(this.httpRoutes, this.httpRouteOwners, extensionId);
117
+ this.removeOwnedEntries(this.commands, this.commandOwners, extensionId);
118
+ this.removeOwnedEntries(this.services, this.serviceOwners, extensionId);
119
+ this.removeOwnedEntries(this.gatewayMethods, this.gatewayMethodOwners, extensionId);
120
+ this.cliRegistrations = this.cliRegistrations.filter((entry) => entry.extensionId !== extensionId);
121
+ this.reloadRegistrations = this.reloadRegistrations.filter((entry) => entry.extensionId !== extensionId);
122
+ this.migrationRegistrations = this.migrationRegistrations.filter((entry) => entry.extensionId !== extensionId);
123
+ this.tuiRegistrations = this.tuiRegistrations.filter((entry) => entry.extensionId !== extensionId);
124
+ this.extensions.delete(extensionId);
125
+ }
126
+ removeOwnedEntries(values, owners, extensionId) {
127
+ for (const [key, owner] of owners) {
128
+ if (owner !== extensionId) continue;
129
+ owners.delete(key);
130
+ values.delete(key);
131
+ }
132
+ }
133
+ httpRouteKey(extensionId, path) {
134
+ return `${extensionId}:${path.startsWith("/") ? path : `/${path}`}`;
135
+ }
68
136
  addTool(tool, extensionId) {
69
137
  if (this.tools.has(tool.name)) log.warn({ tool: tool.name }, `Tool already registered, overwriting`);
70
138
  this.tools.set(tool.name, tool);
@@ -2,7 +2,7 @@
2
2
  * Extension Hook System
3
3
  */
4
4
  import type { ExtensionHookEvent, HookAgentContext as HookContext, AgentMessage, BeforeAgentStartContext } from './types/hooks.js';
5
- import { ExtensionRegistryImpl as ExtensionRegistry } from './loader.js';
5
+ import { ExtensionRegistryImpl as ExtensionRegistry } from './extension-registry-impl.js';
6
6
  export interface HookRunnerOptions {
7
7
  catchErrors?: boolean;
8
8
  logger?: HookLogger;
@@ -5,7 +5,8 @@
5
5
  */
6
6
  export * from './types/index.js';
7
7
  export { ExtensionApiImpl, createExtensionLogger, createPathResolver } from './api.js';
8
- export { ExtensionRegistryImpl, ExtensionLoader, normalizeExtensionConfig, resolveExtensionPath, areExtensionsGloballyDisabled } from './loader.js';
8
+ export { ExtensionRegistryImpl } from './extension-registry-impl.js';
9
+ export { ExtensionLoader, normalizeExtensionConfig, resolveExtensionPath, areExtensionsGloballyDisabled } from './loader.js';
9
10
  export type { ActivationPlanLoadOptions } from './loader.js';
10
11
  export type { ExtensionRegistry } from './types/core.js';
11
12
  export { ManifestRegistry, type ManifestRegistryEntry } from './manifest-registry.js';
@@ -8,6 +8,8 @@ export interface StagedExtensionInstall {
8
8
  }
9
9
  /** Extract, validate, install dependencies, and import-check an extension away from its live path. */
10
10
  export declare function stageExtensionStoreZip(buffer: Buffer, extensionsDir: string): Promise<StagedExtensionInstall>;
11
+ export declare function stageExtensionNpm(packageSpec: string, extensionsDir: string, timeoutMs?: number): Promise<StagedExtensionInstall>;
12
+ export declare function stageExtensionLocal(localPath: string, extensionsDir: string): Promise<StagedExtensionInstall>;
11
13
  /** Move a staged extension into its live path, preserving the previous version for rollback. */
12
14
  export declare function commitStagedExtensionInstall(state: StagedExtensionInstall, overwrite: boolean): void;
13
15
  /** Restore the previous live extension, or remove a newly committed install. */
@@ -1,36 +1,47 @@
1
- import { installExtensionFromStoreZip } from "./install.js";
1
+ import { installExtensionFromStoreZip, installFromLocal, installFromNpm } from "./install.js";
2
2
  import { join } from "node:path";
3
3
  import { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync } from "node:fs";
4
4
  import { pathToFileURL } from "node:url";
5
5
  //#region src/extensions/install-transaction.ts
6
- /** Extract, validate, install dependencies, and import-check an extension away from its live path. */
7
- async function stageExtensionStoreZip(buffer, extensionsDir) {
6
+ async function validateStagedInstall(result, stagingRoot, extensionsDir) {
7
+ if (!result.ok || !result.extensionId || !result.targetDir) throw new Error(result.error ?? "Extension staging failed");
8
+ const manifestPath = join(result.targetDir, "xopc.extension.json");
9
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
10
+ if (!manifest.main) throw new Error("Extension manifest must declare main");
11
+ const mainUrl = pathToFileURL(join(result.targetDir, manifest.main));
12
+ mainUrl.searchParams.set("xopcInstallCheck", `${Date.now()}-${Math.random()}`);
13
+ await import(mainUrl.href);
14
+ return {
15
+ extensionId: result.extensionId,
16
+ stagingRoot,
17
+ stagedExtensionDir: result.targetDir,
18
+ targetDir: join(extensionsDir, result.extensionId),
19
+ committed: false
20
+ };
21
+ }
22
+ async function stageExtensionInstall(extensionsDir, install) {
8
23
  mkdirSync(extensionsDir, { recursive: true });
9
24
  const stagingRoot = mkdtempSync(join(extensionsDir, ".xopc-install-"));
10
25
  try {
11
- const result = await installExtensionFromStoreZip(buffer, stagingRoot);
12
- if (!result.ok || !result.extensionId || !result.targetDir) throw new Error(result.error ?? "Extension staging failed");
13
- const manifestPath = join(result.targetDir, "xopc.extension.json");
14
- const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
15
- if (!manifest.main) throw new Error("Extension manifest must declare main");
16
- const mainUrl = pathToFileURL(join(result.targetDir, manifest.main));
17
- mainUrl.searchParams.set("xopcInstallCheck", `${Date.now()}-${Math.random()}`);
18
- await import(mainUrl.href);
19
- return {
20
- extensionId: result.extensionId,
21
- stagingRoot,
22
- stagedExtensionDir: result.targetDir,
23
- targetDir: join(extensionsDir, result.extensionId),
24
- committed: false
25
- };
26
- } catch (err) {
26
+ return await validateStagedInstall(await install(stagingRoot), stagingRoot, extensionsDir);
27
+ } catch (error) {
27
28
  rmSync(stagingRoot, {
28
29
  recursive: true,
29
30
  force: true
30
31
  });
31
- throw err;
32
+ throw error;
32
33
  }
33
34
  }
35
+ /** Extract, validate, install dependencies, and import-check an extension away from its live path. */
36
+ async function stageExtensionStoreZip(buffer, extensionsDir) {
37
+ return stageExtensionInstall(extensionsDir, (stagingRoot) => installExtensionFromStoreZip(buffer, stagingRoot));
38
+ }
39
+ async function stageExtensionNpm(packageSpec, extensionsDir, timeoutMs) {
40
+ return stageExtensionInstall(extensionsDir, (stagingRoot) => installFromNpm(packageSpec, stagingRoot, timeoutMs));
41
+ }
42
+ async function stageExtensionLocal(localPath, extensionsDir) {
43
+ return stageExtensionInstall(extensionsDir, (stagingRoot) => installFromLocal(localPath, stagingRoot));
44
+ }
34
45
  /** Move a staged extension into its live path, preserving the previous version for rollback. */
35
46
  function commitStagedExtensionInstall(state, overwrite) {
36
47
  if (existsSync(state.targetDir)) {
@@ -71,4 +82,4 @@ function finalizeStagedExtensionInstall(state) {
71
82
  state.backupDir = void 0;
72
83
  }
73
84
  //#endregion
74
- export { commitStagedExtensionInstall, finalizeStagedExtensionInstall, rollbackStagedExtensionInstall, stageExtensionStoreZip };
85
+ export { commitStagedExtensionInstall, finalizeStagedExtensionInstall, rollbackStagedExtensionInstall, stageExtensionLocal, stageExtensionNpm, stageExtensionStoreZip };
@@ -4,13 +4,14 @@ import { init_logger } from "../utils/logger.js";
4
4
  import { init_paths, resolveBundledExtensionsDir, resolveExtensionsDir as resolveExtensionsDir$1 } from "../config/paths.js";
5
5
  import { MAX_EXTENSION_STORE_ZIP_BYTES } from "./store-zip-limits.js";
6
6
  import { checkEngineCompatibility } from "./engine-check.js";
7
+ import { EXTENSION_API_VERSION, EXTENSION_UI_API_VERSION, checkExtensionApiCompatibility } from "./api-version.js";
7
8
  import { collectExtensionPackageDependencyIssues } from "./package-contract.js";
8
9
  import { execFileSync } from "node:child_process";
9
10
  import { dirname, isAbsolute, join, resolve, sep } from "path";
10
11
  import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs";
11
12
  import semver from "semver";
12
- import AdmZip from "adm-zip";
13
13
  import { tmpdir } from "os";
14
+ import AdmZip from "adm-zip";
14
15
  //#region src/extensions/install.ts
15
16
  /**
16
17
  * Extension Installation Module
@@ -140,6 +141,7 @@ function installExtensionProdDependencies(extensionDir) {
140
141
  "install",
141
142
  "--prod",
142
143
  "--no-frozen-lockfile",
144
+ "--package-import-method=copy",
143
145
  ...scriptArgs
144
146
  ]);
145
147
  if (pnpm.ok) return pnpm;
@@ -488,6 +490,21 @@ async function installFromDirectory(sourceDir, extensionsDir) {
488
490
  ok: false,
489
491
  error: engineCheck.reason ?? `xopc ${PACKAGE_VERSION} does not satisfy engines.xopc ${manifest.engines.xopc}`
490
492
  };
493
+ for (const [engineName, requiredRange, currentVersion] of [[
494
+ "extensionApi",
495
+ manifest.engines.extensionApi,
496
+ EXTENSION_API_VERSION
497
+ ], [
498
+ "extensionUiApi",
499
+ manifest.engines.extensionUiApi,
500
+ EXTENSION_UI_API_VERSION
501
+ ]]) {
502
+ const result = checkExtensionApiCompatibility(requiredRange, currentVersion, engineName);
503
+ if (result.parseWarning || !result.compatible) return {
504
+ ok: false,
505
+ error: result.reason ?? `Incompatible engines.${engineName}`
506
+ };
507
+ }
491
508
  if (!manifest.main) return {
492
509
  ok: false,
493
510
  error: "Extension manifest must declare main"
@@ -21,8 +21,8 @@ import { type SlotRegistry } from './slots.js';
21
21
  import { type ExtensionDiagnostics } from './diagnostics.js';
22
22
  export type { ExtensionLoaderOptions, ExtensionSourceOrigin } from './discover-extensions.js';
23
23
  export { areExtensionsGloballyDisabled } from './discover-extensions.js';
24
- export { ExtensionRegistryImpl } from './extension-registry-impl.js';
25
24
  import { ExtensionRegistryImpl } from './extension-registry-impl.js';
25
+ export { ExtensionRegistryImpl } from './extension-registry-impl.js';
26
26
  export interface ActivationPlanLoadOptions extends Partial<ActivationContext> {
27
27
  phase?: ActivationLoadPhase | 'all';
28
28
  }
@@ -30,6 +30,7 @@ export declare class ExtensionLoader {
30
30
  private registry;
31
31
  private options;
32
32
  private extensionInstances;
33
+ private startedServiceIds;
33
34
  private jiti;
34
35
  private _appConfig?;
35
36
  private _runtimeContext?;
@@ -118,6 +119,7 @@ export declare class ExtensionLoader {
118
119
  * Respects configured preferred plugin from config.extensions.slots
119
120
  */
120
121
  private claimExtensionSlots;
122
+ private releaseExtensionSlots;
121
123
  loadManifest(extensionPath: string): ExtensionManifest | null;
122
124
  private moduleEntryCandidates;
123
125
  private loadModule;
@@ -125,10 +127,8 @@ export declare class ExtensionLoader {
125
127
  private initializeExtension;
126
128
  startServices(): Promise<void>;
127
129
  stopServices(): Promise<void>;
128
- /**
129
- * Basic type validation for config values
130
- */
131
- private validateType;
130
+ unloadExtension(extensionId: string): Promise<boolean>;
131
+ shutdown(): Promise<void>;
132
132
  }
133
133
  export declare function resolveExtensionPath(id: string, _options: ExtensionLoaderOptions): string | null;
134
134
  export declare function normalizeExtensionConfig(rawConfig: Record<string, unknown>): ResolvedExtensionConfig[];
@@ -15,7 +15,9 @@ import { mergeActivationContext } from "./activation-context.js";
15
15
  import { checkEngineCompatibility } from "./engine-check.js";
16
16
  import { validateSpeechProviderContracts } from "./speech-provider-contracts.js";
17
17
  import { validateMediaUnderstandingProviderContracts } from "./media-provider-contracts.js";
18
- import { DEFAULT_SECURITY_CONFIG, checkExtensionPathSafety, isExtensionAllowed, logSecurityIssue, provenanceTracker } from "./security.js";
18
+ import { validateExtensionConfig } from "./config-validation.js";
19
+ import { EXTENSION_API_VERSION, EXTENSION_UI_API_VERSION, checkExtensionApiCompatibility } from "./api-version.js";
20
+ import { DEFAULT_SECURITY_CONFIG, checkExtensionDirSafety, checkExtensionPathSafety, isExtensionAllowed, logSecurityIssue, provenanceTracker } from "./security.js";
19
21
  import { getSlotRegistry } from "./slots.js";
20
22
  import { getExtensionCache, getExtensionDiagnostics } from "./diagnostics.js";
21
23
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -59,6 +61,7 @@ var ExtensionLoader = class {
59
61
  registry;
60
62
  options;
61
63
  extensionInstances = /* @__PURE__ */ new Map();
64
+ startedServiceIds = /* @__PURE__ */ new Set();
62
65
  jiti;
63
66
  _appConfig;
64
67
  _runtimeContext;
@@ -316,6 +319,20 @@ var ExtensionLoader = class {
316
319
  }, "Extension blocked because its path is unsafe");
317
320
  return null;
318
321
  }
322
+ if (this.securityConfig.checkPermissions) {
323
+ const directorySafety = checkExtensionDirSafety(extensionPath, extensionPath, source);
324
+ if (!directorySafety.safe) {
325
+ const firstIssue = directorySafety.issues[0];
326
+ if (firstIssue) logSecurityIssue(config.id, firstIssue);
327
+ const detail = firstIssue?.detail ?? "Unsafe file in extension directory";
328
+ this.diagnostics.error(config.id, detail);
329
+ log.error({
330
+ extensionId: config.id,
331
+ detail
332
+ }, "Extension directory safety check failed");
333
+ return null;
334
+ }
335
+ }
319
336
  if (source !== "bundled" && !isExtensionAllowed(config.id, this.securityConfig)) {
320
337
  this.diagnostics.error(config.id, "Extension is not present in extensions.security.allow");
321
338
  log.error({
@@ -377,42 +394,40 @@ var ExtensionLoader = class {
377
394
  this.diagnostics.error(config.id, engineResult.reason ?? "Incompatible xopc version (engines.xopc)");
378
395
  return null;
379
396
  }
380
- if (manifest.configSchema) try {
381
- const schema = manifest.configSchema;
382
- const extensionConfig = config.config;
383
- if (schema.type === "object" && schema.properties) {
384
- const props = schema.properties;
385
- const required = schema.required || [];
386
- for (const field of required) if (extensionConfig[field] === void 0) {
387
- log.error({
388
- extensionId: config.id,
389
- field
390
- }, "Extension config validation failed: missing required field");
391
- return null;
392
- }
393
- for (const [key, value] of Object.entries(extensionConfig)) {
394
- const propSchema = props[key];
395
- if (propSchema) {
396
- if (propSchema.type && !this.validateType(value, propSchema.type)) {
397
- log.error({
398
- extensionId: config.id,
399
- field: key,
400
- expected: propSchema.type,
401
- actual: typeof value
402
- }, "Extension config validation failed: type mismatch");
403
- return null;
404
- }
405
- }
406
- }
397
+ for (const [engineName, requiredRange, currentVersion] of [[
398
+ "extensionApi",
399
+ manifest.engines.extensionApi,
400
+ EXTENSION_API_VERSION
401
+ ], [
402
+ "extensionUiApi",
403
+ manifest.engines.extensionUiApi,
404
+ EXTENSION_UI_API_VERSION
405
+ ]]) {
406
+ const result = checkExtensionApiCompatibility(requiredRange, currentVersion, engineName);
407
+ if (result.parseWarning || !result.compatible) {
408
+ const reason = result.reason ?? `Incompatible engines.${engineName}`;
409
+ log.warn({
410
+ extensionId: config.id,
411
+ requiredRange,
412
+ currentVersion
413
+ }, reason);
414
+ this.diagnostics.error(config.id, reason);
415
+ return null;
416
+ }
417
+ }
418
+ if (manifest.configSchema) {
419
+ const result = validateExtensionConfig(manifest.configSchema, config.config ?? {});
420
+ if (result.valid === false) {
421
+ log.error({
422
+ extensionId: config.id,
423
+ validationErrors: result.errors
424
+ }, `Extension config validation failed: ${result.reason}`);
425
+ this.diagnostics.error(config.id, `Extension config validation failed: ${result.reason}`);
426
+ return null;
407
427
  }
408
428
  log.debug({ extensionId: config.id }, "Extension config validated");
409
- } catch (err) {
410
- log.warn({
411
- err,
412
- extensionId: config.id
413
- }, "Config schema validation skipped");
414
429
  }
415
- const extensionDir = dirname(extensionPath);
430
+ const extensionDir = extensionPath;
416
431
  const api = this.createExtensionApi(manifest, config, extensionDir);
417
432
  const module = await this.loadModule(extensionPath, manifest);
418
433
  if (!module) {
@@ -421,7 +436,14 @@ var ExtensionLoader = class {
421
436
  return null;
422
437
  }
423
438
  if (!this.claimExtensionSlots(config.id, manifest)) log.warn({ extensionId: config.id }, "Failed to claim required slots");
424
- await this.initializeExtension(module, api, manifest);
439
+ try {
440
+ await this.initializeExtension(module, api, manifest);
441
+ } catch (error) {
442
+ api._cleanup();
443
+ this.registry.removeExtensionContributions(config.id);
444
+ this.releaseExtensionSlots(config.id);
445
+ throw error;
446
+ }
425
447
  validateSpeechProviderContracts({
426
448
  extensionId: config.id,
427
449
  manifest,
@@ -490,6 +512,9 @@ var ExtensionLoader = class {
490
512
  if (!claimed) this.diagnostics.warn(extensionId, `Slot "${slotKey}" already claimed by another extension`);
491
513
  return claimed;
492
514
  }
515
+ releaseExtensionSlots(extensionId) {
516
+ for (const [key, claim] of this.slotRegistry.getAllClaims()) if (claim.pluginId === extensionId) this.slotRegistry.release(key, extensionId);
517
+ }
493
518
  loadManifest(extensionPath) {
494
519
  const manifestPath = join(extensionPath, EXTENSION_MANIFEST_FILE);
495
520
  if (existsSync(manifestPath)) try {
@@ -557,13 +582,16 @@ var ExtensionLoader = class {
557
582
  async initializeExtension(module, api, _manifest) {
558
583
  if (typeof module === "function") await module(api);
559
584
  else if (typeof module === "object" && module.register) await module.register(api);
585
+ if (typeof module === "object" && module.activate) await module.activate(api);
560
586
  }
561
587
  async startServices() {
562
588
  const services = Array.from(this.registry.services.values());
563
589
  for (const service of services) {
590
+ if (this.startedServiceIds.has(service.id)) continue;
564
591
  const serviceLog = createServiceLogger(service.id);
565
592
  try {
566
593
  await service.start?.();
594
+ this.startedServiceIds.add(service.id);
567
595
  serviceLog.info(`Started service`);
568
596
  } catch (error) {
569
597
  serviceLog.error({ err: error }, `Failed to start service`);
@@ -572,27 +600,61 @@ var ExtensionLoader = class {
572
600
  }
573
601
  async stopServices() {
574
602
  const services = Array.from(this.registry.services.values()).reverse();
575
- for (const service of services) if (service.stop) {
603
+ for (const service of services) {
604
+ if (!this.startedServiceIds.has(service.id)) continue;
576
605
  const serviceLog = createServiceLogger(service.id);
577
606
  try {
578
- await service.stop();
579
- serviceLog.info(`Stopped service`);
607
+ if (service.stop) {
608
+ await service.stop();
609
+ serviceLog.info(`Stopped service`);
610
+ }
580
611
  } catch (error) {
581
612
  serviceLog.error({ err: error }, `Failed to stop service`);
613
+ } finally {
614
+ this.startedServiceIds.delete(service.id);
582
615
  }
583
616
  }
584
617
  }
585
- /**
586
- * Basic type validation for config values
587
- */
588
- validateType(value, expectedType) {
589
- if (expectedType === "string") return typeof value === "string";
590
- if (expectedType === "number" || expectedType === "integer") return typeof value === "number";
591
- if (expectedType === "boolean") return typeof value === "boolean";
592
- if (expectedType === "array") return Array.isArray(value);
593
- if (expectedType === "object") return typeof value === "object" && value !== null && !Array.isArray(value);
618
+ async unloadExtension(extensionId) {
619
+ const api = this.extensionInstances.get(extensionId);
620
+ const record = this.registry.getExtension(extensionId);
621
+ if (!api || !record) return false;
622
+ for (const service of this.registry.getServicesForExtension(extensionId).reverse()) {
623
+ if (!this.startedServiceIds.has(service.id)) continue;
624
+ try {
625
+ await service.stop?.();
626
+ } catch (error) {
627
+ log.error({
628
+ err: error,
629
+ extensionId,
630
+ serviceId: service.id
631
+ }, "Extension service stop failed");
632
+ } finally {
633
+ this.startedServiceIds.delete(service.id);
634
+ }
635
+ }
636
+ const module = record.module;
637
+ try {
638
+ if (module && typeof module === "object" && module.deactivate) await module.deactivate(api);
639
+ } catch (error) {
640
+ log.error({
641
+ err: error,
642
+ extensionId
643
+ }, "Extension deactivation failed");
644
+ } finally {
645
+ api._cleanup();
646
+ this.registry.removeExtensionContributions(extensionId);
647
+ this.releaseExtensionSlots(extensionId);
648
+ this.extensionInstances.delete(extensionId);
649
+ this.cache.invalidate();
650
+ }
651
+ this.diagnostics.info(extensionId, "Unloaded extension");
594
652
  return true;
595
653
  }
654
+ async shutdown() {
655
+ await this.stopServices();
656
+ for (const extensionId of [...this.extensionInstances.keys()].reverse()) await this.unloadExtension(extensionId);
657
+ }
596
658
  };
597
659
  function resolveExtensionPath(id, _options) {
598
660
  const c = loadConfig();
@@ -1,3 +1,4 @@
1
+ export declare function computeExtensionDirectoryIntegrity(extensionDir: string): string | undefined;
1
2
  export type ExtensionSource = 'npm' | 'local' | 'git' | 'store';
2
3
  export interface ExtensionLockEntry {
3
4
  /** Extension ID */
@@ -37,7 +38,8 @@ export interface ExtensionsLockfile {
37
38
  }
38
39
  export declare class ExtensionLockfileManager {
39
40
  private readonly lockfilePath;
40
- constructor(lockfilePath?: string);
41
+ private readonly extensionsDir;
42
+ constructor(lockfilePath?: string, extensionsDir?: string);
41
43
  /**
42
44
  * Load the lockfile
43
45
  */
@@ -85,10 +87,6 @@ export declare class ExtensionLockfileManager {
85
87
  * Freeze current state (save with validation)
86
88
  */
87
89
  freeze(): Promise<ExtensionsLockfile>;
88
- /**
89
- * Generate integrity hash for a file
90
- */
91
- static generateIntegrity(filePath: string): Promise<string>;
92
90
  }
93
91
  export declare function getExtensionLockfileManager(lockfilePath?: string): ExtensionLockfileManager;
94
92
  export declare function resetExtensionLockfileManager(): void;