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
@@ -1,3 +1,4 @@
1
+ import { toolListView } from './tool-list-view.js';
1
2
  // SynaBun Neural Interface — what the Schedules window shows, without the page.
2
3
  // Which schedules a view lists and in which order, how a schedule's state reads, and the cron
3
4
  // in plain words. ui-schedules-studio.js draws it; tests import this file under Node, so it
@@ -11,49 +12,161 @@ export const OVERDUE_AFTER = 5 * MINUTE;
11
12
  // "Up next" looks this far ahead.
12
13
  export const UP_NEXT_WINDOW = DAY;
13
14
 
14
- const DAY_SHORT = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
15
-
16
15
  export const VIEW_SCOPES = ['upcoming', 'all', 'attention', 'paused', 'timers', 'activity'];
17
16
  export const LIST_SCOPES = ['upcoming', 'all', 'attention', 'paused'];
18
17
  export const SORTS = ['next', 'name', 'last'];
19
18
 
19
+ // ── Words ──
20
+ // SCHEDULES_VIEW_COPY is the English of every word this file shows: `schedules.view.*` in
21
+ // i18n/en.json must equal it, and every locale file holds the same keys (the test checks both).
22
+ // A `{ one, other }` entry is counted, as i18n's tp() counts. Without a translator (tests, Node)
23
+ // the English reads as written; the window installs i18n's t() and the app's locale with
24
+ // setSchedulesViewTranslator.
25
+ export const SCHEDULES_VIEW_COPY = Object.freeze({
26
+ everyDay: 'Every day',
27
+ weekdays: 'Weekdays',
28
+ weekends: 'Weekends',
29
+ dayRange: '{from}–{to}',
30
+ monthDays: { one: 'Day {days} of every month', other: 'Days {days} of every month' },
31
+ everyMinutes: { one: 'every minute', other: 'every {count} minutes' },
32
+ everyHoursAt: { one: 'every hour at :{minute}', other: 'every {count} hours at :{minute}' },
33
+ everyHourBetween: 'every hour from {from} to {to}',
34
+ daysAt: '{days} at {times}',
35
+ daysEvery: '{days}, {every}',
36
+ listAnd: '{list} and {last}',
37
+ dayShort: { sun: 'Sun', mon: 'Mon', tue: 'Tue', wed: 'Wed', thu: 'Thu', fri: 'Fri', sat: 'Sat' },
38
+ dayLong: { sun: 'Sunday', mon: 'Monday', tue: 'Tuesday', wed: 'Wednesday', thu: 'Thursday', fri: 'Friday', sat: 'Saturday' },
39
+ runNever: 'Not run yet',
40
+ runCompleted: 'Completed',
41
+ runStarted: 'Started',
42
+ runAutomationMissing: 'Automation missing',
43
+ runAutomationMissingReason: 'The automation this schedule launches no longer exists.',
44
+ runFailed: 'Failed',
45
+ runFailedReason: 'The run failed.',
46
+ runStopped: 'Stopped',
47
+ runStoppedByYou: 'Stopped by you',
48
+ runInterrupted: 'Interrupted',
49
+ notScheduled: 'Not scheduled',
50
+ dueNow: 'Due now',
51
+ overdue: 'Overdue',
52
+ inSeconds: 'in {n} s',
53
+ inMinutes: 'in {n} min',
54
+ inHoursMinutes: 'in {h} h {m} min',
55
+ inHours: 'in {h} h',
56
+ inDaysHours: 'in {d} d {h} h',
57
+ inDays: 'in {d} d',
58
+ justNow: 'just now',
59
+ minutesAgo: '{n} min ago',
60
+ hoursAgo: '{n} h ago',
61
+ yesterdayAgo: 'yesterday',
62
+ daysAgo: '{n} d ago',
63
+ today: 'Today',
64
+ tomorrow: 'Tomorrow',
65
+ yesterday: 'Yesterday',
66
+ dayAt: '{day} {time}',
67
+ tomorrowAt: 'Tomorrow {time}',
68
+ weekdayAt: '{day} {time}',
69
+ factCli: 'CLI',
70
+ factModel: 'Model',
71
+ factContext: 'Context',
72
+ factThinking: 'Thinking',
73
+ factMcp: 'Tools and MCP servers',
74
+ factAccount: 'OpenAI account',
75
+ factBrowser: 'Browser',
76
+ valueDefault: 'Default',
77
+ valueOn: 'On',
78
+ valueOff: 'Off',
79
+ context1m: '1M tokens',
80
+ contextExtended: 'Extended',
81
+ effort: { none: 'None', minimal: 'Minimal', low: 'Low', medium: 'Medium', high: 'High', xhigh: 'Xhigh', max: 'Max', ultra: 'Ultra', thinking: 'Thinking' },
82
+ });
83
+
84
+ let _translate = null;
85
+ let _locale = null;
86
+
87
+ /**
88
+ * The page's translator, `(key, params) => t('schedules.view.' + key, params)`, and the app's locale
89
+ * (a code or a function that returns one). An answer that is empty, or the key itself (i18n's word for
90
+ * "no such string"), falls back to the English.
91
+ */
92
+ export function setSchedulesViewTranslator(fn, locale = null) {
93
+ _translate = typeof fn === 'function' ? fn : null;
94
+ _locale = locale;
95
+ }
96
+
97
+ const copyAt = (key) => key.split('.').reduce((node, part) => node?.[part], SCHEDULES_VIEW_COPY);
98
+ const fill = (text, params) => String(text).replace(/\{(\w+)\}/g, (whole, name) => (params?.[name] != null ? params[name] : whole));
99
+
100
+ /** A SCHEDULES_VIEW_COPY sentence in the page's language (the translator above, else the English). */
101
+ export function scheduleWord(key, params) {
102
+ if (_translate) {
103
+ try {
104
+ const text = _translate(key, params);
105
+ if (typeof text === 'string' && text && text !== key && text !== `schedules.view.${key}`) return text;
106
+ } catch { /* the English below */ }
107
+ }
108
+ const english = copyAt(key);
109
+ return typeof english === 'string' ? fill(english, params) : key;
110
+ }
111
+
112
+ /** A counted sentence: `key.one` for exactly one, `key.other` otherwise (i18n's tp rule). */
113
+ const countWord = (key, count, params) => scheduleWord(`${key}.${count === 1 ? 'one' : 'other'}`, { count, ...params });
114
+
115
+ /**
116
+ * The locale dates and times are written in. English keeps en-GB: the 24-hour clock and day-first dates
117
+ * ("Wed 22 Oct 09:00") the cron descriptions use. Any other language writes them its own way.
118
+ */
119
+ export function scheduleDateLocale() {
120
+ const locale = typeof _locale === 'function' ? _locale() : _locale;
121
+ return !locale || /^en(-|$)/i.test(locale) ? 'en-GB' : locale;
122
+ }
123
+
124
+ const DAY_KEYS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
125
+
126
+ /** A weekday (0 = Sunday … 6 = Saturday; 7 is Sunday too, as in cron): "Mon", or "Monday" with `long`. */
127
+ export function weekdayName(index, { long = false } = {}) {
128
+ const key = DAY_KEYS[Number(index) % 7];
129
+ return key ? scheduleWord(`${long ? 'dayLong' : 'dayShort'}.${key}`) : '';
130
+ }
131
+
20
132
  const pad = (n) => String(n).padStart(2, '0');
