synabun 2.0.9 → 2.1.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 (679) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +25 -2
  3. package/THIRD-PARTY-LICENSES.md +68 -4
  4. package/bin/synabun.js +71 -24
  5. package/docs/whatsapp.md +2 -2
  6. package/hooks/claude-code/pre-websearch.mjs +12 -1
  7. package/hooks/claude-code/shared.mjs +5 -0
  8. package/hooks/claude-code/stop.mjs +1 -1
  9. package/launcher.mjs +9 -3
  10. package/lib/claude-hooks.js +172 -18
  11. package/lib/client-config-repair.js +17 -8
  12. package/lib/desktop-app.js +7 -1
  13. package/lib/external-tools.js +1 -1
  14. package/lib/first-launch-protection.js +57 -12
  15. package/lib/mcp-dist.js +176 -0
  16. package/lib/release-npm-ci.mjs +138 -0
  17. package/lib/release-publish.mjs +91 -0
  18. package/lib/release-scan.mjs +50 -0
  19. package/lib/server-crash-record.js +123 -0
  20. package/lib/server-exit.js +318 -0
  21. package/lib/server-supervisor.js +508 -0
  22. package/lib/start-launcher.js +43 -5
  23. package/lib/tools-cli.js +45 -0
  24. package/lib/update-snapshot.js +228 -0
  25. package/lib/virustotal.mjs +192 -0
  26. package/lib/windows-crash-event.js +269 -0
  27. package/mcp-server/dist/http.d.ts +20 -1
  28. package/mcp-server/dist/http.d.ts.map +1 -1
  29. package/mcp-server/dist/http.js +59 -12
  30. package/mcp-server/dist/http.js.map +1 -1
  31. package/mcp-server/dist/index.d.ts +33 -27
  32. package/mcp-server/dist/index.d.ts.map +1 -1
  33. package/mcp-server/dist/index.js +128 -143
  34. package/mcp-server/dist/index.js.map +1 -1
  35. package/mcp-server/dist/preload.js +1 -1
  36. package/mcp-server/dist/preload.js.map +1 -1
  37. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  38. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  39. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  40. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  41. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  42. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  43. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  44. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  45. package/mcp-server/dist/services/neural-interface.d.ts +16 -10
  46. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  47. package/mcp-server/dist/services/neural-interface.js +67 -11
  48. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  49. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  50. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  51. package/mcp-server/dist/services/server-instructions.js +20 -62
  52. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  53. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  54. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  55. package/mcp-server/dist/services/tool-catalog.js +339 -0
  56. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  57. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  58. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  59. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  60. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  61. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  62. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  63. package/mcp-server/dist/services/tool-list.js +334 -0
  64. package/mcp-server/dist/services/tool-list.js.map +1 -0
  65. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  66. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  67. package/mcp-server/dist/services/tool-runtime.js +400 -0
  68. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  69. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  70. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  71. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  72. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  73. package/mcp-server/dist/tools/agents.d.ts +10 -10
  74. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  75. package/mcp-server/dist/tools/agents.js +22 -13
  76. package/mcp-server/dist/tools/agents.js.map +1 -1
  77. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  78. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  79. package/mcp-server/dist/tools/image-tools.js +1 -1
  80. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  81. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  82. package/mcp-server/dist/tools/skill-tools.js +639 -0
  83. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  84. package/mcp-server/dist/tools/skill.d.ts +7 -0
  85. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  86. package/mcp-server/dist/tools/skill.js +11 -0
  87. package/mcp-server/dist/tools/skill.js.map +1 -0
  88. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  89. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  90. package/mcp-server/dist/tools/tool-groups.js +147 -0
  91. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  92. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  93. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  94. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  95. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  96. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  97. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  98. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  99. package/mcp-server/package-lock.json +2 -2
  100. package/mcp-server/package.json +1 -1
  101. package/mcp-server/src/http.ts +75 -12
  102. package/mcp-server/src/index.ts +147 -154
  103. package/mcp-server/src/preload.ts +12 -12
  104. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  105. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  106. package/mcp-server/src/services/neural-interface.ts +79 -20
  107. package/mcp-server/src/services/server-instructions.ts +27 -63
  108. package/mcp-server/src/services/tool-catalog.ts +403 -0
  109. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  110. package/mcp-server/src/services/tool-list.ts +410 -0
  111. package/mcp-server/src/services/tool-runtime.ts +457 -0
  112. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  113. package/mcp-server/src/tools/agents.ts +22 -14
  114. package/mcp-server/src/tools/image-tools.ts +1 -1
  115. package/mcp-server/src/tools/skill-tools.ts +589 -0
  116. package/mcp-server/src/tools/skill.ts +13 -0
  117. package/mcp-server/src/tools/tool-groups.ts +164 -0
  118. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  119. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  120. package/neural-interface/i18n/en.json +3680 -206
  121. package/neural-interface/i18n/pt-BR.json +3628 -157
  122. package/neural-interface/lib/account-usage.js +5 -3
  123. package/neural-interface/lib/app-controls-api.js +161 -0
  124. package/neural-interface/lib/assistant-api.js +148 -35
  125. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  126. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  127. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  128. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  129. package/neural-interface/lib/assistant-brains/opencode.js +122 -44
  130. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +59 -0
  131. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +97 -0
  132. package/neural-interface/lib/assistant-catalog.js +23 -9
  133. package/neural-interface/lib/assistant-dispatch.js +874 -156
  134. package/neural-interface/lib/assistant-envelope.js +22 -2
  135. package/neural-interface/lib/assistant-persona.js +80 -11
  136. package/neural-interface/lib/assistant-plan-permissions.js +10 -9
  137. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  138. package/neural-interface/lib/assistant-route-gate.js +6 -4
  139. package/neural-interface/lib/assistant-router.js +13 -8
  140. package/neural-interface/lib/assistant-runtime.js +183 -26
  141. package/neural-interface/lib/assistant-task-prompt.js +78 -14
  142. package/neural-interface/lib/assistant-tools.js +51 -0
  143. package/neural-interface/lib/backup-service.js +620 -3
  144. package/neural-interface/lib/backup-zip-reader.js +10 -5
  145. package/neural-interface/lib/backup-zip-writer.js +257 -0
  146. package/neural-interface/lib/browser-execution.js +10 -2
  147. package/neural-interface/lib/browser-guard-cdp.js +83 -0
  148. package/neural-interface/lib/browser-network-guard.js +284 -0
  149. package/neural-interface/lib/browser-policy-roots.js +64 -0
  150. package/neural-interface/lib/browser-tool-policy.js +186 -31
  151. package/neural-interface/lib/claude-agent-bridge.js +4 -2
  152. package/neural-interface/lib/claude-hooks-status.js +103 -0
  153. package/neural-interface/lib/claude-model-catalog.js +64 -14
  154. package/neural-interface/lib/claude-temporary.js +5 -11
  155. package/neural-interface/lib/cli-install.js +18 -138
  156. package/neural-interface/lib/cli-resolver.js +4 -1
  157. package/neural-interface/lib/cli-update-planner.js +32 -31
  158. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  159. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  160. package/neural-interface/lib/codex-settings-schema.js +109 -47
  161. package/neural-interface/lib/codex-worker-app-server.js +172 -0
  162. package/neural-interface/lib/confined-fs.js +30 -3
  163. package/neural-interface/lib/crash-notice-api.js +98 -0
  164. package/neural-interface/lib/editor-completion-opencode.js +164 -67
  165. package/neural-interface/lib/exec-loop-command.js +4 -1
  166. package/neural-interface/lib/http-guards.js +8 -2
  167. package/neural-interface/lib/install-details.js +4 -1
  168. package/neural-interface/lib/launch-cache.js +293 -0
  169. package/neural-interface/lib/login-start.js +524 -0
  170. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  171. package/neural-interface/lib/mcp-client-config.js +0 -29
  172. package/neural-interface/lib/mcp-external-servers.js +323 -0
  173. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  174. package/neural-interface/lib/morelogin.js +30 -0
  175. package/neural-interface/lib/native-loop-providers.js +565 -50
  176. package/neural-interface/lib/native-loop-runtime.js +287 -41
  177. package/neural-interface/lib/opencode-config.js +557 -0
  178. package/neural-interface/lib/opencode-db-schema.js +58 -0
  179. package/neural-interface/lib/opencode-history.js +49 -204
  180. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  181. package/neural-interface/lib/opencode-native-boundary.js +44 -0
  182. package/neural-interface/lib/opencode-protocol.js +310 -0
  183. package/neural-interface/lib/opencode-provider-view.js +81 -0
  184. package/neural-interface/lib/opencode-runtime-config.js +32 -15
  185. package/neural-interface/lib/opencode-serve-records.js +624 -0
  186. package/neural-interface/lib/opencode-v2-client.js +53 -131
  187. package/neural-interface/lib/opencode-v2-ws-requests.js +35 -195
  188. package/neural-interface/lib/opencode-worker-activity.js +229 -0
  189. package/neural-interface/lib/opencode-worker-data.js +27 -0
  190. package/neural-interface/lib/opencode2-client.js +796 -0
  191. package/neural-interface/lib/opencode2-proxy.js +76 -0
  192. package/neural-interface/lib/opencode2-translate.js +1057 -0
  193. package/neural-interface/lib/owner-authority.js +249 -0
  194. package/neural-interface/lib/page-session.js +275 -0
  195. package/neural-interface/lib/peer-identity.js +763 -0
  196. package/neural-interface/lib/process-identity.js +361 -0
  197. package/neural-interface/lib/request-gate.js +17 -2
  198. package/neural-interface/lib/rulesets/api.js +1 -1
  199. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  200. package/neural-interface/lib/rulesets/installer.js +92 -27
  201. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  202. package/neural-interface/lib/session-cache-builder.js +18 -10
  203. package/neural-interface/lib/session-title-generator.js +58 -18
  204. package/neural-interface/lib/skills/api-v2.js +495 -0
  205. package/neural-interface/lib/skills/bundle.js +418 -0
  206. package/neural-interface/lib/skills/catalog.js +294 -0
  207. package/neural-interface/lib/skills/creation-api.js +191 -0
  208. package/neural-interface/lib/skills/creation-brief.js +247 -0
  209. package/neural-interface/lib/skills/creation-sources.js +267 -0
  210. package/neural-interface/lib/skills/creation.js +843 -0
  211. package/neural-interface/lib/skills/deploy.js +564 -0
  212. package/neural-interface/lib/skills/digest.js +119 -0
  213. package/neural-interface/lib/skills/discover.js +111 -0
  214. package/neural-interface/lib/skills/draft-confinement.js +214 -0
  215. package/neural-interface/lib/skills/eval-confinement.js +397 -0
  216. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  217. package/neural-interface/lib/skills/eval-trace.js +119 -0
  218. package/neural-interface/lib/skills/evals-api.js +212 -0
  219. package/neural-interface/lib/skills/evals.js +1573 -0
  220. package/neural-interface/lib/skills/export.js +200 -0
  221. package/neural-interface/lib/skills/frontmatter.js +64 -0
  222. package/neural-interface/lib/skills/health.js +75 -0
  223. package/neural-interface/lib/skills/json-edit.js +165 -0
  224. package/neural-interface/lib/skills/known-bridge-digests.json +387 -0
  225. package/neural-interface/lib/skills/known-bridges.js +96 -0
  226. package/neural-interface/lib/skills/library.js +823 -0
  227. package/neural-interface/lib/skills/local-store.js +21 -0
  228. package/neural-interface/lib/skills/migration.js +433 -0
  229. package/neural-interface/lib/skills/operations.js +45 -0
  230. package/neural-interface/lib/skills/ownership.js +427 -0
  231. package/neural-interface/lib/skills/packages.js +88 -0
  232. package/neural-interface/lib/skills/reviews.js +212 -0
  233. package/neural-interface/lib/skills/revision.js +80 -0
  234. package/neural-interface/lib/skills/roots.js +262 -0
  235. package/neural-interface/lib/skills/runtime-checks.js +355 -0
  236. package/neural-interface/lib/skills/scan-assets.js +252 -0
  237. package/neural-interface/lib/skills/scan-context.js +26 -0
  238. package/neural-interface/lib/skills/scan-shell.js +324 -0
  239. package/neural-interface/lib/skills/scan.js +364 -0
  240. package/neural-interface/lib/skills/scanners.js +54 -0
  241. package/neural-interface/lib/skills/service.js +522 -0
  242. package/neural-interface/lib/skills/telemetry.js +113 -0
  243. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  244. package/neural-interface/lib/style-guide/api.js +4 -3
  245. package/neural-interface/lib/tool-lists.js +124 -0
  246. package/neural-interface/lib/untrusted-file-headers.js +27 -0
  247. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  248. package/neural-interface/lib/worker-confinement.js +1192 -0
  249. package/neural-interface/lib/worker-guard-setting.js +56 -0
  250. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  251. package/neural-interface/lib/worker-relay-ports.js +227 -0
  252. package/neural-interface/lib/worker-resume.js +229 -0
  253. package/neural-interface/lib/worker-sandbox.js +299 -0
  254. package/neural-interface/package-lock.json +1354 -50
  255. package/neural-interface/package.json +6 -2
  256. package/neural-interface/public/index.html +5 -3
  257. package/neural-interface/public/index2d.html +19 -11
  258. package/neural-interface/public/onboarding.html +2 -2
  259. package/neural-interface/public/shared/account-menu.js +8 -5
  260. package/neural-interface/public/shared/agent-runtime-options.js +76 -16
  261. package/neural-interface/public/shared/api.js +1527 -1336
  262. package/neural-interface/public/shared/app-frame.js +192 -0
  263. package/neural-interface/public/shared/assistant/asst-agents-dock.js +205 -19
  264. package/neural-interface/public/shared/assistant/asst-api.js +11 -3
  265. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  266. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  267. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  268. package/neural-interface/public/shared/assistant/asst-brain-picker.js +241 -112
  269. package/neural-interface/public/shared/assistant/asst-composer.js +1 -1
  270. package/neural-interface/public/shared/assistant/asst-control.js +157 -26
  271. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  272. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  273. package/neural-interface/public/shared/assistant/asst-hosts.js +49 -2
  274. package/neural-interface/public/shared/assistant/asst-limit-dock.js +40 -0
  275. package/neural-interface/public/shared/assistant/asst-limit-wait.js +294 -0
  276. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  277. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  278. package/neural-interface/public/shared/assistant/asst-menu.js +84 -12
  279. package/neural-interface/public/shared/assistant/asst-panel.js +303 -44
  280. package/neural-interface/public/shared/assistant/asst-rack-styles.js +93 -58
  281. package/neural-interface/public/shared/assistant/asst-redact.js +186 -0
  282. package/neural-interface/public/shared/assistant/asst-render.js +770 -100
  283. package/neural-interface/public/shared/assistant/asst-route.js +83 -12
  284. package/neural-interface/public/shared/assistant/asst-run-stage.js +231 -0
  285. package/neural-interface/public/shared/assistant/asst-sanitize.js +193 -3
  286. package/neural-interface/public/shared/assistant/asst-scene-styles.js +273 -0
  287. package/neural-interface/public/shared/assistant/asst-scenes.js +530 -0
  288. package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +3 -15
  289. package/neural-interface/public/shared/assistant/asst-sidepanel.js +67 -4
  290. package/neural-interface/public/shared/assistant/asst-slash.js +9 -7
  291. package/neural-interface/public/shared/assistant/asst-state.js +25 -15
  292. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  293. package/neural-interface/public/shared/assistant/asst-styles.js +102 -21
  294. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +165 -13
  295. package/neural-interface/public/shared/automation-context.js +5 -2
  296. package/neural-interface/public/shared/cc-dropdown.js +550 -0
  297. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  298. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  299. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  300. package/neural-interface/public/shared/cdx/cdx-output.js +8 -7
  301. package/neural-interface/public/shared/cdx/cdx-panel.js +58 -150
  302. package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
  303. package/neural-interface/public/shared/cdx/cdx-render.js +62 -32
  304. package/neural-interface/public/shared/cdx/cdx-requests.js +3 -3
  305. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  306. package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
  307. package/neural-interface/public/shared/cdx/cdx-tabs.js +201 -74
  308. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  309. package/neural-interface/public/shared/cli-install-view.js +4 -8
  310. package/neural-interface/public/shared/cli-status.js +2 -2
  311. package/neural-interface/public/shared/constants.js +2 -2
  312. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  313. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  314. package/neural-interface/public/shared/context-menu-model.js +366 -0
  315. package/neural-interface/public/shared/context-menu.js +372 -0
  316. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  317. package/neural-interface/public/shared/cp/cp-markdown.js +4 -57
  318. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  319. package/neural-interface/public/shared/data-cache.js +223 -0
  320. package/neural-interface/public/shared/desktop-bridge.js +11 -0
  321. package/neural-interface/public/shared/desktop-titlebar-view.js +78 -1
  322. package/neural-interface/public/shared/desktop-titlebar.js +214 -28
  323. package/neural-interface/public/shared/desktop-update-view.js +35 -5
  324. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  325. package/neural-interface/public/shared/file-links.js +73 -8
  326. package/neural-interface/public/shared/html-shell.js +78 -86
  327. package/neural-interface/public/shared/i18n.js +2 -0
  328. package/neural-interface/public/shared/launch-prefetch.js +59 -0
  329. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  330. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  331. package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +3 -2
  332. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  333. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +9 -2
  334. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  335. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  336. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  337. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  338. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  339. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  340. package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +54 -17
  341. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  342. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +140 -254
  343. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  344. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +97 -203
  345. package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +11 -9
  346. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +15 -4
  347. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -22
  348. package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +401 -0
  349. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +20 -13
  350. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  351. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +53 -82
  352. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  353. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  354. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  355. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  356. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +48 -40
  357. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  358. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +205 -62
  359. package/neural-interface/public/shared/opencode-providers.js +39 -0
  360. package/neural-interface/public/shared/page-session.js +96 -0
  361. package/neural-interface/public/shared/registry.js +5 -3
  362. package/neural-interface/public/shared/retired-2d.js +3 -0
  363. package/neural-interface/public/shared/schedules-view.js +452 -0
  364. package/neural-interface/public/shared/settings/settings-app-pane.js +335 -0
  365. package/neural-interface/public/shared/settings/settings-app.js +243 -0
  366. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  367. package/neural-interface/public/shared/settings/settings-data.js +90 -0
  368. package/neural-interface/public/shared/settings/settings-ia.js +23 -6
  369. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  370. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  371. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  372. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  373. package/neural-interface/public/shared/sidepanel-session-status.js +49 -0
  374. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  375. package/neural-interface/public/shared/skills/ss-creation.js +219 -0
  376. package/neural-interface/public/shared/skills/ss-dialog.js +130 -0
  377. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  378. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  379. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  380. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  381. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  382. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  383. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  384. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  385. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  386. package/neural-interface/public/shared/skills/ss-lint.js +141 -0
  387. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  388. package/neural-interface/public/shared/skills/ss-profiles.js +475 -0
  389. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  390. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  391. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  392. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  393. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  394. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  395. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  396. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +236 -0
  397. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  398. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  399. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  400. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  401. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  402. package/neural-interface/public/shared/skills/studio/sx-dom.js +229 -0
  403. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  404. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  405. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  406. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  407. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  408. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  409. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +279 -0
  410. package/neural-interface/public/shared/skills/studio/sx-install.js +296 -0
  411. package/neural-interface/public/shared/skills/studio/sx-library-view.js +639 -0
  412. package/neural-interface/public/shared/skills/studio/sx-library.js +475 -0
  413. package/neural-interface/public/shared/skills/studio/sx-main.js +681 -0
  414. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  415. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  416. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  417. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  418. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  419. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  420. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  421. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  422. package/neural-interface/public/shared/skills/studio/sx-subject.js +248 -0
  423. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  424. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  425. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  426. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +425 -0
  427. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  428. package/neural-interface/public/shared/styles.css +2065 -2150
  429. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  430. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  431. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  432. package/neural-interface/public/shared/tool-list-view.js +112 -0
  433. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  434. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  435. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  436. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  437. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  438. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  439. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  440. package/neural-interface/public/shared/tour/tour.css +144 -0
  441. package/neural-interface/public/shared/ui-assistant.js +27 -5
  442. package/neural-interface/public/shared/ui-automation-studio.js +155 -152
  443. package/neural-interface/public/shared/ui-bookmarks.js +2 -1
  444. package/neural-interface/public/shared/ui-claude-panel.js +153 -13
  445. package/neural-interface/public/shared/ui-codex-panel.js +1 -0
  446. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  447. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  448. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  449. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  450. package/neural-interface/public/shared/ui-detail.js +21 -9
  451. package/neural-interface/public/shared/ui-file-links.js +1 -0
  452. package/neural-interface/public/shared/ui-image-gallery.js +56 -52
  453. package/neural-interface/public/shared/ui-invite.js +18 -2
  454. package/neural-interface/public/shared/ui-keybinds.js +26 -1
  455. package/neural-interface/public/shared/ui-link.js +9 -9
  456. package/neural-interface/public/shared/ui-menubar.js +229 -40
  457. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  458. package/neural-interface/public/shared/ui-native-loop-router.js +9 -1
  459. package/neural-interface/public/shared/ui-navbar.js +4 -24
  460. package/neural-interface/public/shared/ui-opencode-panel-v2.js +1 -0
  461. package/neural-interface/public/shared/ui-panels.js +96 -65
  462. package/neural-interface/public/shared/ui-schedules-studio.js +2267 -953
  463. package/neural-interface/public/shared/ui-sessions.js +20 -7
  464. package/neural-interface/public/shared/ui-settings.js +679 -496
  465. package/neural-interface/public/shared/ui-sidebar.js +4 -4
  466. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +13 -0
  467. package/neural-interface/public/shared/ui-sidepanel-sessions.js +56 -5
  468. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  469. package/neural-interface/public/shared/ui-sidepanel-tray.js +84 -8
  470. package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
  471. package/neural-interface/public/shared/ui-skills.js +42 -2781
  472. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  473. package/neural-interface/public/shared/ui-sync.js +22 -5
  474. package/neural-interface/public/shared/ui-terminal.js +159 -199
  475. package/neural-interface/public/shared/ui-tool-updates.js +3 -1
  476. package/neural-interface/public/shared/ui-tooltip.js +10 -5
  477. package/neural-interface/public/shared/ui-trash.js +14 -5
  478. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  479. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  480. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -61
  481. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  482. package/neural-interface/public/shared/ui-tutorial.js +285 -499
  483. package/neural-interface/public/shared/ui-update.js +121 -16
  484. package/neural-interface/public/shared/ui-whiteboard.js +313 -59
  485. package/neural-interface/public/shared/ui-worker-end.js +4 -0
  486. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  487. package/neural-interface/public/shared/view-variant.js +66 -0
  488. package/neural-interface/public/shared/whatsapp/wa-view.js +1 -1
  489. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  490. package/neural-interface/public/shared/worker-end.js +10 -3
  491. package/neural-interface/public/shared/worker-restart.js +12 -0
  492. package/neural-interface/public/sidepanel-session.html +1 -1
  493. package/neural-interface/public/variant/2d/background.js +2 -1
  494. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  495. package/neural-interface/public/variant/2d/graph.js +42 -20
  496. package/neural-interface/public/variant/2d/hulls.js +14 -9
  497. package/neural-interface/public/variant/2d/lasso.js +11 -7
  498. package/neural-interface/public/variant/2d/main.js +36 -2
  499. package/neural-interface/public/variant/2d/minimap.js +11 -13
  500. package/neural-interface/public/variant/3d/main.js +72 -6
  501. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  502. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  503. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  504. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  505. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  506. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  507. package/neural-interface/public/vendor/highlight/LICENSE +29 -0
  508. package/neural-interface/public/vendor/highlight/github-dark-dimmed-11.12.0.min.css +9 -0
  509. package/neural-interface/public/vendor/highlight/highlight-11.12.0.min.js +1262 -0
  510. package/neural-interface/public/vendor/highlight/manifest.json +5 -0
  511. package/neural-interface/public/vendor/html2canvas/LICENSE +22 -0
  512. package/neural-interface/public/vendor/html2canvas/html2canvas-1.4.1.min.js +20 -0
  513. package/neural-interface/public/vendor/html2canvas/manifest.json +4 -0
  514. package/neural-interface/public/vendor/marked/LICENSE.md +44 -0
  515. package/neural-interface/public/vendor/marked/manifest.json +4 -0
  516. package/neural-interface/public/vendor/marked/marked-14.1.4.esm.js +2502 -0
  517. package/neural-interface/public/vendor/mermaid/LICENSE +21 -0
  518. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/abnfDiagram-PAR5IXJI.mjs +1 -0
  519. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architecture-7GRP2DOG-M7G3SWCO.mjs +1 -0
  520. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/architectureDiagram-2PNWDENW.mjs +36 -0
  521. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/blockDiagram-PUWGUBOA.mjs +129 -0
  522. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/c4Diagram-3NLNHZP5.mjs +38 -0
  523. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-2NMSUPJH.mjs +1 -0
  524. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-32MCUW2P.mjs +206 -0
  525. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3NPNU5GP.mjs +1 -0
  526. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-3SMGFRGC.mjs +1 -0
  527. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4CAJECRU.mjs +14 -0
  528. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-4OADUZ5Q.mjs +10 -0
  529. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IMINLNL.mjs +1 -0
  530. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5IQCK5RY.mjs +3 -0
  531. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-5MVFYWFU.mjs +1 -0
  532. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AQ6EADP3.mjs +1 -0
  533. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-AZZRMDJM.mjs +15 -0
  534. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-CLS4B6BI.mjs +168 -0
  535. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-DZP67EKU.mjs +70 -0
  536. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-EICP7K5X.mjs +1 -0
  537. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-GDY2UAB4.mjs +1 -0
  538. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-H7VHZCWX.mjs +1 -0
  539. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-IJBDOHL6.mjs +1 -0
  540. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JFFVMJIA.mjs +1 -0
  541. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JQRUD6KW.mjs +1 -0
  542. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-JZGDI5JK.mjs +1 -0
  543. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-KD6SPIPN.mjs +2 -0
  544. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NF366YI6.mjs +231 -0
  545. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-NUDPKBEF.mjs +32 -0
  546. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-OJINMHTS.mjs +1 -0
  547. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Q6NGPIAH.mjs +2 -0
  548. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-QJSWEUOL.mjs +132 -0
  549. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-R7JDMUKV.mjs +1 -0
  550. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RCXAM2GK.mjs +1 -0
  551. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-RT4MAWR3.mjs +1 -0
  552. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SFMINX4W.mjs +1 -0
  553. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-SLDQ463B.mjs +88 -0
  554. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-STOV2HOB.mjs +1 -0
  555. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-T5OCTHI4.mjs +1 -0
  556. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-TCEHX7R3.mjs +1 -0
  557. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VQC2EELJ.mjs +1 -0
  558. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VRZKL3EH.mjs +1 -0
  559. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VTHDQ7BV.mjs +1 -0
  560. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-VY2OSTJR.mjs +2 -0
  561. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-WUBWJARI.mjs +1 -0
  562. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YBMQ5JGJ.mjs +2 -0
  563. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-YDMLL4PJ.mjs +1 -0
  564. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-Z6V44ARX.mjs +62 -0
  565. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZJJ7VQJP.mjs +339 -0
  566. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZNLK7HRR.mjs +1 -0
  567. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZQN7UHIL.mjs +1 -0
  568. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZS6VBONO.mjs +174 -0
  569. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/chunk-ZUNWM646.mjs +1 -0
  570. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-FGAMPOII.mjs +1 -0
  571. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/classDiagram-v2-AI5RJEK4.mjs +1 -0
  572. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cose-bilkent-Q72C2OJ3.mjs +1 -0
  573. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefin-OW5HDTMX-6OCTWOGG.mjs +1 -0
  574. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/cynefinDiagram-2OOWUY4M.mjs +62 -0
  575. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/dagre-MPVFI544.mjs +4 -0
  576. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-AE4NWXFW.mjs +24 -0
  577. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-BUJID5UG.mjs +41 -0
  578. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-C44CZ5NI.mjs +24 -0
  579. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-EYOLEXXS.mjs +30 -0
  580. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/diagram-P7B6PWOJ.mjs +3 -0
  581. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ebnfDiagram-FTPZ3PV6.mjs +1 -0
  582. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/erDiagram-H3ERR26V.mjs +99 -0
  583. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/eventmodeling-NTZA5JFV-WKSWQHFS.mjs +1 -0
  584. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/flowDiagram-YHGXBVSY.mjs +1 -0
  585. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ganttDiagram-RWFTB7ED.mjs +292 -0
  586. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraph-4MIJSDKK-JH2HKYUO.mjs +1 -0
  587. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/gitGraphDiagram-MAR6GKOP.mjs +106 -0
  588. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/info-A6RAGUB7-3TX3OFWW.mjs +1 -0
  589. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/infoDiagram-LV547AFH.mjs +2 -0
  590. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/ishikawaDiagram-PUJQGNDS.mjs +70 -0
  591. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/journeyDiagram-EW5QJT4W.mjs +139 -0
  592. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/kanban-definition-JSQERAZB.mjs +89 -0
  593. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/katex-CZ4GXH2S.mjs +257 -0
  594. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/mindmap-definition-VBJCLQLM.mjs +96 -0
  595. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/packet-AYTQ26CC-MKII6P3Y.mjs +1 -0
  596. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pegDiagram-7WILOQTJ.mjs +1 -0
  597. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pie-WAS4IAKB-6B4OPMJ5.mjs +1 -0
  598. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/pieDiagram-EFA7CBSB.mjs +39 -0
  599. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/quadrantDiagram-WARVYA7P.mjs +7 -0
  600. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/radar-RG4KPBEZ-UPTR3XUL.mjs +1 -0
  601. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-74A4TZTK-MEFUPFMS.mjs +1 -0
  602. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-abnf-HS5TGJTU-R5YG2S5D.mjs +1 -0
  603. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-ebnf-LZEXJU2U-G5QEX2L6.mjs +1 -0
  604. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroad-peg-WCYAUIDC-H5I2ZRY2.mjs +1 -0
  605. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/railroadDiagram-5NIQVNLQ.mjs +1 -0
  606. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/requirementDiagram-SXREGOKZ.mjs +84 -0
  607. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sankeyDiagram-VV74M2VP.mjs +40 -0
  608. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sequenceDiagram-52ZFIFDL.mjs +162 -0
  609. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/sizeCapture-FGA5AGYP.mjs +1 -0
  610. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-3QAKPIVI.mjs +1 -0
  611. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/stateDiagram-v2-HN2P4RDZ.mjs +1 -0
  612. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanes-QLVP42QD.mjs +1 -0
  613. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/swimlanesDiagram-JKPDBFCN.mjs +8 -0
  614. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/timeline-definition-GS45XAXW.mjs +120 -0
  615. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treeView-Q6P3EWNA-ZRJGANNQ.mjs +1 -0
  616. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/treemap-WGGIJYW6-K64VN5AS.mjs +1 -0
  617. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/vennDiagram-QIQU2ZRJ.mjs +34 -0
  618. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardley-WFR3VGLG-D67OWCCH.mjs +1 -0
  619. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/wardleyDiagram-U6YNM66N.mjs +78 -0
  620. package/neural-interface/public/vendor/mermaid/chunks/mermaid.esm.min/xychartDiagram-XJAZEDNM.mjs +7 -0
  621. package/neural-interface/public/vendor/mermaid/manifest.json +4 -0
  622. package/neural-interface/public/vendor/mermaid/mermaid-11.17.2.esm.min.mjs +14 -0
  623. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  624. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  625. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  626. package/neural-interface/scripts/build-vendor.mjs +116 -3
  627. package/neural-interface/server.js +4834 -2541
  628. package/neural-interface/templates/rulesets/core.md +1 -1
  629. package/neural-interface/templates/rulesets/legacy-hashes.json +18 -0
  630. package/neural-interface/templates/rulesets/manifest.json +8 -8
  631. package/npm-shrinkwrap.json +18 -12
  632. package/package.json +16 -3
  633. package/postinstall.js +9 -4
  634. package/preuninstall.js +1 -1
  635. package/setup.js +97 -322
  636. package/skills/skill-forge/SKILL.md +177 -0
  637. package/skills/skill-forge/evals/evals.json +54 -0
  638. package/skills/skill-forge/references/package.md +105 -0
  639. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  640. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  641. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  642. package/skills/synabun/SKILL.md +10 -7
  643. package/skills/synabun/modules/audit.md +1 -5
  644. package/skills/synabun/modules/changelog.md +1 -5
  645. package/skills/synabun/modules/idea.md +1 -1
  646. package/skills/synabun/modules/memorize.md +6 -9
  647. package/skills/synabun/modules/schedule.md +5 -5
  648. package/mcp-server/dist/services/profiles.d.ts +0 -120
  649. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  650. package/mcp-server/dist/services/profiles.js +0 -387
  651. package/mcp-server/dist/services/profiles.js.map +0 -1
  652. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  653. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  654. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  655. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  656. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  657. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  658. package/mcp-server/dist/tools/leonardo.js +0 -21
  659. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  660. package/mcp-server/dist/tools/profile.d.ts +0 -17
  661. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  662. package/mcp-server/dist/tools/profile.js +0 -114
  663. package/mcp-server/dist/tools/profile.js.map +0 -1
  664. package/mcp-server/src/services/profiles.ts +0 -428
  665. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  666. package/mcp-server/src/tools/leonardo.ts +0 -30
  667. package/mcp-server/src/tools/profile.ts +0 -122
  668. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  669. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  670. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  671. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  672. package/skills/leonardo/SKILL.md +0 -168
  673. package/skills/leonardo/icon.svg +0 -1
  674. package/skills/leonardo/modules/browser-guide.md +0 -378
  675. package/skills/leonardo/modules/image-prompter.md +0 -283
  676. package/skills/leonardo/modules/model-advisor.md +0 -100
  677. package/skills/leonardo/modules/prompt-library.md +0 -110
  678. package/skills/leonardo/modules/style-guide.md +0 -186
  679. package/skills/leonardo/modules/video-prompter.md +0 -317
