@abot-ai/runtime 1.6.0 → 1.7.0

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 (380) hide show
  1. package/README.md +2 -0
  2. package/dist/src/bridge/request-steering.js +60 -15
  3. package/dist/src/capabilities/normal-invocation/contracts.d.ts +3 -0
  4. package/dist/src/capabilities/normal-invocation/output-channels.d.ts +10 -0
  5. package/dist/src/capabilities/normal-invocation/output-channels.js +29 -0
  6. package/dist/src/capabilities/normal-invocation/validator.js +4 -2
  7. package/dist/src/capabilities/tool-types.d.ts +1 -1
  8. package/dist/src/cli/host-companion-bundle.mjs +7570 -6781
  9. package/dist/src/cli/host-companion-entry.js +5 -22
  10. package/dist/src/cli/host-companion-input.d.ts +3 -0
  11. package/dist/src/cli/host-companion-input.js +21 -0
  12. package/dist/src/cli/host-companion-lifecycle.d.ts +11 -0
  13. package/dist/src/cli/host-companion-lifecycle.js +32 -0
  14. package/dist/src/cli/host-companion-setup-target.d.ts +4 -0
  15. package/dist/src/cli/host-companion-setup-target.js +17 -0
  16. package/dist/src/cli/host-companion-startup.d.ts +2 -0
  17. package/dist/src/cli/host-companion-startup.js +7 -2
  18. package/dist/src/cli/host-companion.d.ts +6 -0
  19. package/dist/src/cli/host-companion.js +30 -27
  20. package/dist/src/cli/windows-companion-store-entry.d.ts +9 -0
  21. package/dist/src/cli/windows-companion-store-entry.js +67 -0
  22. package/dist/src/computer-access/command-output-capture.d.ts +37 -0
  23. package/dist/src/computer-access/command-output-capture.js +136 -0
  24. package/dist/src/computer-access/command-output-retention.d.ts +5 -0
  25. package/dist/src/computer-access/command-output-retention.js +90 -0
  26. package/dist/src/computer-access/command-output.d.ts +7 -0
  27. package/dist/src/computer-access/command-output.js +1 -0
  28. package/dist/src/computer-access/commands.d.ts +1 -0
  29. package/dist/src/computer-access/commands.js +1 -1
  30. package/dist/src/computer-access/companion/command-output-protocol.d.ts +12 -0
  31. package/dist/src/computer-access/companion/command-output-protocol.js +28 -0
  32. package/dist/src/computer-access/companion/command-output.d.ts +13 -0
  33. package/dist/src/computer-access/companion/command-output.js +110 -0
  34. package/dist/src/computer-access/companion/install-link-macos.d.ts +7 -0
  35. package/dist/src/computer-access/companion/install-link-macos.js +48 -0
  36. package/dist/src/computer-access/companion/install-link-registration.d.ts +4 -0
  37. package/dist/src/computer-access/companion/install-link-registration.js +184 -0
  38. package/dist/src/computer-access/companion/install-link-windows.d.ts +4 -0
  39. package/dist/src/computer-access/companion/install-link-windows.js +65 -0
  40. package/dist/src/computer-access/companion/install-link.d.ts +9 -0
  41. package/dist/src/computer-access/companion/install-link.js +54 -0
  42. package/dist/src/computer-access/companion/native-messages.js +3 -0
  43. package/dist/src/computer-access/companion/native-session.d.ts +1 -0
  44. package/dist/src/computer-access/companion/native-session.js +14 -2
  45. package/dist/src/computer-access/companion/native-supervisor.js +1 -0
  46. package/dist/src/computer-access/companion/notification-windows.d.ts +1 -1
  47. package/dist/src/computer-access/companion/notification-windows.js +8 -3
  48. package/dist/src/computer-access/companion/protocol.d.ts +1 -1
  49. package/dist/src/computer-access/companion/protocol.js +6 -0
  50. package/dist/src/computer-access/companion/release-version.d.ts +1 -1
  51. package/dist/src/computer-access/companion/release-version.js +1 -1
  52. package/dist/src/computer-access/companion/windows-store/connection-error.d.ts +7 -0
  53. package/dist/src/computer-access/companion/windows-store/connection-error.js +19 -0
  54. package/dist/src/computer-access/companion/windows-store/connection-link.d.ts +13 -0
  55. package/dist/src/computer-access/companion/windows-store/connection-link.js +109 -0
  56. package/dist/src/computer-access/companion/windows-store/identity.d.ts +13 -0
  57. package/dist/src/computer-access/companion/windows-store/identity.js +13 -0
  58. package/dist/src/computer-access/companion/windows-store/lifecycle.d.ts +5 -0
  59. package/dist/src/computer-access/companion/windows-store/lifecycle.js +90 -0
  60. package/dist/src/computer-access/contracts.d.ts +1 -1
  61. package/dist/src/computer-access/handlers.d.ts +2 -1
  62. package/dist/src/computer-access/handlers.js +5 -1
  63. package/dist/src/computer-access/process-capture.d.ts +6 -0
  64. package/dist/src/computer-access/process-capture.js +1 -0
  65. package/dist/src/computer-access/process-result.d.ts +2 -0
  66. package/dist/src/computer-access/process-result.js +14 -6
  67. package/dist/src/computer-access/process-runner.d.ts +2 -1
  68. package/dist/src/computer-access/process-runner.js +21 -13
  69. package/dist/src/model-gateway/server/configuration.d.ts +2 -0
  70. package/dist/src/model-gateway/server/configuration.js +73 -21
  71. package/dist/src/plugin-contract/install-source.d.ts +13 -0
  72. package/dist/src/plugin-contract/install-source.js +99 -0
  73. package/dist/src/plugin-contract/manifest.d.ts +2 -1
  74. package/dist/src/plugin-sdk/computer-access.d.ts +8 -0
  75. package/dist/src/plugin-sdk/computer-access.js +5 -0
  76. package/dist/src/runtime/adapters/in-memory-session-store.js +6 -16
  77. package/dist/src/runtime/admin/config-control.js +2 -1
  78. package/dist/src/runtime/automations/catalog.d.ts +3 -0
  79. package/dist/src/runtime/automations/catalog.js +1 -0
  80. package/dist/src/runtime/automations/model-dependency-projection.d.ts +2 -0
  81. package/dist/src/runtime/automations/service.d.ts +2 -0
  82. package/dist/src/runtime/capabilities/automation-builder/authoring-reference.d.ts +10 -5
  83. package/dist/src/runtime/capabilities/automation-builder/authoring-reference.js +8 -7
  84. package/dist/src/runtime/capabilities/automation-builder/payload-instructions.d.ts +2 -2
  85. package/dist/src/runtime/capabilities/automation-builder/payload-instructions.js +2 -2
  86. package/dist/src/runtime/capabilities/automation-builder/tool-contract.d.ts +2 -2
  87. package/dist/src/runtime/capabilities/automations/authoring-catalog.js +1 -1
  88. package/dist/src/runtime/capabilities/automations/authoring-preparation.d.ts +11 -5
  89. package/dist/src/runtime/capabilities/automations/tool-module.js +1 -1
  90. package/dist/src/runtime/capabilities/request-permission-catalog.d.ts +3 -1
  91. package/dist/src/runtime/capabilities/request-permission-catalog.js +21 -2
  92. package/dist/src/runtime/capabilities/request-permission-tool-registry.d.ts +2 -1
  93. package/dist/src/runtime/capabilities/request-permission-tool-registry.js +18 -10
  94. package/dist/src/runtime/capabilities/request-runtime-tool-registry.d.ts +2 -0
  95. package/dist/src/runtime/capabilities/request-runtime-tool-registry.js +1 -1
  96. package/dist/src/runtime/capabilities/scheduling/create-operations.d.ts +6 -0
  97. package/dist/src/runtime/config/builders.js +6 -5
  98. package/dist/src/runtime/config/effective-model-config-validation.js +4 -35
  99. package/dist/src/runtime/config/fields.js +15 -0
  100. package/dist/src/runtime/config/model-context-capacity.d.ts +20 -0
  101. package/dist/src/runtime/config/model-context-capacity.js +55 -0
  102. package/dist/src/runtime/config/model-execution-policy.d.ts +5 -1
  103. package/dist/src/runtime/config/model-execution-policy.js +16 -0
  104. package/dist/src/runtime/config/model-plugin-config.d.ts +8 -0
  105. package/dist/src/runtime/config/model-plugin-config.js +40 -0
  106. package/dist/src/runtime/config/schema.js +5 -1
  107. package/dist/src/runtime/config/validation/model-profile-validation.js +2 -0
  108. package/dist/src/runtime/config/validation/runtime-config-validation-contract.d.ts +3 -1
  109. package/dist/src/runtime/config/validation/runtime-config-validation-contract.js +3 -1
  110. package/dist/src/runtime/config/validation/runtime-root-section-validation.js +11 -4
  111. package/dist/src/runtime/config/validation/web-ui-config-validation.js +3 -2
  112. package/dist/src/runtime/config/web-ui.d.ts +5 -0
  113. package/dist/src/runtime/config/web-ui.js +5 -0
  114. package/dist/src/runtime/config.js +2 -0
  115. package/dist/src/runtime/local-application.d.ts +2 -0
  116. package/dist/src/runtime/local-host/app-owner.js +50 -6
  117. package/dist/src/runtime/local-host/app-request-control.d.ts +3 -1
  118. package/dist/src/runtime/local-host/app-request-control.js +91 -11
  119. package/dist/src/runtime/local-host/client-requests.js +32 -5
  120. package/dist/src/runtime/local-host/client-services.d.ts +2 -0
  121. package/dist/src/runtime/local-host/local-request-diagnostics.d.ts +9 -0
  122. package/dist/src/runtime/local-host/local-request-diagnostics.js +47 -0
  123. package/dist/src/runtime/local-host/saved-approvals.js +23 -2
  124. package/dist/src/runtime/model/model-selection.js +4 -1
  125. package/dist/src/runtime/observability/request-control-diagnostics.d.ts +6 -0
  126. package/dist/src/runtime/observability/request-control-diagnostics.js +52 -0
  127. package/dist/src/runtime/plugins/configuration-context.d.ts +9 -0
  128. package/dist/src/runtime/plugins/configuration-context.js +42 -0
  129. package/dist/src/runtime/plugins/configuration-settings.d.ts +2 -0
  130. package/dist/src/runtime/plugins/configuration-settings.js +26 -0
  131. package/dist/src/runtime/plugins/configuration-store.d.ts +23 -0
  132. package/dist/src/runtime/plugins/configuration-store.js +100 -0
  133. package/dist/src/runtime/plugins/configuration-write.d.ts +5 -0
  134. package/dist/src/runtime/plugins/configuration-write.js +58 -0
  135. package/dist/src/runtime/plugins/installation/archive.d.ts +2 -0
  136. package/dist/src/runtime/plugins/installation/archive.js +107 -0
  137. package/dist/src/runtime/plugins/installation/github-download.d.ts +9 -0
  138. package/dist/src/runtime/plugins/installation/github-download.js +72 -0
  139. package/dist/src/runtime/plugins/installation/installed-package.d.ts +9 -0
  140. package/dist/src/runtime/plugins/installation/installed-package.js +66 -0
  141. package/dist/src/runtime/plugins/installation/package.d.ts +45 -0
  142. package/dist/src/runtime/plugins/installation/package.js +79 -0
  143. package/dist/src/runtime/plugins/installation/portable-path.d.ts +2 -0
  144. package/dist/src/runtime/plugins/installation/portable-path.js +10 -0
  145. package/dist/src/runtime/plugins/installation/publication.d.ts +10 -0
  146. package/dist/src/runtime/plugins/installation/publication.js +17 -0
  147. package/dist/src/runtime/plugins/installation/service.d.ts +41 -0
  148. package/dist/src/runtime/plugins/installation/service.js +80 -0
  149. package/dist/src/runtime/plugins/loader.js +15 -29
  150. package/dist/src/runtime/plugins/manifest-projection.js +1 -0
  151. package/dist/src/runtime/plugins/manifest-validator.js +3 -0
  152. package/dist/src/runtime/plugins/module-cache.d.ts +2 -0
  153. package/dist/src/runtime/plugins/module-cache.js +19 -0
  154. package/dist/src/runtime/plugins/selection.d.ts +2 -0
  155. package/dist/src/runtime/plugins/selection.js +16 -11
  156. package/dist/src/runtime/ports.d.ts +6 -4
  157. package/dist/src/runtime/request/dependencies.d.ts +2 -1
  158. package/dist/src/runtime/request/execution-payload-compacted-evidence.d.ts +1 -1
  159. package/dist/src/runtime/request/handler.js +8 -0
  160. package/dist/src/runtime/request/prepared-execution.js +6 -1
  161. package/dist/src/runtime/request/request-steering.d.ts +4 -0
  162. package/dist/src/runtime/request/request-steering.js +37 -12
  163. package/dist/src/runtime/request/worker-capability-composition.d.ts +2 -0
  164. package/dist/src/runtime/request/worker-capability-composition.js +4 -1
  165. package/dist/src/runtime/scheduler/journal-index-state.d.ts +1 -1
  166. package/dist/src/sessions/assistant-initiative-message.d.ts +3 -0
  167. package/dist/src/sessions/assistant-initiative-message.js +12 -0
  168. package/dist/src/sessions/assistant-initiative.d.ts +2 -2
  169. package/dist/src/sessions/assistant-initiative.js +1 -7
  170. package/dist/src/sessions/durable-session-commit.d.ts +2 -1
  171. package/dist/src/sessions/durable-session-commit.js +6 -1
  172. package/dist/src/sessions/metadata/projection.d.ts +15 -0
  173. package/dist/src/sessions/metadata/projection.js +55 -0
  174. package/dist/src/sessions/metadata/publication.d.ts +12 -0
  175. package/dist/src/sessions/metadata/publication.js +78 -0
  176. package/dist/src/sessions/metadata/source-receipt.d.ts +5 -0
  177. package/dist/src/sessions/metadata/source-receipt.js +42 -0
  178. package/dist/src/sessions/metadata/store.d.ts +7 -0
  179. package/dist/src/sessions/metadata/store.js +119 -0
  180. package/dist/src/sessions/record/projection.d.ts +3 -1
  181. package/dist/src/sessions/record/projection.js +26 -18
  182. package/dist/src/sessions/request-lifecycle/service.js +3 -3
  183. package/dist/src/sessions/session-service.d.ts +2 -4
  184. package/dist/src/sessions/session-service.js +4 -16
  185. package/dist/src/sessions/session-store.d.ts +2 -1
  186. package/dist/src/sessions/session-store.js +9 -3
  187. package/dist/src/sessions/snapshot.d.ts +17 -0
  188. package/dist/src/sessions/snapshot.js +105 -0
  189. package/dist/src/sessions/types.d.ts +2 -0
  190. package/dist/src/shared/tool-selection.d.ts +2 -0
  191. package/dist/src/shared/tool-selection.js +7 -0
  192. package/dist/src/web-ui/app/ARCHITECTURE.md +14 -0
  193. package/dist/src/web-ui/app/app.js +6 -3
  194. package/dist/src/web-ui/app/components/config-workspace/config-model.js +2 -0
  195. package/dist/src/web-ui/app/components/config-workspace/model-plugin-permissions.js +130 -0
  196. package/dist/src/web-ui/app/components/config-workspace/model-plugin-selection.js +180 -0
  197. package/dist/src/web-ui/app/components/config-workspace/model-plugin-view-state.js +114 -0
  198. package/dist/src/web-ui/app/components/config-workspace/model-rendering.js +3 -0
  199. package/dist/src/web-ui/app/components/config-workspace/model-summary.js +39 -0
  200. package/dist/src/web-ui/app/components/config-workspace/summary-rendering.js +30 -0
  201. package/dist/src/web-ui/app/components/config-workspace/workspace-events.js +37 -0
  202. package/dist/src/web-ui/app/components/config-workspace/workspace-mutations.js +2 -0
  203. package/dist/src/web-ui/app/components/config-workspace/workspace-persistence.js +9 -1
  204. package/dist/src/web-ui/app/components/config-workspace/workspace-view.js +23 -67
  205. package/dist/src/web-ui/app/components/config-workspace.js +11 -2
  206. package/dist/src/web-ui/app/components/conversation-view.js +36 -5
  207. package/dist/src/web-ui/app/components/dashboard/recent-conversations.js +2 -1
  208. package/dist/src/web-ui/app/components/dashboard/workspace.js +2 -1
  209. package/dist/src/web-ui/app/components/operations-summary.js +105 -0
  210. package/dist/src/web-ui/app/components/passive-learning/home.js +1 -9
  211. package/dist/src/web-ui/app/components/plugins/configuration-draft.js +34 -0
  212. package/dist/src/web-ui/app/components/plugins/configuration-editor.js +147 -0
  213. package/dist/src/web-ui/app/components/plugins/configuration-fields.js +103 -0
  214. package/dist/src/web-ui/app/components/plugins/configuration-retained-secrets.js +20 -0
  215. package/dist/src/web-ui/app/components/plugins/configuration-settings.js +108 -0
  216. package/dist/src/web-ui/app/components/plugins/discovery-rendering.js +37 -0
  217. package/dist/src/web-ui/app/components/plugins/installation.js +212 -0
  218. package/dist/src/web-ui/app/components/plugins/manager.js +160 -6
  219. package/dist/src/web-ui/app/components/plugins/removal.js +130 -0
  220. package/dist/src/web-ui/app/components/plugins/rendering.js +14 -2
  221. package/dist/src/web-ui/app/components/plugins/summary.js +54 -0
  222. package/dist/src/web-ui/app/components/plugins/tabs.js +31 -0
  223. package/dist/src/web-ui/app/components/plugins/view-state.js +3 -1
  224. package/dist/src/web-ui/app/components/runtime-setup/connection-form.js +5 -2
  225. package/dist/src/web-ui/app/components/runtime-setup/connection-state.js +9 -1
  226. package/dist/src/web-ui/app/components/runtime-setup/context-window-feedback.js +71 -0
  227. package/dist/src/web-ui/app/components/runtime-setup/optional-steps.js +2 -0
  228. package/dist/src/web-ui/app/components/runtime-setup-guide.js +15 -3
  229. package/dist/src/web-ui/app/components/spark-chat/empty-state.js +1 -0
  230. package/dist/src/web-ui/app/components/spark-chat/panel.js +1 -0
  231. package/dist/src/web-ui/app/components/system-host/connection-card.js +35 -0
  232. package/dist/src/web-ui/app/components/system-host/macos-setup.js +1 -1
  233. package/dist/src/web-ui/app/components/system-host/manager.js +45 -12
  234. package/dist/src/web-ui/app/components/system-host/rendering.js +111 -106
  235. package/dist/src/web-ui/app/components/system-host/windows-store-setup.js +293 -0
  236. package/dist/src/web-ui/app/components/workspace-shell.js +6 -0
  237. package/dist/src/web-ui/app/computer-access-feature.js +22 -5
  238. package/dist/src/web-ui/app/configuration-feature.js +35 -2
  239. package/dist/src/web-ui/app/controllers/app-event-bindings.js +4 -1
  240. package/dist/src/web-ui/app/controllers/conversation-read-state-controller.d.ts +1 -0
  241. package/dist/src/web-ui/app/controllers/conversation-read-state-controller.js +7 -3
  242. package/dist/src/web-ui/app/controllers/conversation-request-hydration.js +88 -0
  243. package/dist/src/web-ui/app/controllers/conversation-session-controller.d.ts +9 -3
  244. package/dist/src/web-ui/app/controllers/conversation-session-controller.js +52 -144
  245. package/dist/src/web-ui/app/controllers/history-pagination.js +111 -0
  246. package/dist/src/web-ui/app/controllers/operations-controller.d.ts +12 -0
  247. package/dist/src/web-ui/app/controllers/operations-controller.js +28 -21
  248. package/dist/src/web-ui/app/controllers/runtime-onboarding-controller.d.ts +1 -0
  249. package/dist/src/web-ui/app/controllers/runtime-onboarding-controller.js +11 -0
  250. package/dist/src/web-ui/app/controllers/session-controller.js +10 -2
  251. package/dist/src/web-ui/app/controllers/session-list-pagination.js +71 -0
  252. package/dist/src/web-ui/app/controllers/session-sidebar-controller.js +6 -4
  253. package/dist/src/web-ui/app/controllers/spark-chat-reading.js +1 -0
  254. package/dist/src/web-ui/app/controllers/spark-chat-sync.js +24 -5
  255. package/dist/src/web-ui/app/controllers/workspace-route-controller.js +21 -19
  256. package/dist/src/web-ui/app/dashboard-feature.js +2 -2
  257. package/dist/src/web-ui/app/index.html +6 -2
  258. package/dist/src/web-ui/app/lib/history-page-messages.js +49 -0
  259. package/dist/src/web-ui/app/lib/request-lifecycle-view.js +8 -0
  260. package/dist/src/web-ui/app/lib/workspace-route.d.ts +3 -0
  261. package/dist/src/web-ui/app/lib/workspace-route.js +4 -0
  262. package/dist/src/web-ui/app/passive-learning-feature.js +0 -1
  263. package/dist/src/web-ui/app/runtime-onboarding-feature.js +3 -0
  264. package/dist/src/web-ui/app/schedules-feature.js +1 -1
  265. package/dist/src/web-ui/app/services/runtime-web-client/configuration.js +20 -0
  266. package/dist/src/web-ui/app/services/runtime-web-client/plugin-configuration.js +19 -0
  267. package/dist/src/web-ui/app/services/runtime-web-client/spark-chat.js +4 -4
  268. package/dist/src/web-ui/app/services/runtime-web-client/system-host.js +2 -0
  269. package/dist/src/web-ui/app/services/runtime-web-client.d.ts +6 -1
  270. package/dist/src/web-ui/app/services/runtime-web-client.js +12 -3
  271. package/dist/src/web-ui/app/spark-chat-feature.js +76 -19
  272. package/dist/src/web-ui/app/styles/11-product-links.css +30 -0
  273. package/dist/src/web-ui/app/styles/41-plugin-configuration.css +79 -0
  274. package/dist/src/web-ui/app/styles/41-plugin-discovery.css +132 -0
  275. package/dist/src/web-ui/app/styles/41-plugin-management.css +6 -0
  276. package/dist/src/web-ui/app/styles/42-model-plugin-permissions.css +173 -0
  277. package/dist/src/web-ui/app/styles/46-system-host.css +61 -107
  278. package/dist/src/web-ui/app/styles/47-config-controls.css +13 -1
  279. package/dist/src/web-ui/app/styles/54-spark-chat.css +33 -1
  280. package/dist/src/web-ui/app/styles.css +4 -0
  281. package/dist/src/web-ui/local-runtime/api-router.js +11 -6
  282. package/dist/src/web-ui/local-runtime/approval-request-attachment.js +14 -5
  283. package/dist/src/web-ui/local-runtime/configuration-activation-source.d.ts +1 -1
  284. package/dist/src/web-ui/local-runtime/configuration-activation-source.js +9 -3
  285. package/dist/src/web-ui/local-runtime/contracts.d.ts +4 -3
  286. package/dist/src/web-ui/local-runtime/environment-registry.d.ts +5 -1
  287. package/dist/src/web-ui/local-runtime/environment-registry.js +53 -11
  288. package/dist/src/web-ui/local-runtime/history-pagination.d.ts +16 -0
  289. package/dist/src/web-ui/local-runtime/history-pagination.js +20 -0
  290. package/dist/src/web-ui/local-runtime/plugin-configuration-routes.d.ts +16 -0
  291. package/dist/src/web-ui/local-runtime/plugin-configuration-routes.js +68 -0
  292. package/dist/src/web-ui/local-runtime/plugin-installation-routes.d.ts +16 -0
  293. package/dist/src/web-ui/local-runtime/plugin-installation-routes.js +96 -0
  294. package/dist/src/web-ui/local-runtime/plugin-management-routes.d.ts +8 -1
  295. package/dist/src/web-ui/local-runtime/plugin-management-routes.js +17 -0
  296. package/dist/src/web-ui/local-runtime/plugin-mutation-admission.d.ts +7 -0
  297. package/dist/src/web-ui/local-runtime/plugin-mutation-admission.js +17 -0
  298. package/dist/src/web-ui/local-runtime/plugin-removal-routes.d.ts +18 -0
  299. package/dist/src/web-ui/local-runtime/plugin-removal-routes.js +60 -0
  300. package/dist/src/web-ui/local-runtime/realtime-controller.js +41 -2
  301. package/dist/src/web-ui/local-runtime/request-cancellation-route.js +28 -1
  302. package/dist/src/web-ui/local-runtime/request-control-observation.d.ts +19 -0
  303. package/dist/src/web-ui/local-runtime/request-control-observation.js +80 -0
  304. package/dist/src/web-ui/local-runtime/request-execution.js +69 -37
  305. package/dist/src/web-ui/local-runtime/runtime-setup-context-window.d.ts +20 -0
  306. package/dist/src/web-ui/local-runtime/runtime-setup-context-window.js +44 -0
  307. package/dist/src/web-ui/local-runtime/runtime-setup-routes.js +2 -0
  308. package/dist/src/web-ui/local-runtime/runtime-setup-validation.js +9 -2
  309. package/dist/src/web-ui/local-runtime/session-routes.d.ts +1 -0
  310. package/dist/src/web-ui/local-runtime/session-routes.js +16 -4
  311. package/dist/src/web-ui/local-runtime/spark-chat-routes.js +4 -3
  312. package/dist/src/web-ui/plugin-capability-selection.js +4 -1
  313. package/dist/src/web-ui/plugin-configuration-input.d.ts +12 -0
  314. package/dist/src/web-ui/plugin-configuration-input.js +68 -0
  315. package/dist/src/web-ui/plugin-configuration-retained-secrets.d.ts +9 -0
  316. package/dist/src/web-ui/plugin-configuration-retained-secrets.js +48 -0
  317. package/dist/src/web-ui/plugin-configuration-service.d.ts +52 -0
  318. package/dist/src/web-ui/plugin-configuration-service.js +66 -0
  319. package/dist/src/web-ui/plugin-configuration-view.d.ts +25 -0
  320. package/dist/src/web-ui/plugin-configuration-view.js +45 -0
  321. package/dist/src/web-ui/plugin-disabled-selection.d.ts +7 -0
  322. package/dist/src/web-ui/plugin-disabled-selection.js +17 -0
  323. package/dist/src/web-ui/plugin-management-catalog.d.ts +3 -1
  324. package/dist/src/web-ui/plugin-management-catalog.js +11 -1
  325. package/dist/src/web-ui/plugin-management-selection.js +22 -9
  326. package/dist/src/web-ui/plugin-management-service.d.ts +5 -1
  327. package/dist/src/web-ui/plugin-management-service.js +11 -7
  328. package/dist/src/web-ui/plugin-removal-error.d.ts +7 -0
  329. package/dist/src/web-ui/plugin-removal-error.js +16 -0
  330. package/dist/src/web-ui/plugin-removal-service.d.ts +30 -0
  331. package/dist/src/web-ui/plugin-removal-service.js +109 -0
  332. package/dist/src/web-ui/runtime-setup-gateway.d.ts +6 -2
  333. package/dist/src/web-ui/runtime-setup-gateway.js +30 -10
  334. package/dist/src/web-ui/server.js +6 -2
  335. package/dist/src/web-ui/session-read-state/overview.d.ts +42 -0
  336. package/dist/src/web-ui/session-read-state/overview.js +16 -0
  337. package/dist/src/web-ui/session-read-state/pagination.d.ts +15 -0
  338. package/dist/src/web-ui/session-read-state/pagination.js +42 -0
  339. package/dist/src/web-ui/session-read-state/projection.d.ts +4 -3
  340. package/dist/src/web-ui/session-read-state/service.d.ts +213 -20
  341. package/dist/src/web-ui/session-read-state/service.js +25 -23
  342. package/dist/src/web-ui/session-read-state/visible-messages.d.ts +3 -3
  343. package/dist/src/web-ui/system-host-setup/companion-linux.js +1 -1
  344. package/dist/src/web-ui/system-host-setup/installer-contract.d.ts +1 -1
  345. package/dist/src/web-ui/system-host-setup/installer-contract.js +2 -2
  346. package/dist/src/web-ui/system-host-setup/installers.js +0 -7
  347. package/dist/src/web-ui/system-host-setup/local-connection.d.ts +4 -1
  348. package/dist/src/web-ui/system-host-setup/local-connection.js +10 -17
  349. package/dist/src/web-ui/system-host-setup/routes.d.ts +2 -0
  350. package/dist/src/web-ui/system-host-setup/routes.js +32 -9
  351. package/dist/src/web-ui/system-host-setup/setup-mutation.d.ts +9 -0
  352. package/dist/src/web-ui/system-host-setup/setup-mutation.js +27 -0
  353. package/dist/src/web-ui/system-host-setup/windows-store-route.d.ts +13 -0
  354. package/dist/src/web-ui/system-host-setup/windows-store-route.js +68 -0
  355. package/docs/configuration.md +46 -0
  356. package/docs/installation.md +45 -24
  357. package/docs/plugins.md +165 -2
  358. package/docs/projects-and-full-plus.md +2 -6
  359. package/docs/runtime-library.md +0 -1
  360. package/docs/windows-companion-store.md +127 -0
  361. package/package.json +3 -3
  362. package/plugins/document-reader/plugin.json +1 -0
  363. package/plugins/exec/plugin.json +3 -0
  364. package/plugins/filesystem/plugin.json +2 -0
  365. package/plugins/local-search/plugin.json +1 -0
  366. package/plugins/system/README.md +43 -3
  367. package/plugins/system/plugin.json +5 -0
  368. package/plugins/system/source/companion-command-output.ts +82 -0
  369. package/plugins/system/source/host-dispatch.ts +4 -0
  370. package/plugins/system/source/index.ts +11 -5
  371. package/plugins/system/source/local-command-output.ts +61 -0
  372. package/plugins/system/source/request-system-modules.ts +2 -0
  373. package/plugins/system/src/index.cjs +474 -39
  374. package/plugins/web/README.md +2 -2
  375. package/plugins/web/plugin.json +4 -0
  376. package/runtime.config.schema.json +25 -1
  377. package/src/runtime/README.md +12 -2
  378. package/dist/src/web-ui/system-host-setup/companion-windows.d.ts +0 -2
  379. package/dist/src/web-ui/system-host-setup/companion-windows.js +0 -108
  380. package/docs/publishing.md +0 -167