21
133
  const time = (t) => (Number.isFinite(t) ? t : NaN);
22
134
  const parse = (iso) => (iso ? time(Date.parse(iso)) : NaN);
23
135
 
24
- /** "a", "a and b", "a, b and c". */
136
+ /** "a", "a and b", "a, b and c" (the last joint in the page's language). */
25
137
  export function listJoin(items) {
26
- const list = items.filter(Boolean);
138
+ const list = items.filter(item => item || item === 0).map(String);
27
139
  if (list.length <= 1) return list.join('');
28
- return `${list.slice(0, -1).join(', ')} and ${list.at(-1)}`;
140
+ return scheduleWord('listAnd', { list: list.slice(0, -1).join(', '), last: list.at(-1) });
29
141
  }
30
142
 
143
+ /** The days of a cron's day-of-week field: `{ text, everyDay }`, or null when it cannot be said plainly. */
31
144
  function dayList(field) {
32
- if (field === '*' || field === '?') return 'Every day';
33
- if (field === '1-5') return 'Weekdays';
34
- if (field === '0,6' || field === '6,0' || field === '6,7') return 'Weekends';
145
+ if (field === '*' || field === '?') return { text: scheduleWord('everyDay'), everyDay: true };
146
+ if (field === '1-5') return { text: scheduleWord('weekdays') };
147
+ if (field === '0,6' || field === '6,0' || field === '6,7') return { text: scheduleWord('weekends') };
35
148
  const parts = field.split(',');
36
149
  const names = [];
37
150
  for (const part of parts) {
38
151
  const range = part.match(/^(\d)-(\d)$/);
39
152
  if (range) {
40
- const from = DAY_SHORT[+range[1] % 7], to = DAY_SHORT[+range[2] % 7];
153
+ const from = weekdayName(range[1]), to = weekdayName(range[2]);
41
154
  if (!from || !to) return null;
42
- names.push(`${from}–${to}`);
155
+ names.push(scheduleWord('dayRange', { from, to }));
43
156
  } else if (/^\d$/.test(part)) {
44
- names.push(DAY_SHORT[+part % 7]);
157
+ names.push(weekdayName(part));
45
158
  } else {
46
159
  return null;
47
160
  }
48
161
  }
49
- return listJoin(names);
162
+ return { text: listJoin(names) };
50
163
  }
51
164
 