@@ -1,3 +1,4 @@
1
+ import { fetchToolCatalog } from '../agent-runtime-options.js';
1
2
  // ═══════════════════════════════════════════
2
3
  // SynaBun Assistant — panel (mount / lifecycle)
3
4
  // ═══════════════════════════════════════════
@@ -40,6 +41,7 @@ import { getWhiteboardElementById } from '../ui-whiteboard.js';
40
41
  import { focusNativeLoopRun } from '../ui-native-loop-router.js';
41
42
  import { wireFileLinks } from '../ui-file-links.js';
42
43
  import { injectAssistantStyles } from './asst-styles.js';
44
+ import { tipsSeen, tourOffered } from '../tour/tour-state.js';
43
45
  import { createAssistantSocket } from './asst-ws.js';
44
46
  import { createRenderer, ICON_ASSISTANT, mdInto } from './asst-render.js';
45
47
  import { createMascotDirector, MASCOT_TIMING, turnEndPose } from './asst-mascot.js';
@@ -47,19 +49,22 @@ import { lastInputAt, onKey, onPointer } from '../synabun-ticker.js';
47
49
  import { buildControlResponse, closedControlState, normalizeControlRequest, renderControlCard } from './asst-control.js';
48
50
  import { buildPromptText, createComposer } from './asst-composer.js';
