synabun 2.0.10 → 2.2.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 (656) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/README.md +25 -2
  3. package/THIRD-PARTY-LICENSES.md +22 -0
  4. package/bin/synabun.js +71 -24
  5. package/docs/whatsapp.md +13 -13
  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/lib/claude-hooks.js +172 -18
  10. package/lib/client-config-repair.js +30 -17
  11. package/lib/desktop-app.js +7 -1
  12. package/lib/external-tools.js +7 -6
  13. package/lib/first-launch-protection.js +57 -12
  14. package/lib/mcp-dist.js +176 -0
  15. package/lib/release-npm-ci.mjs +138 -0
  16. package/lib/release-publish.mjs +91 -0
  17. package/lib/release-scan.mjs +50 -0
  18. package/lib/server-crash-record.js +123 -0
  19. package/lib/server-exit.js +318 -0
  20. package/lib/server-supervisor.js +508 -0
  21. package/lib/start-launcher.js +37 -4
  22. package/lib/tools-cli.js +45 -0
  23. package/lib/update-snapshot.js +302 -0
  24. package/lib/virustotal.mjs +203 -0
  25. package/lib/windows-crash-event.js +269 -0
  26. package/mcp-server/dist/http.d.ts +20 -1
  27. package/mcp-server/dist/http.d.ts.map +1 -1
  28. package/mcp-server/dist/http.js +59 -12
  29. package/mcp-server/dist/http.js.map +1 -1
  30. package/mcp-server/dist/index.d.ts +33 -27
  31. package/mcp-server/dist/index.d.ts.map +1 -1
  32. package/mcp-server/dist/index.js +128 -143
  33. package/mcp-server/dist/index.js.map +1 -1
  34. package/mcp-server/dist/preload.js +1 -1
  35. package/mcp-server/dist/preload.js.map +1 -1
  36. package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
  37. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
  38. package/mcp-server/dist/services/budget-judgments.js +5 -3
  39. package/mcp-server/dist/services/budget-judgments.js.map +1 -1
  40. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  41. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  42. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  43. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  44. package/mcp-server/dist/services/identity.d.ts +2 -2
  45. package/mcp-server/dist/services/identity.js +2 -2
  46. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  47. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  48. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  49. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  50. package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
  51. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
  52. package/mcp-server/dist/services/memory-sessions.js +28 -2
  53. package/mcp-server/dist/services/memory-sessions.js.map +1 -1
  54. package/mcp-server/dist/services/neural-interface.d.ts +18 -11
  55. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  56. package/mcp-server/dist/services/neural-interface.js +67 -11
  57. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  58. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  59. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  60. package/mcp-server/dist/services/server-instructions.js +22 -63
  61. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  62. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  63. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  64. package/mcp-server/dist/services/tool-catalog.js +339 -0
  65. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  66. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  67. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  68. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  69. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  70. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  71. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  72. package/mcp-server/dist/services/tool-list.js +334 -0
  73. package/mcp-server/dist/services/tool-list.js.map +1 -0
  74. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  75. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  76. package/mcp-server/dist/services/tool-runtime.js +400 -0
  77. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  78. package/mcp-server/dist/services/typesafe-config.js +1 -1
  79. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  80. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  81. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  82. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  83. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  84. package/mcp-server/dist/tools/agents.d.ts +14 -14
  85. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  86. package/mcp-server/dist/tools/agents.js +29 -19
  87. package/mcp-server/dist/tools/agents.js.map +1 -1
  88. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  89. package/mcp-server/dist/tools/choice.d.ts +6 -0
  90. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  91. package/mcp-server/dist/tools/choice.js +18 -13
  92. package/mcp-server/dist/tools/choice.js.map +1 -1
  93. package/mcp-server/dist/tools/git-tools.js +2 -2
  94. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  95. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  96. package/mcp-server/dist/tools/image-tools.js +1 -1
  97. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  98. package/mcp-server/dist/tools/morelogin.js +9 -6
  99. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  100. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  101. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  102. package/mcp-server/dist/tools/skill-tools.js +642 -0
  103. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  104. package/mcp-server/dist/tools/skill.d.ts +7 -0
  105. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  106. package/mcp-server/dist/tools/skill.js +11 -0
  107. package/mcp-server/dist/tools/skill.js.map +1 -0
  108. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  109. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  110. package/mcp-server/dist/tools/tool-groups.js +147 -0
  111. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  112. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  113. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  114. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  115. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  116. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  117. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  118. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  119. package/mcp-server/package-lock.json +2 -2
  120. package/mcp-server/package.json +1 -1
  121. package/mcp-server/src/http.ts +75 -12
  122. package/mcp-server/src/index.ts +147 -154
  123. package/mcp-server/src/preload.ts +12 -12
  124. package/mcp-server/src/services/budget-judgments.ts +5 -3
  125. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  126. package/mcp-server/src/services/identity.ts +2 -2
  127. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  128. package/mcp-server/src/services/memory-sessions.ts +24 -3
  129. package/mcp-server/src/services/neural-interface.ts +81 -21
  130. package/mcp-server/src/services/server-instructions.ts +29 -64
  131. package/mcp-server/src/services/tool-catalog.ts +403 -0
  132. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  133. package/mcp-server/src/services/tool-list.ts +410 -0
  134. package/mcp-server/src/services/tool-runtime.ts +457 -0
  135. package/mcp-server/src/services/typesafe-config.ts +1 -1
  136. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  137. package/mcp-server/src/tools/agents.ts +29 -20
  138. package/mcp-server/src/tools/choice.ts +17 -12
  139. package/mcp-server/src/tools/git-tools.ts +2 -2
  140. package/mcp-server/src/tools/image-tools.ts +1 -1
  141. package/mcp-server/src/tools/morelogin.ts +6 -4
  142. package/mcp-server/src/tools/skill-tools.ts +592 -0
  143. package/mcp-server/src/tools/skill.ts +13 -0
  144. package/mcp-server/src/tools/tool-groups.ts +164 -0
  145. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  146. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  147. package/neural-interface/i18n/en.json +3953 -228
  148. package/neural-interface/i18n/pt-BR.json +3901 -179
  149. package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
  150. package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
  151. package/neural-interface/lib/antigravity/acp-connection.js +299 -0
  152. package/neural-interface/lib/antigravity/bypass.js +100 -0
  153. package/neural-interface/lib/antigravity/catalog.js +273 -0
  154. package/neural-interface/lib/antigravity/home.js +260 -0
  155. package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
  156. package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
  157. package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
  158. package/neural-interface/lib/antigravity/policy.js +74 -0
  159. package/neural-interface/lib/antigravity/tool-call.js +178 -0
  160. package/neural-interface/lib/antigravity/transcripts.js +252 -0
  161. package/neural-interface/lib/antigravity/usage.js +43 -0
  162. package/neural-interface/lib/assistant-api.js +128 -28
  163. package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
  164. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  165. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  166. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  167. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  168. package/neural-interface/lib/assistant-brains/opencode.js +120 -54
  169. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
  170. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
  171. package/neural-interface/lib/assistant-budget-planner.js +7 -3
  172. package/neural-interface/lib/assistant-budget-split.js +42 -15
  173. package/neural-interface/lib/assistant-catalog.js +81 -15
  174. package/neural-interface/lib/assistant-config.js +6 -3
  175. package/neural-interface/lib/assistant-dispatch.js +1073 -200
  176. package/neural-interface/lib/assistant-envelope.js +156 -2
  177. package/neural-interface/lib/assistant-evidence.js +80 -0
  178. package/neural-interface/lib/assistant-hidden-models.js +7 -5
  179. package/neural-interface/lib/assistant-persona.js +93 -19
  180. package/neural-interface/lib/assistant-plan-permissions.js +25 -9
  181. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  182. package/neural-interface/lib/assistant-route-gate.js +6 -4
  183. package/neural-interface/lib/assistant-router.js +245 -38
  184. package/neural-interface/lib/assistant-runtime.js +214 -30
  185. package/neural-interface/lib/assistant-task-prompt.js +87 -21
  186. package/neural-interface/lib/assistant-tools.js +51 -0
  187. package/neural-interface/lib/assistant-usage.js +29 -0
  188. package/neural-interface/lib/backup-service.js +626 -4
  189. package/neural-interface/lib/backup-zip-reader.js +10 -5
  190. package/neural-interface/lib/backup-zip-writer.js +257 -0
  191. package/neural-interface/lib/browser-execution.js +10 -2
  192. package/neural-interface/lib/browser-guard-cdp.js +84 -0
  193. package/neural-interface/lib/browser-network-guard.js +476 -0
  194. package/neural-interface/lib/browser-policy-roots.js +64 -0
  195. package/neural-interface/lib/browser-tool-policy.js +198 -38
  196. package/neural-interface/lib/claude-agent-bridge.js +11 -2
  197. package/neural-interface/lib/claude-history-cache.js +210 -0
  198. package/neural-interface/lib/claude-hooks-status.js +103 -0
  199. package/neural-interface/lib/claude-model-catalog.js +5 -1
  200. package/neural-interface/lib/claude-temporary.js +5 -11
  201. package/neural-interface/lib/cli-install-api.js +1 -1
  202. package/neural-interface/lib/cli-install.js +163 -154
  203. package/neural-interface/lib/cli-resolver.js +13 -3
  204. package/neural-interface/lib/cli-update-planner.js +52 -41
  205. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  206. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  207. package/neural-interface/lib/codex-rollout-reader.js +52 -0
  208. package/neural-interface/lib/codex-worker-app-server.js +191 -0
  209. package/neural-interface/lib/confined-fs.js +30 -3
  210. package/neural-interface/lib/crash-notice-api.js +98 -0
  211. package/neural-interface/lib/editor-completion-opencode.js +68 -68
  212. package/neural-interface/lib/editor-git-api.js +3 -20
  213. package/neural-interface/lib/exec-loop-command.js +13 -10
  214. package/neural-interface/lib/file-explorer-api.js +74 -40
  215. package/neural-interface/lib/file-explorer-watch.js +9 -3
  216. package/neural-interface/lib/git-bash/install.js +52 -6
  217. package/neural-interface/lib/git-bash/manager.js +59 -17
  218. package/neural-interface/lib/git-bash/pins.js +12 -0
  219. package/neural-interface/lib/git-read.js +2 -2
  220. package/neural-interface/lib/git-status-runner.js +390 -0
  221. package/neural-interface/lib/git-status-watchdog.js +40 -0
  222. package/neural-interface/lib/greeting/budgets.js +1 -0
  223. package/neural-interface/lib/greeting/engine.js +2 -2
  224. package/neural-interface/lib/greeting/sources.js +10 -12
  225. package/neural-interface/lib/greeting/writer.js +1 -1
  226. package/neural-interface/lib/http-guards.js +8 -2
  227. package/neural-interface/lib/install-details.js +4 -1
  228. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  229. package/neural-interface/lib/mcp-client-config.js +35 -33
  230. package/neural-interface/lib/mcp-external-servers.js +332 -0
  231. package/neural-interface/lib/mcp-installer.js +2 -1
  232. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  233. package/neural-interface/lib/memory-session-capture.js +17 -3
  234. package/neural-interface/lib/morelogin.js +177 -25
  235. package/neural-interface/lib/native-loop-providers.js +965 -66
  236. package/neural-interface/lib/native-loop-runtime.js +290 -42
  237. package/neural-interface/lib/opencode-config.js +557 -0
  238. package/neural-interface/lib/opencode-db-schema.js +17 -34
  239. package/neural-interface/lib/opencode-history.js +48 -218
  240. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  241. package/neural-interface/lib/opencode-native-boundary.js +53 -0
  242. package/neural-interface/lib/opencode-protocol.js +249 -112
  243. package/neural-interface/lib/opencode-runtime-config.js +32 -22
  244. package/neural-interface/lib/opencode-serve-records.js +39 -21
  245. package/neural-interface/lib/opencode-v2-client.js +48 -153
  246. package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
  247. package/neural-interface/lib/opencode-worker-data.js +27 -0
  248. package/neural-interface/lib/opencode2-client.js +73 -37
  249. package/neural-interface/lib/opencode2-proxy.js +23 -63
  250. package/neural-interface/lib/opencode2-translate.js +51 -2
  251. package/neural-interface/lib/owner-authority.js +249 -0
  252. package/neural-interface/lib/page-session.js +275 -0
  253. package/neural-interface/lib/path-confine.js +12 -9
  254. package/neural-interface/lib/peer-identity.js +793 -0
  255. package/neural-interface/lib/pty-host/core.js +28 -1
  256. package/neural-interface/lib/pty-host/lifetime.js +12 -0
  257. package/neural-interface/lib/pty-host/manager.js +12 -1
  258. package/neural-interface/lib/remote-policy.js +1 -1
  259. package/neural-interface/lib/request-gate.js +20 -2
  260. package/neural-interface/lib/rulesets/api.js +7 -6
  261. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  262. package/neural-interface/lib/rulesets/installer.js +180 -36
  263. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  264. package/neural-interface/lib/rulesets/render.js +1 -1
  265. package/neural-interface/lib/session-cache-builder.js +81 -31
  266. package/neural-interface/lib/session-title-generator.js +58 -36
  267. package/neural-interface/lib/skills/api-v2.js +495 -0
  268. package/neural-interface/lib/skills/bundle.js +418 -0
  269. package/neural-interface/lib/skills/catalog.js +298 -0
  270. package/neural-interface/lib/skills/creation-api.js +191 -0
  271. package/neural-interface/lib/skills/creation-brief.js +247 -0
  272. package/neural-interface/lib/skills/creation-sources.js +285 -0
  273. package/neural-interface/lib/skills/creation.js +843 -0
  274. package/neural-interface/lib/skills/deploy.js +569 -0
  275. package/neural-interface/lib/skills/digest.js +119 -0
  276. package/neural-interface/lib/skills/discover.js +111 -0
  277. package/neural-interface/lib/skills/draft-confinement.js +216 -0
  278. package/neural-interface/lib/skills/eval-confinement.js +399 -0
  279. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  280. package/neural-interface/lib/skills/eval-trace.js +135 -0
  281. package/neural-interface/lib/skills/evals-api.js +212 -0
  282. package/neural-interface/lib/skills/evals.js +1573 -0
  283. package/neural-interface/lib/skills/export.js +203 -0
  284. package/neural-interface/lib/skills/frontmatter.js +64 -0
  285. package/neural-interface/lib/skills/health.js +75 -0
  286. package/neural-interface/lib/skills/json-edit.js +165 -0
  287. package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
  288. package/neural-interface/lib/skills/known-bridges.js +96 -0
  289. package/neural-interface/lib/skills/library.js +823 -0
  290. package/neural-interface/lib/skills/local-store.js +21 -0
  291. package/neural-interface/lib/skills/migration.js +433 -0
  292. package/neural-interface/lib/skills/operations.js +45 -0
  293. package/neural-interface/lib/skills/ownership.js +427 -0
  294. package/neural-interface/lib/skills/packages.js +88 -0
  295. package/neural-interface/lib/skills/reviews.js +212 -0
  296. package/neural-interface/lib/skills/revision.js +80 -0
  297. package/neural-interface/lib/skills/roots.js +269 -0
  298. package/neural-interface/lib/skills/runtime-checks.js +358 -0
  299. package/neural-interface/lib/skills/scan-assets.js +252 -0
  300. package/neural-interface/lib/skills/scan-context.js +26 -0
  301. package/neural-interface/lib/skills/scan-shell.js +324 -0
  302. package/neural-interface/lib/skills/scan.js +364 -0
  303. package/neural-interface/lib/skills/scanners.js +54 -0
  304. package/neural-interface/lib/skills/service.js +530 -0
  305. package/neural-interface/lib/skills/telemetry.js +119 -0
  306. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  307. package/neural-interface/lib/synabun-version.js +1 -1
  308. package/neural-interface/lib/system-activity.js +1 -1
  309. package/neural-interface/lib/tool-lists.js +124 -0
  310. package/neural-interface/lib/whatsapp/brain.js +7 -3
  311. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  312. package/neural-interface/lib/whatsapp/cards.js +22 -9
  313. package/neural-interface/lib/whatsapp/config.js +1 -1
  314. package/neural-interface/lib/worker-confinement.js +1268 -0
  315. package/neural-interface/lib/worker-guard-setting.js +56 -0
  316. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  317. package/neural-interface/lib/worker-question.js +74 -0
  318. package/neural-interface/lib/worker-relay-ports.js +227 -0
  319. package/neural-interface/lib/worker-resume.js +238 -0
  320. package/neural-interface/lib/worker-sandbox.js +329 -0
  321. package/neural-interface/package-lock.json +34 -12
  322. package/neural-interface/package.json +3 -2
  323. package/neural-interface/public/index.html +3 -1
  324. package/neural-interface/public/index2d.html +19 -11
  325. package/neural-interface/public/onboarding.html +3 -3
  326. package/neural-interface/public/shared/account-menu.js +8 -5
  327. package/neural-interface/public/shared/agent-runtime-options.js +125 -31
  328. package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
  329. package/neural-interface/public/shared/agy/agy-client.js +266 -0
  330. package/neural-interface/public/shared/agy/agy-commands.js +120 -0
  331. package/neural-interface/public/shared/agy/agy-copy.js +326 -0
  332. package/neural-interface/public/shared/agy/agy-diff.js +161 -0
  333. package/neural-interface/public/shared/agy/agy-events.js +469 -0
  334. package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
  335. package/neural-interface/public/shared/agy/agy-options.js +232 -0
  336. package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
  337. package/neural-interface/public/shared/agy/agy-render.js +392 -0
  338. package/neural-interface/public/shared/agy/agy-setup.js +149 -0
  339. package/neural-interface/public/shared/agy/agy-styles.js +604 -0
  340. package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
  341. package/neural-interface/public/shared/api.js +1527 -1336
  342. package/neural-interface/public/shared/app-frame.js +192 -0
  343. package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
  344. package/neural-interface/public/shared/assistant/asst-api.js +1 -1
  345. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  346. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  347. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  348. package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
  349. package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
  350. package/neural-interface/public/shared/assistant/asst-control.js +205 -26
  351. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  352. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  353. package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
  354. package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
  355. package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
  356. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  357. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  358. package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
  359. package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
  360. package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
  361. package/neural-interface/public/shared/assistant/asst-render.js +445 -82
  362. package/neural-interface/public/shared/assistant/asst-route.js +304 -53
  363. package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
  364. package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
  365. package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
  366. package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
  367. package/neural-interface/public/shared/assistant/asst-state.js +87 -24
  368. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  369. package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
  370. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
  371. package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
  372. package/neural-interface/public/shared/automation-context.js +5 -2
  373. package/neural-interface/public/shared/cc-dropdown.js +89 -19
  374. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  375. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  376. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  377. package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
  378. package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
  379. package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
  380. package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
  381. package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
  382. package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
  383. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  384. package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
  385. package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
  386. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  387. package/neural-interface/public/shared/cli-install-controller.js +218 -0
  388. package/neural-interface/public/shared/cli-install-view.js +11 -12
  389. package/neural-interface/public/shared/cli-status.js +11 -10
  390. package/neural-interface/public/shared/constants.js +5 -4
  391. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  392. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  393. package/neural-interface/public/shared/context-menu-model.js +367 -0
  394. package/neural-interface/public/shared/context-menu.js +372 -0
  395. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  396. package/neural-interface/public/shared/cp/cp-restore.js +162 -0
  397. package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
  398. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  399. package/neural-interface/public/shared/desktop-bridge.js +17 -0
  400. package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
  401. package/neural-interface/public/shared/desktop-titlebar.js +13 -4
  402. package/neural-interface/public/shared/desktop-update-view.js +21 -0
  403. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  404. package/neural-interface/public/shared/explorer/fx-api.js +4 -4
  405. package/neural-interface/public/shared/explorer/fx-links.js +3 -3
  406. package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
  407. package/neural-interface/public/shared/explorer/fx-main.js +48 -16
  408. package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
  409. package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
  410. package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
  411. package/neural-interface/public/shared/html-shell.js +30 -15
  412. package/neural-interface/public/shared/i18n.js +2 -0
  413. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  414. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  415. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  416. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
  417. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  418. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  419. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  420. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  421. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  422. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  423. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  424. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
  425. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  426. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
  427. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
  428. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
  429. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
  430. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  431. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
  432. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  433. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  434. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  435. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  436. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
  437. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  438. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
  439. package/neural-interface/public/shared/page-session.js +96 -0
  440. package/neural-interface/public/shared/provider-icons.js +4 -2
  441. package/neural-interface/public/shared/registry.js +5 -3
  442. package/neural-interface/public/shared/retired-2d.js +3 -0
  443. package/neural-interface/public/shared/schedules-view.js +195 -61
  444. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  445. package/neural-interface/public/shared/settings/settings-data.js +3 -1
  446. package/neural-interface/public/shared/settings/settings-ia.js +6 -6
  447. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  448. package/neural-interface/public/shared/settings/settings-rules.js +2 -2
  449. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  450. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  451. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  452. package/neural-interface/public/shared/showcase-privacy.js +6 -1
  453. package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
  454. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  455. package/neural-interface/public/shared/skills/ss-creation.js +222 -0
  456. package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
  457. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  458. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  459. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  460. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  461. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  462. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  463. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  464. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  465. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  466. package/neural-interface/public/shared/skills/ss-lint.js +149 -0
  467. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  468. package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
  469. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  470. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  471. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  472. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  473. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  474. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  475. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  476. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
  477. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  478. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  479. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  480. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  481. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  482. package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
  483. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  484. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  485. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  486. package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
  487. package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
  488. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  489. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  490. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  491. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
  492. package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
  493. package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
  494. package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
  495. package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
  496. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  497. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  498. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  499. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  500. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  501. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  502. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  503. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  504. package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
  505. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  506. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  507. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  508. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
  509. package/neural-interface/public/shared/state.js +1 -1
  510. package/neural-interface/public/shared/streaming-markdown.js +58 -0
  511. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  512. package/neural-interface/public/shared/styles.css +1822 -1756
  513. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  514. package/neural-interface/public/shared/text-cache.js +29 -0
  515. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  516. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  517. package/neural-interface/public/shared/tool-list-view.js +112 -0
  518. package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
  519. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  520. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  521. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  522. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  523. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  524. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  525. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  526. package/neural-interface/public/shared/tour/tour.css +144 -0
  527. package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
  528. package/neural-interface/public/shared/ui-assistant.js +2 -0
  529. package/neural-interface/public/shared/ui-automation-studio.js +111 -140
  530. package/neural-interface/public/shared/ui-claude-panel.js +376 -82
  531. package/neural-interface/public/shared/ui-cli-banner.js +23 -167
  532. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  533. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  534. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  535. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  536. package/neural-interface/public/shared/ui-detail.js +15 -3
  537. package/neural-interface/public/shared/ui-file-explorer.js +48 -6
  538. package/neural-interface/public/shared/ui-file-links.js +2 -2
  539. package/neural-interface/public/shared/ui-games.js +2 -2
  540. package/neural-interface/public/shared/ui-image-gallery.js +50 -47
  541. package/neural-interface/public/shared/ui-judgments.js +1 -1
  542. package/neural-interface/public/shared/ui-keybinds.js +33 -2
  543. package/neural-interface/public/shared/ui-link.js +3 -3
  544. package/neural-interface/public/shared/ui-menubar.js +10 -20
  545. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  546. package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
  547. package/neural-interface/public/shared/ui-navbar.js +49 -24
  548. package/neural-interface/public/shared/ui-notifications.js +1 -0
  549. package/neural-interface/public/shared/ui-panels.js +96 -65
  550. package/neural-interface/public/shared/ui-resume.js +9 -7
  551. package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
  552. package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
  553. package/neural-interface/public/shared/ui-sessions.js +27 -15
  554. package/neural-interface/public/shared/ui-settings.js +683 -526
  555. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
  556. package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
  557. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  558. package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
  559. package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
  560. package/neural-interface/public/shared/ui-skills.js +33 -2830
  561. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  562. package/neural-interface/public/shared/ui-sync.js +15 -5
  563. package/neural-interface/public/shared/ui-terminal.js +270 -190
  564. package/neural-interface/public/shared/ui-tool-updates.js +6 -4
  565. package/neural-interface/public/shared/ui-tooltip.js +81 -51
  566. package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
  567. package/neural-interface/public/shared/ui-trash.js +6 -4
  568. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  569. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  570. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
  571. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  572. package/neural-interface/public/shared/ui-tutorial.js +285 -509
  573. package/neural-interface/public/shared/ui-update.js +38 -2
  574. package/neural-interface/public/shared/ui-whiteboard.js +312 -59
  575. package/neural-interface/public/shared/ui-worker-end.js +5 -1
  576. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  577. package/neural-interface/public/shared/view-variant.js +66 -0
  578. package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
  579. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  580. package/neural-interface/public/shared/worker-end.js +10 -3
  581. package/neural-interface/public/shared/worker-questions.js +34 -0
  582. package/neural-interface/public/shared/worker-restart.js +12 -0
  583. package/neural-interface/public/sidepanel-session.html +2 -2
  584. package/neural-interface/public/variant/2d/background.js +2 -1
  585. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  586. package/neural-interface/public/variant/2d/graph.js +42 -20
  587. package/neural-interface/public/variant/2d/hulls.js +14 -9
  588. package/neural-interface/public/variant/2d/lasso.js +11 -7
  589. package/neural-interface/public/variant/2d/main.js +32 -1
  590. package/neural-interface/public/variant/2d/minimap.js +11 -13
  591. package/neural-interface/public/variant/3d/main.js +69 -6
  592. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  593. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  594. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  595. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  596. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  597. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  598. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  599. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  600. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  601. package/neural-interface/scripts/build-vendor.mjs +32 -0
  602. package/neural-interface/server.js +4553 -2855
  603. package/neural-interface/templates/rulesets/README.md +1 -1
  604. package/neural-interface/templates/rulesets/core.md +1 -1
  605. package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
  606. package/neural-interface/templates/rulesets/manifest.json +8 -8
  607. package/npm-shrinkwrap.json +34 -12
  608. package/package.json +17 -3
  609. package/postinstall.js +9 -4
  610. package/preuninstall.js +1 -1
  611. package/setup.js +97 -322
  612. package/skills/skill-forge/SKILL.md +177 -0
  613. package/skills/skill-forge/evals/evals.json +54 -0
  614. package/skills/skill-forge/references/package.md +105 -0
  615. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  616. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  617. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  618. package/skills/synabun/SKILL.md +10 -7
  619. package/skills/synabun/modules/audit.md +1 -5
  620. package/skills/synabun/modules/changelog.md +1 -5
  621. package/skills/synabun/modules/idea.md +1 -1
  622. package/skills/synabun/modules/memorize.md +6 -9
  623. package/skills/synabun/modules/schedule.md +6 -6
  624. package/mcp-server/dist/services/profiles.d.ts +0 -120
  625. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  626. package/mcp-server/dist/services/profiles.js +0 -387
  627. package/mcp-server/dist/services/profiles.js.map +0 -1
  628. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  629. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  630. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  631. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  632. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  633. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  634. package/mcp-server/dist/tools/leonardo.js +0 -21
  635. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  636. package/mcp-server/dist/tools/profile.d.ts +0 -17
  637. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  638. package/mcp-server/dist/tools/profile.js +0 -114
  639. package/mcp-server/dist/tools/profile.js.map +0 -1
  640. package/mcp-server/src/services/profiles.ts +0 -428
  641. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  642. package/mcp-server/src/tools/leonardo.ts +0 -30
  643. package/mcp-server/src/tools/profile.ts +0 -122
  644. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  645. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  646. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  647. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  648. package/skills/leonardo/SKILL.md +0 -168
  649. package/skills/leonardo/icon.svg +0 -1
  650. package/skills/leonardo/modules/browser-guide.md +0 -378
  651. package/skills/leonardo/modules/image-prompter.md +0 -283
  652. package/skills/leonardo/modules/model-advisor.md +0 -100
  653. package/skills/leonardo/modules/prompt-library.md +0 -110
  654. package/skills/leonardo/modules/style-guide.md +0 -186
  655. package/skills/leonardo/modules/video-prompter.md +0 -317
  656. /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