52
165
  function timesOf(minute, hour) {
53
166
  const m = /^\d{1,2}$/.test(minute) ? +minute : null;
54
- if (minute === '*' && hour === '*') return { every: 'every minute' };
167
+ if (minute === '*' && hour === '*') return { every: countWord('everyMinutes', 1) };
55
168
  const minStep = minute.match(/^\*\/(\d+)$/);
56
- if (minStep && hour === '*') return { every: `every ${minStep[1]} minutes` };
169
+ if (minStep && hour === '*') return { every: countWord('everyMinutes', +minStep[1]) };
57
170
  if (m == null) {
58
171
  // Several minutes in one hour: "at 09:00 and 09:30".
59
172
  if (/^\d{1,2}(,\d{1,2})+$/.test(minute) && /^\d{1,2}$/.test(hour)) {
@@ -61,15 +174,18 @@ function timesOf(minute, hour) {
61
174
  }
62
175
  return null;
63
176
  }
64
- if (hour === '*') return { every: `every hour at :${pad(m)}` };
177
+ if (hour === '*') return { every: countWord('everyHoursAt', 1, { minute: pad(m) }) };
65
178
  const hourStep = hour.match(/^\*\/(\d+)$/);
66
- if (hourStep) return { every: `every ${hourStep[1]} hours at :${pad(m)}` };
179
+ if (hourStep) return { every: countWord('everyHoursAt', +hourStep[1], { minute: pad(m) }) };
67
180
  const hourRange = hour.match(/^(\d{1,2})-(\d{1,2})$/);
68
- if (hourRange) return { every: `every hour from ${pad(+hourRange[1])}:${pad(m)} to ${pad(+hourRange[2])}:${pad(m)}` };
181
+ if (hourRange) return { every: scheduleWord('everyHourBetween', { from: `${pad(+hourRange[1])}:${pad(m)}`, to: `${pad(+hourRange[2])}:${pad(m)}` }) };
69
182
  if (/^\d{1,2}(,\d{1,2})*$/.test(hour)) return { at: listJoin(hour.split(',').map(h => `${pad(+h)}:${pad(m)}`)) };
70
183
  return null;
71
184
  }
72
185
 
186
+ // A sentence that starts with a phrase written for its middle ("every 15 minutes").
187
+ const capitalize = (text) => text.charAt(0).toLocaleUpperCase(scheduleDateLocale()) + text.slice(1);
188
+
73
189
  /**
74
190
  * A five-field cron in plain words: "Every day at 06:55, 14:55 and 20:55", "Weekdays at 09:00",
75
191
  * "Every 15 minutes". Anything it cannot say plainly comes back as the expression itself.
@@ -84,13 +200,12 @@ export function describeCron(cron) {
84
200
  if (dom === '*' || dom === '?') days = dayList(dow);
85
201
  else if (dow === '*' && /^\d{1,2}(,\d{1,2})*$/.test(dom)) {
86
202
  const dates = dom.split(',').map(Number);
87
- days = `${dates.length > 1 ? 'Days' : 'Day'} ${listJoin(dates)} of every month`;
203
+ days = { text: countWord('monthDays', dates.length, { days: listJoin(dates) }) };
88
204
  } else return expr;
89
205
  const times = timesOf(minute, hour);
90
206
  if (!days || !times) return expr;
91
- if (times.at) return `${days} at ${times.at}`;
92
- const every = times.every.charAt(0).toUpperCase() + times.every.slice(1);
93
- return days === 'Every day' ? every : `${days}, ${times.every}`;
207
+ if (times.at) return scheduleWord('daysAt', { days: days.text, times: times.at });
208
+ return days.everyDay ? capitalize(times.every) : scheduleWord('daysEvery', { days: days.text, every: times.every });
94
209
  }
95
210
 
96
211
  /** One line of text from a run result: no newlines, no runs of spaces. */
@@ -104,17 +219,18 @@ export function oneLine(text) {
104
219
  */
105
220
  export function lastRunState(schedule) {
106
221
  const raw = schedule?.lastRunResult;
107
- if (raw == null || raw === '') return { kind: 'never', label: 'Not run yet', reason: '' };
222
+ if (raw == null || raw === '') return { kind: 'never', label: scheduleWord('runNever'), reason: '' };
108
223
  const text = String(raw);
109
- if (text === 'completed') return { kind: 'ok', label: 'Completed', reason: '' };
110
- if (text === 'launched' || text === 'running' || text === 'started') return { kind: 'started', label: 'Started', reason: '' };
111
- if (text === 'template_missing') return { kind: 'failed', label: 'Automation missing', reason: 'The automation this schedule launches no longer exists.' };
224
+ if (text === 'completed') return { kind: 'ok', label: scheduleWord('runCompleted'), reason: '' };
225
+ if (text === 'launched' || text === 'running' || text === 'started') return { kind: 'started', label: scheduleWord('runStarted'), reason: '' };
226
+ if (text === 'template_missing') return { kind: 'failed', label: scheduleWord('runAutomationMissing'), reason: scheduleWord('runAutomationMissingReason') };
227
+ // What follows the colon is the server's own message: it shows as it came.
112
228
  const colon = text.indexOf(':');
113
229
  const head = (colon >= 0 ? text.slice(0, colon) : text).trim();
114
230
  const reason = colon >= 0 ? text.slice(colon + 1).trim() : '';
115
- if (head === 'error') return { kind: 'failed', label: 'Failed', reason: reason || 'The run failed.' };
116
- if (head === 'stopped') return { kind: 'stopped', label: 'Stopped', reason: reason === 'user' ? 'Stopped by you' : reason };
117
- if (head === 'interrupted') return { kind: 'interrupted', label: 'Interrupted', reason };
231
+ if (head === 'error') return { kind: 'failed', label: scheduleWord('runFailed'), reason: reason || scheduleWord('runFailedReason') };
232
+ if (head === 'stopped') return { kind: 'stopped', label: scheduleWord('runStopped'), reason: reason === 'user' ? scheduleWord('runStoppedByYou') : reason };
233
+ if (head === 'interrupted') return { kind: 'interrupted', label: scheduleWord('runInterrupted'), reason };
118
234
  return { kind: 'other', label: head.charAt(0).toUpperCase() + head.slice(1), reason };
119
235
  }
120
236
 
@@ -215,17 +331,17 @@ export function sortSchedules(list, sort = 'next') {
215
331
  /** "in 45 s", "in 26 min", "in 3 h 5 min", "in 2 d 4 h"; "Due now"; "Overdue". */
216
332
  export function formatCountdown(iso, now = Date.now()) {
217
333
  const next = parse(iso);
218
- if (!Number.isFinite(next)) return { text: 'Not scheduled', state: 'none' };
334
+ if (!Number.isFinite(next)) return { text: scheduleWord('notScheduled'), state: 'none' };
219
335
  const diff = next - now;
220
- if (diff <= 0) return diff > -OVERDUE_AFTER ? { text: 'Due now', state: 'due' } : { text: 'Overdue', state: 'overdue' };
221
- if (diff < MINUTE) return { text: `in ${Math.ceil(diff / 1000)} s`, state: 'soon' };
222
- if (diff < HOUR) return { text: `in ${Math.floor(diff / MINUTE)} min`, state: diff < 15 * MINUTE ? 'soon' : 'future' };
336
+ if (diff <= 0) return diff > -OVERDUE_AFTER ? { text: scheduleWord('dueNow'), state: 'due' } : { text: scheduleWord('overdue'), state: 'overdue' };
337
+ if (diff < MINUTE) return { text: scheduleWord('inSeconds', { n: Math.ceil(diff / 1000) }), state: 'soon' };
338
+ if (diff < HOUR) return { text: scheduleWord('inMinutes', { n: Math.floor(diff / MINUTE) }), state: diff < 15 * MINUTE ? 'soon' : 'future' };
223
339
  if (diff < DAY) {
224
340
  const h = Math.floor(diff / HOUR), m = Math.floor((diff % HOUR) / MINUTE);
225
- return { text: m ? `in ${h} h ${m} min` : `in ${h} h`, state: 'future' };
341
+ return { text: m ? scheduleWord('inHoursMinutes', { h, m }) : scheduleWord('inHours', { h }), state: 'future' };
226
342
  }
227
343
  const d = Math.floor(diff / DAY), h = Math.floor((diff % DAY) / HOUR);
228
- return { text: h ? `in ${d} d ${h} h` : `in ${d} d`, state: 'future' };
344
+ return { text: h ? scheduleWord('inDaysHours', { d, h }) : scheduleWord('inDays', { d }), state: 'future' };
229
345
  }
230
346
 
231
347
  /** "just now", "5 min ago", "2 h ago", "yesterday", "3 d ago". */
@@ -233,59 +349,77 @@ export function formatAgo(iso, now = Date.now()) {
233
349
  const then = parse(iso);
234
350
  if (!Number.isFinite(then)) return '';
235
351
  const diff = Math.max(0, now - then);
236
- if (diff < MINUTE) return 'just now';
237
- if (diff < HOUR) return `${Math.floor(diff / MINUTE)} min ago`;
238
- if (diff < DAY) return `${Math.floor(diff / HOUR)} h ago`;
352
+ if (diff < MINUTE) return scheduleWord('justNow');
353
+ if (diff < HOUR) return scheduleWord('minutesAgo', { n: Math.floor(diff / MINUTE) });
354
+ if (diff < DAY) return scheduleWord('hoursAgo', { n: Math.floor(diff / HOUR) });
239
355
  const days = Math.floor(diff / DAY);
240
- return days === 1 ? 'yesterday' : `${days} d ago`;
356
+ return days === 1 ? scheduleWord('yesterdayAgo') : scheduleWord('daysAgo', { n: days });
241
357
  }
242
358
 
243
359
  const sameDay = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
244
- // The window's words are English, so are its dates: "Wed 22 Oct", never half in another language.
245
- const LOCALE = 'en-GB';
246
360
 
247
361
  /** "Today", "Tomorrow", "Yesterday" or the weekday and date, for a heading or a time. */
248
- export function dayLabel(iso, now = Date.now(), locale = LOCALE) {
362
+ export function dayLabel(iso, now = Date.now(), locale = scheduleDateLocale()) {
249
363
  const then = new Date(parse(iso));
250
364
  if (Number.isNaN(then.getTime())) return '';
251
365
  const today = new Date(now);
252
- if (sameDay(then, today)) return 'Today';
253
- if (sameDay(then, new Date(now + DAY))) return 'Tomorrow';
254
- if (sameDay(then, new Date(now - DAY))) return 'Yesterday';
366
+ if (sameDay(then, today)) return scheduleWord('today');
367
+ if (sameDay(then, new Date(now + DAY))) return scheduleWord('tomorrow');
368
+ if (sameDay(then, new Date(now - DAY))) return scheduleWord('yesterday');
255
369
  return then.toLocaleDateString(locale, { weekday: 'short', day: 'numeric', month: 'short' });
256
370
  }
257
371
 
258
372
  /** 24-hour clock, as the cron descriptions are: "14:55". */
259
- export function clockTime(iso, locale = LOCALE) {
373
+ export function clockTime(iso, locale = scheduleDateLocale()) {
260
374
  const then = new Date(parse(iso));
261
375
  if (Number.isNaN(then.getTime())) return '';
262
376
  return then.toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' });
263
377
  }
264
378
 
265
379
  /** "Today 14:55", "Tomorrow 09:00", "Wed 22 Oct 09:00". */
266
- export function whenLabel(iso, now = Date.now(), locale = LOCALE) {
380
+ export function whenLabel(iso, now = Date.now(), locale = scheduleDateLocale()) {
267
381
  const day = dayLabel(iso, now, locale);
268
382
  const clock = clockTime(iso, locale);
269
- return day && clock ? `${day} ${clock}` : '';
383
+ return day && clock ? scheduleWord('dayAt', { day, time: clock }) : '';
270
384
  }
271
385
 
272
386
  /** A run time in the fewest words: "14:55" today, "Tomorrow 09:00", "Wed 09:00" this week, then "22 Oct". */
273
- export function shortWhen(iso, now = Date.now(), locale = LOCALE) {
387
+ export function shortWhen(iso, now = Date.now(), locale = scheduleDateLocale()) {
274
388
  const at = parse(iso);
275
389
  if (!Number.isFinite(at)) return '';
276
390
  const then = new Date(at);
277
391
  const clock = clockTime(iso, locale);
278
392
  if (sameDay(then, new Date(now))) return clock;
279
- if (sameDay(then, new Date(now + DAY))) return `Tomorrow ${clock}`;
280
- if (at > now && at - now < 6 * DAY) return `${then.toLocaleDateString(locale, { weekday: 'short' })} ${clock}`;
393
+ if (sameDay(then, new Date(now + DAY))) return scheduleWord('tomorrowAt', { time: clock });
394
+ if (at > now && at - now < 6 * DAY) return scheduleWord('weekdayAt', { day: then.toLocaleDateString(locale, { weekday: 'short' }), time: clock });
281
395
  return then.toLocaleDateString(locale, { day: 'numeric', month: 'short' });
282
396
  }
283
397
 
398
+ /** A date and time in full, for a tooltip: "22/10/2026, 14:55:03" in English, the locale's own way otherwise. */
399
+ export function fullDateTime(iso, locale = scheduleDateLocale()) {
400
+ const then = new Date(parse(iso));
401
+ return Number.isNaN(then.getTime()) ? '' : then.toLocaleString(locale);
402
+ }
403
+
404
+ const capitalized = (value) => String(value).charAt(0).toUpperCase() + String(value).slice(1);
405
+
406
+ /** A context choice in words: "1M tokens", "Extended"; one this file does not know reads as its id. */
407
+ export function contextWord(value) {
408
+ if (value === '1m') return scheduleWord('context1m');
409
+ if (value === 'extended') return scheduleWord('contextExtended');
410
+ return capitalized(value);
411
+ }
412
+
413
+ /** A thinking level in words: "Low", "High"; one this file does not know reads as its id. */
414
+ export function effortWord(value) {
415
+ return Object.prototype.hasOwnProperty.call(SCHEDULES_VIEW_COPY.effort, value) ? scheduleWord(`effort.${value}`) : capitalized(value);
416
+ }
417
+
284
418
  /**
285
419
  * The launch settings a run will use and where each comes from: the schedule's own value wins,
286
- * then its group's, then the automation's. `labels` names CLIs (`profiles`) and MCP presets.
420
+ * then its group's, then the automation's. `labels` names CLIs (`profiles`) and tool groups.
287
421
  */
288
- export function launchFacts(schedule, { group = null, template = null, profiles = [], mcpLabels = {} } = {}) {
422
+ export function launchFacts(schedule, { group = null, template = null, profiles = [], toolCatalog = null, translate } = {}) {
289
423
  const pick = (field) => {
290
424
  for (const [source, owner] of [['schedule', schedule], ['group', group], ['automation', template]]) {
291
425
  const value = owner?.[field];
@@ -296,23 +430,23 @@ export function launchFacts(schedule, { group = null, template = null, profiles
296
430
  const facts = [];
297
431
  const profile = pick('profile');
298
432
  const profileId = profile.value || 'claude-code';
299
- facts.push({ key: 'profile', label: 'CLI', value: profiles.find(p => p.id === profileId)?.label || profileId, source: profile.value ? profile.source : 'default' });
433
+ facts.push({ key: 'profile', label: scheduleWord('factCli'), value: profiles.find(p => p.id === profileId)?.label || profileId, source: profile.value ? profile.source : 'default' });
300
434
  const model = pick('model');
301
- facts.push({ key: 'model', label: 'Model', value: model.value || 'Default', source: model.source, mono: !!model.value });
435
+ facts.push({ key: 'model', label: scheduleWord('factModel'), value: model.value || scheduleWord('valueDefault'), source: model.source, mono: !!model.value });
302
436
  const context = pick('contextMode');
303
- if (context.value && context.value !== 'default') facts.push({ key: 'contextMode', label: 'Context', value: context.value === '1m' ? '1M tokens' : context.value.charAt(0).toUpperCase() + context.value.slice(1), source: context.source });
437
+ if (context.value && context.value !== 'default') facts.push({ key: 'contextMode', label: scheduleWord('factContext'), value: contextWord(context.value), source: context.source });
304
438
  const effort = pick('effort');
305
- if (effort.value && effort.value !== 'off') facts.push({ key: 'effort', label: 'Thinking', value: effort.value.charAt(0).toUpperCase() + effort.value.slice(1), source: effort.source });
306
- const mcp = pick('mcpProfile');
439
+ if (effort.value && effort.value !== 'off') facts.push({ key: 'effort', label: scheduleWord('factThinking'), value: effortWord(effort.value), source: effort.source });
440
+ const mcp = pick('tools');
307
441
  if (mcp.value) {
308
- const value = mcpLabels[mcp.value] || String(mcp.value).split(',').map(x => x.trim()).filter(Boolean).join(', ');
309
- facts.push({ key: 'mcpProfile', label: 'MCP tools', value, source: mcp.source });
442
+ const value = toolCatalog ? toolListView(toolCatalog, mcp.value, { translate }).summary : mcp.value.filter(id => !id.startsWith('mcp:')).join(', ') || scheduleWord('valueDefault');
443
+ facts.push({ key: 'tools', label: scheduleWord('factMcp'), value, source: mcp.source });
310
444
  }
311
445
  if (profileId === 'codex') {
312
446
  const account = pick('codexAccountId');
313
- if (account.value) facts.push({ key: 'codexAccountId', label: 'OpenAI account', value: account.value, source: account.source });
447
+ if (account.value) facts.push({ key: 'codexAccountId', label: scheduleWord('factAccount'), value: account.value, source: account.source });
314
448
  }
315
449
  const browser = pick('usesBrowser');
316
- facts.push({ key: 'usesBrowser', label: 'Browser', value: browser.value === true ? 'On' : 'Off', source: browser.source });
450
+ facts.push({ key: 'usesBrowser', label: scheduleWord('factBrowser'), value: scheduleWord(browser.value === true ? 'valueOn' : 'valueOff'), source: browser.source });
317
451
  return facts;
318
452
  }
@@ -0,0 +1,135 @@
1
+ // ═══════════════════════════════════════════
2
+ // SETTINGS — SynaBun's Claude Code hooks, in words
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // What `GET /api/claude-code/integrations` says in `claudeHooks` (lib/claude-hooks-status.js) about Settings →
6
+ // Automations → Automation behavior → SynaBun hooks in Claude Code: whether a Claude Code session the owner starts
7
+ // by themselves runs SynaBun's hooks, what stands in the way, and whether the switch can change it. Pure: no DOM
8
+ // and no import, so node runs it (tests/settings-claude-hooks-view.test.mjs).
9
+ //
10
+ // readClaudeHooksResponse({ status, body, error }) what the server answered → a reading
11
+ // describeClaudeHooks(reading, { tx }) the row as ui-settings.js draws it
12
+ // describeClaudeHooksSaveFailure(input, { tx }) the sentence for a change that could not be made
13
+ //
14
+ // `tx(key, params)` is the caller's translate function over the settings.redesign.* strings (the kit's `tx`).
15
+ // The row never shows "off" for what it could not read: a refusal (SynaBun's automation browser), a server started
16
+ // before this, an unreadable settings file each say what they are, with the switch disabled.
17
+
18
+ const K = 'settings.redesign.hooks.claudeHooks';
19
+
20
+ /** The rows of the "Hooks for standalone Claude Code" list: one per moment, the guards over two events. */
21
+ export const CLAUDE_HOOK_ROWS = Object.freeze([
22
+ Object.freeze({ key: 'SessionStart', events: ['SessionStart'] }),
23
+ Object.freeze({ key: 'UserPromptSubmit', events: ['UserPromptSubmit'] }),
24
+ Object.freeze({ key: 'PreCompact', events: ['PreCompact'] }),
25
+ Object.freeze({ key: 'Stop', events: ['Stop'] }),
26
+ Object.freeze({ key: 'PreToolUse', events: ['PreToolUse', 'PostToolBatch'] }),
27
+ Object.freeze({ key: 'PostToolUse', events: ['PostToolUse'] }),
28
+ Object.freeze({ key: 'SubagentStart', events: ['SubagentStart'] }),
29
+ Object.freeze({ key: 'SubagentStop', events: ['SubagentStop'] }),
30
+ ]);
31
+
32
+ /** The refusals of SynaBun's owner-only routes for a browser that is not the owner's (lib/owner-authority.js). */
33
+ const REFUSED_CODES = new Set(['WORKER_BROWSER', 'PEER_REFUSED']);
34
+
35
+ const clean = (value, max = 240) => {
36
+ const text = String(value ?? '').replace(/\s+/g, ' ').trim();
37
+ return text.length > max ? `${text.slice(0, max - 1)}…` : text;
38
+ };
39
+ const names = (list) => [...new Set((list || []).map((p) => clean(p.label || String(p.path || '').split(/[\\/]/).filter(Boolean).pop() || p.path, 60)))].join(', ');
40
+
41
+ /**
42
+ * What the server answered.
43
+ *
44
+ * ready `hooks` is the server's claudeHooks
45
+ * old-server an answer without claudeHooks: the running server was started before it (public/ is served live,
46
+ * lib/ only after a restart), and its own reading of the settings may be wrong
47
+ * refused 403 WORKER_BROWSER / PEER_REFUSED: SynaBun's automation browser, never the owner's own window
48
+ * forbidden 403 otherwise (a guest)
49
+ * unreadable anything else (no answer, an error, a body that is not the payload)
50
+ */
51
+ export function readClaudeHooksResponse({ status = 0, body = null, error = null } = {}) {
52
+ const code = Number(status) || 0;
53
+ if (code >= 200 && code < 300 && body && typeof body === 'object' && body.ok === true) {
54
+ const hooks = body.claudeHooks;
55
+ if (hooks && typeof hooks === 'object' && Number(hooks.version) >= 1 && typeof hooks.state === 'string') return { state: 'ready', hooks, reason: null };
56
+ return { state: 'old-server', hooks: null, reason: null };
57
+ }
58
+ if (code === 403) {
59
+ const refusal = String(body?.code || '');
60
+ return { state: REFUSED_CODES.has(refusal) ? 'refused' : 'forbidden', hooks: null, reason: clean(body?.error) || null, code: refusal || null };
61
+ }
62
+ return { state: 'unreadable', hooks: null, reason: clean(error || body?.error || (code ? `HTTP ${code}` : '')) || null };
63
+ }
64
+
65
+ /** Which list rows are on: every event of the row has all of SynaBun's handlers. */
66
+ export function claudeHookRowsOn(events) {
67
+ return Object.fromEntries(CLAUDE_HOOK_ROWS.map((row) => [row.key, row.events.every((event) => events?.[event] === true)]));
68
+ }
69
+
70
+ /**
71
+ * The row: { state, ready, disabled, on, notes: [{ text, tone }], note: { text, tone } | null, repair, applies,
72
+ * rows: { [rowKey]: boolean } | null (the list below; null when nothing could be read), onRows, totalRows }.
73
+ * `note` says why nothing below can be trusted or changed; `notes` describe what is installed.
74
+ */
75
+ export function describeClaudeHooks(reading, { tx }) {
76
+ const r = reading || readClaudeHooksResponse({ status: 0 });
77
+ const view = { state: r.state, ready: false, disabled: true, on: false, notes: [], note: null, repair: false, applies: tx(`${K}.applies`), rows: null, onRows: 0, totalRows: CLAUDE_HOOK_ROWS.length };
78
+ if (r.state === 'old-server') { view.note = { text: tx(`${K}.restart`), tone: 'warn' }; return view; }
79
+ if (r.state === 'refused') { view.note = { text: tx(`${K}.refused`), tone: 'warn' }; return view; }
80
+ if (r.state === 'forbidden') { view.note = { text: tx(`${K}.forbidden`), tone: 'warn' }; return view; }
81
+ if (r.state !== 'ready') {
82
+ view.note = { text: r.reason ? tx(`${K}.unreadable`, { reason: r.reason }) : tx(`${K}.unreadableNoReason`), tone: 'warn' };
83
+ return view;
84
+ }
85
+ const h = r.hooks;
86
+ if (h.state === 'error') {
87
+ view.note = { text: tx(`${K}.settingsUnreadable`, { path: h.settingsPath || '~/.claude/settings.json', reason: clean(h.error) || '?' }), tone: 'warn' };
88
+ return view;
89
+ }
90
+ const path = h.settingsPath || '~/.claude/settings.json';
91
+ const rows = claudeHookRowsOn(h.events);
92
+ const onRows = Object.values(rows).filter(Boolean).length;
93
+ const installed = h.state === 'on' || h.state === 'partial';
94
+ const managed = h.blockedBy?.scope === 'managed';
95
+ view.ready = true;
96
+ view.rows = rows;
97
+ view.onRows = onRows;
98
+ // On means "a session the owner starts runs them": installed and not switched off by Claude Code itself.
99
+ view.on = installed && !h.blockedBy;
100
+ // The organization's managed settings, and a packaged app started from a temporary place, cannot be switched here.
101
+ view.disabled = managed || !!h.installBlocker;
102
+
103
+ if (h.installBlocker) view.notes.push({ text: clean(h.installBlocker, 400), tone: 'warn' });
104
+ if (managed) view.notes.push({ text: tx(`${K}.blocked.managed.${h.blockedBy.setting === 'allowManagedHooksOnly' ? 'managedOnly' : 'disableAll'}`, { path: h.blockedBy.path }), tone: 'warn' });
105
+ else if (h.blockedBy) view.notes.push({ text: tx(`${K}.blocked.user`, { path: h.blockedBy.path || path }), tone: 'warn' });
106
+ else if (h.state === 'on') view.notes.push({ text: tx(`${K}.on`, { path }), tone: 'info' });
107
+ else if (h.state === 'partial') view.notes.push({ text: tx(`${K}.partial`, { on: onRows, total: CLAUDE_HOOK_ROWS.length }), tone: 'info' });
108
+ else view.notes.push({ text: tx(`${K}.off`), tone: 'info' });
109
+
110
+ if (h.needsRepair && !managed) {
111
+ view.repair = !h.installBlocker;
112
+ if (h.current < h.installed) view.notes.push({ text: tx(`${K}.repair.stale`, { count: h.installed - h.current }), tone: 'warn' });
113
+ if (h.duplicates > 0) view.notes.push({ text: tx(`${K}.repair.duplicates`, { count: h.duplicates }), tone: 'warn' });
114
+ const different = (h.projects || []).filter((p) => p.issue === 'different');
115
+ if (different.length) view.notes.push({ text: tx(`${K}.repair.projects`, { names: names(different) }), tone: 'warn' });
116
+ if (h.nodeMissing) view.notes.push({ text: tx(`${K}.repair.node`), tone: 'warn' });
117
+ }
118
+ const off = (h.projects || []).filter((p) => p.issue === 'disableAllHooks');
119
+ if (off.length) view.notes.push({ text: tx(`${K}.projectsOff`, { names: names(off) }), tone: 'warn' });
120
+ const stillOn = (h.projects || []).filter((p) => p.issue === 'project-only');
121
+ if (stillOn.length) view.notes.push({ text: tx(`${K}.projectsStillOn`, { names: names(stillOn) }), tone: 'warn' });
122
+ return view;
123
+ }
124
+
125
+ /**
126
+ * The sentence for a change that could not be made: { action: 'on' | 'off' | 'repair', status, body, error }.
127
+ * An answer without claudeHooks after a change that worked is a server started before this (said as such).
128
+ */
129
+ export function describeClaudeHooksSaveFailure({ action = 'on', status = 0, body = null, error = null } = {}, { tx }) {
130
+ const verb = ['on', 'off', 'repair'].includes(action) ? action : 'on';
131
+ const code = Number(status) || 0;
132
+ if (!code) return tx(`${K}.save.noAnswer.${verb}`);
133
+ if (code === 403 && REFUSED_CODES.has(String(body?.code || ''))) return tx(`${K}.save.refused.${verb}`);
134
+ return tx(`${K}.save.failed.${verb}`, { reason: clean(body?.error || error) || `HTTP ${code}` });
135
+ }
@@ -21,7 +21,8 @@ const okBody = (body) => !!body && typeof body === 'object' && body.ok !== false
21
21
  export const SETTINGS_READS = Object.freeze({
22
22
  settings: { url: '/api/settings', accept: okBody },
23
23
  connections: { url: '/api/connections', accept: (body) => Array.isArray(body?.connections) },
24
- integrations: { url: '/api/claude-code/integrations', accept: (body) => body?.ok === true },
24
+ // Raw: the hooks' row tells a refusal, an old server and an unreadable file apart (settings-claude-hooks.js).
25
+ integrations: { url: '/api/claude-code/integrations', raw: true },
25
26
  skills: { url: '/api/claude-code/skills', accept: (body) => body?.ok === true },
26
27
  // The tunnel changes by itself (starting, stopping from the Share menu): asked again after a few seconds.
27
28
  tunnel: { url: '/api/tunnel/status', accept: (body) => body?.ok === true, ttlMs: 10_000 },
@@ -38,6 +39,7 @@ export const SETTINGS_READS = Object.freeze({
38
39
  youtube: { url: '/api/youtube/config', accept: (body) => body?.ok === true },
39
40
  typesafe: { url: '/api/typesafe/config', accept: (body) => body?.ok === true },
40
41
  userContext: { url: '/api/assistant/user-context', raw: true },
42
+ workerGuard: { url: '/api/assistant/worker-guard', raw: true },
41
43
  });
42
44
 
43
45
  const caches = Object.fromEntries(Object.entries(SETTINGS_READS).map(([name, spec]) => [name, createDataCache(`settings:${name}`, {
@@ -103,7 +103,7 @@ export const SETTINGS_PAGES = [
103
103
  id: 'connected-tools', key: 'connected_tools', group: 'tools', icon: 'mcp',
104
104
  panes: [{ id: 'mcp' }, { id: 'morelogin', titleKey: k('pane.morelogin') }],
105
105
  sections: [
106
- { id: 'stg-sec-tool-profiles', key: 'tool_profiles', state: 'open' },
106
+ { id: 'stg-sec-default-tools', key: 'default_tools', state: 'open' },
107
107
  { id: 'stg-sec-added-servers', key: 'added_servers', state: 'open' },
108
108
  { id: 'stg-sec-ml-connection', key: 'morelogin_connection', state: 'open' },
109
109
  { id: 'stg-sec-ml-profiles', key: 'morelogin_profiles', state: 'open' },
@@ -253,7 +253,7 @@ export const SETTINGS_CONTROLS = {
253
253
  'stg-sec-manual-setup': 'SET029 SET030 SET031 SET032',
254
254
  'cc-cli-paths': 'CLI001 CLI002 CLI007 CLI003 CLI004 CLI005 CLI006',
255
255
  'stg-sec-opencode-service': 'OCP001 OCP002 OCP003 OCP004 OCP005 OCP021 OCP022 OCP019',
256
- 'stg-sec-opencode-behavior': 'OCP013 OCP014 OCP015 OCP016',
256
+ 'stg-sec-opencode-behavior': 'OCP013 OCP015 OCP016',
257
257
  'stg-sec-opencode-tools': 'OCP017',
258
258
  'stg-sec-opencode-history': 'OCP023 OCP018',
259
259
  'stg-sec-database': 'GEN015 GEN001 GEN002 GEN003 GEN016 GEN004 GEN005 GEN006 GEN017 DB003',
@@ -268,18 +268,18 @@ export const SETTINGS_CONTROLS = {
268
268
  'bcg-identity': 'BRW021 BRW022 BRW023 BRW024 BRW025',
269
269
  'bcg-viewport': 'BRW026 BRW027 BRW028 BRW029 BRW030 BRW031 BRW032',
270
270
  'bcg-advanced': 'BRW033 BRW034 BRW035 BRW036 BRW037 BRW038 BRW039 BRW040 BRW041 BRW042 BRW043 BRW044 BRW045 BRW046 BRW047 BRW048 BRW049 BRW050 BRW051 BRW052 BRW053 BRW054 BRW055 BRW056 BRW057 BRW058 BRW059 BRW060 BRW061 BRW062 BRW063 BRW064 BRW065 BRW066 BRW067 BRW068 BRW069 BRW070 BRW071 BRW072 BRW073 BRW074 BRW075 BRW076 BRW077 BRW078 BRW079 BRW080',
271
- 'stg-sec-tool-profiles': 'MCP022 MCP024',
271
+ 'stg-sec-default-tools': 'MCP022 MCP024 MCP005 MCP004',
272
272
  'stg-sec-added-servers': 'MCP026 MCP006 MCP007 MCP008 MCP009 MCP010 MCP011 MCP012 MCP013 MCP014 MCP015 MCP027 MCP016 MCP017 MCP018 MCP019 MCP020 MCP021',
273
273
  'stg-sec-ml-connection': 'ML015 ML001 ML002 ML003',
274
274
  'stg-sec-ml-profiles': 'ML004 ML005 ML006 ML016 ML017 ML018 ML019',
275
275
  'stg-sec-ml-credentials': 'ML007 ML008 ML009 ML010 ML011',
276
276
  'stg-sec-ml-server': 'ML012 ML013 ML014',
277
277
  'stg-sec-skills': 'SKL004 SKL001',
278
- 'stg-sec-tool-permissions': 'PER012 PER001 PER002 PER003 PER004 PER005 PER006 PER007 PER008 PER009 PER010 PER011',
278
+ 'stg-sec-tool-permissions': 'PER012 PER001 PER002 PER003 PER004 PER005 PER006 PER008 PER009 PER010 PER011',
279
279
  'stg-sec-editor-editing': 'EDT014 EDT015 EDT016 EDT017 EDT018 EDT019 EDT020 EDT021 EDT022 EDT023',
280
280
  'stg-sec-editor-ai': 'EDT001 EDT002 EDT003 EDT004 EDT005 EDT006 EDT007 EDT008 EDT009 EDT010 EDT011 EDT012 EDT013',
281
281
  'stg-sec-greetings': 'AUT058 AUT059 AUT060',
282
- 'stg-sec-automation-behavior': 'AUT053 AUT054 AUT055 AUT056 AUT057 AUT046 AUT036 AUT037 AUT038 AUT039 AUT040 AUT041 AUT028 AUT029 AUT030 AUT031 AUT032 AUT033 AUT034 AUT035',
282
+ 'stg-sec-automation-behavior': 'AUT053 AUT054 AUT055 AUT061 AUT062 AUT056 AUT057 AUT046 AUT036 AUT037 AUT038 AUT039 AUT040 AUT041 AUT028 AUT029 AUT030 AUT031 AUT032 AUT033 AUT034 AUT035',
283
283
  'stg-sec-online-access': 'AUT048 AUT042 AUT043 AUT044 AUT045 AUT049 AUT050 AUT051 AUT052',
284
284
  'stg-sec-social': 'SOC003 SOC001 SOC002',
285
285
  'stg-sec-youtube': 'YT017 YT001 YT002 YT003 YT004 YT005 YT006 YT007 YT008 YT009 YT010 YT011 YT012 YT013 YT014 YT015 YT016 YT018',
@@ -349,7 +349,7 @@ export const SETTINGS_TAB_ALIASES = {
349
349
  judgments: { page: 'ai-decisions', section: 'jv-sec-connection' },
350
350
  projects: { page: 'projects', section: 'stg-sec-workspaces' },
351
351
  browser: { page: 'browser', section: 'setup-browser' },
352
- mcp: { page: 'connected-tools', section: 'stg-sec-tool-profiles' },
352
+ mcp: { page: 'connected-tools', section: 'stg-sec-default-tools' },
353
353
  morelogin: { page: 'connected-tools', section: 'stg-sec-ml-connection' },
354
354
  skills: { page: 'tool-access', section: 'stg-sec-skills' },
355
355
  permissions: { page: 'tool-access', section: 'stg-sec-tool-permissions' },