49
51
  import { buildDispatchSpec, parseSlashCommand, slashHelpMarkdown } from './asst-slash.js';
52
+ import { resolveStopTarget } from './asst-stop.js';
53
+ import { plural } from './asst-tool-kinds.js';
50
54
  import { cachedProjects, createBrainPicker, testDensityLabel } from './asst-brain-picker.js';
51
55
  import { createRovingToolbar } from './asst-roving.js';
52
56
  import { openAccountsManager } from './asst-accounts.js';
53
57
  import { createAgentsDock } from './asst-agents-dock.js';
58
+ import { activityOf } from './asst-scenes.js';
54
59
  import { createUsageGauge } from './asst-usage.js';
55
- import { closeMenu, isMenuOpen, openMenu } from './asst-menu.js';
60
+ import { closeMenu, currentMenuAnchor, isMenuOpen, openMenu } from './asst-menu.js';
56
61
  import { createRouteModeControl, openModelsManager, openRoutesEditor, refreshModelsManager, renderRouteCard, routeModeLabel } from './asst-route.js';
57
62
  import { budgetChipText, budgetSpendText, budgetTone, closeBudgetEditor, createBudgetController, mountBudgetChip, openBudgetEditor } from './asst-budget.js';
58
63
  import { computerRemoteView, createComputerPanel, createComputerToggle, normalizeComputerRemote, openFrameLightbox, closeFrameLightbox, requestDesktopStop } from './asst-computer.js';