@@ -0,0 +1,130 @@
1
+ function isDefinitiveRemovalRejection(error) {
2
+ if (!(error.status >= 400 && error.status < 500)) return false;
3
+ return [
4
+ "plugin_not_removable",
5
+ "plugin_not_found",
6
+ "invalid_plugin_configuration",
7
+ "plugin_selection_conflict",
8
+ "plugin_mutation_unavailable",
9
+ "invalid_plugin_removal",
10
+ "runtime_setup_required",
11
+ "plugin_removal_unavailable",
12
+ "request_origin_required",
13
+ "method_not_allowed",
14
+ "configuration_request_rejected",
15
+ "plugin_runtime_busy",
16
+ "plugin_owner_unavailable",
17
+ ].includes(error.code);
18
+ }
19
+
20
+ /** Removal is an explicit local action; busy owners keep their files until a retry. */
21
+ export function createPluginRemoval({
22
+ removePlugin,
23
+ getEnvironmentId,
24
+ beginRuntimeMutation,
25
+ endRuntimeMutation,
26
+ refreshRuntimeConfig,
27
+ onConfigurationSaved,
28
+ onConfigurationApplied,
29
+ onConfigurationSettled = () => true,
30
+ onSnapshot,
31
+ render,
32
+ confirmRemoval = (message) => window.confirm(message),
33
+ }) {
34
+ const state = { busy: false, message: "", error: "" };
35
+ let environment = getEnvironmentId();
36
+ let generation = 0;
37
+ function resetEnvironment() {
38
+ if (environment === getEnvironmentId()) return;
39
+ environment = getEnvironmentId();
40
+ generation += 1;
41
+ Object.assign(state, { busy: false, message: "", error: "" });
42
+ }
43
+ async function remove(pluginId) {
44
+ resetEnvironment();
45
+ if (state.busy || !removePlugin) return false;
46
+ if (
47
+ !confirmRemoval(
48
+ `Remove ${pluginId}? This disables the plugin, applies the change when Runtime is idle, and deletes its installed folder. If Runtime is busy, try Remove again after it finishes.`,
49
+ )
50
+ )
51
+ return false;
52
+ if (!beginRuntimeMutation("plugin removal")) return false;
53
+ const request = ++generation;
54
+ const selected = environment;
55
+ const current = () =>
56
+ request === generation && selected === getEnvironmentId();
57
+ Object.assign(state, { busy: true, message: "", error: "" });
58
+ render();
59
+ let removed = false;
60
+ let activated = false;
61
+ try {
62
+ const result = await removePlugin({ pluginId }, selected);
63
+ if (!current()) return false;
64
+ removed = result.removed === true;
65
+ onSnapshot(result);
66
+ state.message = result.message;
67
+ activated = result.activation?.status === "ready";
68
+ if (activated) await onConfigurationApplied();
69
+ else onConfigurationSaved();
70
+ if (!current()) return false;
71
+ const refreshed = await refreshRuntimeConfig(
72
+ "Plugin removal; refresh required",
73
+ );
74
+ if (!current()) return false;
75
+ if (!refreshed)
76
+ state.error = "Refresh configuration before making more changes.";
77
+ return removed;
78
+ } catch (error) {
79
+ if (!current()) return false;
80
+ state.error =
81
+ (removed ? "Plugin removed; refresh failed: " : "") +
82
+ (error.message || String(error));
83
+ if (removed || activated) return false;
84
+ activated = error.payload?.activation?.status === "ready";
85
+ if (!activated && isDefinitiveRemovalRejection(error)) return false;
86
+ let projectionRefreshed = true;
87
+ if (activated) {
88
+ projectionRefreshed = await Promise.resolve()
89
+ .then(onConfigurationApplied)
90
+ .then(
91
+ () => true,
92
+ () => false,
93
+ );
94
+ if (!current()) return false;
95
+ }
96
+ // Apply may have succeeded for an older revision while a newer save is pending.
97
+ if (!activated || error.code === "config_changed") onConfigurationSaved();
98
+ const refreshed = await refreshRuntimeConfig(
99
+ "Plugin removal incomplete; refresh required",
100
+ ).catch(() => false);
101
+ if (current() && (!projectionRefreshed || !refreshed))
102
+ state.error += " Refresh configuration before making more changes.";
103
+ return false;
104
+ } finally {
105
+ endRuntimeMutation();
106
+ if (current()) state.busy = false;
107
+ if (activated && current()) {
108
+ try {
109
+ if (onConfigurationSettled() === false)
110
+ state.error = [
111
+ state.error,
112
+ "Finish your current edits, then refresh configuration to update environments.",
113
+ ]
114
+ .filter(Boolean)
115
+ .join(" ");
116
+ } catch {
117
+ state.error = [
118
+ state.error,
119
+ "Refresh configuration to update environments.",
120
+ ]
121
+ .filter(Boolean)
122
+ .join(" ");
123
+ }
124
+ }
125
+ if (current()) render();
126
+ }
127
+ }
128
+
129
+ return { state, remove, resetEnvironment };
130
+ }
@@ -56,7 +56,13 @@ function renderCapabilities(plugin, busy, open) {
56
56
  </section>`;
57
57
  }
58
58
 
59
- function renderPluginCard(plugin, busy, openPluginIds) {
59
+ function renderPluginCard(
60
+ plugin,
61
+ busy,
62
+ openPluginIds,
63
+ canRemove,
64
+ canConfigure,
65
+ ) {
60
66
  const toolsOpen = openPluginIds.has(plugin.id);
61
67
  const selected = pluginMasterIsEnabled(plugin);
62
68
  const disabled = busy || plugin.blockedByGlobalPolicy;
@@ -74,8 +80,12 @@ function renderPluginCard(plugin, busy, openPluginIds) {
74
80
  <p class="plugin-description" title="${escapeAttribute(plugin.description || "Installed Runtime plugin.")}">${escapeHtml(plugin.description || "Installed Runtime plugin.")}</p>
75
81
  <div class="plugin-card-footer">
76
82
  <span>${plugin.selectedCapabilityCount} of ${plugin.capabilityCount} capabilities selected</span>
83
+ <div class="plugin-card-actions">
84
+ ${canConfigure && plugin.configurable ? `<button type="button" data-plugin-configure="${escapeAttribute(plugin.id)}" ${busy ? "disabled" : ""}>Configure</button>` : ""}
85
+ ${canRemove && plugin.removable ? `<button type="button" data-plugin-remove="${escapeAttribute(plugin.id)}" aria-label="${escapeAttribute(`Remove ${plugin.id}`)}" ${busy ? "disabled" : ""}>Remove</button>` : ""}
77
86
  <button type="button" data-plugin-toggle="${escapeAttribute(plugin.id)}" data-plugin-enabled="${selected ? "false" : "true"}"
78
87
  aria-label="${escapeAttribute(`${action} ${plugin.id}`)}" ${disabled ? "disabled" : ""}>${action}</button>
88
+ </div>
79
89
  </div>
80
90
  <button type="button" class="plugin-tools-open" data-plugin-tools-open="${escapeAttribute(plugin.id)}" aria-controls="${escapeAttribute(`plugin-tools-${encodeURIComponent(plugin.id)}`)}" aria-expanded="${toolsOpen}" aria-label="${escapeAttribute(`Manage tools in ${plugin.id}`)}">
81
91
  <svg aria-hidden="true" viewBox="0 0 24 24"><path d="M4 7h9m4 0h3M4 17h3m4 0h9"/><circle cx="15" cy="7" r="2"/><circle cx="9" cy="17" r="2"/></svg>
@@ -103,6 +113,8 @@ export function renderPluginManager({
103
113
  message,
104
114
  error,
105
115
  openPluginIds = new Set(),
116
+ canRemove = false,
117
+ canConfigure = false,
106
118
  }) {
107
119
  const plugins = snapshot?.plugins || [];
108
120
  const globalMessage = globalPolicyMessage(snapshot?.selection);
@@ -119,6 +131,6 @@ export function renderPluginManager({
119
131
  <p class="plugin-application-note">This list shows saved configuration. Apply changes or restart Runtime to use a new selection.</p>
120
132
  ${globalMessage ? `<p class="plugin-policy-note">${escapeHtml(globalMessage)}</p>` : ""}
121
133
  <div class="plugin-manager-status ${error ? "error-text" : ""}" role="${error ? "alert" : "status"}" aria-live="polite">${escapeHtml(status)}</div>
122
- ${plugins.length ? `<div class="plugin-grid">${plugins.map((plugin) => renderPluginCard(plugin, busy, openPluginIds)).join("")}</div>` : `<div class="empty-state compact">${busy ? "Loading installed plugins..." : "No installed plugins found."}</div>`}
134
+ ${plugins.length ? `<div class="plugin-grid">${plugins.map((plugin) => renderPluginCard(plugin, busy, openPluginIds, canRemove, canConfigure)).join("")}</div>` : `<div class="empty-state compact">${busy ? "Loading installed plugins..." : "No installed plugins found."}</div>`}
123
135
  </section>`;
124
136
  }