@@ -0,0 +1,372 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — Context menu component
3
+ // One menu at a time, at the pointer or by the focused element, in the box of
4
+ // the menubar's dropdown and with its rows (.menu-item, .menu-shortcut,
5
+ // .menu-submenu-arrow, .menu-sep). Items are data (context-menu-logic.js);
6
+ // this module draws them, places the menu and its submenus inside the window,
7
+ // takes the keys while it is open and closes on a press outside, Escape,
8
+ // Tab, scroll, resize, window blur and after an action. Any area can open
9
+ // one; the app's global right-click menu is ui-context-menu.js.
10
+ // ═══════════════════════════════════════════
11
+
12
+ import {
13
+ anchorPoint, firstIndex, lastIndex, normalizeItems, placeMenu, placeSubmenu, stepIndex, typeaheadIndex,
14
+ } from './context-menu-logic.js';
15
+ import { boundsForPoint, frameRect } from './app-frame.js';
16
+
17
+ const SUBMENU_OPEN_DELAY = 120; // hover intent before a submenu opens
18
+ const SUBMENU_GRACE = 300; // the pointer may cross other rows on its way into an open submenu
19
+ const TYPEAHEAD_RESET = 600;
20
+ const ARROW_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>';
21
+
22
+ let _open = null; // the open menu's handle
23
+
24
+ /** Whether a menu is open. */
25
+ export const isContextMenuOpen = () => !!_open;
26
+
27
+ /** Close the open menu, if there is one. `refocus: false` leaves the keyboard where it is. */
28
+ export function closeContextMenu(o) { _open?.close(o); }
29
+
30
+ /** The root element of the open menu, or null. */
31
+ export const openContextMenuElement = () => _open?.element || null;
32
+
33
+ /**
34
+ * Open a menu.
35
+ * @param {object} o
36
+ * @param {import('./context-menu-logic.js').MenuItem[]} o.items
37
+ * @param {number} [o.x] @param {number} [o.y] where the press was (client px)
38
+ * @param {DOMRect | null} [o.anchorRect] opened from the keyboard: the focused element's box, used when x/y are missing
39
+ * @param {string} [o.label] the menu's accessible name
40
+ * @param {boolean} [o.keyboard] opened from the keyboard: the first row has the focus from the start
41
+ * @param {Element | null} [o.returnFocus] where the keyboard goes back to when the menu closes
42
+ * @param {() => void} [o.onClose]
43
+ * @returns {{ close: Function, element: HTMLElement } | null} null when no item is left to show
44
+ */
45
+ export function openContextMenu({ items, x, y, anchorRect = null, label = '', keyboard = false,
46
+ returnFocus = document.activeElement, onClose } = {}) {
47
+ // A menu opened over another one hands the keyboard back to where the first one would have.
48
+ if (_open && (!returnFocus || _open.contains(returnFocus))) returnFocus = _open.returnFocus;
49
+ closeContextMenu({ refocus: false });
50
+ const list = normalizeItems(items);
51
+ if (!list.length) return null;
52
+
53
+ const levels = []; // [{ el, items, rows, active, parentRow }]
54
+ let bounds = null; // the app frame for a menu opened inside it (it and its submenus stay in it), else the window
55
+ let closed = false;
56
+ let subTimer = 0;
57
+ let subPending = null;
58
+ let typed = '';
59
+ let typedAt = 0;
60
+
61
+ // ── Drawing ──
62
+ function drawRow(item) {
63
+ if (item.separator) {
64
+ const sep = document.createElement('div');
65
+ sep.className = 'menu-sep';
66
+ sep.setAttribute('role', 'separator');
67
+ return sep;
68
+ }
69
+ const row = document.createElement('div');
70
+ row.className = 'menu-item';
71
+ row.tabIndex = -1;
72
+ const checkable = typeof item.checked === 'boolean';
73
+ row.setAttribute('role', checkable ? 'menuitemcheckbox' : 'menuitem');
74
+ if (checkable) {
75
+ row.setAttribute('aria-checked', String(item.checked));
76
+ row.classList.toggle('active', item.checked);
77
+ }
78
+ if (item.id) row.dataset.ctxId = item.id;
79
+ if (item.disabled) {
80
+ row.classList.add('disabled');
81
+ row.setAttribute('aria-disabled', 'true');
82
+ }
83
+ const check = document.createElement('span');
84
+ check.className = 'menu-check';
85
+ check.setAttribute('aria-hidden', 'true');
86
+ check.textContent = checkable ? '✓' : '';
87
+ const text = document.createElement('span');
88
+ text.className = 'menu-text';
89
+ if (item.icon) {
90
+ const icon = document.createElement('span');
91
+ icon.className = 'menu-icon';
92
+ icon.setAttribute('aria-hidden', 'true');
93
+ icon.innerHTML = item.icon; // the app's own markup, never text from the page
94
+ text.append(icon);
95
+ }
96
+ const name = document.createElement('span');
97
+ name.className = 'app-ctx-label';
98
+ name.textContent = item.label;
99
+ text.append(name);
100
+ row.append(check, text);
101
+ if (item.submenu) {
102
+ row.setAttribute('aria-haspopup', 'menu');
103
+ row.setAttribute('aria-expanded', 'false');
104
+ const arrow = document.createElement('span');
105
+ arrow.className = 'menu-submenu-arrow';
106
+ arrow.setAttribute('aria-hidden', 'true');
107
+ arrow.innerHTML = ARROW_SVG;
108
+ row.append(arrow);
109
+ } else if (item.shortcut) {
110
+ const key = document.createElement('span');
111
+ key.className = 'menu-shortcut';
112
+ key.textContent = item.shortcut;
113
+ row.append(key);
114
+ }
115
+ return row;
116
+ }
117
+
118
+ function drawLevel(levelItems, name) {
119
+ const el = document.createElement('div');
120
+ el.className = 'app-ctx-menu';
121
+ el.setAttribute('role', 'menu');
122
+ if (name) el.setAttribute('aria-label', name);
123
+ el.tabIndex = -1;
124
+ el.style.visibility = 'hidden';
125
+ const rows = levelItems.map(drawRow);
126
+ el.append(...rows);
127
+ const level = { el, items: levelItems, rows, active: -1, parentRow: null };
128
+ el.addEventListener('pointermove', (event) => onHover(level, event));
129
+ el.addEventListener('click', (event) => {
130
+ const index = rowIndex(level, event.target);
131
+ if (index >= 0) activate(level, index);
132
+ });
133
+ // The press stays off the page: nothing selected there is cleared, nothing behind the menu is focused.
134
+ el.addEventListener('pointerdown', (event) => event.preventDefault());
135
+ el.addEventListener('mousedown', (event) => event.preventDefault());
136
+ el.addEventListener('contextmenu', (event) => event.preventDefault());
137
+ document.body.appendChild(el);
138
+ return level;
139
+ }
140
+
141
+ const rowIndex = (level, node) => {
142
+ const row = node?.closest?.('.menu-item');
143
+ return row ? level.rows.indexOf(row) : -1;
144
+ };
145
+ const levelOf = (index) => levels[index];
146
+ const levelIndex = (level) => levels.indexOf(level);
147
+
148
+ // ── The row the keyboard and the pointer are on ──
149
+ function setActive(level, index, { focus = true } = {}) {
150
+ if (level.active >= 0) level.rows[level.active]?.classList.remove('focused');
151
+ level.active = index;
152
+ const row = index >= 0 ? level.rows[index] : null;
153
+ if (!row) { if (focus) level.el.focus({ preventScroll: true }); return; }
154
+ row.classList.add('focused');
155
+ if (focus) row.focus({ preventScroll: true });
156
+ row.scrollIntoView?.({ block: 'nearest' });
157
+ }
158
+
159
+ // The level the keyboard is in: the deepest one with a row on, else the deepest one open.
160
+ function keyLevel() {
161
+ for (let i = levels.length - 1; i >= 0; i--) if (levels[i].active >= 0) return levels[i];
162
+ return levels[levels.length - 1];
163
+ }
164
+
165
+ // ── Submenus ──
166
+ function openSubmenu(level, index, { focusFirst = false } = {}) {
167
+ cancelTimer();
168
+ const item = level.items[index];
169
+ const row = level.rows[index];
170
+ if (!item?.submenu || item.disabled) return;
171
+ const depth = levelIndex(level);
172
+ const next = levelOf(depth + 1);
173
+ if (next?.parentRow !== row) {
174
+ closeFrom(depth + 1);
175
+ const sub = drawLevel(item.submenu, item.label);
176
+ sub.parentRow = row;
177
+ levels.push(sub);
178
+ row.classList.add('submenu-open');
179
+ row.setAttribute('aria-expanded', 'true');
180
+ const menuRect = level.el.getBoundingClientRect();
181
+ const rowRect = row.getBoundingClientRect();
182
+ const box = sub.el.getBoundingClientRect();
183
+ const at = placeSubmenu({ menuRect, rowRect, width: box.width, height: box.height,
184
+ viewportWidth: window.innerWidth, viewportHeight: window.innerHeight, bounds });
185
+ sub.el.style.left = `${at.left}px`;
186
+ sub.el.style.top = `${at.top}px`;
187
+ sub.el.dataset.side = at.side;
188
+ sub.el.style.visibility = '';
189
+ }
190
+ if (focusFirst) setActive(levelOf(depth + 1), firstIndex(item.submenu));
191
+ }
192
+
193
+ // Close every level from `depth` down; the row that opened the first of them is no longer open.
194
+ function closeFrom(depth) {
195
+ while (levels.length > Math.max(depth, 1)) {
196
+ const level = levels.pop();
197
+ level.parentRow?.classList.remove('submenu-open');
198
+ level.parentRow?.setAttribute('aria-expanded', 'false');
199
+ level.el.remove();
200
+ }
201
+ }
202
+
203
+ function scheduleTimer(row, fn, ms) {
204
+ clearTimeout(subTimer);
205
+ subPending = row;
206
+ subTimer = setTimeout(() => { subTimer = 0; subPending = null; if (!closed) fn(); }, ms);
207
+ }
208
+ function cancelTimer() {
209
+ clearTimeout(subTimer);
210
+ subTimer = 0;
211
+ subPending = null;
212
+ }
213
+
214
+ function onHover(level, event) {
215
+ const index = rowIndex(level, event.target);
216
+ if (index < 0) return;
217
+ const item = level.items[index];
218
+ const row = level.rows[index];
219
+ if (item.disabled) return;
220
+ if (level.active !== index) setActive(level, index);
221
+ // Back in a parent level: the deeper ones lose their highlight, not their place.
222
+ const depth = levelIndex(level);
223
+ for (let i = depth + 1; i < levels.length; i++) setActive(levels[i], -1, { focus: false });
224
+ if (row === subPending) return;
225
+ const next = levelOf(depth + 1);
226
+ if (next) {
227
+ if (next.parentRow === row) { cancelTimer(); return; }
228
+ scheduleTimer(row, () => (item.submenu ? openSubmenu(level, index) : closeFrom(depth + 1)), SUBMENU_GRACE);
229
+ } else if (item.submenu) {
230
+ scheduleTimer(row, () => openSubmenu(level, index), SUBMENU_OPEN_DELAY);
231
+ } else {
232
+ cancelTimer();
233
+ }
234
+ }
235
+
236
+ // ── Choosing ──
237
+ function activate(level, index) {
238
+ const item = level.items[index];
239
+ if (!item || item.separator || item.disabled) return;
240
+ if (item.submenu) { openSubmenu(level, index, { focusFirst: true }); return; }
241
+ close({ refocus: true });
242
+ try {
243
+ const result = item.run?.();
244
+ if (result && typeof result.catch === 'function') result.catch((err) => console.warn('[context-menu] action failed:', err));
245
+ } catch (err) {
246
+ console.warn('[context-menu] action failed:', err);
247
+ }
248
+ }
249
+
250
+ // ── Keys (at the window, before anything in the page; the app's single-key shortcuts must not fire) ──
251
+ function onKey(event) {
252
+ if (event.ctrlKey || event.metaKey || event.altKey) {
253
+ if (event.key === 'Escape') { event.preventDefault(); close({ refocus: true }); }
254
+ return; // the browser's and the system's keys stay theirs
255
+ }
256
+ const level = keyLevel();
257
+ const depth = levelIndex(level);
258
+ const deepest = levels.length - 1; // a submenu the pointer opened may be open without the keyboard in it
259
+ const { key } = event;
260
+ const handled = () => { event.preventDefault(); event.stopPropagation(); };
261
+ // Moving to another row closes a submenu that belongs to the row left.
262
+ const move = (index) => {
263
+ setActive(level, index);
264
+ if (levelOf(depth + 1) && levelOf(depth + 1).parentRow !== level.rows[level.active]) closeFrom(depth + 1);
265
+ };
266
+ switch (key) {
267
+ case 'ArrowDown': handled(); move(stepIndex(level.items, level.active, 1)); return;
268
+ case 'ArrowUp': handled(); move(stepIndex(level.items, level.active, -1)); return;
269
+ case 'Home': handled(); move(firstIndex(level.items)); return;
270
+ case 'End': handled(); move(lastIndex(level.items)); return;
271
+ case 'ArrowRight':
272
+ handled();
273
+ if (level.items[level.active]?.submenu) openSubmenu(level, level.active, { focusFirst: true });
274
+ return;
275
+ case 'ArrowLeft':
276
+ handled();
277
+ if (deepest > 0) backTo(deepest);
278
+ return;
279
+ case 'Escape':
280
+ handled();
281
+ if (deepest > 0) backTo(deepest); else close({ refocus: true });
282
+ return;
283
+ case 'Tab': handled(); close({ refocus: true }); return;
284
+ case 'Enter':
285
+ case ' ':
286
+ handled();
287
+ if (level.active >= 0) activate(level, level.active);
288
+ return;
289
+ default:
290
+ if (key.length !== 1) return;
291
+ handled();
292
+ {
293
+ const now = Date.now();
294
+ typed = now - typedAt > TYPEAHEAD_RESET ? key : typed + key;
295
+ typedAt = now;
296
+ const index = typeaheadIndex(level.items, level.active, typed);
297
+ if (index >= 0) move(index);
298
+ }
299
+ }
300
+ }
301
+ // A Space released on a row must not reach it as a click either.
302
+ function onKeyUp(event) {
303
+ if (!event.ctrlKey && !event.metaKey && !event.altKey && (event.key === ' ' || event.key === 'Enter')) {
304
+ event.preventDefault();
305
+ event.stopPropagation();
306
+ }
307
+ }
308
+
309
+ // Leave a submenu for the row that opened it.
310
+ function backTo(depth) {
311
+ const parent = levelOf(depth - 1);
312
+ const row = levelOf(depth).parentRow;
313
+ closeFrom(depth);
314
+ setActive(parent, parent.rows.indexOf(row));
315
+ }
316
+
317
+ // ── Closing ──
318
+ const inside = (node) => levels.some((level) => level.el.contains(node));
319
+ const onOutsidePress = (event) => { if (!inside(event.target)) close({ refocus: false }); };
320
+ const onScroll = (event) => { if (!inside(event.target)) close({ refocus: false }); };
321
+ const onGone = () => close({ refocus: false });
322
+
323
+ function close({ refocus = true } = {}) {
324
+ if (closed) return;
325
+ closed = true;
326
+ if (_open === handle) _open = null;
327
+ cancelTimer();
328
+ window.removeEventListener('keydown', onKey, true);
329
+ window.removeEventListener('keyup', onKeyUp, true);
330
+ document.removeEventListener('pointerdown', onOutsidePress, true);
331
+ document.removeEventListener('scroll', onScroll, true);
332
+ document.removeEventListener('wheel', onScroll, true);
333
+ window.removeEventListener('resize', onGone);
334
+ window.removeEventListener('blur', onGone);
335
+ // The keyboard goes back where it was, unless the press outside already took it somewhere.
336
+ const active = document.activeElement;
337
+ const held = !active || active === document.body || inside(active);
338
+ for (const level of levels.splice(0)) level.el.remove();
339
+ if (refocus && held && returnFocus?.isConnected && typeof returnFocus.focus === 'function') {
340
+ try { returnFocus.focus({ preventScroll: true }); } catch { /* not focusable any more */ }
341
+ }
342
+ try { onClose?.(); } catch (err) { console.warn('[context-menu] onClose failed:', err); }
343
+ }
344
+
345
+ // ── Open ──
346
+ const root = drawLevel(list, label);
347
+ levels.push(root);
348
+ const box = root.el.getBoundingClientRect();
349
+ let px = x;
350
+ let py = y;
351
+ if (!Number.isFinite(px) || !Number.isFinite(py)) ({ x: px, y: py } = anchorPoint(anchorRect, window.innerWidth, window.innerHeight));
352
+ bounds = boundsForPoint(frameRect(), px, py);
353
+ const at = placeMenu({ x: px, y: py, width: box.width, height: box.height,
354
+ viewportWidth: window.innerWidth, viewportHeight: window.innerHeight, bounds });
355
+ root.el.style.left = `${at.left}px`;
356
+ root.el.style.top = `${at.top}px`;
357
+ root.el.style.visibility = '';
358
+ root.el.classList.add('app-ctx-menu--root');
359
+
360
+ const handle = { close, element: root.el, returnFocus, contains: inside };
361
+ _open = handle;
362
+ window.addEventListener('keydown', onKey, true);
363
+ window.addEventListener('keyup', onKeyUp, true);
364
+ document.addEventListener('pointerdown', onOutsidePress, true);
365
+ document.addEventListener('scroll', onScroll, true);
366
+ document.addEventListener('wheel', onScroll, { capture: true, passive: true });
367
+ window.addEventListener('resize', onGone);
368
+ window.addEventListener('blur', onGone);
369
+ if (keyboard) setActive(root, firstIndex(list));
370
+ else root.el.focus({ preventScroll: true });
371
+ return handle;
372
+ }
@@ -12,6 +12,7 @@
12
12
 