59
64
  import {
60
65
  applyLimit, applyLimitPacket, applyUsagePacket, brainLabel, createRenameWriter, createTabState, DEFAULT_ROUTE_MODE, deserializeTabState, fmtCost, fmtRunLine, limitExpiresIn, limitNoticeText, modelShortName,
61
66
  brainModePatch, normalizeBrain, normalizeComputerMode, permissionModeLabel, normalizeRouteMode, normalizeTestDensity, projectLabel, providerShortLabel, readStoredBrain, runFromPayload,
62
- serializeTabState, tabStorageKey, userSessionTitle,
67
+ serializeTabState, sessionStatus, tabStorageKey, userSessionTitle,
63
68
  } from './asst-state.js';
64
69
  import {
65
70
  closeAssistantSession, dispatchAssistantRun, escalateAssistantRun, focusAssistantRun, getAssistantRun,
@@ -74,6 +79,7 @@ const ICON_COG = '<svg viewBox="0 0 24 24"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v
74
79
  const ICON_ROUTE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h13l-3-3M20 17H7l3 3"/></svg>';
75
80
  const ICON_COMPUTER = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="12" rx="2"/><path d="M8 20h8M12 16v4"/></svg>';
76
81
  const ICON_CLOSE = '<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>';
82
+ const ICON_TRASH = '<svg viewBox="0 0 24 24"><path d="M3 6h18M8 6V4.5A1.5 1.5 0 0 1 9.5 3h5A1.5 1.5 0 0 1 16 4.5V6M18.5 6l-.8 13a2 2 0 0 1-2 1.9H8.3a2 2 0 0 1-2-1.9L5.5 6M10 11v6M14 11v6"/></svg>';
77
83
  const REPLAY_WAIT_MS = 1500; // a replay that stops short of its count is drawn after this long
78
84
 
79
85
  function el(tag, className, text) {
@@ -148,7 +154,9 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
148
154
  usageView: saved?.usageView || null,
149
155
  });
150
156
  Object.assign(st, {
151
- status: 'idle',
157
+ status: 'idle', // the brain's own: its turn, its cards (setStatus)
158
+ workers: { working: 0, waiting: 0 }, // its dispatched agents, from the agents tray (sessionStatus)
159
+ shownStatus: 'idle', // what the host shows: both together (pushStatus)
152
160
  dispatchUsd: 0,
153
161
  serverCost: false,
154
162
  engine: '',
@@ -165,6 +173,9 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
165
173
  desktopProbe: false,
166
174
  routingProbe: false,
167
175
  sessionTitle: String(session?.title || ''), // the server's name (the user's rename, else the first prompt): history + notifications
176
+ // Whether this session holds a chat (a prompt was sent): until then the server keeps it as a draft,
177
+ // New reuses it, and leaving it for another session closes it (nothing of it is stored).
178
+ chatStarted: !!session?.chatStartedAt || Number(session?.turns) > 0,
168
179
  });