@@ -0,0 +1,54 @@
1
+ const SUMMARY_LABELS = [
2
+ "Installed plugins",
3
+ "Enabled in saved config",
4
+ "Selected tools (saved)",
5
+ "Excluded tools (saved)",
6
+ ];
7
+
8
+ function unavailablePluginSummaryValue(state, environmentId) {
9
+ if (state.environmentId !== environmentId) return "Not loaded";
10
+ if (state.busy) return "Loading…";
11
+ if (state.snapshot) return null;
12
+ if (state.error) return "Unavailable";
13
+ return "Not loaded";
14
+ }
15
+
16
+ /** Counts describe the saved catalog selection, never the running Runtime. */
17
+ export function projectPluginSummary(state, environmentId) {
18
+ const unavailable = unavailablePluginSummaryValue(state, environmentId);
19
+ if (unavailable) {
20
+ return {
21
+ label: "Plugins · saved configuration",
22
+ items: SUMMARY_LABELS.map((label) => ({
23
+ label,
24
+ value: unavailable,
25
+ status: true,
26
+ })),
27
+ };
28
+ }
29
+ const plugins = state.snapshot.plugins;
30
+ const enabled = plugins.filter(
31
+ (plugin) => plugin.pluginEnabled === true,
32
+ ).length;
33
+ const selected = plugins.reduce(
34
+ (sum, plugin) => sum + plugin.selectedCapabilityCount,
35
+ 0,
36
+ );
37
+ const total = plugins.reduce(
38
+ (sum, plugin) => sum + plugin.capabilityCount,
39
+ 0,
40
+ );
41
+ const values = [
42
+ String(plugins.length),
43
+ String(enabled),
44
+ `${selected} / ${total}`,
45
+ String(total - selected),
46
+ ];
47
+ return {
48
+ label: "Plugins · saved configuration",
49
+ items: SUMMARY_LABELS.map((label, index) => ({
50
+ label,
51
+ value: values[index],
52
+ })),
53
+ };
54
+ }
@@ -0,0 +1,31 @@
1
+ import { renderPluginDiscovery } from "./discovery-rendering.js";
2
+ const names = ["installed", "discover"];
3
+
4
+ export function renderPluginTabs(installed, discovery, active = "installed") {
5
+ const button = (name, label) =>
6
+ `<button type="button" id="plugin-${name}-tab" class="config-category-tab${active === name ? " active" : ""}" role="tab" data-plugin-tab="${name}" aria-controls="plugin-${name}-panel" aria-selected="${active === name}" tabindex="${active === name ? 0 : -1}">${label}</button>`;
7
+ return `<div class="plugin-workspace"><nav class="config-category-nav" role="tablist" aria-label="Plugin views">${button("installed", "Installed")}${button("discover", "Discover")}</nav>
8
+ <div id="plugin-installed-panel" class="config-category-panel" role="tabpanel" aria-labelledby="plugin-installed-tab" tabindex="0"${active === "installed" ? "" : " hidden"}>${installed}</div>
9
+ <div id="plugin-discover-panel" class="config-category-panel" role="tabpanel" aria-labelledby="plugin-discover-tab" tabindex="0"${active === "discover" ? "" : " hidden"}>${renderPluginDiscovery(discovery)}</div></div>`;
10
+ }
11
+
12
+ export function bindPluginTabs(root, activate) {
13
+ for (const button of root.querySelectorAll("[data-plugin-tab]")) {
14
+ button.addEventListener("click", () =>
15
+ activate(button.dataset.pluginTab, true),
16
+ );
17
+ button.addEventListener("keydown", (event) => {
18
+ const index = names.indexOf(button.dataset.pluginTab);
19
+ let target;
20
+ if (event.key === "ArrowRight")
21
+ target = names[(index + 1) % names.length];
22
+ if (event.key === "ArrowLeft")
23
+ target = names[(index + names.length - 1) % names.length];
24
+ if (event.key === "Home") target = names[0];
25
+ if (event.key === "End") target = names.at(-1);
26
+ if (!target) return;
27
+ event.preventDefault();
28
+ activate(target, true);
29
+ });
30
+ }
31
+ }
@@ -10,6 +10,8 @@ export function createPluginViewState() {
10
10
  if (element.dataset.pluginCapabilityToggle) {
11
11
  return { kind: "capability", pluginId: element.dataset.pluginParent, capabilityId: element.dataset.pluginCapabilityToggle };
12
12
  }
13
+ if (element.dataset.pluginTab) return { kind: "tab", pluginId: element.dataset.pluginTab };
14
+ if (element.dataset.pluginRemove) return { kind: "remove", pluginId: element.dataset.pluginRemove };
13
15
  if (element.dataset.pluginToggle) return { kind: "plugin", pluginId: element.dataset.pluginToggle };
14
16
  if (element.dataset.pluginToolsOpen) return { kind: "open", pluginId: element.dataset.pluginToolsOpen };
15
17
  if (element.dataset.pluginToolsBack) return { kind: "back", pluginId: element.dataset.pluginToolsBack };
@@ -72,7 +74,7 @@ export function createPluginViewState() {
72
74
  restoreToolScroll(root);
73
75
  if (!focusedControl) return;
74
76
  if (busy && !isCardNavigationFocus()) return;
75
- const controls = root.querySelectorAll("[data-plugin-toggle], [data-plugin-capability-toggle], [data-plugin-tools-open], [data-plugin-tools-back], [data-plugin-refresh]");
77
+ const controls = root.querySelectorAll("[data-plugin-tab], [data-plugin-remove], [data-plugin-toggle], [data-plugin-capability-toggle], [data-plugin-tools-open], [data-plugin-tools-back], [data-plugin-refresh]");
76
78
  let target = [...controls].find((element) => matchesIdentity(element, focusedControl));
77
79
  if (target?.disabled) {
78
80
  target = [...controls].find((element) => element.dataset.pluginToolsBack === focusedControl.pluginId);
@@ -25,6 +25,7 @@ export function renderConnectionField({
25
25
  value = "",
26
26
  placeholder = "",
27
27
  help = "",
28
+ error = "",
28
29
  required = true,
29
30
  readonly = false,
30
31
  min = "",
@@ -32,8 +33,9 @@ export function renderConnectionField({
32
33
  idPrefix = "runtimeSetup",
33
34
  }) {
34
35
  return `<label class="runtime-setup-field"><span>${label}</span>
35
- <input type="${type}" data-runtime-setup-field="${field}" value="${escapeAttribute(value)}" placeholder="${escapeAttribute(placeholder)}" autocomplete="${type === "password" ? "new-password" : "off"}" spellcheck="false" ${min ? `min="${escapeAttribute(min)}"` : ""} ${step ? `step="${escapeAttribute(step)}"` : ""} ${required ? "required" : ""} ${readonly ? "readonly" : ""} aria-describedby="${idPrefix}Help-${field}" />
36
+ <input type="${type}" data-runtime-setup-field="${field}" value="${escapeAttribute(value)}" placeholder="${escapeAttribute(placeholder)}" autocomplete="${type === "password" ? "new-password" : "off"}" spellcheck="false" ${min ? `min="${escapeAttribute(min)}"` : ""} ${step ? `step="${escapeAttribute(step)}"` : ""} ${required ? "required" : ""} ${readonly ? "readonly" : ""} ${error ? 'aria-invalid="true"' : ""} aria-describedby="${idPrefix}Help-${field}${error ? ` ${idPrefix}Error-${field}` : ""}" />
36
37
  <small id="${idPrefix}Help-${field}">${help}</small>
38
+ ${error ? `<small id="${idPrefix}Error-${field}" class="runtime-setup-feedback error" role="alert">${escapeHtml(error)}</small>` : ""}
37
39
  </label>`;
38
40
  }
39
41
 
@@ -60,7 +62,8 @@ export function renderConnectionFields(state) {
60
62
  label: "Context window (tokens)",
61
63
  type: "number",
62
64
  value: state.contextWindowTokens,
63
- min: "1",
65
+ min: state.contextWindowFeedback?.minimumTokens || "1",
66
+ error: state.contextWindowFeedback?.message,
64
67
  step: "1",
65
68
  readonly: !canEditSetupConnection(state),
66
69
  help: "Use a value supported by your model. Larger windows need more memory with Ollama. You can change this later in Models.",
@@ -1,5 +1,6 @@
1
1
  import { textOf } from "../../lib/text-format.js";
2
2
  import { normalizeProvider } from "./validation.js";
3
+ import { readSetupContextWindowFeedback } from "./context-window-feedback.js";
3
4
 
4
5
  export function selectSetupProvider(state, value) {
5
6
  const provider = normalizeProvider(value);
@@ -36,7 +37,14 @@ export function setupConnectionSubmitLabel(state, apiKey = "") {
36
37
  : "Save connection";
37
38
  }
38
39
 
39
- export function setupConnectionSaveError(error) {
40
+ export function receiveSetupConnectionSaveError(state, error) {
41
+ state.contextWindowFeedback = readSetupContextWindowFeedback(error);
42
+ state.error = "";
43
+ if (state.contextWindowFeedback) return;
44
+ state.error = setupConnectionSaveError(error);
45
+ }
46
+
47
+ function setupConnectionSaveError(error) {
40
48
  if (error?.payload?.error === "setup_configuration_changed")
41
49
  return "Your connection changed in another window. Refresh this page before editing it again.";
42
50
  return "Could not save your connection. Check the model and connection details, then try again.";
@@ -0,0 +1,71 @@
1
+ function hasPositiveContextTokenCount(value) {
2
+ if (!Number.isSafeInteger(value)) return false;
3
+ return value > 0;
4
+ }
5
+
6
+ function hasSupportedContextConstraint(details) {
7
+ if (details?.field !== "contextWindowTokens") return false;
8
+ for (const field of ["declaredTokens", "effectiveTokens", "minimumTokens"]) {
9
+ if (!hasPositiveContextTokenCount(details[field])) return false;
10
+ }
11
+ if (!Number.isSafeInteger(details.reservedTokens)) return false;
12
+ if (details.reservedTokens < 0) return false;
13
+ if (details.effectiveTokens > details.reservedTokens) return false;
14
+ if (details.effectiveTokens > details.declaredTokens) return false;
15
+ if (details.minimumTokens <= details.reservedTokens) return false;
16
+ if (details.allocationTokens === undefined) return true;
17
+ if (!hasPositiveContextTokenCount(details.allocationTokens)) return false;
18
+ return details.effectiveTokens <= details.allocationTokens;
19
+ }
20
+
21
+ function hasInsufficientContextAllocation(details) {
22
+ if (details.allocationTokens === undefined) return false;
23
+ return details.allocationTokens < details.minimumTokens;
24
+ }
25
+
26
+ function formatContextConstraintMessage(details) {
27
+ const tokens = (value) => value.toLocaleString("en-US");
28
+ const capacity = `The effective context window is ${tokens(details.effectiveTokens)} tokens, but the current configuration reserves ${tokens(details.reservedTokens)} tokens.`;
29
+ const minimum = `Use a context window of at least ${tokens(details.minimumTokens)} tokens supported by your model, or adjust the configured reserves.`;
30
+ if (!hasInsufficientContextAllocation(details))
31
+ return `${capacity} ${minimum}`;
32
+ return `${capacity} ${minimum} The configured Ollama allocation (num_ctx) is ${tokens(details.allocationTokens)} tokens. It must also reach that minimum; increasing this field alone is insufficient.`;
33
+ }
34
+
35
+ /** Only numeric details from this known contract become user-visible feedback. */
36
+ export function readSetupContextWindowFeedback(error) {
37
+ if (error?.status !== 400) return null;
38
+ const payload = error.payload;
39
+ if (payload?.ok !== false) return null;
40
+ if (payload.error !== "context_window_too_small") return null;
41
+ if (!hasSupportedContextConstraint(payload.contextWindow)) return null;
42
+ return {
43
+ minimumTokens: payload.contextWindow.minimumTokens,
44
+ message: formatContextConstraintMessage(payload.contextWindow),
45
+ };
46
+ }
47
+
48
+ /** A server constraint belongs to the rejected candidate, never later edits. */
49
+ export function clearSetupContextWindowFeedback(state, container) {
50
+ if (!state.contextWindowFeedback) return;
51
+ state.contextWindowFeedback = null;
52
+ const field = container.querySelector(
53
+ '[data-runtime-setup-field="context-window"]',
54
+ );
55
+ field?.removeAttribute?.("aria-invalid");
56
+ field?.setAttribute?.("aria-describedby", "runtimeSetupHelp-context-window");
57
+ field?.setAttribute?.("min", "1");
58
+ container.querySelector("#runtimeSetupError-context-window")?.remove?.();
59
+ }
60
+
61
+ export function focusSetupContextWindowFeedback(
62
+ container,
63
+ feedback,
64
+ restoreFocus,
65
+ ) {
66
+ if (!feedback) return;
67
+ if (!restoreFocus) return;
68
+ container
69
+ .querySelector('[data-runtime-setup-field="context-window"]')
70
+ ?.focus?.();
71
+ }
@@ -16,6 +16,7 @@ export function createSetupOptionalSteps({
16
16
  loadHostConnection,
17
17
  connectLocalHost,
18
18
  createHostPairing,
19
+ requestHostStoreConnection,
19
20
  requestHostPermissions,
20
21
  downloadHostSetup,
21
22
  revokeHostConnection,
@@ -48,6 +49,7 @@ export function createSetupOptionalSteps({
48
49
  loadConnection: loadHostConnection,
49
50
  connectLocal: connectLocalHost,
50
51
  createPairing: createHostPairing,
52
+ requestStoreConnection: requestHostStoreConnection,
51
53
  requestPermissions: requestHostPermissions,
52
54
  downloadSetup: downloadHostSetup,
53
55
  revokeConnection: revokeHostConnection,
@@ -13,7 +13,7 @@ import {
13
13
  hasSetupConnectionChanges,
14
14
  receiveSetupConnection,
15
15
  selectSetupProvider,
16
- setupConnectionSaveError,
16
+ receiveSetupConnectionSaveError,
17
17
  setupConnectionSubmitLabel,
18
18
  updateSetupConnectionField,
19
19
  } from "./runtime-setup/connection-state.js";
@@ -23,6 +23,10 @@ import {
23
23
  validateConnectionFields,
24
24
  showConnectionFieldError,
25
25
  } from "./runtime-setup/connection-form.js";
26
+ import {
27
+ clearSetupContextWindowFeedback,
28
+ focusSetupContextWindowFeedback,
29
+ } from "./runtime-setup/context-window-feedback.js";
26
30
  import {
27
31
  DEFAULT_OLLAMA_BASE_URL,
28
32
  normalizeProvider,
@@ -48,6 +52,7 @@ export function createRuntimeSetupGuide({
48
52
  loadHostConnection,
49
53
  connectLocalHost,
50
54
  createHostPairing,
55
+ requestHostStoreConnection,
51
56
  requestHostPermissions,
52
57
  downloadHostSetup,
53
58
  revokeHostConnection,
@@ -82,12 +87,13 @@ export function createRuntimeSetupGuide({
82
87
  const optionalSteps = createSetupOptionalSteps({
83
88
  container, getEnvironmentId, getPreferredProvider: () => state.provider,
84
89
  loadEmbeddingStatus, discoverEmbeddingModels, saveEmbedding, loadPlugins,
85
- setPlugin, loadHostConnection, connectLocalHost, createHostPairing, requestHostPermissions, downloadHostSetup, revokeHostConnection,
90
+ setPlugin, loadHostConnection, connectLocalHost, createHostPairing, requestHostStoreConnection, requestHostPermissions, downloadHostSetup, revokeHostConnection,
86
91
  onChange: paint, goToStep,
87
92
  });
88
93
  const { embedding, plugins, readyStep } = optionalSteps;
89
94
 
90
95
  function goToStep(step) {
96
+ clearSetupContextWindowFeedback(state, container);
91
97
  state.step = step;
92
98
  state.error = "";
93
99
  paint({ focus: true });
@@ -100,6 +106,7 @@ export function createRuntimeSetupGuide({
100
106
  }
101
107
 
102
108
  function reset() {
109
+ clearSetupContextWindowFeedback(state, container);
103
110
  revision += 1;
104
111
  optionalSteps.reset();
105
112
  viewState.reset();
@@ -153,6 +160,7 @@ export function createRuntimeSetupGuide({
153
160
 
154
161
  async function loadOptions() {
155
162
  if (state.loading) return;
163
+ clearSetupContextWindowFeedback(state, container);
156
164
  const operationRevision = ++revision;
157
165
  const operationEnvironment = getEnvironmentId();
158
166
  state.loading = true;
@@ -217,6 +225,7 @@ export function createRuntimeSetupGuide({
217
225
  async function submitConnection() {
218
226
  const input = connectionInput();
219
227
  if (!input) return;
228
+ clearSetupContextWindowFeedback(state, container);
220
229
  const connectionChanged = hasSetupConnectionChanges(state);
221
230
  const operationRevision = ++revision;
222
231
  const operationEnvironment = getEnvironmentId();
@@ -247,12 +256,13 @@ export function createRuntimeSetupGuide({
247
256
  state.step = 2;
248
257
  } catch (error) {
249
258
  if (!operationIsCurrent(operationRevision, operationEnvironment)) return;
250
- state.error = setupConnectionSaveError(error);
259
+ receiveSetupConnectionSaveError(state, error);
251
260
  } finally {
252
261
  delete input.apiKey;
253
262
  if (operationIsCurrent(operationRevision, operationEnvironment)) {
254
263
  state.saving = false;
255
264
  paint({ focus: true });
265
+ focusSetupContextWindowFeedback(container, state.contextWindowFeedback, viewState.canRestoreFocus());
256
266
  if (state.step === 2) void embedding.load();
257
267
  }
258
268
  }
@@ -392,6 +402,7 @@ export function createRuntimeSetupGuide({
392
402
  embedding.input(field.dataset.runtimeSetupField, textOf(field.value));
393
403
  return;
394
404
  }
405
+ clearSetupContextWindowFeedback(state, container);
395
406
  field.removeAttribute?.("aria-invalid");
396
407
  updateSetupConnectionField(
397
408
  state,
@@ -420,6 +431,7 @@ export function createRuntimeSetupGuide({
420
431
  field?.dataset.runtimeSetupField !== "provider"
421
432
  )
422
433
  return;
434
+ clearSetupContextWindowFeedback(state, container);
423
435
  selectSetupProvider(state, field.value);
424
436
  state.error = "";
425
437
  paint();
@@ -35,6 +35,7 @@ export function createSparkChatEmptyState({ getConfiguration, onOpenModelSetting
35
35
  if (model.needsModel) {
36
36
  const action = documentRoot.createElement("button");
37
37
  action.setAttribute("type", "button");
38
+ action.className = "spark-setup-button";
38
39
  action.textContent = "Choose model";
39
40
  action.addEventListener("click", onOpenModelSettings);
40
41
  empty.append(action);
@@ -48,6 +48,7 @@ export function createSparkChatPanel({ documentRoot = document, launcherAnchor }
48
48
  dom.launcherButton.insertAdjacentHTML("beforeend", '<span class="spark-launcher-label">SPARK</span>');
49
49
  const panel = root.querySelector(".spark-chat-panel");
50
50
  const notice = root.querySelector(".spark-message-notice");
51
+ dom.launcherButton.hidden = true;
51
52
  const placement = createSparkChatPlacement({ root, launcher: dom.launcherButton, panel, notice, dockAnchor: launcherSlot });
52
53
  dom.launcherButton.title = "Open SPARK · Drag to move · Alt + arrows to move · Alt + Home to return to sidebar";
53
54
  let timer;
@@ -0,0 +1,35 @@
1
+ import { escapeHtml } from "../../lib/text-format.js";
2
+
3
+ export function renderComputerMetadata(snapshot, disabled = false) {
4
+ const identity = snapshot?.identity || {};
5
+ const os = { windows: "Windows", macos: "macOS", linux: "Linux" }[identity.os] || identity.os;
6
+ const summary = [identity.name, os, identity.user]
7
+ .filter((value) => typeof value === "string" && value.length > 0).join(" · ");
8
+ if (!summary && !snapshot?.paired) return "";
9
+ return `<div class="system-host-card-computer"><span>${escapeHtml(summary)}</span>${snapshot?.paired ? `<button type="button" data-system-host-revoke title="Disconnect this computer. Saved insights are kept." ${disabled ? "disabled" : ""}>Remove this computer</button>` : ""}</div>`;
10
+ }
11
+
12
+ function renderConnectionStatus(status, ready, compact = false) {
13
+ return `<span class="system-host-card-status" role="status" ${compact ? `aria-label="${escapeHtml(status)}"` : ""} data-tone="${ready ? "ready" : "unavailable"}"><i aria-hidden="true"></i>${compact ? "" : escapeHtml(status)}</span>`;
14
+ }
15
+
16
+ /** Platform actions are supplied by their existing owners; this module renders the shared layout. */
17
+ export function renderConnectionCard({
18
+ title, status, ready, disabled = false, compact = false, description = "",
19
+ actions = "", help = "", metadata = "", error = "", message = "", details = "", attributes = "",
20
+ }) {
21
+ if (compact) return `<section class="system-host-panel system-host-card system-host-card-ready" aria-label="Computer access" ${attributes}>
22
+ <h2 class="system-host-card-ready-title">${renderConnectionStatus(status, ready, true)}${escapeHtml(title)}</h2>
23
+ ${metadata}
24
+ ${details}
25
+ </section>`;
26
+ return `<section class="system-host-panel system-host-card" aria-label="Computer access" aria-busy="${disabled ? "true" : "false"}" ${attributes}>
27
+ <div class="system-host-card-heading"><h2>${escapeHtml(title)}</h2>${renderConnectionStatus(status, ready)}</div>
28
+ ${description ? `<p class="system-host-card-description">${escapeHtml(description)}</p>` : ""}
29
+ ${actions ? `<div class="system-host-card-action">${actions}</div>` : ""}
30
+ ${help ? `<p class="system-host-card-hint">${escapeHtml(help)}</p>` : ""}
31
+ ${error || message ? `<p class="${error ? "error-text" : "system-host-card-message"}" role="${error ? "alert" : "status"}" aria-live="polite">${escapeHtml(error || message)}</p>` : ""}
32
+ ${metadata}
33
+ ${details}
34
+ </section>`;
35
+ }
@@ -58,7 +58,7 @@ export function renderMacSetupAction(snapshot, disabled) {
58
58
  : "Connect this Mac";
59
59
  const label = local ? localLabel : "Connect a Mac";
60
60
  const action = local ? "local" : "manual";
61
- return `<button type="button" data-system-host-mac="${action}" ${disabled ? "disabled" : ""}>${label}</button>`;
61
+ return `<button type="button" class="system-host-card-primary" data-system-host-mac="${action}" ${disabled ? "disabled" : ""}>${label}</button>`;
62
62
  }
63
63
 
64
64
  export function renderMacSetupNotice(snapshot) {