@abot-ai/runtime 1.7.0 → 1.8.1

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 (532) hide show
  1. package/README.md +216 -222
  2. package/dist/src/capabilities/tool-definition-validator/definition-parser.js +8 -0
  3. package/dist/src/capabilities/tool-request-resources.d.ts +3 -0
  4. package/dist/src/capabilities/tool-types.d.ts +4 -0
  5. package/dist/src/cli/abot.js +2 -0
  6. package/dist/src/cli/host-companion-bundle.mjs +751 -333
  7. package/dist/src/computer-access/collection-consent.d.ts +9 -0
  8. package/dist/src/computer-access/collection-consent.js +47 -0
  9. package/dist/src/computer-access/command-output-capture.d.ts +17 -6
  10. package/dist/src/computer-access/command-output-capture.js +134 -68
  11. package/dist/src/computer-access/command-output-protection.d.ts +17 -0
  12. package/dist/src/computer-access/command-output-protection.js +59 -0
  13. package/dist/src/computer-access/companion/command-output.d.ts +1 -0
  14. package/dist/src/computer-access/companion/command-output.js +23 -6
  15. package/dist/src/computer-access/companion/install-link-macos.js +2 -1
  16. package/dist/src/computer-access/companion/native-notifications.js +3 -2
  17. package/dist/src/computer-access/companion/native-session.js +6 -2
  18. package/dist/src/computer-access/companion/observation-filter.js +2 -26
  19. package/dist/src/computer-access/companion/observation-process.d.ts +2 -0
  20. package/dist/src/computer-access/companion/observation-process.js +51 -25
  21. package/dist/src/computer-access/companion/observation-redaction.d.ts +2 -7
  22. package/dist/src/computer-access/companion/observation-redaction.js +2 -111
  23. package/dist/src/computer-access/companion/secret-protection-protocol.d.ts +6 -0
  24. package/dist/src/computer-access/companion/secret-protection-protocol.js +6 -0
  25. package/dist/src/computer-access/computer/companion-sessions.js +7 -6
  26. package/dist/src/computer-access/computer/unix-native-process.js +23 -11
  27. package/dist/src/computer-access/handlers.d.ts +2 -1
  28. package/dist/src/computer-access/handlers.js +79 -11
  29. package/dist/src/computer-access/host-observation.d.ts +3 -3
  30. package/dist/src/computer-access/native-observation-connection.d.ts +12 -0
  31. package/dist/src/computer-access/native-observation-connection.js +78 -0
  32. package/dist/src/computer-access/native-observation-ownership.d.ts +6 -0
  33. package/dist/src/computer-access/native-observation-ownership.js +55 -0
  34. package/dist/src/computer-access/native-observation-shutdown.d.ts +7 -0
  35. package/dist/src/computer-access/native-observation-shutdown.js +58 -0
  36. package/dist/src/computer-access/observation-source.d.ts +6 -0
  37. package/dist/src/computer-access/observation-source.js +10 -0
  38. package/dist/src/computer-access/security/desktop-result.d.ts +8 -0
  39. package/dist/src/computer-access/security/desktop-result.js +146 -0
  40. package/dist/src/computer-access/security/observed-error.d.ts +2 -0
  41. package/dist/src/computer-access/security/observed-error.js +10 -0
  42. package/dist/src/computer-access/security/secret-text.d.ts +7 -0
  43. package/dist/src/computer-access/security/secret-text.js +111 -0
  44. package/dist/src/computer-access/security/system-results.d.ts +2 -0
  45. package/dist/src/computer-access/security/system-results.js +53 -0
  46. package/dist/src/computer-access/system-result-protection.d.ts +11 -0
  47. package/dist/src/computer-access/system-result-protection.js +1 -0
  48. package/dist/src/model-gateway/observability/provider-response-capture.d.ts +60 -0
  49. package/dist/src/model-gateway/observability/provider-response-capture.js +68 -0
  50. package/dist/src/model-gateway/observability/provider-response-prefix.d.ts +7 -0
  51. package/dist/src/model-gateway/observability/provider-response-prefix.js +14 -0
  52. package/dist/src/model-gateway/observability/provider-response-tail.d.ts +8 -0
  53. package/dist/src/model-gateway/observability/provider-response-tail.js +28 -0
  54. package/dist/src/model-gateway/observability/provider-sse-diagnostics.d.ts +30 -0
  55. package/dist/src/model-gateway/observability/provider-sse-diagnostics.js +119 -0
  56. package/dist/src/model-gateway/observability/provider-trace.js +30 -8
  57. package/dist/src/model-gateway/protocol/message-contract.d.ts +1 -0
  58. package/dist/src/model-gateway/protocol/message-contract.js +1 -1
  59. package/dist/src/model-gateway/providers/ollama/adapter.js +8 -2
  60. package/dist/src/model-gateway/providers/ollama/stream-normalizer.js +70 -50
  61. package/dist/src/model-gateway/providers/ollama/stream-termination.d.ts +6 -0
  62. package/dist/src/model-gateway/providers/ollama/stream-termination.js +20 -0
  63. package/dist/src/model-gateway/providers/openai/adapter.js +9 -7
  64. package/dist/src/model-gateway/providers/openai/diagnostics.d.ts +0 -1
  65. package/dist/src/model-gateway/providers/openai/diagnostics.js +0 -9
  66. package/dist/src/model-gateway/providers/openai/function-output.d.ts +11 -0
  67. package/dist/src/model-gateway/providers/openai/function-output.js +37 -0
  68. package/dist/src/model-gateway/providers/openai/function-result.d.ts +7 -0
  69. package/dist/src/model-gateway/providers/openai/function-result.js +35 -0
  70. package/dist/src/model-gateway/providers/openai/message-output-policy.d.ts +3 -0
  71. package/dist/src/model-gateway/providers/openai/message-output-policy.js +16 -0
  72. package/dist/src/model-gateway/providers/openai/payload.d.ts +0 -2
  73. package/dist/src/model-gateway/providers/openai/payload.js +6 -23
  74. package/dist/src/model-gateway/providers/openai/response-lifetime.d.ts +2 -0
  75. package/dist/src/model-gateway/providers/openai/response-lifetime.js +64 -0
  76. package/dist/src/model-gateway/providers/openai/sse-data.d.ts +9 -0
  77. package/dist/src/model-gateway/providers/openai/sse-data.js +67 -0
  78. package/dist/src/model-gateway/providers/openai/stream-normalizer.d.ts +10 -22
  79. package/dist/src/model-gateway/providers/openai/stream-normalizer.js +78 -79
  80. package/dist/src/model-gateway/providers/openai/stream.js +13 -41
  81. package/dist/src/model-gateway/providers/openai/structured-message-output.d.ts +42 -0
  82. package/dist/src/model-gateway/providers/openai/structured-message-output.js +175 -0
  83. package/dist/src/model-gateway/server/chat-handler.js +5 -7
  84. package/dist/src/model-gateway/server/chat-stream-response.d.ts +7 -0
  85. package/dist/src/model-gateway/server/chat-stream-response.js +25 -0
  86. package/dist/src/model-gateway/server.js +5 -1
  87. package/dist/src/plugin-contract/index.d.ts +1 -0
  88. package/dist/src/plugin-contract/index.js +1 -0
  89. package/dist/src/plugin-contract/manifest.d.ts +2 -0
  90. package/dist/src/plugin-contract/manifest.js +1 -0
  91. package/dist/src/plugin-contract/platform-compatibility.d.ts +16 -0
  92. package/dist/src/plugin-contract/platform-compatibility.js +3 -0
  93. package/dist/src/plugin-sdk/computer-access.d.ts +4 -0
  94. package/dist/src/plugin-sdk/computer-access.js +1 -0
  95. package/dist/src/plugin-sdk/files-windows/process.d.ts +3 -0
  96. package/dist/src/plugin-sdk/files-windows/process.js +93 -0
  97. package/dist/src/plugin-sdk/files-windows/read-script.d.ts +1 -0
  98. package/dist/src/plugin-sdk/files-windows/read-script.js +43 -0
  99. package/dist/src/plugin-sdk/files-windows/read.d.ts +6 -0
  100. package/dist/src/plugin-sdk/files-windows/read.js +56 -0
  101. package/dist/src/plugin-sdk/files-windows/result.d.ts +4 -0
  102. package/dist/src/plugin-sdk/files-windows/result.js +67 -0
  103. package/dist/src/plugin-sdk/files.js +4 -0
  104. package/dist/src/plugin-sdk/index.d.ts +1 -0
  105. package/dist/src/plugin-sdk/index.js +1 -0
  106. package/dist/src/plugin-sdk/mutation-result.d.ts +7 -0
  107. package/dist/src/plugin-sdk/mutation-result.js +11 -0
  108. package/dist/src/runtime/adapters/long-term-memory/file-lock/acquisition.js +20 -3
  109. package/dist/src/runtime/adapters/long-term-memory/file-lock/owner-record.js +3 -1
  110. package/dist/src/runtime/adapters/long-term-memory/file-lock/path-observation.d.ts +3 -0
  111. package/dist/src/runtime/adapters/long-term-memory/file-lock/path-observation.js +20 -0
  112. package/dist/src/runtime/adapters/long-term-memory/file-lock/snapshot.js +7 -3
  113. package/dist/src/runtime/adapters/passive-learning-runtime.d.ts +1 -1
  114. package/dist/src/runtime/adapters/passive-learning-runtime.js +3 -3
  115. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-rejection.d.ts +2 -2
  116. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-rejection.js +2 -2
  117. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/prepared-execution.js +17 -11
  118. package/dist/src/runtime/adapters/runtime-observation-connection.d.ts +5 -0
  119. package/dist/src/runtime/adapters/runtime-observation-connection.js +13 -0
  120. package/dist/src/runtime/capabilities/tool-availability.js +6 -0
  121. package/dist/src/runtime/context/capability-brief.d.ts +2 -2
  122. package/dist/src/runtime/context/capability-brief.js +3 -3
  123. package/dist/src/runtime/context/capability-descriptions.d.ts +3 -2
  124. package/dist/src/runtime/context/capability-descriptions.js +57 -20
  125. package/dist/src/runtime/local-host/windows-private-access.js +2 -0
  126. package/dist/src/runtime/long-term-memory/conversation-authoring/context.d.ts +6 -1
  127. package/dist/src/runtime/long-term-memory/conversation-authoring/context.js +51 -25
  128. package/dist/src/runtime/long-term-memory/initial-context.d.ts +17 -0
  129. package/dist/src/runtime/long-term-memory/initial-context.js +57 -0
  130. package/dist/src/runtime/long-term-memory/projection.js +1 -1
  131. package/dist/src/runtime/orchestration/role-calls/candidate-validation.js +2 -1
  132. package/dist/src/runtime/orchestration/role-calls/checkpoint-state.d.ts +1 -1
  133. package/dist/src/runtime/orchestration/role-calls/checkpoint-state.js +5 -2
  134. package/dist/src/runtime/orchestration/role-calls/contracts.d.ts +2 -1
  135. package/dist/src/runtime/orchestration/role-calls/ledger.d.ts +2 -1
  136. package/dist/src/runtime/orchestration/role-calls/ledger.js +2 -2
  137. package/dist/src/runtime/orchestration/role-calls/memory-recall-contract.d.ts +7 -0
  138. package/dist/src/runtime/orchestration/role-calls/memory-recall-state-validation.d.ts +2 -0
  139. package/dist/src/runtime/orchestration/role-calls/memory-recall-state-validation.js +88 -0
  140. package/dist/src/runtime/orchestration/role-calls/reducer.d.ts +1 -1
  141. package/dist/src/runtime/orchestration/role-calls/reducer.js +2 -1
  142. package/dist/src/runtime/orchestration/worker-capabilities/contracts.d.ts +3 -1
  143. package/dist/src/runtime/orchestration/worker-capabilities/contracts.js +1 -1
  144. package/dist/src/runtime/orchestration/worker-capabilities/execution/approval-group.js +5 -1
  145. package/dist/src/runtime/orchestration/worker-capabilities/execution/execution-freshness.d.ts +5 -0
  146. package/dist/src/runtime/orchestration/worker-capabilities/execution/execution-freshness.js +31 -0
  147. package/dist/src/runtime/passive-learning/application-catalog.js +3 -1
  148. package/dist/src/runtime/passive-learning/collection-source.js +7 -0
  149. package/dist/src/runtime/passive-learning/service.js +2 -3
  150. package/dist/src/runtime/passive-learning/status-projection.d.ts +2 -0
  151. package/dist/src/runtime/passive-learning/status-projection.js +9 -0
  152. package/dist/src/runtime/plugins/installation/package.d.ts +8 -0
  153. package/dist/src/runtime/plugins/installation/package.js +2 -0
  154. package/dist/src/runtime/plugins/installation/service.d.ts +7 -0
  155. package/dist/src/runtime/plugins/loader.js +24 -14
  156. package/dist/src/runtime/plugins/manifest-platform-compatibility.d.ts +2 -0
  157. package/dist/src/runtime/plugins/manifest-platform-compatibility.js +39 -0
  158. package/dist/src/runtime/plugins/manifest-projection.js +3 -0
  159. package/dist/src/runtime/plugins/manifest-validator.js +9 -1
  160. package/dist/src/runtime/plugins/platform-compatibility.d.ts +4 -0
  161. package/dist/src/runtime/plugins/platform-compatibility.js +44 -0
  162. package/dist/src/runtime/request/approval-wait/activation-events.js +19 -7
  163. package/dist/src/runtime/request/approval-wait/execution-compaction-restore.d.ts +20 -0
  164. package/dist/src/runtime/request/approval-wait/execution-compaction-restore.js +118 -0
  165. package/dist/src/runtime/request/approval-wait/super-compaction-restore.js +2 -1
  166. package/dist/src/runtime/request/capability-execution-freshness.js +6 -1
  167. package/dist/src/runtime/request/execution-agent-root-execution.js +11 -1
  168. package/dist/src/runtime/request/prepared-execution.js +3 -0
  169. package/dist/src/runtime/request/root-contract.d.ts +2 -0
  170. package/dist/src/runtime/request/root-execution-kernel.js +1 -0
  171. package/dist/src/runtime/request/runner.js +9 -3
  172. package/dist/src/runtime/request/supervisor-root-execution.js +6 -0
  173. package/dist/src/runtime/steps/execution-agent/capability-result-context.d.ts +6 -0
  174. package/dist/src/runtime/steps/execution-agent/capability-result-context.js +29 -0
  175. package/dist/src/runtime/steps/execution-agent/contracts.d.ts +10 -0
  176. package/dist/src/runtime/steps/execution-agent/decision-parsing.js +13 -1
  177. package/dist/src/runtime/steps/execution-agent/direct-response-configuration.d.ts +3 -0
  178. package/dist/src/runtime/steps/execution-agent/direct-response-configuration.js +64 -0
  179. package/dist/src/runtime/steps/execution-agent/direct-response-contract.d.ts +7 -0
  180. package/dist/src/runtime/steps/execution-agent/direct-response-contract.js +56 -0
  181. package/dist/src/runtime/steps/execution-agent/direct-response-policy.d.ts +9 -0
  182. package/dist/src/runtime/steps/execution-agent/direct-response-policy.js +30 -0
  183. package/dist/src/runtime/steps/execution-agent/direct-response-prompt.d.ts +7 -0
  184. package/dist/src/runtime/steps/execution-agent/direct-response-prompt.js +43 -0
  185. package/dist/src/runtime/steps/execution-agent/format.js +4 -3
  186. package/dist/src/runtime/steps/execution-agent/input.d.ts +2 -0
  187. package/dist/src/runtime/steps/execution-agent/input.js +22 -1
  188. package/dist/src/runtime/steps/execution-agent/plugin-catalog.d.ts +4 -0
  189. package/dist/src/runtime/steps/execution-agent/plugin-catalog.js +8 -0
  190. package/dist/src/runtime/steps/execution-agent/prompt.d.ts +1 -0
  191. package/dist/src/runtime/steps/execution-agent/prompt.js +7 -8
  192. package/dist/src/runtime/steps/execution-agent/response-prompt.js +1 -0
  193. package/dist/src/runtime/steps/execution-agent/response-run.js +5 -11
  194. package/dist/src/runtime/steps/execution-agent/run.js +4 -1
  195. package/dist/src/runtime/steps/execution-agent/state-context.d.ts +3 -5
  196. package/dist/src/runtime/steps/execution-agent/state-context.js +5 -51
  197. package/dist/src/runtime/steps/execution-agent/work-plan-contract.d.ts +1 -3
  198. package/dist/src/runtime/steps/execution-agent/work-plan-contract.js +0 -55
  199. package/dist/src/runtime/steps/execution-agent/work-plan-schema.d.ts +3 -0
  200. package/dist/src/runtime/steps/execution-agent/work-plan-schema.js +61 -0
  201. package/dist/src/runtime/steps/planner-decision/capability-brief.d.ts +2 -0
  202. package/dist/src/runtime/steps/planner-decision/prompt.js +26 -49
  203. package/dist/src/runtime/steps/supervisor-decision/input.d.ts +1 -0
  204. package/dist/src/runtime/steps/supervisor-decision/input.js +5 -0
  205. package/dist/src/runtime/steps/supervisor-decision/prompt.d.ts +1 -0
  206. package/dist/src/runtime/steps/supervisor-decision/prompt.js +6 -2
  207. package/dist/src/runtime/steps/supervisor-decision/run.d.ts +1 -0
  208. package/dist/src/runtime/steps/supervisor-decision/run.js +4 -0
  209. package/dist/src/runtime/steps/supervisor-response/run.d.ts +2 -0
  210. package/dist/src/runtime/steps/supervisor-response/run.js +3 -6
  211. package/dist/src/sessions/durable-session-commit.js +3 -3
  212. package/dist/src/sessions/prepared-session-replacement.d.ts +6 -0
  213. package/dist/src/sessions/prepared-session-replacement.js +46 -0
  214. package/dist/src/sessions/session-store.js +3 -3
  215. package/dist/src/shared/passive-observation-self-exclusion.d.ts +5 -0
  216. package/dist/src/shared/passive-observation-self-exclusion.js +37 -0
  217. package/dist/src/shared/windows-file-io/authority-script.d.ts +1 -0
  218. package/dist/src/shared/windows-file-io/authority-script.js +94 -0
  219. package/dist/src/shared/windows-file-io/native-script.d.ts +2 -0
  220. package/dist/src/shared/windows-file-io/native-script.js +120 -0
  221. package/dist/src/shared/windows-file-io/read-bytes-script.d.ts +1 -0
  222. package/dist/src/shared/windows-file-io/read-bytes-script.js +18 -0
  223. package/dist/src/shared/windows-job-object.d.ts +2 -0
  224. package/dist/src/shared/windows-job-object.js +66 -0
  225. package/dist/src/web-ui/app/ARCHITECTURE.md +1 -1
  226. package/dist/src/web-ui/app/app-bootstrap.js +14 -1
  227. package/dist/src/web-ui/app/app-state.js +0 -7
  228. package/dist/src/web-ui/app/app.js +54 -156
  229. package/dist/src/web-ui/app/components/automations/node-inspector.js +3 -2
  230. package/dist/src/web-ui/app/components/automations/step-editor-dialog.js +3 -0
  231. package/dist/src/web-ui/app/components/automations/timeline.js +3 -2
  232. package/dist/src/web-ui/app/components/composer-submission-notice.js +50 -0
  233. package/dist/src/web-ui/app/components/config-workspace/model-plugin-permissions.js +7 -1
  234. package/dist/src/web-ui/app/components/config-workspace/workspace-mutations.js +22 -2
  235. package/dist/src/web-ui/app/components/dashboard/compact-layout.js +137 -0
  236. package/dist/src/web-ui/app/components/dashboard/icons.js +5 -0
  237. package/dist/src/web-ui/app/components/dashboard/widget-card.js +85 -0
  238. package/dist/src/web-ui/app/components/dashboard/widget-dialog.js +83 -0
  239. package/dist/src/web-ui/app/components/dashboard/widget-summaries.js +155 -0
  240. package/dist/src/web-ui/app/components/dashboard/workspace.js +28 -4
  241. package/dist/src/web-ui/app/components/home-guidance/daily-review.js +2 -2
  242. package/dist/src/web-ui/app/components/home-guidance/home-guidance.js +20 -6
  243. package/dist/src/web-ui/app/components/model-setup/context-window-feedback.js +53 -0
  244. package/dist/src/web-ui/app/components/model-setup/save-flow.js +3 -1
  245. package/dist/src/web-ui/app/components/model-setup/save-outcome.js +1 -0
  246. package/dist/src/web-ui/app/components/model-setup/wizard.js +12 -0
  247. package/dist/src/web-ui/app/components/operations-summary.js +2 -1
  248. package/dist/src/web-ui/app/components/passive-learning/activity-controls.js +4 -0
  249. package/dist/src/web-ui/app/components/passive-learning/collection-access.js +35 -0
  250. package/dist/src/web-ui/app/components/passive-learning/collection-consent-dialog.js +59 -0
  251. package/dist/src/web-ui/app/components/passive-learning/collection-consent-gate.js +94 -0
  252. package/dist/src/web-ui/app/components/passive-learning/computer-update-notice.js +6 -0
  253. package/dist/src/web-ui/app/components/passive-learning/failure-copy.js +1 -0
  254. package/dist/src/web-ui/app/components/passive-learning/home-widget-preview.js +32 -0
  255. package/dist/src/web-ui/app/components/passive-learning/home.js +11 -3
  256. package/dist/src/web-ui/app/components/passive-learning/macos-collection-restart-notice.js +1 -0
  257. package/dist/src/web-ui/app/components/passive-learning/memory.js +2 -4
  258. package/dist/src/web-ui/app/components/passive-learning/workspace-view.js +2 -2
  259. package/dist/src/web-ui/app/components/plugins/compatibility.js +13 -0
  260. package/dist/src/web-ui/app/components/plugins/discovery-rendering.js +9 -1
  261. package/dist/src/web-ui/app/components/plugins/installation-compatibility.js +7 -0
  262. package/dist/src/web-ui/app/components/plugins/installation.js +2 -1
  263. package/dist/src/web-ui/app/components/plugins/rendering.js +3 -0
  264. package/dist/src/web-ui/app/components/reasoning-override-prompt.js +82 -0
  265. package/dist/src/web-ui/app/components/runtime-config-activation.js +22 -8
  266. package/dist/src/web-ui/app/components/runtime-setup/optional-steps.js +7 -4
  267. package/dist/src/web-ui/app/components/runtime-setup/plugins.js +3 -1
  268. package/dist/src/web-ui/app/components/runtime-setup/rendering.js +6 -4
  269. package/dist/src/web-ui/app/components/runtime-setup-guide.d.ts +1 -0
  270. package/dist/src/web-ui/app/components/schedules/details.js +3 -2
  271. package/dist/src/web-ui/app/components/schedules/form.js +10 -8
  272. package/dist/src/web-ui/app/components/schedules/workspace.js +23 -4
  273. package/dist/src/web-ui/app/components/session-sidebar-sections.js +2 -2
  274. package/dist/src/web-ui/app/components/spark-chat/handoff-actions.js +9 -3
  275. package/dist/src/web-ui/app/components/spark-chat/panel.js +1 -1
  276. package/dist/src/web-ui/app/components/spark-chat/placement.js +4 -7
  277. package/dist/src/web-ui/app/components/spark-chat/settings.js +8 -4
  278. package/dist/src/web-ui/app/components/system-host/home-widget-permission-preview.js +75 -0
  279. package/dist/src/web-ui/app/components/system-host/home-widget-summary.js +93 -0
  280. package/dist/src/web-ui/app/components/system-host/macos-permission-rendering.js +2 -2
  281. package/dist/src/web-ui/app/components/system-host/macos-permissions.js +2 -0
  282. package/dist/src/web-ui/app/components/system-host/native-windows-access.js +50 -0
  283. package/dist/src/web-ui/app/components/system-host/rendering.js +6 -3
  284. package/dist/src/web-ui/app/components/system-host/windows-store-setup.js +2 -2
  285. package/dist/src/web-ui/app/components/workspace-storage-notice.js +37 -0
  286. package/dist/src/web-ui/app/computer-access-feature.js +13 -1
  287. package/dist/src/web-ui/app/configuration-environment-refresh.js +27 -34
  288. package/dist/src/web-ui/app/configuration-feature.js +11 -1
  289. package/dist/src/web-ui/app/controllers/app-event-bindings.js +38 -105
  290. package/dist/src/web-ui/app/controllers/chat-request-controller.d.ts +28 -0
  291. package/dist/src/web-ui/app/controllers/chat-request-controller.js +34 -66
  292. package/dist/src/web-ui/app/controllers/composer-attachments-controller.d.ts +15 -40
  293. package/dist/src/web-ui/app/controllers/composer-attachments-controller.js +26 -69
  294. package/dist/src/web-ui/app/controllers/composer-draft-view.d.ts +27 -0
  295. package/dist/src/web-ui/app/controllers/composer-draft-view.js +48 -0
  296. package/dist/src/web-ui/app/controllers/composer-drafts.d.ts +55 -0
  297. package/dist/src/web-ui/app/controllers/composer-drafts.js +120 -0
  298. package/dist/src/web-ui/app/controllers/composer-feature.d.ts +65 -0
  299. package/dist/src/web-ui/app/controllers/composer-feature.js +124 -0
  300. package/dist/src/web-ui/app/controllers/composer-queue-controller.d.ts +33 -94
  301. package/dist/src/web-ui/app/controllers/composer-queue-controller.js +185 -251
  302. package/dist/src/web-ui/app/controllers/composer-submission-lifecycle.d.ts +48 -0
  303. package/dist/src/web-ui/app/controllers/composer-submission-lifecycle.js +97 -0
  304. package/dist/src/web-ui/app/controllers/composer-submit-controller.d.ts +30 -61
  305. package/dist/src/web-ui/app/controllers/composer-submit-controller.js +56 -138
  306. package/dist/src/web-ui/app/controllers/composer-surface-controller.js +6 -0
  307. package/dist/src/web-ui/app/controllers/composer-workspace-controller.d.ts +22 -40
  308. package/dist/src/web-ui/app/controllers/composer-workspace-controller.js +49 -165
  309. package/dist/src/web-ui/app/controllers/conversation-navigation-intent.js +15 -0
  310. package/dist/src/web-ui/app/controllers/conversation-request-hydration.js +20 -17
  311. package/dist/src/web-ui/app/controllers/conversation-session-controller.d.ts +1 -2
  312. package/dist/src/web-ui/app/controllers/conversation-session-controller.js +49 -22
  313. package/dist/src/web-ui/app/controllers/conversation-workspace-activation.js +27 -0
  314. package/dist/src/web-ui/app/controllers/daily-memory-review.js +15 -16
  315. package/dist/src/web-ui/app/controllers/environment-transition.js +126 -0
  316. package/dist/src/web-ui/app/controllers/environment-workspace-preparation.js +18 -0
  317. package/dist/src/web-ui/app/controllers/home-composer-feature.d.ts +14 -36
  318. package/dist/src/web-ui/app/controllers/home-composer-feature.js +17 -114
  319. package/dist/src/web-ui/app/controllers/home-conversation-activation.js +6 -8
  320. package/dist/src/web-ui/app/controllers/operations-controller.js +2 -1
  321. package/dist/src/web-ui/app/controllers/passive-learning-controller.js +56 -0
  322. package/dist/src/web-ui/app/controllers/projects-controller.d.ts +1 -1
  323. package/dist/src/web-ui/app/controllers/projects-controller.js +6 -1
  324. package/dist/src/web-ui/app/controllers/reasoning-mode-controller.js +174 -0
  325. package/dist/src/web-ui/app/controllers/runtime-selection-controller.d.ts +7 -0
  326. package/dist/src/web-ui/app/controllers/runtime-selection-controller.js +20 -155
  327. package/dist/src/web-ui/app/controllers/session-controller.js +33 -17
  328. package/dist/src/web-ui/app/controllers/session-pin-updates.js +14 -0
  329. package/dist/src/web-ui/app/controllers/session-sidebar-controller.js +12 -14
  330. package/dist/src/web-ui/app/controllers/spark-chat-sync.js +2 -2
  331. package/dist/src/web-ui/app/controllers/steer-controller.js +9 -7
  332. package/dist/src/web-ui/app/controllers/tool-permission-mode-controller.js +1 -1
  333. package/dist/src/web-ui/app/controllers/workspace-conversation-opener.js +34 -0
  334. package/dist/src/web-ui/app/dashboard-feature.js +12 -2
  335. package/dist/src/web-ui/app/lib/reasoning-controls.js +40 -0
  336. package/dist/src/web-ui/app/lib/session-composer-queue-ownership.js +58 -0
  337. package/dist/src/web-ui/app/lib/session-composer-queue.d.ts +12 -0
  338. package/dist/src/web-ui/app/lib/session-composer-queue.js +25 -6
  339. package/dist/src/web-ui/app/passive-learning-feature.js +18 -5
  340. package/dist/src/web-ui/app/schedules-feature.js +5 -3
  341. package/dist/src/web-ui/app/services/client-preferences.d.ts +18 -10
  342. package/dist/src/web-ui/app/services/client-preferences.js +25 -16
  343. package/dist/src/web-ui/app/services/home-guidance-preferences.js +13 -13
  344. package/dist/src/web-ui/app/services/reasoning-override.js +12 -0
  345. package/dist/src/web-ui/app/services/runtime-web-client/automations.js +10 -2
  346. package/dist/src/web-ui/app/services/runtime-web-client/memory.js +7 -2
  347. package/dist/src/web-ui/app/services/runtime-web-client/system-host.js +2 -0
  348. package/dist/src/web-ui/app/services/runtime-web-client.d.ts +2 -0
  349. package/dist/src/web-ui/app/services/runtime-web-client.js +2 -0
  350. package/dist/src/web-ui/app/services/server-composer-queue.js +32 -0
  351. package/dist/src/web-ui/app/services/session-sidebar-preferences.js +5 -5
  352. package/dist/src/web-ui/app/services/workspace-state-storage.js +116 -0
  353. package/dist/src/web-ui/app/services/workspace-state.js +27 -0
  354. package/dist/src/web-ui/app/spark-chat-conversation.js +34 -45
  355. package/dist/src/web-ui/app/spark-chat-feature.js +10 -4
  356. package/dist/src/web-ui/app/styles/21-composer-controls.css +16 -0
  357. package/dist/src/web-ui/app/styles/41-plugin-management.css +8 -0
  358. package/dist/src/web-ui/app/styles/42-model-plugin-permissions.css +1 -0
  359. package/dist/src/web-ui/app/styles/49-collection-consent.css +30 -0
  360. package/dist/src/web-ui/app/styles/64-workspace-storage.css +23 -0
  361. package/dist/src/web-ui/app/styles/95-home-widgets.css +109 -0
  362. package/dist/src/web-ui/app/styles.css +3 -0
  363. package/dist/src/web-ui/client-state/contracts.d.ts +15 -0
  364. package/dist/src/web-ui/client-state/contracts.js +13 -0
  365. package/dist/src/web-ui/client-state/preference-shapes.d.ts +2 -0
  366. package/dist/src/web-ui/client-state/preference-shapes.js +80 -0
  367. package/dist/src/web-ui/client-state/preferences.d.ts +3 -0
  368. package/dist/src/web-ui/client-state/preferences.js +84 -0
  369. package/dist/src/web-ui/client-state/queue.d.ts +3 -0
  370. package/dist/src/web-ui/client-state/queue.js +43 -0
  371. package/dist/src/web-ui/client-state/routes.d.ts +7 -0
  372. package/dist/src/web-ui/client-state/routes.js +58 -0
  373. package/dist/src/web-ui/client-state/store.d.ts +14 -0
  374. package/dist/src/web-ui/client-state/store.js +88 -0
  375. package/dist/src/web-ui/local-runtime/configuration-activation-source.js +2 -0
  376. package/dist/src/web-ui/local-runtime/http.js +11 -2
  377. package/dist/src/web-ui/local-runtime/model-context-capacity-error.d.ts +14 -0
  378. package/dist/src/web-ui/local-runtime/model-context-capacity-error.js +28 -0
  379. package/dist/src/web-ui/local-runtime/model-setup-context-window.d.ts +15 -0
  380. package/dist/src/web-ui/local-runtime/model-setup-context-window.js +25 -0
  381. package/dist/src/web-ui/local-runtime/model-setup-routes.js +2 -0
  382. package/dist/src/web-ui/local-runtime/model-setup-service.js +5 -2
  383. package/dist/src/web-ui/local-runtime/model-setup-validation.d.ts +1 -0
  384. package/dist/src/web-ui/local-runtime/model-setup-validation.js +14 -7
  385. package/dist/src/web-ui/local-runtime/request-body-error.d.ts +11 -0
  386. package/dist/src/web-ui/local-runtime/request-body-error.js +14 -0
  387. package/dist/src/web-ui/local-runtime/request-control-observation.js +2 -2
  388. package/dist/src/web-ui/local-runtime/request-execution.js +18 -18
  389. package/dist/src/web-ui/local-runtime/runtime-setup-connection-edit.d.ts +2 -0
  390. package/dist/src/web-ui/local-runtime/runtime-setup-connection-edit.js +35 -22
  391. package/dist/src/web-ui/local-runtime/runtime-setup-context-window.d.ts +2 -9
  392. package/dist/src/web-ui/local-runtime/runtime-setup-context-window.js +4 -27
  393. package/dist/src/web-ui/local-runtime/runtime-setup-credentials.d.ts +15 -1
  394. package/dist/src/web-ui/local-runtime/runtime-setup-credentials.js +30 -11
  395. package/dist/src/web-ui/local-runtime/runtime-setup-edit-files.d.ts +20 -0
  396. package/dist/src/web-ui/local-runtime/runtime-setup-edit-files.js +104 -0
  397. package/dist/src/web-ui/local-runtime/runtime-setup-edit-journal.d.ts +29 -0
  398. package/dist/src/web-ui/local-runtime/runtime-setup-edit-journal.js +151 -0
  399. package/dist/src/web-ui/local-runtime/runtime-setup-edit-recovery.d.ts +7 -0
  400. package/dist/src/web-ui/local-runtime/runtime-setup-edit-recovery.js +87 -0
  401. package/dist/src/web-ui/local-runtime/runtime-setup-edit-transaction.d.ts +3 -0
  402. package/dist/src/web-ui/local-runtime/runtime-setup-edit-transaction.js +37 -0
  403. package/dist/src/web-ui/local-runtime/runtime-setup-service.js +4 -0
  404. package/dist/src/web-ui/local-runtime-backend.js +14 -0
  405. package/dist/src/web-ui/plugin-management-catalog.d.ts +3 -1
  406. package/dist/src/web-ui/plugin-management-catalog.js +3 -1
  407. package/dist/src/web-ui/plugin-management-service.d.ts +1 -0
  408. package/dist/src/web-ui/plugin-removal-service.d.ts +1 -0
  409. package/dist/src/web-ui/server-readiness.d.ts +3 -0
  410. package/dist/src/web-ui/server-readiness.js +36 -0
  411. package/dist/src/web-ui/server.d.ts +2 -0
  412. package/dist/src/web-ui/server.js +23 -1
  413. package/dist/src/web-ui/system-host-service.js +13 -2
  414. package/dist/src/web-ui/system-host-setup/collection-consent-route.d.ts +3 -0
  415. package/dist/src/web-ui/system-host-setup/collection-consent-route.js +30 -0
  416. package/docs/installation.md +44 -5
  417. package/docs/plugins.md +174 -28
  418. package/docs/tool-execution-result-evidence-contract.md +57 -0
  419. package/docs/windows-companion-store.md +5 -0
  420. package/package.json +4 -2
  421. package/plugins/capability-brief/plugin.json +5 -1
  422. package/plugins/code-outline/README.md +20 -0
  423. package/plugins/code-outline/plugin.json +2 -1
  424. package/plugins/code-outline/source/index.ts +16 -20
  425. package/plugins/code-outline/source/read-failure.ts +40 -0
  426. package/plugins/code-outline/src/index.cjs +614 -29
  427. package/plugins/document-reader/README.md +33 -0
  428. package/plugins/document-reader/plugin.json +2 -1
  429. package/plugins/document-reader/source/pdf-contract.ts +57 -0
  430. package/plugins/document-reader/source/pdf-parser.ts +139 -0
  431. package/plugins/document-reader/source/pdf-process-main.ts +56 -0
  432. package/plugins/document-reader/source/pdf-process.ts +207 -0
  433. package/plugins/document-reader/source/pdf-result.ts +79 -0
  434. package/plugins/document-reader/source/pdf-worker.ts +39 -303
  435. package/plugins/document-reader/source/pdf.ts +4 -1
  436. package/plugins/document-reader/source/read-failure.ts +37 -0
  437. package/plugins/document-reader/source/reader.ts +3 -19
  438. package/plugins/document-reader/src/index.cjs +995 -211
  439. package/plugins/exec/README.md +19 -0
  440. package/plugins/exec/plugin.json +4 -3
  441. package/plugins/exec/skills/exec_skill/SKILL.md +3 -2
  442. package/plugins/exec/source/filesystem-file-observer.ts +98 -0
  443. package/plugins/exec/source/filesystem-observer.ts +8 -79
  444. package/plugins/exec/source/output-files.ts +12 -6
  445. package/plugins/exec/source/paths.ts +3 -1
  446. package/plugins/exec/source/process-manager.ts +8 -24
  447. package/plugins/exec/source/shell-platform.ts +19 -3
  448. package/plugins/exec/source/shell-process.ts +55 -0
  449. package/plugins/exec/source/windows-job-source.ts +1 -0
  450. package/plugins/exec/source/windows-shell-bootstrap.ts +20 -0
  451. package/plugins/exec/src/index.cjs +252 -96
  452. package/plugins/filesystem/README.md +65 -0
  453. package/plugins/filesystem/plugin.json +7 -3
  454. package/plugins/filesystem/source/atomic-write.ts +2 -0
  455. package/plugins/filesystem/source/bounded-io.ts +80 -306
  456. package/plugins/filesystem/source/directory-sample.ts +2 -0
  457. package/plugins/filesystem/source/errors.ts +14 -0
  458. package/plugins/filesystem/source/file-observation.ts +151 -0
  459. package/plugins/filesystem/source/file-version.ts +41 -0
  460. package/plugins/filesystem/source/index.ts +6 -0
  461. package/plugins/filesystem/source/mutation-coordinator.ts +1 -0
  462. package/plugins/filesystem/source/windows/authority-script.ts +1 -0
  463. package/plugins/filesystem/source/windows/native-script.ts +1 -0
  464. package/plugins/filesystem/source/windows/operations.ts +197 -0
  465. package/plugins/filesystem/source/windows/process.ts +214 -0
  466. package/plugins/filesystem/source/windows/publication-script.ts +29 -0
  467. package/plugins/filesystem/source/windows/read-script.ts +63 -0
  468. package/plugins/filesystem/source/windows/request-availability.ts +67 -0
  469. package/plugins/filesystem/source/windows/source.ts +42 -0
  470. package/plugins/filesystem/source/windows/storage-script.ts +11 -0
  471. package/plugins/filesystem/source/windows/streams-script.ts +24 -0
  472. package/plugins/filesystem/source/windows/write-script.ts +86 -0
  473. package/plugins/filesystem/src/index.cjs +1208 -322
  474. package/plugins/json-inspector/README.md +18 -0
  475. package/plugins/json-inspector/plugin.json +2 -1
  476. package/plugins/json-inspector/source/index.ts +16 -19
  477. package/plugins/json-inspector/source/read-failure.ts +42 -0
  478. package/plugins/json-inspector/src/index.cjs +612 -27
  479. package/plugins/local-search/README.md +29 -0
  480. package/plugins/local-search/plugin.json +2 -1
  481. package/plugins/local-search/source/errors.ts +2 -0
  482. package/plugins/local-search/source/paths.ts +3 -0
  483. package/plugins/local-search/source/ripgrep-process.ts +31 -5
  484. package/plugins/local-search/source/ripgrep.ts +3 -3
  485. package/plugins/local-search/source/windows-authority.ts +99 -0
  486. package/plugins/local-search/source/windows-search-lease.ts +49 -0
  487. package/plugins/local-search/source/windows-search-process.ts +91 -0
  488. package/plugins/local-search/source/windows-search-script.ts +52 -0
  489. package/plugins/local-search/src/index.cjs +595 -26
  490. package/plugins/memory/plugin.json +5 -1
  491. package/plugins/memory/source/lock-directory-claim.ts +56 -0
  492. package/plugins/memory/source/lock-owner-file.ts +71 -0
  493. package/plugins/memory/source/lock-path-observation.ts +26 -0
  494. package/plugins/memory/source/prepared-memory-replacement.ts +40 -0
  495. package/plugins/memory/source/store-lock.ts +12 -7
  496. package/plugins/memory/source/store.ts +3 -2
  497. package/plugins/memory/src/index.cjs +174 -25
  498. package/plugins/project-orientation/README.md +23 -0
  499. package/plugins/project-orientation/plugin.json +2 -1
  500. package/plugins/project-orientation/source/index.ts +12 -9
  501. package/plugins/project-orientation/source/inspection-failure.ts +70 -0
  502. package/plugins/project-orientation/source/manifest-summary.ts +9 -2
  503. package/plugins/project-orientation/source/tree.ts +6 -0
  504. package/plugins/project-orientation/src/index.cjs +647 -31
  505. package/plugins/system/README.md +51 -15
  506. package/plugins/system/plugin.json +6 -2
  507. package/plugins/system/skills/system_actions/SKILL.md +1 -1
  508. package/plugins/system/source/command-working-directory.ts +47 -0
  509. package/plugins/system/source/computer/handlers.ts +13 -9
  510. package/plugins/system/source/computer/observation-result.ts +10 -5
  511. package/plugins/system/source/computer/request-computers.ts +10 -3
  512. package/plugins/system/source/computer/request-modules.ts +3 -6
  513. package/plugins/system/source/computer/runtime-platform.ts +18 -0
  514. package/plugins/system/source/host-dispatch.ts +18 -2
  515. package/plugins/system/source/index.ts +5 -3
  516. package/plugins/system/source/local-command-output-retention.ts +16 -0
  517. package/plugins/system/source/local-command-output.ts +16 -8
  518. package/plugins/system/source/request-system-modules.ts +12 -2
  519. package/plugins/system/source/request-target-snapshot.ts +2 -1
  520. package/plugins/system/source/security/desktop-result.ts +177 -0
  521. package/plugins/system/source/security/observed-error.ts +10 -0
  522. package/plugins/system/source/security/secret-text.ts +118 -0
  523. package/plugins/system/source/security/system-results.ts +62 -0
  524. package/plugins/system/source/security/windows-output-directory.ts +82 -0
  525. package/plugins/system/src/index.cjs +837 -151
  526. package/plugins/system-probe/plugin.json +9 -3
  527. package/plugins/system-probe/source/disk-path.ts +8 -0
  528. package/plugins/system-probe/source/index.ts +10 -5
  529. package/plugins/system-probe/source/machine-load.ts +33 -0
  530. package/plugins/system-probe/source/metrics.ts +6 -8
  531. package/plugins/system-probe/src/index.cjs +49 -16
  532. package/plugins/web/plugin.json +5 -1