169
180
  let recordName = userSessionTitle(session); // the name the session record holds as the user's ('' = never renamed)
170
181
  const controls = new Map(); // requestId → { card, origin, kind }
@@ -236,6 +247,23 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
236
247
  const providerIcon = (p) => getProviderMeta(p).icon;
237
248
  const providerColor = (p) => getProviderMeta(p).color;
238
249
  const visible = () => { try { return host.isVisible ? !!host.isVisible() : true; } catch { return true; } };
250
+
251
+ // ── Just-in-time tips (../tour/tour-tips.js): once each, ever; never in a replay or while the tour runs ──
252
+ function tip(id, targetOf) {
253
+ if (destroyed || replaying || !visible() || guestBlocked() || tipsSeen(storage).has(id)) return;
254
+ requestAnimationFrame(() => {
255
+ if (destroyed) return;
256
+ let target = null;
257
+ try { target = targetOf(); } catch { target = null; }
258
+ if (!target?.isConnected) return;
259
+ import('../tour/tour-tips.js')
260
+ .then(async ({ ensureTourStyles, showTip }) => {
261
+ await ensureTourStyles();
262
+ if (!destroyed && target.isConnected) showTip(id, { storage, tr: (key) => t(key), root, target, renderer, reduced: () => matchMedia('(prefers-reduced-motion: reduce)').matches });
263
+ })
264
+ .catch(() => { /* a tip is never worth an error */ });
265
+ });
266
+ }
239
267
  const hostId = host.id || null; // routing only (assistant:new / resume / focused) — never a feature switch
240
268
 
241
269
  function persist() {
@@ -315,18 +343,33 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
315
343
  notify(host.notifySource || 'cli', type, notifyLabel(), { sessionId, provider: 'assistant', panel: 'assistant' });
316
344
  }
317
345
 
318
- /** root[data-status] and data-computer drive status styling (the live dot, the Computer switch). */
346
+ /** root[data-status] (the session's status, sessionStatus) and data-computer drive status styling (the live dot, the Computer switch). */
319
347
  function renderStatus() {
320
- root.dataset.status = st.status || 'idle';
348
+ root.dataset.status = st.shownStatus || 'idle';
321
349
  if (st.desktopActive) root.dataset.computer = 'active';
322
350
  else delete root.dataset.computer;
323
351
  }
324
352
 
353
+ /** The brain's own status: its turn ('working', 'done', 'idle') and its cards ('action'). */
325
354
  function setStatus(status) {
326
355
  st.status = status || 'idle';
327
- renderStatus();
356
+ pushStatus(true);
328
357
  syncBlocked();
329
- try { host.setStatus?.(st.status); } catch { /* ignore */ }
358
+ }
359
+
360
+ /**
361
+ * What the host shows (tray pill, header, terminal badge) is the session's status: the brain's own and
362
+ * its dispatched agents' together (asst-state.js sessionStatus), so the gold stays while a worker works
363
+ * after the turn that dispatched it ended, and a worker that waits on you makes the session need you.
364
+ * The brain's own changes always reach the host; a change of the agents' counts only when the status moved.
365
+ */
366
+ function pushStatus(always = false) {
367
+ if (destroyed) return;
368
+ const next = sessionStatus(st.status, st.workers);
369
+ if (!always && next === st.shownStatus) return;
370
+ st.shownStatus = next;
371
+ renderStatus();
372
+ try { host.setStatus?.(next); } catch { /* ignore */ }
330
373
  }
331
374
 