13
13
  import { cpCtx } from './cp-ctx.js';
14
14
  import { contextReading, contextMenuModel, isUnset } from './cp-context-model.js';
15
+ import { frameRect } from '../app-frame.js';
15
16
 
16
17
  const POP_ID = 'cp-context-popover';
17
18
  const LABEL = 'Context settings';
@@ -149,24 +150,24 @@ function tipClipped() {
149
150
  }
150
151
 
151
152
  // Below the cog, its right edge on the cog's; above it when there is more room
152
- // there; always inside the viewport, scrolling inside when it is taller.
153
+ // there; always inside the app frame, scrolling inside when it is taller.
153
154
  function place() {
154
155
  const $cog = cog();
155
156
  if (!_open || !_pop || !$cog) return;
156
157
  const r = $cog.getBoundingClientRect();
157
- const vw = window.innerWidth;
158
- const vh = window.innerHeight;
159
- const width = Math.max(0, Math.min(WIDTH, vw - MARGIN * 2));
158
+ // Inside the app frame (app-frame.js; the whole window on a page without it)
159
+ const f = frameRect();
160
+ const width = Math.max(0, Math.min(WIDTH, f.width - MARGIN * 2));
160
161
  _pop.style.width = `${width}px`;
161
- const below = vh - r.bottom - GAP - MARGIN;
162
- const above = r.top - GAP - MARGIN;
162
+ const below = f.bottom - r.bottom - GAP - MARGIN;
163
+ const above = r.top - f.top - GAP - MARGIN;
163
164
  const up = below < 220 && above > below;
164
165
  _pop.style.maxHeight = `${Math.max(120, up ? above : below)}px`;
165
166
  const height = _pop.offsetHeight;
166
- const left = Math.max(MARGIN, Math.min(r.right - width, vw - width - MARGIN));
167
+ const left = Math.max(f.left + MARGIN, Math.min(r.right - width, f.right - width - MARGIN));
167
168
  const top = up
168
- ? Math.max(MARGIN, r.top - GAP - height)
169
- : Math.max(MARGIN, Math.min(r.bottom + GAP, vh - MARGIN - height));
169
+ ? Math.max(f.top + MARGIN, r.top - GAP - height)
170
+ : Math.max(f.top + MARGIN, Math.min(r.bottom + GAP, f.bottom - MARGIN - height));
170
171
  _pop.style.left = `${Math.round(left)}px`;
171
172
  _pop.style.top = `${Math.round(top)}px`;
172
173
  // Once it has its width: only now is a cut value known.
@@ -6,6 +6,7 @@
6
6
 
7
7
  import { normalizeSession } from './cp-session-model.js';
8
8
  import { TOOL_POLICIES, BYPASS_MODE } from './cp-permission-model.js';
9
+ import { applyTaskTool } from './cp-tool-results.js';
9
10
 
10
11
  const ACCOUNT_ID = /^[A-Za-z0-9_-]{1,64}$/;
11
12
  const PERMISSION_MODES = new Set(['default', 'acceptEdits', 'plan', 'bypassPermissions', 'dontAsk', 'auto']);
@@ -222,3 +223,164 @@ export function pagerState(dataset, labelText = '') {
222
223
  if (!Number.isInteger(start) || !Number.isInteger(total) || start <= 0 || total <= start) return null;
223
224
  return { start, total };
224
225
  }
226
+
227
+ /**
228
+ * Split a history page into `{ head, tail }` so the visible tail (~40 rows) can
229
+ * paint and scroll immediately while earlier rows prepend in chunked tasks.
230
+ * Never splits an `assistant` `tool_use` from its matching `tool_result`.
231
+ */
232
+ export function splitHistoryTail(messages, tailSize = 40) {
233
+ const list = Array.isArray(messages) ? messages : [];
234
+ const cap = Math.max(1, Number(tailSize) || 40);
235
+ if (list.length <= Math.ceil(cap * 1.5)) return { head: [], tail: list };
236
+ let cut = list.length - cap;
237
+ const indexOfToolUse = new Map();
238
+ for (let i = 0; i < list.length; i++) {
239
+ const m = list[i];
240
+ if (m?.role === 'assistant' && Array.isArray(m.tools)) {
241
+ for (const t of m.tools) if (t?.id) indexOfToolUse.set(String(t.id), i);
242
+ }
243
+ }
244
+ for (let i = cut; i < list.length; i++) {
245
+ const m = list[i];
246
+ if (m?.role === 'tool_result' && m.toolUseId) {
247
+ const ownerIdx = indexOfToolUse.get(String(m.toolUseId));
248
+ if (ownerIdx !== undefined && ownerIdx < cut) cut = ownerIdx;
249
+ }
250
+ }
251
+ while (cut > 0 && list[cut]?.role === 'tool_result') cut--;
252
+ if (cut <= 0) return { head: [], tail: list };
253
+ return { head: list.slice(0, cut), tail: list.slice(cut) };
254
+ }
255
+
256
+ /**
257
+ * Chronologically replay TaskCreate / TaskUpdate / TaskList results from a
258
+ * history page so tail-first DOM rendering still preserves exact todo order.
259
+ */
260
+ export function replayTodosFromMessages(messages, initialTodos = []) {
261
+ const list = Array.isArray(messages) ? messages : [];
262
+ const calls = new Map();
263
+ for (const m of list) {
264
+ if (m?.role === 'assistant' && Array.isArray(m.tools)) {
265
+ for (const t of m.tools) {
266
+ if (t?.id && (t.name === 'TaskCreate' || t.name === 'TaskUpdate' || t.name === 'TaskList')) {
267
+ calls.set(String(t.id), t);
268
+ }
269
+ }
270
+ }
271
+ }
272
+ if (!calls.size) return null;
273
+ let todos = Array.isArray(initialTodos) ? initialTodos : [];
274
+ let changed = false;
275
+ for (const m of list) {
276
+ if (m?.role !== 'tool_result' || m.isError || !m.toolUseId) continue;
277
+ const call = calls.get(String(m.toolUseId));
278
+ if (!call) continue;
279
+ const next = applyTaskTool(todos, call.name, call.input || {}, m.structured);
280
+ if (next) {
281
+ todos = next;
282
+ changed = true;
283
+ }
284
+ }
285
+ return changed ? todos : null;
286
+ }
287
+
288
+ // ── One transcript container, several history loads ──
289
+ // A container can be asked for its history more than once while a load is still
290
+ // running (a restored tab shown while its reattach says "resynced", an in-tab
291
+ // session switch). Loads of one container run one after the other, and only the
292
+ // newest asked for renders; rows a rebuild put in are marked so the next one
293
+ // takes them out instead of appending a second copy after them. Rows that came
294
+ // live stay, after the history.
295
+
296
+ /** The property a history row carries: the load (ticket) that rendered it. */
297
+ export const HISTORY_ROW = '_cpHistoryRow';
298
+
299
+ export function markHistoryRows(nodes, ticket) {
300
+ for (const n of nodes || []) if (n && typeof n === 'object') n[HISTORY_ROW] = ticket;
301
+ }
302
+
303
+ /** Rows an earlier rebuild (finished, aborted, or a snapshot put back) left in the container. */
304
+ export function earlierHistoryRows(children, ticket) {
305
+ return [...(children || [])].filter((n) => n && n[HISTORY_ROW] != null && n[HISTORY_ROW] !== ticket);
306
+ }
307
+
308
+ /** Rows that came live: no history mark and not the empty-state placeholder. */
309
+ export function liveRows(children) {
310
+ return [...(children || [])].filter((n) => n && n[HISTORY_ROW] == null && !n.classList?.contains?.('cp-empty'));
311
+ }
312
+
313
+ /**
314
+ * Starts a load of `$msgs`: it waits for the one running there and is skipped when
315
+ * a newer load was asked for meanwhile. `run(isStale)` does the work; `isStale()`
316
+ * is true as soon as a newer load was asked for (the running one stops at its next
317
+ * yield). Returns the promise of this load.
318
+ */
319
+ export function queueHistoryLoad(container, run) {
320
+ const ticket = (container._historyTicket || 0) + 1;
321
+ container._historyTicket = ticket;
322
+ const isStale = () => container._historyTicket !== ticket;
323
+ const prev = container._historyChain || Promise.resolve();
324
+ const job = prev.catch(() => {}).then(() => (isStale() ? undefined : run(isStale, ticket)));
325
+ container._historyChain = job;
326
+ return job;
327
+ }
328
+
329
+ // Messages that put rows in a transcript. One of these for a restored tab whose
330
+ // history is still deferred loads that history first; while any history load of
331
+ // the tab runs, they wait in the tab's buffer, so the history always comes first.
332
+ const TRANSCRIPT_MESSAGES = new Set(['event', 'turn_started', 'stderr', 'done', 'aborted', 'error']);
333
+
334
+ /** 'load' (start the deferred history, then hold the message), 'hold', or 'pass'. */
335
+ export function historyGate(tab, msg, bypass = false) {
336
+ if (!tab || bypass) return 'pass';
337
+ const deferred = !!tab._historyDeferred && tab._historyDeferred === tab.sessionId && !tab.automationRunId;
338
+ if (deferred && TRANSCRIPT_MESSAGES.has(msg?.type)) return 'load';
339
+ if (tab._historyHold > 0) return 'hold';
340
+ return 'pass';
341
+ }
342
+
343
+ /**
344
+ * A live tool result whose card a running replay has not rendered yet (it sits in
345
+ * a head chunk still to come) is kept here and applied when the card is built.
346
+ */
347
+ export function holdPendingResult(tab, ev) {
348
+ if (!tab || !ev?.tool_use_id || !(tab._historyRendering > 0) || tab._replayRow) return false;
349
+ if (!(tab._pendingResults instanceof Map)) tab._pendingResults = new Map();
350
+ tab._pendingResults.set(String(ev.tool_use_id), ev);
351
+ return true;
352
+ }
353
+
354
+ export function takePendingResult(tab, toolUseId) {
355
+ const map = tab?._pendingResults;
356
+ if (!(map instanceof Map) || !toolUseId) return null;
357
+ const ev = map.get(String(toolUseId)) || null;
358
+ if (ev) map.delete(String(toolUseId));
359
+ return ev;
360
+ }
361
+
362
+ /** Whether a task tool's result may change the todo list now (a replayed one is in the precomputed list). */
363
+ export function taskResultAppliesTodos(tab, ev) {
364
+ if (!tab || tab._agentScope || ev?.is_error) return false;
365
+ return !(tab._skipReplayTodos && tab._replayRow);
366
+ }
367
+
368
+ /**
369
+ * Renders `rows` with `render(row)` (which appends to `container`), marks the
370
+ * nodes it added as load `ticket`'s and moves them before `before` (a live row,
371
+ * or the first row of the tail already shown), so rows already on screen are
372
+ * never moved or rebuilt: the browser's scroll anchoring keeps a reader who
373
+ * scrolled up where they were while older rows go in above. `skip` holds nodes
374
+ * that are never taken as added (the live rows). Returns the added nodes.
375
+ */
376
+ export function renderHistoryRowsInto(container, rows, render, { before = null, ticket = null, skip = null } = {}) {
377
+ const marker = container.lastElementChild;
378
+ for (const row of rows || []) render(row);
379
+ const added = [];
380
+ for (let n = marker ? marker.nextElementSibling : container.firstElementChild; n; n = n.nextElementSibling) {
381
+ if (!skip || !skip.has(n)) added.push(n);
382
+ }
383
+ markHistoryRows(added, ticket);
384
+ if (before && before.parentNode === container) for (const n of added) container.insertBefore(n, before);
385
+ return added;
386
+ }
@@ -3,6 +3,7 @@
3
3
  // puts that on the card. Live tool results and replayed history take the same
4
4
  // path, so a reopened session looks like the live one did.
5
5
 
6
+ import { taskResultAppliesTodos } from './cp-restore.js';
6
7
  import { cpCtx } from './cp-ctx.js';
7
8
  import { escapeHtml } from './cp-markdown.js';
8
9
  import {
@@ -212,11 +213,12 @@ export function applyStructuredResult(tab, card, ev) {
212
213
  body.appendChild(stats);
213
214
  }
214
215
  // The task tools keep the list the todo dock shows (root conversation only).
215
- if (!tab._agentScope && !ev.is_error) {
216
+ // A replayed result is already in the list the replay computed; a live one is applied over it.
217
+ if (taskResultAppliesTodos(tab, ev)) {
216
218
  const next = applyTaskTool(tab.todos, name, input, ev.tool_use_result);
217
219
  if (next) {
218
220
  tab.todos = next;
219
- try { cpCtx.renderTodoWidget(tab); } catch {}
221
+ if (!tab._replaying) { try { cpCtx.renderTodoWidget(tab); } catch {} }
220
222
  }
221
223
  }
222
224
  return { view, content: view.content };
@@ -285,7 +287,12 @@ export function buildHistoryPlanCard(block) {
285
287
 
286
288
  /** A replayed result for one of the two cards above. True when it was one of them. */
287
289
  export function fillHistoryCard($msgs, row) {
288
- const card = $msgs.querySelector(`.cp-history-card[data-tool-id="${CSS.escape(String(row.toolUseId || ''))}"]`);
290
+ const id = String(row.toolUseId || '');
291
+ let card = null;
292
+ // A replay indexes the cards it builds (no selector scan per result); a card it did not build is looked up.
293
+ const indexed = $msgs?._replayCards instanceof Map ? $msgs._replayCards.get(id) : null;
294
+ if (indexed) card = indexed.classList?.contains('cp-history-card') ? indexed : null;
295
+ else card = $msgs.querySelector(`.cp-history-card[data-tool-id="${CSS.escape(id)}"]`);
289
296
  if (!card) return false;
290
297
  if (card.classList.contains('cp-ask-history')) {
291
298
  const rows = askAnswerRows(card._toolInput, row.structured, row.isError ? '' : (row.text || ''));