@@ -0,0 +1,137 @@
1
+ import { createHomeWidgetCard } from "./widget-card.js";
2
+ import { createHomeWidgetDialog } from "./widget-dialog.js";
3
+
4
+ export const HOME_WIDGET_MEDIA_QUERY = "(max-width: 1440px)";
5
+ const widgetOrder = ["learning", "conversations", "approvals", "activity", "automations", "computer"];
6
+
7
+ /** Home-only presentation; component owners keep their data, DOM and actions. */
8
+ export function createCompactHomeLayout({
9
+ root, content, homeRegion = root.parentElement,
10
+ viewport = root.ownerDocument.defaultView,
11
+ }) {
12
+ const media = viewport?.matchMedia?.(HOME_WIDGET_MEDIA_QUERY);
13
+ const entries = new Map();
14
+ let enabled = false;
15
+ let workspace = "home";
16
+ let compact = false;
17
+ let grid;
18
+ let dialog;
19
+
20
+ function canShowCompactHome() {
21
+ if (!enabled) return false;
22
+ return media?.matches === true;
23
+ }
24
+
25
+ function canOpenWidget(entry) {
26
+ if (!compact || workspace !== "home") return false;
27
+ return Boolean(entry?.isAvailable());
28
+ }
29
+
30
+ function ensureSurface() {
31
+ if (grid || !media) return;
32
+ grid = root.ownerDocument.createElement("div");
33
+ grid.className = "home-widget-grid";
34
+ grid.setAttribute("aria-label", "Home overview");
35
+ grid.hidden = true;
36
+ content.appendChild(grid);
37
+ dialog = createHomeWidgetDialog({
38
+ root,
39
+ onClosed(entry, restoreFocus) {
40
+ if (restoreFocus && canOpenWidget(entry)) entry.button.focus({ preventScroll: true });
41
+ },
42
+ });
43
+ }
44
+
45
+ function open(id) {
46
+ const entry = entries.get(id);
47
+ if (!canOpenWidget(entry)) return false;
48
+ dialog.open(entry);
49
+ entry.onOpen?.();
50
+ dialog.refresh();
51
+ return true;
52
+ }
53
+
54
+ function refresh() {
55
+ for (const entry of entries.values()) {
56
+ const available = entry.isAvailable();
57
+ entry.button.hidden = !available;
58
+ if (!available && dialog.isExpanded(entry.element)) dialog.close({ restoreFocus: false });
59
+ const summary = entry.getSummary();
60
+ entry.render(summary);
61
+ }
62
+ dialog?.refresh();
63
+ }
64
+
65
+ function reconcileViewport() {
66
+ const next = canShowCompactHome();
67
+ if (next === compact) return;
68
+ const focused = root.ownerDocument.activeElement;
69
+ const focusedEntry = [...entries.values()].find((entry) => entry.element.contains(focused) || entry.button === focused);
70
+ const expandedEntry = [...entries.values()].find((entry) => dialog?.isExpanded(entry.element));
71
+ dialog?.close({ restoreFocus: false });
72
+ compact = next;
73
+ homeRegion?.classList.toggle("home-widgets-compact", compact);
74
+ if (grid) grid.hidden = !compact;
75
+ refresh();
76
+ if (!enabled || workspace !== "home") return;
77
+ if (compact && focusedEntry?.isAvailable()) {
78
+ focusedEntry.button.focus({ preventScroll: true });
79
+ return;
80
+ }
81
+ if (compact) return;
82
+ if (focusedEntry?.element.contains(focused) && !focusedEntry.element.hidden) {
83
+ focused.focus({ preventScroll: true });
84
+ return;
85
+ }
86
+ const returnEntry = focusedEntry || expandedEntry;
87
+ if (returnEntry) focusDesktopContent(returnEntry);
88
+ }
89
+
90
+ function focusDesktopContent(entry) {
91
+ const controls = [...entry.element.querySelectorAll("button, summary, input, textarea")];
92
+ const control = controls.find((node) => !node.disabled && !node.closest("[hidden]"));
93
+ const target = control || root.querySelector("textarea");
94
+ target?.focus({ preventScroll: true });
95
+ }
96
+
97
+ function register({ id, label, icon = "neutral", element, getSummary,
98
+ isAvailable = () => true, emptyMessage, onOpen, getReturnParent }) {
99
+ if (!media || !element) return () => {};
100
+ ensureSurface();
101
+ const { button, render } = createHomeWidgetCard({ documentRoot: root.ownerDocument, id, label, icon });
102
+ const entry = { id, label, element, getSummary, isAvailable, emptyMessage, onOpen, getReturnParent, button, render };
103
+ entries.set(id, entry);
104
+ element.classList.add("home-widget-source");
105
+ const position = widgetOrder.indexOf(id);
106
+ const following = [...entries.values()].find((candidate) => widgetOrder.indexOf(candidate.id) > position);
107
+ grid.insertBefore(button, following?.button || null);
108
+ button.addEventListener("click", () => open(id));
109
+ refresh();
110
+ return () => {
111
+ if (dialog.isExpanded(element)) dialog.close({ restoreFocus: false });
112
+ element.classList.remove("home-widget-source");
113
+ button.remove();
114
+ entries.delete(id);
115
+ };
116
+ }
117
+
118
+ media?.addEventListener("change", reconcileViewport);
119
+ return {
120
+ register, refresh, open,
121
+ isExpanded: (element) => dialog?.isExpanded(element) === true,
122
+ close: (options) => dialog?.close(options),
123
+ setEnabled(value) { enabled = value; reconcileViewport(); },
124
+ setWorkspace(value) {
125
+ workspace = value;
126
+ if (value !== "home") dialog?.close({ restoreFocus: false });
127
+ },
128
+ dispose() {
129
+ dialog?.dispose();
130
+ for (const entry of entries.values()) entry.element.classList.remove("home-widget-source");
131
+ entries.clear();
132
+ grid?.remove();
133
+ homeRegion?.classList.remove("home-widgets-compact");
134
+ media?.removeEventListener("change", reconcileViewport);
135
+ },
136
+ };
137
+ }
@@ -1,4 +1,9 @@
1
1
  const paths = {
2
+ unread: '<rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 6 9 7 9-7"/>',
3
+ collecting: '<path d="M2 12h5l3-8 4 16 3-8h5"/>',
4
+ paused: '<path d="M9 5v14M15 5v14"/>',
5
+ unknown: '<circle cx="12" cy="12" r="9"/><path d="M9 9a3 3 0 0 1 6 0c0 2-3 2-3 4m0 4h.01"/>',
6
+ computer: '<rect x="5" y="3" width="14" height="13" rx="2"/><path d="M5 16 2 21h20l-3-5"/>',
2
7
  upload: '<path d="M12 16V4m-4 4 4-4 4 4"/><path d="M4 16v4h16v-4"/>',
3
8
  job: '<rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 11h18m-9 3v4m-2-2h4"/>',
4
9
  conversations:
@@ -0,0 +1,85 @@
1
+ import { escapeHtml } from "../../lib/text-format.js";
2
+ import { dashboardIcon } from "./icons.js";
3
+
4
+ const compactLabels = { conversations: "Conversations", approvals: "Approvals" };
5
+
6
+ function symbolMarkup(indicator) {
7
+ if (!indicator) return "";
8
+ const label = escapeHtml(indicator.label || "");
9
+ const value = indicator.value === undefined ? "" : `<span aria-hidden="true">${escapeHtml(String(indicator.value))}</span>`;
10
+ const glyph = indicator.icon ? dashboardIcon(indicator.icon) : "";
11
+ return `<span class="home-widget-symbol" data-tone="${escapeHtml(indicator.tone || "neutral")}" role="img" aria-label="${label}" title="${label}">${glyph}${value}</span>`;
12
+ }
13
+
14
+ function copyMarkup(title, detail = "") {
15
+ return `<span class="home-widget-copy"><span class="home-widget-item-title" dir="auto" title="${escapeHtml(title)}">${escapeHtml(title)}</span><span class="home-widget-meta" dir="auto" title="${escapeHtml(detail)}">${escapeHtml(detail)}</span></span>`;
16
+ }
17
+
18
+ function rowsMarkup(preview) {
19
+ return preview.items.map((item) => `<span class="home-widget-row">${copyMarkup(item.title, item.detail)}${symbolMarkup(item.indicator)}</span>`).join("");
20
+ }
21
+
22
+ function metricsMarkup(preview) {
23
+ return `<span class="home-widget-metrics">${preview.items.map((item) => `<span class="home-widget-metric">${symbolMarkup(item.indicator)}<span>${escapeHtml(item.label)}</span></span>`).join("")}</span>`;
24
+ }
25
+
26
+ function computerMarkup(preview) {
27
+ const checks = preview.items.map((item) => `<span class="home-widget-check"><span>${escapeHtml(item.label)}</span>${symbolMarkup(item.indicator)}</span>`).join("");
28
+ return `<span class="home-widget-computer"><span class="home-widget-device"><span class="home-widget-item-title" dir="auto">${escapeHtml(preview.title)}</span><span class="home-widget-meta">${escapeHtml(preview.detail || "")}</span></span><span class="home-widget-checks">${checks}</span></span>`;
29
+ }
30
+
31
+ function previewMarkup(summary) {
32
+ const preview = summary.preview;
33
+ if (preview?.kind === "rows") return rowsMarkup(preview);
34
+ if (preview?.kind === "metrics") return metricsMarkup(preview);
35
+ if (preview?.kind === "computer") return computerMarkup(preview);
36
+ if (preview?.kind === "automation")
37
+ return `<span class="home-widget-automation">${symbolMarkup(preview.indicator)}${copyMarkup(preview.title, preview.detail)}</span>`;
38
+ return `<span class="home-widget-fallback"><span class="home-widget-title" dir="auto">${escapeHtml(summary.title || "")}</span><span class="home-widget-detail" dir="auto">${escapeHtml(summary.detail || "")}</span><span class="home-widget-status" dir="auto">${escapeHtml(summary.status || "")}</span></span>`;
39
+ }
40
+
41
+ function previewDescriptions(summary) {
42
+ const preview = summary.preview;
43
+ if (!preview) return [];
44
+ const descriptions = [preview.title, preview.detail];
45
+ descriptions.push(...(preview.items || []).map((item) =>
46
+ [item.title, item.label, item.detail, item.indicator?.label].filter(Boolean).join(": "),
47
+ ));
48
+ if (preview.indicator) descriptions.push(preview.indicator.label);
49
+ return descriptions.filter(Boolean);
50
+ }
51
+
52
+ /** A stable button; only the read-only preview changes, never the live component. */
53
+ export function createHomeWidgetCard({ documentRoot, id, label, icon }) {
54
+ const button = documentRoot.createElement("button");
55
+ button.type = "button";
56
+ button.className = "home-widget";
57
+ button.dataset.homeWidget = id;
58
+ button.setAttribute("aria-haspopup", "dialog");
59
+ const glyph = id === "learning" ? '<img src="/spark-mascot.svg" alt="" />' : dashboardIcon(icon);
60
+ button.innerHTML = `<span class="home-widget-heading"><span class="home-widget-heading-icon">${glyph}</span><span data-widget-label></span><span class="home-widget-badge" hidden></span><span class="home-widget-arrow" aria-hidden="true">›</span></span><span class="home-widget-preview"></span>`;
61
+ button.querySelector("[data-widget-label]").textContent = compactLabels[id] || label;
62
+ const body = button.querySelector(".home-widget-preview");
63
+ const badge = button.querySelector(".home-widget-badge");
64
+ let previousMarkup;
65
+ let previousBadge;
66
+ function render(summary) {
67
+ const markup = previewMarkup(summary);
68
+ if (markup !== previousMarkup) {
69
+ body.innerHTML = markup;
70
+ previousMarkup = markup;
71
+ }
72
+ const badgeMarkup = symbolMarkup(summary.preview?.badge);
73
+ if (badgeMarkup !== previousBadge) {
74
+ badge.innerHTML = badgeMarkup;
75
+ previousBadge = badgeMarkup;
76
+ }
77
+ badge.hidden = !badgeMarkup;
78
+ button.dataset.tone = summary.tone || "neutral";
79
+ button.setAttribute("aria-label", `${label} — open details`);
80
+ const description = [...new Set([summary.title, summary.detail, summary.status, ...previewDescriptions(summary)].filter(Boolean))].join(". ");
81
+ button.setAttribute("aria-description", description);
82
+ button.setAttribute("title", description);
83
+ }
84
+ return { button, render };
85
+ }
@@ -0,0 +1,83 @@
1
+ /** The original live panel is borrowed temporarily, never rendered a second time. */
2
+ export function createHomeWidgetDialog({ root, onClosed }) {
3
+ const documentRoot = root.ownerDocument;
4
+ const dialog = documentRoot.createElement("dialog");
5
+ dialog.className = "home-widget-dialog";
6
+ dialog.setAttribute("aria-labelledby", "home-widget-detail-title");
7
+ dialog.innerHTML = `<header class="home-widget-dialog-header">
8
+ <h2 id="home-widget-detail-title"></h2>
9
+ <button type="button" class="home-text-button" data-home-widget-close aria-label="Close details">Close</button>
10
+ </header><div class="home-widget-dialog-body"></div>`;
11
+ root.appendChild(dialog);
12
+ const title = dialog.querySelector("h2");
13
+ const body = dialog.querySelector(".home-widget-dialog-body");
14
+ const closeButton = dialog.querySelector("[data-home-widget-close]");
15
+ const empty = documentRoot.createElement("p");
16
+ empty.className = "home-panel-state";
17
+ empty.setAttribute("role", "status");
18
+ let borrowed = null;
19
+
20
+ function restorePanel() {
21
+ if (!borrowed) return null;
22
+ const previous = borrowed;
23
+ borrowed = null;
24
+ previous.entry.element.classList.remove("home-widget-expanded");
25
+ const parent = previous.entry.getReturnParent?.() || previous.parent;
26
+ const next = previous.nextSibling;
27
+ const anchor = next?.parentNode === parent ? next : null;
28
+ parent.insertBefore(previous.entry.element, anchor);
29
+ empty.remove();
30
+ return previous.entry;
31
+ }
32
+
33
+ function close({ restoreFocus = true } = {}) {
34
+ const entry = restorePanel();
35
+ if (dialog.open) dialog.close();
36
+ if (entry) onClosed(entry, restoreFocus);
37
+ }
38
+
39
+ function refresh() {
40
+ if (!borrowed) return;
41
+ const summary = borrowed.entry.getSummary();
42
+ empty.textContent = borrowed.entry.emptyMessage || [summary.title, summary.detail].filter(Boolean).join(" · ");
43
+ empty.hidden = !borrowed.entry.element.hidden;
44
+ }
45
+
46
+ function open(entry) {
47
+ if (borrowed?.entry === entry) return;
48
+ close({ restoreFocus: false });
49
+ const element = entry.element;
50
+ borrowed = { entry, parent: element.parentNode, nextSibling: element.nextSibling };
51
+ title.textContent = entry.label;
52
+ element.classList.add("home-widget-expanded");
53
+ body.appendChild(element);
54
+ body.appendChild(empty);
55
+ refresh();
56
+ body.scrollTop = 0;
57
+ dialog.showModal();
58
+ closeButton.focus({ preventScroll: true });
59
+ }
60
+
61
+ closeButton.addEventListener("click", () => close());
62
+ dialog.addEventListener("cancel", (event) => {
63
+ event.preventDefault();
64
+ close();
65
+ });
66
+ dialog.addEventListener("close", () => {
67
+ if (dialog.open) return;
68
+ const entry = restorePanel();
69
+ if (entry) onClosed(entry, true);
70
+ });
71
+ dialog.addEventListener("click", (event) => {
72
+ if (event.target !== dialog) return;
73
+ const bounds = dialog.getBoundingClientRect();
74
+ const inside = event.clientX >= bounds.left && event.clientX <= bounds.right &&
75
+ event.clientY >= bounds.top && event.clientY <= bounds.bottom;
76
+ if (!inside) close();
77
+ });
78
+ return {
79
+ open, close, refresh,
80
+ isExpanded: (element) => borrowed?.entry.element === element,
81
+ dispose() { close({ restoreFocus: false }); dialog.remove(); },
82
+ };
83
+ }
@@ -0,0 +1,155 @@
1
+ import {
2
+ dashboardTimePresentation,
3
+ projectDashboardActivity,
4
+ projectDashboardConversations,
5
+ } from "../../lib/dashboard-presentation.js";
6
+ import { coWorkerAgentState } from "../passive-learning/agent-state.js";
7
+ import { learningWidgetPreview } from "../passive-learning/home-widget-preview.js";
8
+ import { formatToolName } from "../../lib/event-presentation.js";
9
+ import { projectToolActivityEvent } from "../../lib/tool-activity-event.js";
10
+ import { textOf } from "../../lib/text-format.js";
11
+
12
+ function learningSnapshotMatchesEnvironment(snapshot, learning) {
13
+ if (!snapshot.environmentId || !learning?.environmentId) return true;
14
+ return snapshot.environmentId === learning.environmentId;
15
+ }
16
+
17
+ function learningSummary(snapshot, learning) {
18
+ const current = learningSnapshotMatchesEnvironment(snapshot, learning) ? learning : null;
19
+ if (current?.statusError)
20
+ return { title: "Connection interrupted", detail: "Open Spark to check its current activity.", status: "Status unavailable", tone: "attention" };
21
+ const presentation = coWorkerAgentState(current || {});
22
+ const tones = { attention: "attention", collecting: "active", reviewing: "active" };
23
+ return {
24
+ title: presentation.title,
25
+ detail: presentation.description,
26
+ status: presentation.label,
27
+ tone: tones[presentation.mode] || "neutral",
28
+ preview: learningWidgetPreview(current?.status),
29
+ };
30
+ }
31
+
32
+ function conversationsSummary(snapshot) {
33
+ const overview = snapshot.sessionOverview;
34
+ const projection = projectDashboardConversations(overview?.sessions ?? snapshot.sessions ?? [], 2);
35
+ const latest = projection.recentConversations[0];
36
+ const title = latest?.title || "A fresh start.";
37
+ if (snapshot.sessionsError)
38
+ return { title: latest?.title || "Conversations unavailable", detail: "Recent conversations could not be refreshed.", status: "Status unavailable", tone: "attention" };
39
+ if (snapshot.loadingSessions)
40
+ return { title: latest?.title || "Loading conversations…", detail: "", status: "Loading", tone: "neutral" };
41
+ const unavailable = overview?.hasUnavailableReadState ?? projection.hasUnavailableReadState;
42
+ if (unavailable)
43
+ return { title, detail: "Unread status unavailable", status: "Open chats", tone: "attention" };
44
+ const unread = overview?.unreadCount ?? projection.unreadCount;
45
+ const preview = conversationsPreview(projection, unread);
46
+ if (unread > 0)
47
+ return { title, detail: latest ? "Latest conversation" : "Open chats to read replies.", status: `${unread} unread ${unread === 1 ? "message" : "messages"}`, tone: "active", preview };
48
+ return { title, detail: latest ? "Latest conversation" : "Your conversations will appear here.", status: latest ? "No unread messages" : "No conversations yet", tone: "neutral", preview };
49
+ }
50
+
51
+ function activitySummary(snapshot) {
52
+ if (snapshot.supportsSchedules === false)
53
+ return { title: "Jobs unavailable", detail: "Choose a Runtime environment to use scheduled jobs.", status: "Unavailable", tone: "neutral" };
54
+ const latest = projectDashboardActivity(snapshot.runs ?? [], 1)[0];
55
+ if (snapshot.activityError)
56
+ return { title: latest?.title || "Activity unavailable", detail: "Recent activity could not be refreshed.", status: "Status unavailable", tone: "attention" };
57
+ if (snapshot.loadingActivity)
58
+ return { title: latest?.title || "Loading activity…", detail: "", status: "Loading", tone: "neutral" };
59
+ if (!latest)
60
+ return { title: "No activity yet", detail: "Try a ready-to-use job.", status: "View jobs", tone: "neutral" };
61
+ return { title: latest.title, detail: "Latest scheduled run", status: latest.statusLabel, tone: latest.tone, preview: activityPreview(snapshot.runs) };
62
+ }
63
+
64
+ function automationsSummary(snapshot) {
65
+ const active = snapshot.activeAutomations ?? [];
66
+ if (snapshot.automationStatusUnavailable)
67
+ return { title: "Automation status unavailable", detail: active[0]?.title || "Open ABot Studio to check runs.", status: active.length ? `${active.length} last seen in progress` : "Status unavailable", tone: "attention" };
68
+ if (!active.length)
69
+ return { title: "No automations in progress", detail: "ABot Studio", status: "No active runs", tone: "neutral" };
70
+ return {
71
+ title: `${active.length} ${active.length === 1 ? "automation" : "automations"} in progress`,
72
+ detail: active[0].title || "ABot Automation",
73
+ status: "View live timeline",
74
+ tone: "active",
75
+ preview: {
76
+ kind: "automation", title: active[0].title || "ABot Automation", detail: "ABot Studio",
77
+ indicator: { icon: "active", label: `${active.length} ${active.length === 1 ? "automation" : "automations"} in progress`, value: active.length, tone: "active" },
78
+ },
79
+ };
80
+ }
81
+
82
+ function approvalsSummary(snapshot) {
83
+ if (snapshot.supportsToolApprovals === false)
84
+ return { title: "Home approvals unavailable", detail: "Open the conversation to review pending actions.", status: "Unavailable", tone: "neutral" };
85
+ const count = snapshot.approvals?.length || 0;
86
+ const pendingTitle = `${count} ${count === 1 ? "action" : "actions"} waiting`;
87
+ if (snapshot.approvalDecisionError)
88
+ return { title: count ? pendingTitle : "Approval decision failed", detail: "Open approvals to review the failed decision.", status: "Needs attention", tone: "attention" };
89
+ if (snapshot.approvalsError)
90
+ return { title: count ? pendingTitle : "Approvals unavailable", detail: "Pending actions could not be refreshed.", status: "Status unavailable", tone: "attention" };
91
+ if (snapshot.loadingApprovals)
92
+ return { title: count ? pendingTitle : "Checking approvals…", detail: "", status: "Loading", tone: "neutral" };
93
+ if (count)
94
+ return { title: pendingTitle, detail: "Review the action before allowing it.", status: "Needs review", tone: "attention", preview: approvalsPreview(snapshot) };
95
+ return { title: "No pending approvals", detail: "Actions waiting for your decision appear here.", status: "Nothing waiting", tone: "neutral" };
96
+ }
97
+
98
+ function conversationIndicator(session) {
99
+ if (session.readStateUnavailable)
100
+ return { icon: "unknown", label: "Unread status unavailable", tone: "attention" };
101
+ if (!session.unreadCount) return null;
102
+ return { icon: "unread", label: `${session.unreadCount} unread ${session.unreadCount === 1 ? "message" : "messages"}`, value: session.unreadCount, tone: "active" };
103
+ }
104
+
105
+ function conversationsPreview(projection, unread) {
106
+ if (!projection.recentConversations.length) return undefined;
107
+ return {
108
+ kind: "rows",
109
+ badge: unread > 0 ? { icon: "unread", label: `${unread} unread ${unread === 1 ? "message" : "messages"} in all conversations`, value: unread, tone: "active" } : undefined,
110
+ items: projection.recentConversations.map((session) => ({
111
+ title: session.title,
112
+ detail: dashboardTimePresentation(session.updatedAt)?.label || "",
113
+ indicator: conversationIndicator(session),
114
+ })),
115
+ };
116
+ }
117
+
118
+ function activityPreview(runs) {
119
+ return {
120
+ kind: "rows",
121
+ items: projectDashboardActivity(runs, 2).map((run) => ({
122
+ title: run.title,
123
+ detail: dashboardTimePresentation(run.timestamp)?.label || "",
124
+ indicator: { icon: run.tone, label: run.statusLabel, tone: run.tone },
125
+ })),
126
+ };
127
+ }
128
+
129
+ function approvalsPreview(snapshot) {
130
+ return {
131
+ kind: "rows",
132
+ badge: { value: snapshot.approvals.length, label: `${snapshot.approvals.length} pending ${snapshot.approvals.length === 1 ? "approval" : "approvals"}`, tone: "attention" },
133
+ items: snapshot.approvals.slice(0, 2).map((approval) => {
134
+ const event = approval.event || {};
135
+ const activity = projectToolActivityEvent(event);
136
+ const conversation = (snapshot.sessions || []).find((session) => session.id === approval.sessionId);
137
+ return {
138
+ title: formatToolName(event.tool) || "Tool",
139
+ detail: activity?.target || textOf(conversation?.displayName || conversation?.title),
140
+ indicator: { icon: "active", label: "Awaiting approval", tone: "attention" },
141
+ };
142
+ }),
143
+ };
144
+ }
145
+
146
+ /** Read-only presentation of the existing Home owners; no new reads or state. */
147
+ export function dashboardWidgetSummaries(snapshot = {}, learningSnapshot) {
148
+ return {
149
+ learning: learningSummary(snapshot, learningSnapshot),
150
+ conversations: conversationsSummary(snapshot),
151
+ activity: activitySummary(snapshot),
152
+ automations: automationsSummary(snapshot),
153
+ approvals: approvalsSummary(snapshot),
154
+ };
155
+ }
@@ -3,6 +3,8 @@ import { getDashboardJobTemplates } from "../../lib/dashboard-job-templates.js";
3
3
  import { renderDashboardActivity } from "./activity.js";
4
4
  import { renderDashboardConversations } from "./recent-conversations.js";
5
5
  import { renderDashboardAutomations } from "./automations.js";
6
+ import { createCompactHomeLayout } from "./compact-layout.js";
7
+ import { dashboardWidgetSummaries } from "./widget-summaries.js";
6
8
  import {
7
9
  hasPendingDashboardApprovals,
8
10
  renderDashboardApprovals,
@@ -37,7 +39,26 @@ export function createDashboardWorkspace({ root, actions, passiveLearning }) {
37
39
  const setupHost = root.querySelector("[data-dashboard-setup]");
38
40
  const learningPanel = root.querySelector("[data-dashboard-learning]");
39
41
  const automationPanel = root.querySelector("[data-dashboard-automations]");
40
- passiveLearning?.mountHome(root.querySelector("[data-dashboard-learning-content]"));
42
+ let currentSnapshot = {};
43
+ function approvalHome() {
44
+ if (hasPendingDashboardApprovals(currentSnapshot)) return approvalDock;
45
+ return content;
46
+ }
47
+ const returnParents = { approvals: approvalHome };
48
+ const compactWidgets = createCompactHomeLayout({ root, content });
49
+ for (const [id, label, icon, element] of [
50
+ ["learning", "ABot Spark", "learning", learningPanel],
51
+ ["conversations", "Recent conversations", "conversations", conversations],
52
+ ["activity", "Recent activity", "active", activity],
53
+ ["automations", "Automations", "job", automationPanel],
54
+ ["approvals", "Pending approvals", "success", approvals],
55
+ ]) compactWidgets.register({
56
+ id, label, icon, element,
57
+ getReturnParent: returnParents[id],
58
+ isAvailable: () => id !== "learning" || Boolean(passiveLearning),
59
+ getSummary: () => dashboardWidgetSummaries(currentSnapshot, passiveLearning?.snapshot?.())[id],
60
+ });
61
+ passiveLearning?.mountHome(root.querySelector("[data-dashboard-learning-content]"), compactWidgets.refresh);
41
62
  const composerNote = root.querySelector(".home-composer-note");
42
63
  const handlers = {
43
64
  template: (button) => actions.createJob(button.dataset.templateId),
@@ -57,12 +78,14 @@ export function createDashboardWorkspace({ root, actions, passiveLearning }) {
57
78
  });
58
79
 
59
80
  function render(snapshot) {
81
+ currentSnapshot = snapshot;
60
82
  const setupRequired = snapshot.composerAvailable === false;
83
+ compactWidgets.setEnabled(!setupRequired);
61
84
  const pendingApprovals = hasPendingDashboardApprovals(snapshot);
62
85
  approvalDock.hidden = setupRequired || !pendingApprovals;
63
86
  // Keep pending actions beside the composer; refresh errors stay in content.
64
- const approvalParent = pendingApprovals ? approvalDock : content;
65
- if (approvals.parentElement !== approvalParent)
87
+ const approvalParent = approvalHome();
88
+ if (!compactWidgets.isExpanded(approvals) && approvals.parentElement !== approvalParent)
66
89
  approvalParent.appendChild(approvals);
67
90
  root.classList.toggle("home-setup-active", setupRequired);
68
91
  learningPanel.hidden = setupRequired || !passiveLearning;
@@ -118,7 +141,8 @@ export function createDashboardWorkspace({ root, actions, passiveLearning }) {
118
141
  "aria-busy",
119
142
  String(Boolean(snapshot.loadingSessions)),
120
143
  );
144
+ compactWidgets.refresh();
121
145
  }
122
146
 
123
- return { render, composerHost, setupHost };
147
+ return { render, composerHost, setupHost, compactWidgets };
124
148
  }
@@ -14,7 +14,7 @@ export function createDailyReviewDialog({ container, onDecision, onDismiss }) {
14
14
  <p class="daily-review-error" role="alert" data-review-error hidden></p>
15
15
  <div class="daily-review-actions"><button type="button" data-review-delete>Delete memory</button>
16
16
  <button type="button" data-review-keep>Keep memory</button></div>
17
- <p class="daily-review-note">These memories are already saved. Keep marks them as reviewed in this browser.</p>
17
+ <p class="daily-review-note">These memories are already saved. Keep marks them as reviewed in this ABot installation.</p>
18
18
  <button type="button" class="daily-review-later" data-review-later>Not now</button>`;
19
19
  container.append(dialog);
20
20
  let returnFocus;
@@ -53,7 +53,7 @@ export function createDailyReviewDialog({ container, onDecision, onDismiss }) {
53
53
  dialog.querySelector("[data-review-error]").hidden = !error;
54
54
  dialog.querySelector(".daily-review-actions").hidden = !record;
55
55
  for (const button of dialog.querySelectorAll(".daily-review-actions button")) button.disabled = busy;
56
- dialog.querySelector("[data-review-delete]").textContent = busy ? "Deleting…" : "Delete memory";
56
+ dialog.querySelector("[data-review-delete]").textContent = busy ? "Saving…" : "Delete memory";
57
57
  const later = dialog.querySelector("[data-review-later]");
58
58
  later.textContent = record ? "Not now" : "Done";
59
59
  if (hasReviewLoadError) later.textContent = "Close";
@@ -5,14 +5,14 @@ import { createHomeGuidancePreferences } from "../../services/home-guidance-pref
5
5
  import { createDailyMemoryReview } from "../../controllers/daily-memory-review.js";
6
6
  import { createDailyReviewDialog } from "./daily-review.js";
7
7
  import { createDailyReviewEntry } from "./daily-review-entry.js";
8
+ import { workspaceStorage } from "../../services/workspace-state.js";
8
9
 
9
10
  export function createHomeGuidance({ container, homeRegion, client, getEnvironmentId,
10
11
  getLearningSnapshot, getConnectionState, supportsConnection, refreshConnection,
11
12
  onOpen, isRuntimeReady = () => true, storage }) {
12
13
  const documentRoot = container?.ownerDocument;
13
14
  if (!documentRoot) return { render() {}, dispose() {} };
14
- let preferenceStorage = storage;
15
- try { preferenceStorage ??= documentRoot.defaultView?.localStorage; } catch { /* Session-only preferences. */ }
15
+ const preferenceStorage = storage ?? workspaceStorage();
16
16
  const preferences = createHomeGuidancePreferences(preferenceStorage);
17
17
  const root = documentRoot.createElement("aside");
18
18
  root.className = "home-guidance";
@@ -42,16 +42,19 @@ export function createHomeGuidance({ container, homeRegion, client, getEnvironme
42
42
  });
43
43
  review = createDailyMemoryReview({ client, getEnvironmentId, preferences, render: (snapshot) => {
44
44
  dialog.render(snapshot);
45
- if (canOfferDailyReview(snapshot) && dialog.canOpen() && review.markOffered()) dialog.open();
45
+ if (canOfferDailyReview(snapshot) && dialog.canOpen()) void offerReview();
46
46
  renderSuggestion();
47
47
  } });
48
48
  root.querySelector("[data-guidance-open]").addEventListener("click", () => {
49
49
  if (root.hidden || !selected) return;
50
50
  onOpen(selected.id);
51
51
  });
52
- root.querySelector("[data-guidance-dismiss]").addEventListener("click", () => {
52
+ root.querySelector("[data-guidance-dismiss]").addEventListener("click", async () => {
53
53
  if (!selected) return;
54
- preferences.dismiss(environment, selected.id);
54
+ const target = environment;
55
+ try { await preferences.dismiss(environment, selected.id); }
56
+ catch { return; }
57
+ if (target !== environment || disposed) return;
55
58
  hiddenThisVisit = true;
56
59
  renderSuggestion();
57
60
  });
@@ -105,6 +108,14 @@ export function createHomeGuidance({ container, homeRegion, client, getEnvironme
105
108
  if (!visible || reviewDismissed || !snapshot.remaining) return false;
106
109
  return hasCurrentLearningActivity();
107
110
  }
111
+ async function offerReview() {
112
+ const target = environment;
113
+ try {
114
+ if (!await review.markOffered()) return;
115
+ if (target !== getEnvironmentId() || !canOfferDailyReview(review.snapshot())) return;
116
+ if (dialog.canOpen()) dialog.open();
117
+ } catch { /* The shared storage failure remains visible; no success is claimed. */ }
118
+ }
108
119
  async function openMemoryReview() {
109
120
  if (openingReview || !canReviewSavedMemories() || !dialog.canOpen()) return;
110
121
  const operation = revision;
@@ -115,7 +126,10 @@ export function createHomeGuidance({ container, homeRegion, client, getEnvironme
115
126
  if (disposed || operation !== revision || target !== getEnvironmentId()) return;
116
127
  openingReview = false;
117
128
  if (loadedReview && canReviewSavedMemories() && dialog.canOpen()) {
118
- review.markOffered();
129
+ try { await review.markOffered(); }
130
+ catch { return; }
131
+ if (disposed || operation !== revision || target !== getEnvironmentId()) return;
132
+ if (!canReviewSavedMemories() || !dialog.canOpen()) return;
119
133
  dialog.open();
120
134
  }
121
135
  renderSuggestion();