332
375
  /**
@@ -484,7 +527,18 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
484
527
  emptyBudgetChip?.destroy();
485
528
  emptyBudgetChip = null;
486
529
  },
487
- onSuggestion: (template) => composer.fillTemplate(template),
530
+ // The first-visit row asks for the Workspace tour on this panel (ui-tutorial.js); the others fill the composer.
531
+ onSuggestion: (template, s) => {
532
+ if (s?.action === 'tour') { emit('tour:open', { host: controller.tourHost(), from: 'starter' }); return; }
533
+ composer.fillTemplate(template);
534
+ },
535
+ // A follow-up under a finished message, or Retry now on a usage-limit card: sent as the user's next
536
+ // message (queued while a turn runs, like a typed one). "Something else…" is the composer.
537
+ onFollowup: (text) => { submit(clickPayload(text)); },
538
+ onFollowupOther: () => composer.focus(),
539
+ onLimitRetry: (text) => { submit(clickPayload(text)); },
540
+ limitInfo: () => st.limit,
541
+ brainProvider: () => st.brain.provider,
488
542
  heroOrigin: () => { try { return host.takeHeroOrigin?.() || null; } catch { return null; } },
489
543
  onMascotChange: () => director?.retarget(),
490
544
  onInit: (ev) => {
@@ -514,12 +568,20 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
514
568
  },
515
569
  });
516
570
 
571
+ /** What a click sends: the text alone, shaped like a typed message with nothing attached. */
572
+ function clickPayload(text) {
573
+ return { text: String(text ?? ''), images: [], files: [], uploads: [], memories: [] };
574
+ }
575
+
517
576
  function emptySuggestions() {
518
577
  const project = projectLabel(st.brain.project, cachedProjects()) || tt('assistant.empty.thisProject', 'this project');
519
578
  const list = [];
579
+ // Until the Workspace tour is completed or skipped, its starter comes first. It never opens by itself.
580
+ if (tourOffered(storage) && !guestBlocked()) list.push({ id: 'tour', action: 'tour', kind: 'ask', label: tt('tour.starter', 'Show me the workspace'), meta: tt('tour.starterTime', '2 min') });
520
581
  if (computerAvailable()) list.push({ id: 'computer', label: tt('assistant.empty.suggestComputer', 'Use my Mac to…'), template: tt('assistant.empty.templateComputer', 'Use my Mac to {caret}') });
521
582
  list.push({ id: 'web', label: tt('assistant.empty.suggestWeb', 'Look up … on the web'), template: tt('assistant.empty.templateWeb', 'Look up {caret} on the web') });
522
583
  list.push({ id: 'fix', label: tt('assistant.empty.suggestFix', 'Fix … in {project}', { project }), template: tt('assistant.empty.templateFix', 'Fix {caret} in {project}', { project }) });
584
+ list.push({ id: 'skill', label: tt('assistant.empty.suggestSkill', 'Create Skill'), template: tt('assistant.empty.templateSkill', 'Create a skill that {caret}') });
523
585
  list.push({ id: 'schedule', label: tt('assistant.empty.suggestSchedule', 'Schedule …'), template: tt('assistant.empty.templateSchedule', 'Schedule {caret}') });
524
586
  list.push({ id: 'remember', label: tt('assistant.empty.suggestRemember', 'Remember …'), template: tt('assistant.empty.templateRemember', 'Remember {caret}') });
525
587
  return list;
@@ -531,7 +593,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
531
593
  describeSlash: (cmd) => tt(cmd.descKey, cmd.desc),
532
594
  resolveMemory: (id) => appState.allNodes?.find(n => n.id === id) || null,
533
595
  resolveWhiteboardImage: (id) => { const wb = getWhiteboardElementById(id); return wb?.type === 'image' && wb.dataUrl ? { dataUrl: wb.dataUrl } : null; },
534
- onDraftChange: (text) => { st.draft = text; persist(); director?.type(!!String(text || '').trim()); },
596
+ onDraftChange: (text) => { st.draft = text; persist(); director?.type(!!String(text || '').trim()); renderer.setDrafting?.(!!String(text || '').trim()); },
535
597
  onFocusChange: (focused) => { if (focused) director?.touch(); else director?.stopTyping(); },
536
598
  onAbort: () => abort(),
537
599
  onToast: toast,
@@ -569,6 +631,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
569
631
  const accountHooks = () => ({ t, onChanged: () => picker.refresh(true), onSelect: (id) => applyBrain({ ...st.brain, accountId: id }, { requiresSwitch: true, field: 'account' }) });
570
632
  // Model · effort · permission mode · account sit in the composer row next to attach; project and MCP in the toolbar.
571
633
  const picker = createBrainPicker({ brain: composer.el.querySelector('.asst-composer-brain'), context: barGroups.context }, {
634
+ getSessionId: () => st.sessionId,
572
635
  t,
573
636
  mascot: () => director,
574
637
  getBrain: () => st.brain,
@@ -632,18 +695,40 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
632
695
  onStopAll: () => stopAll(),
633
696
  onRemove: (runId) => removeRun(runId),
634
697
  onClearFinished: () => clearFinished(),
698
+ // A mini scene or a lane: that run's card in the transcript (drawn first when this window never got it).
699
+ onReveal: (runId) => {
700
+ if (renderer.revealRun(runId)) return;
701
+ const run = dock.getRun(runId);
702
+ if (run) { renderer.restoreRuns([run]); renderer.revealRun(runId); }
703
+ },
704
+ // Whatever told the tray (the sync bus, its fetch), the transcript's card and route line follow.
705
+ onRunChange: (run) => renderer.syncRun(run),
635
706
  onToggle: (open) => { st.dockOpen = open; agentsBtn.setAttribute('aria-pressed', open ? 'true' : 'false'); persist(); },
636
707
  onShowAllChange: (showAll) => { st.dockShowAll = showAll; persist(); },
637
- onCountChange: ({ total, active, attention, visible: shown }) => {
708
+ onCountChange: ({ total, active, attention, working = 0, waiting = 0, visible: shown }) => {
638
709
  agentsCount.textContent = String(active || total);
639
710
  agentsCount.classList.toggle('attention', attention > 0);
640
711
  agentsBtn.hidden = !shown;
641
712
  agentsBtn.classList.toggle('attention', attention > 0);
713
+ // Whatever told the tray (this socket, the sync bus, its fetch after a reload): the session's status follows.
714
+ st.workers = { working, waiting };
715
+ pushStatus();
642
716
  },
643
717
  });
644
718
  agentsBtn.setAttribute('aria-pressed', st.dockOpen ? 'true' : 'false');
645
719
 
646
720
  const usage = createUsageGauge(root.querySelector('.asst-usage-host'), { t, sessionId });
721
+ // The first usage strip on screen gets its tip (once, ever).
722
+ const usageHostEl = root.querySelector('.asst-usage-host');
723
+ if (typeof MutationObserver === 'function' && !tipsSeen(storage).has('usage')) {
724
+ const usageTipWatch = new MutationObserver(() => {
725
+ if (usageHostEl.hidden) return;
726
+ usageTipWatch.disconnect();
727
+ tip('usage', () => usageHostEl.querySelector('.asst-usage-strip') || usageHostEl);
728
+ });
729
+ usageTipWatch.observe(usageHostEl, { attributes: true, attributeFilter: ['hidden'] });
730
+ unsubs.push(() => usageTipWatch.disconnect());
731
+ }
647
732
  if (st.usageView) { usage.apply({ type: 'assistant:usage', ...st.usageView }); usage.setConnection('reconnecting'); }
648
733
  let usageFetchSeq = 0;
649
734
  let usageSocketOpened = false;
@@ -688,6 +773,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
688
773
  clearTimeout(limitTimer);
689
774
  limitTimer = null;
690
775
  const limit = st.limit;
776
+ renderer.noteLimit(limit); // the waiting card of this turn's limit error counts to the reported reset
691
777
  limitEl.hidden = !limit;
692
778
  limitEl.dataset.status = limit?.status || '';
693
779
  const text = limitNoticeText(limit, tt);
@@ -777,6 +863,8 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
777
863
  lockControl(packet.request_id, resolvedLabel(packet.origin, tt('assistant.control.state.answered', 'Answered')));
778
864
  return;
779
865
  case 'reattach_result':
866
+ // Whether a turn runs now: a route the journal left open is that turn's, or nobody's.
867
+ renderer.reattached(!!(packet.ok && packet.running));
780
868
  if (packet.ok) {
781
869
  if (packet.sessionId) st.providerSessionId = packet.sessionId;
782
870
  if (packet.resynced) rehydrate({ force: true });
@@ -805,6 +893,8 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
805
893
  finishTurn({ aborted: true });
806
894
  return;
807
895
  case 'error': {
896
+ // The server no longer has this session: no error row and no retry loop; the host closes the tab.
897
+ if (packet.code === 'SESSION_NOT_FOUND') { sessionGone(); return; }
808
898
  // A rejected route answer keeps its card open with the message.
809
899
  const routeCard = packet.request_id ? routeCardByRequest(packet.request_id) : null;
810
900
  if (routeCard) { routeCard.fail(packet.message); return; }
@@ -833,7 +923,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
833
923
  return;
834
924
  case 'assistant:dispatch': {
835
925
  const run = runFromPayload(packet);
836
- if (run) { dock.upsertRun(run); renderer.upsertRunCard(dock.getRun(run.runId) || run); }
926
+ if (run) { dock.upsertRun(run); renderer.upsertRunCard(dock.getRun(run.runId) || run); tip('run', () => renderer.getRunCard(run.runId)); }
837
927
  return;
838
928
  }
839
929
  case 'assistant:permission-request':
@@ -877,7 +967,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
877
967
  switch (ev.type) {
878
968
  case 'synabun.dispatch': {
879
969
  const run = runFromPayload(ev);
880
- if (run) { dock.upsertRun(run); renderer.upsertRunCard(dock.getRun(run.runId) || run); }
970
+ if (run) { dock.upsertRun(run); renderer.upsertRunCard(dock.getRun(run.runId) || run); tip('run', () => renderer.getRunCard(run.runId)); }
881
971
  return;
882
972
  }
883
973
  case 'synabun.dispatch_result': {
@@ -930,11 +1020,12 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
930
1020
  if (meta.id && meta.id !== sessionId) return;
931
1021
  // The server's title names the conversation (history, notifications); the tab's name is the host's.
932
1022
  applyRecordName(meta);
1023
+ if (meta.chatStartedAt || Number(meta.turns) > 0) st.chatStarted = true;
933
1024
  if (meta.brain && typeof meta.brain === 'object') {
934
1025
  const next = normalizeBrain({ ...st.brain, ...meta.brain, provider: meta.brain.provider || meta.brain.brain || st.brain.provider });
935
1026
  if (JSON.stringify(next) !== JSON.stringify(st.brain)) { st.brain = next; picker.render(); host.setBrain?.(next); persist(); }
936
1027
  } else if (typeof meta.brain === 'string') {
937
- const next = normalizeBrain({ ...st.brain, provider: meta.brain, model: meta.model ?? st.brain.model, effort: meta.effort ?? st.brain.effort, accountId: meta.accountId ?? st.brain.accountId, mcpProfile: meta.mcpProfile ?? st.brain.mcpProfile, project: meta.cwd ?? st.brain.project });
1028
+ const next = normalizeBrain({ ...st.brain, provider: meta.brain, model: meta.model ?? st.brain.model, effort: meta.effort ?? st.brain.effort, accountId: meta.accountId ?? st.brain.accountId, tools: meta.tools ?? st.brain.tools, project: meta.cwd ?? st.brain.project });
938
1029
  if (JSON.stringify(next) !== JSON.stringify(st.brain)) { st.brain = next; picker.render(); host.setBrain?.(next); persist(); }
939
1030
  }
940
1031
  if (meta.budget && typeof meta.budget === 'object') budgetController.receiveSession(meta.budget);
@@ -1118,6 +1209,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1118
1209
  if (st.computerRemote) { explainRemoteComputer(); return; }
1119
1210
  const next = enabled === true;
1120
1211
  const wasActive = st.desktopActive;
1212
+ if (next && !st.computerEffective) tip('computer', () => (isRendered(computerToggle.el) ? computerToggle.el : moreBtn));
1121
1213
  st.computerUse = next;
1122
1214
  st.computerEffective = next;
1123
1215
  persist();
@@ -1143,7 +1235,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1143
1235
  elapsedMs: st.turnStartedAt ? Date.now() - st.turnStartedAt : 0,
1144
1236
  }) : null;
1145
1237
  const answer = wasRunning && !aborted ? renderer.turnAnswer() : '';
1146
- renderer.finishTurn({ holdMs: pose ? MASCOT_TIMING.oneShotMs[pose] : 0 });
1238
+ renderer.finishTurn({ holdMs: pose ? MASCOT_TIMING.oneShotMs[pose] : 0, guess: !aborted && !errored });
1147
1239
  if (wasRunning) director.turnEnded(pose);
1148
1240
  if (answer && !silent) announce(tt('assistant.announce.replied', 'SynaBun replied: {text}', { text: answer }));
1149
1241
  st.running = false;
@@ -1183,6 +1275,8 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1183
1275
  providerIcon,
1184
1276
  scrollEnd: () => renderer.scrollEnd(),
1185
1277
  onRespond: (n, decision) => respondControl(n, decision),
1278
+ // A question card's Esc, and its answer when focus was in it: back to the message box.
1279
+ focusComposer: () => composer.focus(),
1186
1280
  renderRoute: (_container, n) => mountRouteCard(n),
1187
1281
  });
1188
1282
  if (!entry) return;
@@ -1224,6 +1318,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1224
1318
  renderer.appendNode(card.el);
1225
1319
  routeCards.set(card.routeId, card);
1226
1320
  routeChip.render();
1321
+ tip('route', () => card.el);
1227
1322
  requestAnimationFrame(() => { if (!destroyed && !card.collapsed) card.focusIfIdle(); });
1228
1323
  return card;
1229
1324
  }
@@ -1343,6 +1438,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1343
1438
  st.turnStartedAt = Date.now();
1344
1439
  setRunning(true);
1345
1440
  sock.send(msg);
1441
+ st.chatStarted = true; // the server stores the session with this prompt
1346
1442
  // Name the conversation like the server will (its first prompt) — not the tab.
1347
1443
  if (!st.userRenamed && (!st.sessionTitle || /^(?:SynaBun|Assistant(?: \d+)?)$/.test(st.sessionTitle))) {
1348
1444
  const guess = String(payload.text || '').split('\n')[0].trim().slice(0, 60);
@@ -1391,8 +1487,9 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1391
1487
  else renames.settled().then(() => { if (!destroyed) sock.send({ type: 'list_sessions' }); }); // a rename on its way is in the list
1392
1488
  return true;
1393
1489
  case 'stop':
1490
+ // /stop all: every run of the session, at once. /stop <target>: the one run it names, or nothing.
1394
1491
  if (parsed.all) await stopAll();
1395
- else if (parsed.target) await stopRun(parsed.target);
1492
+ else if (parsed.target) await stopNamedRun(parsed.target);
1396
1493
  else abort();
1397
1494
  return true;
1398
1495
  case 'agents': {
@@ -1475,7 +1572,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1475
1572
  }
1476
1573
 
1477
1574
  async function dispatch(parsed, payload) {
1478
- const spec = buildDispatchSpec(parsed, st.brain, { assistantSessionId: sessionId });
1575
+ const spec = buildDispatchSpec(parsed, st.brain, { assistantSessionId: sessionId, toolCatalog: await fetchToolCatalog() });
1479
1576
  renderer.appendUser(payload.text);
1480
1577
  try {
1481
1578
  const res = await dispatchAssistantRun(spec);
@@ -1504,15 +1601,34 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1504
1601
  if (!st.running) setRunning(true, { label: tt('assistant.compacting', 'compacting…') });
1505
1602
  }
1506
1603
 
1604
+ /** Nobody chatted in this session yet (and nothing runs in it): New reuses it, leaving it closes it. */
1605
+ function unused() {
1606
+ return !st.chatStarted && !st.running;
1607
+ }
1608
+
1507
1609
  function newSession(provider) {
1508
1610
  const b = provider ? normalizeBrain({ ...st.brain, provider, model: '', effort: null, agent: null, accountId: null }) : st.brain;
1611
+ // This one is still empty: it is the new session (the server keeps one draft, not a pile of them).
1612
+ // /new <provider> switches its brain as the picker does; what only this page showed (/help) is cleared.
1613
+ if (unused() && !destroyed) {
1614
+ if (provider && provider !== st.brain.provider) applyBrain(b, { requiresSwitch: true, field: 'provider' });
1615
+ if (!renderer.isEmpty()) clearTranscript();
1616
+ composer.focus();
1617
+ return;
1618
+ }
1509
1619
  emit('assistant:new', { brain: b, host: hostId });
1510
1620
  }
1511
1621
 
1622
+ /** Open another assistant session; this one goes with it when nobody chatted in it (`replaces`). */
1623
+ function openOther(id) {
1624
+ emit('assistant:resume', { sessionId: id, host: hostId, replaces: unused() ? sessionId : null });
1625
+ }
1626
+
1512
1627
  function resume(id) {
1513
1628
  if (!id) return;
1514
- if (String(id).startsWith('assistant-')) { emit('assistant:resume', { sessionId: id, host: hostId }); return; }
1629
+ if (String(id).startsWith('assistant-')) { if (id !== sessionId) openOther(id); return; }
1515
1630
  sock.send({ type: 'resume', providerSessionId: id });
1631
+ st.chatStarted = true; // a provider conversation: the server stores the session with it
1516
1632
  renderer.appendDivider(tt('assistant.status.resuming', 'resuming {id}', { id: String(id).slice(0, 8) }));
1517
1633
  }
1518
1634
 
@@ -1527,7 +1643,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1527
1643
  if (meta.silent) return;
1528
1644
  if (meta.requiresSwitch) {
1529
1645
  const b = st.brain;
1530
- if (!meta.restartBrain) sock.send({ type: 'switch_brain', brain: b.provider, model: b.model || undefined, effort: b.effort || undefined, accountId: b.accountId || undefined, mcpProfile: b.mcpProfile || undefined, cwd: b.project || undefined, agent: b.agent || undefined, permissionMode: b.permissionMode, planMode: b.planMode === true });
1646
+ if (!meta.restartBrain) sock.send({ type: 'switch_brain', brain: b.provider, model: b.model || undefined, effort: b.effort || undefined, accountId: b.accountId || undefined, tools: b.tools ?? undefined, cwd: b.project || undefined, agent: b.agent || undefined, permissionMode: b.permissionMode, planMode: b.planMode === true });
1531
1647
  renderer.appendDivider(`${tt('assistant.status.brain', 'brain')} → ${brainLabel(b)}`);
1532
1648
  renderer.forgetSeen(); // the new brain's ids start over
1533
1649
  } else if (before.permissionMode !== st.brain.permissionMode || !!before.planMode !== !!st.brain.planMode) {
@@ -1580,9 +1696,29 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1580
1696
  }
1581
1697
  }
1582
1698
 
1699
+ /**
1700
+ * /stop <target>: the run of this session it names (its id or the start of it, its title, the words
1701
+ * of its title: asst-stop.js), and only that one. A target that fits none, or more than one, stops nothing.
1702
+ */
1703
+ async function stopNamedRun(target) {
1704
+ const found = resolveStopTarget(target, dock.getRuns());
1705
+ if (found.run && !found.error) return stopRun(found.run.runId);
1706
+ if (found.passthrough) return stopRun(found.passthrough); // a full id the tray has not loaded: the server knows
1707
+ const name = (run) => `${run.title || run.runId}${run.title ? ` (${String(run.runId).slice(0, 8)})` : ''}`;
1708
+ const message = found.error === 'ambiguous'
1709
+ ? tt('assistant.slash.stopAmbiguous', '"{target}" matches {count} agents: {list}. Nothing was stopped; name one of them.', { target, count: found.matches.length, list: found.matches.map(name).join(', ') })
1710
+ : found.error === 'finished'
1711
+ ? tt('assistant.slash.stopFinished', '{name} has already finished.', { name: name(found.run) })
1712
+ : tt('assistant.slash.stopNoMatch', 'No agent of this session matches "{target}". Nothing was stopped; /agents lists them.', { target });
1713
+ renderer.appendStatus(message);
1714
+ }
1715
+
1583
1716
  async function stopAll() {
1584
- try { await killAllAssistantRuns(sessionId); toast(tt('assistant.status.stopAllRequested', 'Stopping all dispatched agents…')); }
1585
- catch (err) { renderer.appendError(`${tt('assistant.status.stopFailed', 'Stop failed')}: ${err?.message || err}`); }
1717
+ try {
1718
+ const res = await killAllAssistantRuns(sessionId);
1719
+ const count = Array.isArray(res?.stopped) ? res.stopped.length : null;
1720
+ toast(count === null ? tt('assistant.status.stopAllRequested', 'Stopping all dispatched agents…') : plural(tt, 'assistant.status.stopAllDone', count, 'Stopped {count} agent.', 'Stopped {count} agents.'));
1721
+ } catch (err) { renderer.appendError(`${tt('assistant.status.stopFailed', 'Stop failed')}: ${err?.message || err}`); }
1586
1722
  }
1587
1723
 
1588
1724
  async function escalateRun(runId, target) {
@@ -1634,35 +1770,109 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1634
1770
  }
1635
1771
 
1636
1772
  // ── Menus ──
1773
+ /**
1774
+ * The Sessions menu: New, then every session that holds a chat (the server lists no other). Each row
1775
+ * opens its session; its Remove (hover / focus, → from the row, Delete) asks in the row itself, then
1776
+ * removes the session for good: its running turn and agents stop (the question says so), every host
1777
+ * drops its tab, and the session showing here is replaced by a fresh one, as New does.
1778
+ */
1637
1779
  function showSessionsMenu(list) {
1638
- const sessions = (Array.isArray(list) ? list : []).filter(s => s?.id);
1639
- const items = [
1640
- { id: 'new', label: tt('assistant.topbar.new', 'New assistant session'), desc: brainLabel(st.brain), icon: ICON_NEW, onSelect: () => newSession(null) },
1641
- { kind: 'separator' },
1642
- ];
1643
- if (!sessions.length) items.push({ kind: 'info', label: tt('assistant.sessions.empty', 'No other sessions') });
1644
- else items.push({ kind: 'header', label: tt('assistant.sessions.recent', 'Recent') });
1645
- for (const s of sessions.slice(0, 30)) {
1646
- const isCurrent = s.id === sessionId;
1647
- const b = s.brain && typeof s.brain === 'object' ? s.brain : { provider: s.brain, model: s.model, effort: s.effort };
1648
- items.push({
1649
- kind: 'radio',
1650
- id: s.id,
1651
- label: s.title || s.label || s.id,
1652
- desc: [brainLabel(b), relativeTime(s.updatedAt || s.createdAt), s.status].filter(Boolean).join(' · '),
1653
- selected: isCurrent,
1654
- onSelect: () => { if (!isCurrent) emit('assistant:resume', { sessionId: s.id, host: hostId }); },
1655
- });
1656
- }
1657
- openMenu(sessionsBtn, {
1780
+ let sessions = (Array.isArray(list) ? list : []).filter(s => s?.id);
1781
+ let asking = null; // the id of the row that asks "Remove …?"
1782
+ const nameOf = (s) => s.title || s.label || s.id;
1783
+ const build = () => {
1784
+ const items = [
1785
+ { id: 'new', label: tt('assistant.topbar.new', 'New assistant session'), desc: brainLabel(st.brain), icon: ICON_NEW, onSelect: () => newSession(null) },
1786
+ { kind: 'separator' },
1787
+ ];
1788
+ if (!sessions.length) items.push({ kind: 'info', label: tt('assistant.sessions.empty', 'No other sessions') });
1789
+ else items.push({ kind: 'header', label: tt('assistant.sessions.recent', 'Recent') });
1790
+ for (const s of sessions.slice(0, 30)) {
1791
+ const isCurrent = s.id === sessionId;
1792
+ const name = nameOf(s);
1793
+ if (s.id === asking) { items.push(removeQuestion(s, name, isCurrent)); continue; }
1794
+ const b = s.brain && typeof s.brain === 'object' ? s.brain : { provider: s.brain, model: s.model, effort: s.effort };
1795
+ items.push({
1796
+ kind: 'radio',
1797
+ id: s.id,
1798
+ label: name,
1799
+ desc: [brainLabel(b), relativeTime(s.updatedAt || s.createdAt), s.status].filter(Boolean).join(' · '),
1800
+ selected: isCurrent,
1801
+ onSelect: () => { if (!isCurrent) openOther(s.id); },
1802
+ action: {
1803
+ id: `remove:${s.id}`,
1804
+ icon: ICON_TRASH,
1805
+ label: tt('assistant.sessions.removeNamed', 'Remove “{title}”', { title: name }),
1806
+ tooltip: tt('assistant.sessions.remove', 'Remove session'),
1807
+ onSelect: () => ask(s.id),
1808
+ },
1809
+ });
1810
+ }
1811
+ return items;
1812
+ };
1813
+ /** "Remove “name”? …" with Remove and Cancel, in place of the row (it still matches the filter by name). */
1814
+ const removeQuestion = (s, name, isCurrent) => {
1815
+ const runs = Math.max(0, Number(s.activeRuns) || 0);
1816
+ const running = isCurrent ? st.running : s.running === true;
1817
+ const question = [
1818
+ tt('assistant.sessions.removeAsk', 'Remove “{title}” for good?', { title: name }),
1819
+ running ? tt('assistant.sessions.removeStopsTurn', 'Its running turn stops.') : '',
1820
+ runs ? tt('assistant.sessions.removeStopsAgents', 'Its running agents stop ({count}).', { count: runs }) : '',
1821
+ ].filter(Boolean).join(' ');
1822
+ return {
1823
+ kind: 'buttons',
1824
+ id: `ask:${s.id}`,
1825
+ className: 'asst-dd-confirm',
1826
+ label: question,
1827
+ buttons: [
1828
+ { id: `remove-yes:${s.id}`, label: tt('assistant.sessions.removeConfirm', 'Remove'), danger: true, keywords: name, keepOpen: true, onSelect: () => confirmRemove(s, isCurrent) },
1829
+ { id: `remove-no:${s.id}`, label: tt('common.cancel', 'Cancel'), keywords: name, keepOpen: true, onSelect: () => cancel() },
1830
+ ],
1831
+ };
1832
+ };
1833
+ const handle = openMenu(sessionsBtn, {
1658
1834
  title: tt('assistant.topbar.sessions', 'Sessions'),
1659
- items,
1835
+ items: build(),
1660
1836
  role: 'menu',
1661
1837
  placement: 'below',
1662
1838
  width: 300,
1663
1839
  filter: sessions.length > 8,
1664
1840
  filterPlaceholder: tt('assistant.sessions.filter', 'Filter sessions…'),
1841
+ // Esc while a row asks: back to the row, the menu stays open.
1842
+ onEscape: () => { if (!asking) return false; cancel(); return true; },
1665
1843
  });
1844
+ function ask(id) {
1845
+ asking = id;
1846
+ handle?.update({ items: build(), focus: `remove-no:${id}` });
1847
+ }
1848
+ function cancel() {
1849
+ const id = asking;
1850
+ asking = null;
1851
+ handle?.update({ items: build(), focus: id });
1852
+ }
1853
+ function confirmRemove(s, isCurrent) {
1854
+ asking = null;
1855
+ const name = nameOf(s);
1856
+ const done = (result) => {
1857
+ if (result?.ok) return;
1858
+ const text = tt('assistant.sessions.removeFailed', 'Could not remove “{title}”: {error}', { title: name, error: result?.error || tt('assistant.errorGeneric', 'Something went wrong') });
1859
+ if (destroyed) return;
1860
+ renderer.appendError(text);
1861
+ announce(text);
1862
+ };
1863
+ if (isCurrent) {
1864
+ // This panel's own session: a fresh one takes its place (as New), then this one goes.
1865
+ closeMenu();
1866
+ emit('assistant:remove', { sessionId: s.id, fresh: true, brain: st.brain, done });
1867
+ return;
1868
+ }
1869
+ // Another session (open elsewhere or not): its row goes now, and focus stays in the list.
1870
+ const at = sessions.findIndex((row) => row.id === s.id);
1871
+ sessions = sessions.filter((row) => row.id !== s.id);
1872
+ const next = sessions[Math.min(at, sessions.length - 1)];
1873
+ handle?.update({ items: build(), focus: next ? next.id : 'new' });
1874
+ emit('assistant:remove', { sessionId: s.id, fresh: false, done });
1875
+ }
1666
1876
  }
1667
1877
 
1668
1878
  function engineText() {
@@ -1720,6 +1930,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1720
1930
  items.push({ kind: 'info', label: tt('assistant.topbar.cost', 'Session cost'), value: fmtCost(totalCost()) || '$0.00' });
1721
1931
  if (Number(st.dispatchUsd) > 0) items.push({ kind: 'info', label: tt('assistant.topbar.agentsCost', 'Agents'), value: fmtCost(st.dispatchUsd) });
1722
1932
  openMenu(moreBtn, { label: tt('assistant.toolbar.more', 'More options'), items, role: 'menu', placement: 'below', width: 280 });
1933
+ tip('more', () => document.querySelector('.asst-dd-menu'));
1723
1934
  }
1724
1935
 
1725
1936
  // Assistant → Models: switch models off (hidden from routing, dispatch and every model menu).
@@ -1898,6 +2109,18 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1898
2109
  const requestId = msg?.request_id || msg?.requestId;
1899
2110
  if (requestId) lockControl(requestId, resolvedLabel(msg.resolvedBy));
1900
2111
  }));
2112
+ // What this session's workers do right now (Claude and Codex workers stream their events to the page,
2113
+ // OpenCode workers a compact copy of their tool calls: lib/opencode-worker-activity.js):
2114
+ // their stages and the tray's scenes follow the current call.
2115
+ unsubs.push(on('sync:sidepanel:provider-event', (msg) => {
2116
+ const runId = msg?.run?.runId;
2117
+ if (!runId || !dock.getRun(runId)) return;
2118
+ const activity = activityOf(msg.event);
2119
+ if (!activity) return;
2120
+ const stamped = { ...activity, at: Date.now() };
2121
+ renderer.setRunActivity(runId, stamped);
2122
+ dock.setRunActivity(runId, stamped);
2123
+ }));
1901
2124
  unsubs.push(on('sync:assistant:desktop', (msg) => computerPanel.applyDesktop(msg)));
1902
2125
  unsubs.push(on('sync:assistant:desktop-setup', (msg) => computerPanel.applySetup(msg)));
1903
2126
  // Models switched on/off elsewhere: the open Models manager reloads (the menus drop their cache on their own).
@@ -1924,6 +2147,19 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1924
2147
  }
1925
2148
 
1926
2149
  // ── Rehydration ──
2150
+ /**
2151
+ * The server no longer has this session: a draft it dropped (a restart before its first prompt, a
2152
+ * page away too long) or one removed while this page missed the broadcast. The tab closes; one that
2153
+ * was showing with no chat in it is replaced by a fresh session (asst-hosts.js gone), never left dead.
2154
+ */
2155
+ let gone = false;
2156
+ function sessionGone() {
2157
+ if (gone || destroyed) return;
2158
+ gone = true;
2159
+ sock.close();
2160
+ emit('assistant:gone', { sessionId, fresh: visible() && unused(), brain: st.brain });
2161
+ }
2162
+
1927
2163
  async function rehydrate({ force = false } = {}) {
1928
2164
  try {
1929
2165
  const data = await getAssistantSession(sessionId);
@@ -1936,7 +2172,11 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1936
2172
  // A conversation with nothing in it yet may be greeted; a restored one never is.
1937
2173
  if (Array.isArray(transcript) && !transcript.length && !(Number(meta?.turns) > 0)) renderer.offerGreeting();
1938
2174
  for (const run of (Array.isArray(data?.runs) ? data.runs : [])) dock.upsertRun(run);
2175
+ // Run cards are not journaled: the runs the tray fetched come back into the transcript, next to the
2176
+ // calls that dispatched them, and a worker that still works is live at once (its stage, its route line).
2177
+ dock.ready.then(() => { if (!destroyed) renderer.restoreRuns(dock.getRuns()); });
1939
2178
  } catch (err) {
2179
+ if (err?.status === 404) { sessionGone(); return; }
1940
2180
  console.warn('[assistant] could not restore the conversation', err);
1941
2181
  renderer.showEmpty();
1942
2182
  }
@@ -1951,7 +2191,7 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1951
2191
  if (session && typeof session === 'object') applySessionMeta(session);
1952
2192
  else applyFeatures();
1953
2193
  rehydrate().finally(() => {
1954
- if (destroyed) return;
2194
+ if (destroyed || gone) return;
1955
2195
  probeFeatures();
1956
2196
  applyLastUsedRouteMode();
1957
2197
  applyLastUsedTestDensity();
@@ -1984,6 +2224,22 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1984
2224
  resume,
1985
2225
  setRouteMode: (mode) => setRouteMode(mode),
1986
2226
  setComputerUse: (enabled) => setComputerUse(enabled),
2227
+ /**
2228
+ * What the Workspace tour presents on (public/shared/tour/): this panel's own board,
2229
+ * its controls and its director, while the empty state shows its character and nothing
2230
+ * runs. null otherwise (the tour then uses a session-free preview).
2231
+ */
2232
+ tourHost() {
2233
+ const hero = renderer.mascot();
2234
+ if (destroyed || st.running || hero?.kind !== 'hero' || hero.parked?.()) return null;
2235
+ return {
2236
+ root, transcript: transcriptEl, announcer, bar: barEl, renderer, director, composer,
2237
+ live: true,
2238
+ computer: computerAvailable(),
2239
+ refreshStarters: () => renderer.refreshEmpty(),
2240
+ focusComposer: () => composer.focus(),
2241
+ };
2242
+ },
1987
2243
  attachMemory: (node) => composer.addMemory(node),
1988
2244
  attachImageDataUrl: (dataUrl, name) => composer.addImageDataUrl(dataUrl, name),
1989
2245
  insertText: (text) => composer.insertText(text),
@@ -1991,7 +2247,8 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
1991
2247
  attachPath: (path) => { if (path) { composer.insertText(`\`${path}\` `); composer.focus(); } },
1992
2248
  /** The server's name for the conversation (the user's rename, else the first prompt): tooltips. */
1993
2249
  getConversationTitle: () => st.sessionTitle || '',
1994
- getStatus: () => st.status || 'idle',
2250
+ /** The session's status as its host shows it: the brain's own with its dispatched agents' (sessionStatus). */
2251
+ getStatus: () => st.shownStatus || 'idle',
1995
2252
  focus: () => composer.focus(),
1996
2253
  onShown: () => { syncTabLabel(); renderer.scrollEnd(true); if (visible()) composer.focus(); director.touch(); },
1997
2254
  onHidden: () => { closeMenu(); picker.close(); director.stopTyping(); },
@@ -2012,7 +2269,9 @@ export function mountAssistant(viewport, { sessionId, brain, host = {}, session
2012
2269
  unsubs.forEach(off => { try { off(); } catch { /* ignore */ } });
2013
2270
  document.removeEventListener('keydown', onEscCapture, true);
2014
2271
  surfaces.forEach((node) => { node.removeEventListener('keydown', onRootKey); node.removeEventListener('focusin', onFocusIn); });
2015
- closeMenu();
2272
+ // Its own menu closes; another panel's stays open (its Sessions menu may be what removed this session).
2273
+ const menuAnchor = currentMenuAnchor();
2274
+ if (!menuAnchor || !menuAnchor.isConnected || root.contains(menuAnchor) || barEl.contains(menuAnchor)) closeMenu();
2016
2275
  closeFrameLightbox();
2017
2276
  if (helpModal) { helpModal.remove(); helpModal = null; }
2018
2277
  for (const card of routeCards.values()) card.destroy();