synabun 1.3.0 → 2.0.0-beta

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 (1153) hide show
  1. package/CHANGELOG.md +197 -662
  2. package/LICENSE-COMMERCIAL.md +33 -0
  3. package/NOTICE +17 -0
  4. package/README.md +175 -853
  5. package/THIRD-PARTY-LICENSES.md +131 -0
  6. package/benchmarks/browser-live-results.json +79 -0
  7. package/benchmarks/browser-v2-results.json +258 -0
  8. package/benchmarks/fixtures/browser/README.md +57 -0
  9. package/benchmarks/fixtures/browser/page-state.json +132 -0
  10. package/benchmarks/fixtures/browser/social.json +92 -0
  11. package/benchmarks/fixtures/browser/target.json +319 -0
  12. package/benchmarks/fixtures/desktop/README.md +58 -0
  13. package/benchmarks/fixtures/desktop/abstention.json +59 -0
  14. package/benchmarks/fixtures/desktop/adversarial.json +22 -0
  15. package/benchmarks/fixtures/desktop/forbidden.json +93 -0
  16. package/benchmarks/fixtures/desktop/generate.mjs +1023 -0
  17. package/benchmarks/fixtures/desktop/target.json +136 -0
  18. package/bin/synabun.js +30 -0
  19. package/docs/browser-v2.md +109 -0
  20. package/docs/hook-integrity.md +89 -0
  21. package/docs/judgments.md +182 -0
  22. package/docs/style-guide.md +246 -0
  23. package/docs/whatsapp.md +325 -0
  24. package/hooks/claude-code/post-plan.mjs +613 -391
  25. package/hooks/claude-code/post-remember.mjs +246 -122
  26. package/hooks/claude-code/pre-compact.mjs +171 -110
  27. package/hooks/claude-code/pre-task.mjs +133 -0
  28. package/hooks/claude-code/pre-websearch.mjs +15 -4
  29. package/hooks/claude-code/prompt-origin.mjs +94 -0
  30. package/hooks/claude-code/prompt-submit.mjs +1244 -861
  31. package/hooks/claude-code/session-start.mjs +114 -156
  32. package/hooks/claude-code/shared.mjs +1228 -368
  33. package/hooks/claude-code/state.mjs +167 -0
  34. package/hooks/claude-code/stop.mjs +515 -140
  35. package/hooks/claude-code/subagent-start.mjs +154 -0
  36. package/hooks/claude-code/subagent-stop.mjs +102 -0
  37. package/hooks/claude-code/task-gate.mjs +150 -0
  38. package/lib/claude-hooks.js +84 -0
  39. package/lib/claude-usage-audit.js +141 -0
  40. package/lib/client-config-repair.js +144 -0
  41. package/lib/data-home-migration.js +498 -0
  42. package/lib/first-launch-protection.js +240 -0
  43. package/lib/paths.d.ts +21 -0
  44. package/lib/paths.js +103 -0
  45. package/mcp-server/dist/config.d.ts +22 -0
  46. package/mcp-server/dist/config.d.ts.map +1 -0
  47. package/mcp-server/dist/config.js +109 -0
  48. package/mcp-server/dist/config.js.map +1 -0
  49. package/mcp-server/dist/http.d.ts +30 -0
  50. package/mcp-server/dist/http.d.ts.map +1 -0
  51. package/mcp-server/dist/http.js +276 -0
  52. package/mcp-server/dist/http.js.map +1 -0
  53. package/mcp-server/dist/index.d.ts +48 -0
  54. package/mcp-server/dist/index.d.ts.map +1 -0
  55. package/mcp-server/dist/index.js +538 -0
  56. package/mcp-server/dist/index.js.map +1 -0
  57. package/mcp-server/dist/preload-http.d.ts +3 -0
  58. package/mcp-server/dist/preload-http.d.ts.map +1 -0
  59. package/mcp-server/dist/preload-http.js +28 -0
  60. package/mcp-server/dist/preload-http.js.map +1 -0
  61. package/mcp-server/dist/preload.d.ts +3 -0
  62. package/mcp-server/dist/preload.d.ts.map +1 -0
  63. package/mcp-server/dist/preload.js +32 -0
  64. package/mcp-server/dist/preload.js.map +1 -0
  65. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts +19 -0
  66. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts.map +1 -0
  67. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js +403 -0
  68. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js.map +1 -0
  69. package/mcp-server/dist/scripts/setup-embeddings.d.ts +3 -0
  70. package/mcp-server/dist/scripts/setup-embeddings.d.ts.map +1 -0
  71. package/mcp-server/dist/scripts/setup-embeddings.js +15 -0
  72. package/mcp-server/dist/scripts/setup-embeddings.js.map +1 -0
  73. package/mcp-server/dist/services/assistant-judgments.d.ts +79 -0
  74. package/mcp-server/dist/services/assistant-judgments.d.ts.map +1 -0
  75. package/mcp-server/dist/services/assistant-judgments.js +128 -0
  76. package/mcp-server/dist/services/assistant-judgments.js.map +1 -0
  77. package/mcp-server/dist/services/browser-assist-gate.d.ts +314 -0
  78. package/mcp-server/dist/services/browser-assist-gate.d.ts.map +1 -0
  79. package/mcp-server/dist/services/browser-assist-gate.js +344 -0
  80. package/mcp-server/dist/services/browser-assist-gate.js.map +1 -0
  81. package/mcp-server/dist/services/browser-assist.d.ts +104 -0
  82. package/mcp-server/dist/services/browser-assist.d.ts.map +1 -0
  83. package/mcp-server/dist/services/browser-assist.js +282 -0
  84. package/mcp-server/dist/services/browser-assist.js.map +1 -0
  85. package/mcp-server/dist/services/browser-bench.d.ts +772 -0
  86. package/mcp-server/dist/services/browser-bench.d.ts.map +1 -0
  87. package/mcp-server/dist/services/browser-bench.js +424 -0
  88. package/mcp-server/dist/services/browser-bench.js.map +1 -0
  89. package/mcp-server/dist/services/browser-judgments.d.ts +196 -0
  90. package/mcp-server/dist/services/browser-judgments.d.ts.map +1 -0
  91. package/mcp-server/dist/services/browser-judgments.js +363 -0
  92. package/mcp-server/dist/services/browser-judgments.js.map +1 -0
  93. package/mcp-server/dist/services/browser-risk.d.ts +166 -0
  94. package/mcp-server/dist/services/browser-risk.d.ts.map +1 -0
  95. package/mcp-server/dist/services/browser-risk.js +458 -0
  96. package/mcp-server/dist/services/browser-risk.js.map +1 -0
  97. package/mcp-server/dist/services/categories.d.ts +61 -0
  98. package/mcp-server/dist/services/categories.d.ts.map +1 -0
  99. package/mcp-server/dist/services/categories.js +377 -0
  100. package/mcp-server/dist/services/categories.js.map +1 -0
  101. package/mcp-server/dist/services/codex-config-heal.d.ts +49 -0
  102. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -0
  103. package/mcp-server/dist/services/codex-config-heal.js +346 -0
  104. package/mcp-server/dist/services/codex-config-heal.js.map +1 -0
  105. package/mcp-server/dist/services/desktop-assist-gate.d.ts +198 -0
  106. package/mcp-server/dist/services/desktop-assist-gate.d.ts.map +1 -0
  107. package/mcp-server/dist/services/desktop-assist-gate.js +202 -0
  108. package/mcp-server/dist/services/desktop-assist-gate.js.map +1 -0
  109. package/mcp-server/dist/services/desktop-assist.d.ts +104 -0
  110. package/mcp-server/dist/services/desktop-assist.d.ts.map +1 -0
  111. package/mcp-server/dist/services/desktop-assist.js +266 -0
  112. package/mcp-server/dist/services/desktop-assist.js.map +1 -0
  113. package/mcp-server/dist/services/desktop-bench.d.ts +553 -0
  114. package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -0
  115. package/mcp-server/dist/services/desktop-bench.js +311 -0
  116. package/mcp-server/dist/services/desktop-bench.js.map +1 -0
  117. package/mcp-server/dist/services/desktop-client.d.ts +23 -0
  118. package/mcp-server/dist/services/desktop-client.d.ts.map +1 -0
  119. package/mcp-server/dist/services/desktop-client.js +79 -0
  120. package/mcp-server/dist/services/desktop-client.js.map +1 -0
  121. package/mcp-server/dist/services/desktop-judgments.d.ts +125 -0
  122. package/mcp-server/dist/services/desktop-judgments.d.ts.map +1 -0
  123. package/mcp-server/dist/services/desktop-judgments.js +177 -0
  124. package/mcp-server/dist/services/desktop-judgments.js.map +1 -0
  125. package/mcp-server/dist/services/desktop-risk.d.ts +283 -0
  126. package/mcp-server/dist/services/desktop-risk.d.ts.map +1 -0
  127. package/mcp-server/dist/services/desktop-risk.js +605 -0
  128. package/mcp-server/dist/services/desktop-risk.js.map +1 -0
  129. package/mcp-server/dist/services/discord.d.ts +112 -0
  130. package/mcp-server/dist/services/discord.d.ts.map +1 -0
  131. package/mcp-server/dist/services/discord.js +477 -0
  132. package/mcp-server/dist/services/discord.js.map +1 -0
  133. package/mcp-server/dist/services/edit-stale.d.ts +81 -0
  134. package/mcp-server/dist/services/edit-stale.d.ts.map +1 -0
  135. package/mcp-server/dist/services/edit-stale.js +358 -0
  136. package/mcp-server/dist/services/edit-stale.js.map +1 -0
  137. package/mcp-server/dist/services/embedding-service.d.ts +16 -0
  138. package/mcp-server/dist/services/embedding-service.d.ts.map +1 -0
  139. package/mcp-server/dist/services/embedding-service.js +126 -0
  140. package/mcp-server/dist/services/embedding-service.js.map +1 -0
  141. package/mcp-server/dist/services/embedding-worker.d.ts +2 -0
  142. package/mcp-server/dist/services/embedding-worker.d.ts.map +1 -0
  143. package/mcp-server/dist/services/embedding-worker.js +52 -0
  144. package/mcp-server/dist/services/embedding-worker.js.map +1 -0
  145. package/mcp-server/dist/services/fb-regions.d.ts +71 -0
  146. package/mcp-server/dist/services/fb-regions.d.ts.map +1 -0
  147. package/mcp-server/dist/services/fb-regions.js +211 -0
  148. package/mcp-server/dist/services/fb-regions.js.map +1 -0
  149. package/mcp-server/dist/services/file-checksums.d.ts +22 -0
  150. package/mcp-server/dist/services/file-checksums.d.ts.map +1 -0
  151. package/mcp-server/dist/services/file-checksums.js +55 -0
  152. package/mcp-server/dist/services/file-checksums.js.map +1 -0
  153. package/mcp-server/dist/services/file-excerpt.d.ts +24 -0
  154. package/mcp-server/dist/services/file-excerpt.d.ts.map +1 -0
  155. package/mcp-server/dist/services/file-excerpt.js +65 -0
  156. package/mcp-server/dist/services/file-excerpt.js.map +1 -0
  157. package/mcp-server/dist/services/identity.d.ts +124 -0
  158. package/mcp-server/dist/services/identity.d.ts.map +1 -0
  159. package/mcp-server/dist/services/identity.js +241 -0
  160. package/mcp-server/dist/services/identity.js.map +1 -0
  161. package/mcp-server/dist/services/local-embeddings.d.ts +2 -0
  162. package/mcp-server/dist/services/local-embeddings.d.ts.map +1 -0
  163. package/mcp-server/dist/services/local-embeddings.js +3 -0
  164. package/mcp-server/dist/services/local-embeddings.js.map +1 -0
  165. package/mcp-server/dist/services/memory-client.d.ts +4 -0
  166. package/mcp-server/dist/services/memory-client.d.ts.map +1 -0
  167. package/mcp-server/dist/services/memory-client.js +27 -0
  168. package/mcp-server/dist/services/memory-client.js.map +1 -0
  169. package/mcp-server/dist/services/memory-judge-backfill.d.ts +135 -0
  170. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -0
  171. package/mcp-server/dist/services/memory-judge-backfill.js +510 -0
  172. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -0
  173. package/mcp-server/dist/services/memory-judgments.d.ts +362 -0
  174. package/mcp-server/dist/services/memory-judgments.d.ts.map +1 -0
  175. package/mcp-server/dist/services/memory-judgments.js +674 -0
  176. package/mcp-server/dist/services/memory-judgments.js.map +1 -0
  177. package/mcp-server/dist/services/memory-maintenance.d.ts +108 -0
  178. package/mcp-server/dist/services/memory-maintenance.d.ts.map +1 -0
  179. package/mcp-server/dist/services/memory-maintenance.js +403 -0
  180. package/mcp-server/dist/services/memory-maintenance.js.map +1 -0
  181. package/mcp-server/dist/services/memory-retrieval.d.ts +66 -0
  182. package/mcp-server/dist/services/memory-retrieval.d.ts.map +1 -0
  183. package/mcp-server/dist/services/memory-retrieval.js +412 -0
  184. package/mcp-server/dist/services/memory-retrieval.js.map +1 -0
  185. package/mcp-server/dist/services/memory-schema.d.ts +16 -0
  186. package/mcp-server/dist/services/memory-schema.d.ts.map +1 -0
  187. package/mcp-server/dist/services/memory-schema.js +282 -0
  188. package/mcp-server/dist/services/memory-schema.js.map +1 -0
  189. package/mcp-server/dist/services/memory-sessions.d.ts +24 -0
  190. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -0
  191. package/mcp-server/dist/services/memory-sessions.js +110 -0
  192. package/mcp-server/dist/services/memory-sessions.js.map +1 -0
  193. package/mcp-server/dist/services/memory-triage.d.ts +60 -0
  194. package/mcp-server/dist/services/memory-triage.d.ts.map +1 -0
  195. package/mcp-server/dist/services/memory-triage.js +189 -0
  196. package/mcp-server/dist/services/memory-triage.js.map +1 -0
  197. package/mcp-server/dist/services/memory-verification.d.ts +24 -0
  198. package/mcp-server/dist/services/memory-verification.d.ts.map +1 -0
  199. package/mcp-server/dist/services/memory-verification.js +92 -0
  200. package/mcp-server/dist/services/memory-verification.js.map +1 -0
  201. package/mcp-server/dist/services/memory-writer.d.ts +26 -0
  202. package/mcp-server/dist/services/memory-writer.d.ts.map +1 -0
  203. package/mcp-server/dist/services/memory-writer.js +126 -0
  204. package/mcp-server/dist/services/memory-writer.js.map +1 -0
  205. package/mcp-server/dist/services/neural-interface.d.ts +439 -0
  206. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -0
  207. package/mcp-server/dist/services/neural-interface.js +1135 -0
  208. package/mcp-server/dist/services/neural-interface.js.map +1 -0
  209. package/mcp-server/dist/services/profiles.d.ts +120 -0
  210. package/mcp-server/dist/services/profiles.d.ts.map +1 -0
  211. package/mcp-server/dist/services/profiles.js +387 -0
  212. package/mcp-server/dist/services/profiles.js.map +1 -0
  213. package/mcp-server/dist/services/secret-gate.d.ts +29 -0
  214. package/mcp-server/dist/services/secret-gate.d.ts.map +1 -0
  215. package/mcp-server/dist/services/secret-gate.js +43 -0
  216. package/mcp-server/dist/services/secret-gate.js.map +1 -0
  217. package/mcp-server/dist/services/server-instructions.d.ts +10 -0
  218. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -0
  219. package/mcp-server/dist/services/server-instructions.js +101 -0
  220. package/mcp-server/dist/services/server-instructions.js.map +1 -0
  221. package/mcp-server/dist/services/sqlite.d.ts +235 -0
  222. package/mcp-server/dist/services/sqlite.d.ts.map +1 -0
  223. package/mcp-server/dist/services/sqlite.js +1185 -0
  224. package/mcp-server/dist/services/sqlite.js.map +1 -0
  225. package/mcp-server/dist/services/typesafe-bench.d.ts +99 -0
  226. package/mcp-server/dist/services/typesafe-bench.d.ts.map +1 -0
  227. package/mcp-server/dist/services/typesafe-bench.js +218 -0
  228. package/mcp-server/dist/services/typesafe-bench.js.map +1 -0
  229. package/mcp-server/dist/services/typesafe-config.d.ts +342 -0
  230. package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -0
  231. package/mcp-server/dist/services/typesafe-config.js +746 -0
  232. package/mcp-server/dist/services/typesafe-config.js.map +1 -0
  233. package/mcp-server/dist/services/typesafe.d.ts +213 -0
  234. package/mcp-server/dist/services/typesafe.d.ts.map +1 -0
  235. package/mcp-server/dist/services/typesafe.js +330 -0
  236. package/mcp-server/dist/services/typesafe.js.map +1 -0
  237. package/mcp-server/dist/services/vector-cache.d.ts +68 -0
  238. package/mcp-server/dist/services/vector-cache.d.ts.map +1 -0
  239. package/mcp-server/dist/services/vector-cache.js +271 -0
  240. package/mcp-server/dist/services/vector-cache.js.map +1 -0
  241. package/mcp-server/dist/services/whiteboard-geometry.d.ts +305 -0
  242. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -0
  243. package/mcp-server/dist/services/whiteboard-geometry.js +666 -0
  244. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -0
  245. package/mcp-server/dist/tools/agents.d.ts +212 -0
  246. package/mcp-server/dist/tools/agents.d.ts.map +1 -0
  247. package/mcp-server/dist/tools/agents.js +407 -0
  248. package/mcp-server/dist/tools/agents.js.map +1 -0
  249. package/mcp-server/dist/tools/bluesky.d.ts +39 -0
  250. package/mcp-server/dist/tools/bluesky.d.ts.map +1 -0
  251. package/mcp-server/dist/tools/bluesky.js +1144 -0
  252. package/mcp-server/dist/tools/bluesky.js.map +1 -0
  253. package/mcp-server/dist/tools/browser-advanced.d.ts +58 -0
  254. package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -0
  255. package/mcp-server/dist/tools/browser-advanced.js +106 -0
  256. package/mcp-server/dist/tools/browser-advanced.js.map +1 -0
  257. package/mcp-server/dist/tools/browser-batch.d.ts +99 -0
  258. package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -0
  259. package/mcp-server/dist/tools/browser-batch.js +187 -0
  260. package/mcp-server/dist/tools/browser-batch.js.map +1 -0
  261. package/mcp-server/dist/tools/browser-cheatsheet.d.ts +21 -0
  262. package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -0
  263. package/mcp-server/dist/tools/browser-cheatsheet.js +144 -0
  264. package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -0
  265. package/mcp-server/dist/tools/browser-interact.d.ts +239 -0
  266. package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -0
  267. package/mcp-server/dist/tools/browser-interact.js +300 -0
  268. package/mcp-server/dist/tools/browser-interact.js.map +1 -0
  269. package/mcp-server/dist/tools/browser-navigate.d.ts +90 -0
  270. package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -0
  271. package/mcp-server/dist/tools/browser-navigate.js +142 -0
  272. package/mcp-server/dist/tools/browser-navigate.js.map +1 -0
  273. package/mcp-server/dist/tools/browser-observe.d.ts +561 -0
  274. package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -0
  275. package/mcp-server/dist/tools/browser-observe.js +2009 -0
  276. package/mcp-server/dist/tools/browser-observe.js.map +1 -0
  277. package/mcp-server/dist/tools/browser.d.ts +34 -0
  278. package/mcp-server/dist/tools/browser.d.ts.map +1 -0
  279. package/mcp-server/dist/tools/browser.js +112 -0
  280. package/mcp-server/dist/tools/browser.js.map +1 -0
  281. package/mcp-server/dist/tools/card-tools.d.ts +82 -0
  282. package/mcp-server/dist/tools/card-tools.d.ts.map +1 -0
  283. package/mcp-server/dist/tools/card-tools.js +137 -0
  284. package/mcp-server/dist/tools/card-tools.js.map +1 -0
  285. package/mcp-server/dist/tools/card.d.ts +8 -0
  286. package/mcp-server/dist/tools/card.d.ts.map +1 -0
  287. package/mcp-server/dist/tools/card.js +16 -0
  288. package/mcp-server/dist/tools/card.js.map +1 -0
  289. package/mcp-server/dist/tools/category.d.ts +32 -0
  290. package/mcp-server/dist/tools/category.d.ts.map +1 -0
  291. package/mcp-server/dist/tools/category.js +290 -0
  292. package/mcp-server/dist/tools/category.js.map +1 -0
  293. package/mcp-server/dist/tools/choice.d.ts +160 -0
  294. package/mcp-server/dist/tools/choice.d.ts.map +1 -0
  295. package/mcp-server/dist/tools/choice.js +80 -0
  296. package/mcp-server/dist/tools/choice.js.map +1 -0
  297. package/mcp-server/dist/tools/computer.d.ts +71 -0
  298. package/mcp-server/dist/tools/computer.d.ts.map +1 -0
  299. package/mcp-server/dist/tools/computer.js +174 -0
  300. package/mcp-server/dist/tools/computer.js.map +1 -0
  301. package/mcp-server/dist/tools/discord-channel.d.ts +44 -0
  302. package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -0
  303. package/mcp-server/dist/tools/discord-channel.js +236 -0
  304. package/mcp-server/dist/tools/discord-channel.js.map +1 -0
  305. package/mcp-server/dist/tools/discord-guild.d.ts +20 -0
  306. package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -0
  307. package/mcp-server/dist/tools/discord-guild.js +138 -0
  308. package/mcp-server/dist/tools/discord-guild.js.map +1 -0
  309. package/mcp-server/dist/tools/discord-member.d.ts +26 -0
  310. package/mcp-server/dist/tools/discord-member.d.ts.map +1 -0
  311. package/mcp-server/dist/tools/discord-member.js +122 -0
  312. package/mcp-server/dist/tools/discord-member.js.map +1 -0
  313. package/mcp-server/dist/tools/discord-message.d.ts +36 -0
  314. package/mcp-server/dist/tools/discord-message.d.ts.map +1 -0
  315. package/mcp-server/dist/tools/discord-message.js +184 -0
  316. package/mcp-server/dist/tools/discord-message.js.map +1 -0
  317. package/mcp-server/dist/tools/discord-onboarding.d.ts +32 -0
  318. package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -0
  319. package/mcp-server/dist/tools/discord-onboarding.js +179 -0
  320. package/mcp-server/dist/tools/discord-onboarding.js.map +1 -0
  321. package/mcp-server/dist/tools/discord-role.d.ts +34 -0
  322. package/mcp-server/dist/tools/discord-role.d.ts.map +1 -0
  323. package/mcp-server/dist/tools/discord-role.js +178 -0
  324. package/mcp-server/dist/tools/discord-role.js.map +1 -0
  325. package/mcp-server/dist/tools/discord-thread.d.ts +28 -0
  326. package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -0
  327. package/mcp-server/dist/tools/discord-thread.js +88 -0
  328. package/mcp-server/dist/tools/discord-thread.js.map +1 -0
  329. package/mcp-server/dist/tools/discord-webhook.d.ts +32 -0
  330. package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -0
  331. package/mcp-server/dist/tools/discord-webhook.js +154 -0
  332. package/mcp-server/dist/tools/discord-webhook.js.map +1 -0
  333. package/mcp-server/dist/tools/discord.d.ts +7 -0
  334. package/mcp-server/dist/tools/discord.d.ts.map +1 -0
  335. package/mcp-server/dist/tools/discord.js +25 -0
  336. package/mcp-server/dist/tools/discord.js.map +1 -0
  337. package/mcp-server/dist/tools/fb-groups.d.ts +98 -0
  338. package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -0
  339. package/mcp-server/dist/tools/fb-groups.js +369 -0
  340. package/mcp-server/dist/tools/fb-groups.js.map +1 -0
  341. package/mcp-server/dist/tools/forget.d.ts +14 -0
  342. package/mcp-server/dist/tools/forget.d.ts.map +1 -0
  343. package/mcp-server/dist/tools/forget.js +26 -0
  344. package/mcp-server/dist/tools/forget.js.map +1 -0
  345. package/mcp-server/dist/tools/git-tools.d.ts +24 -0
  346. package/mcp-server/dist/tools/git-tools.d.ts.map +1 -0
  347. package/mcp-server/dist/tools/git-tools.js +107 -0
  348. package/mcp-server/dist/tools/git-tools.js.map +1 -0
  349. package/mcp-server/dist/tools/git.d.ts +7 -0
  350. package/mcp-server/dist/tools/git.d.ts.map +1 -0
  351. package/mcp-server/dist/tools/git.js +11 -0
  352. package/mcp-server/dist/tools/git.js.map +1 -0
  353. package/mcp-server/dist/tools/gsc/experience.d.ts +135 -0
  354. package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -0
  355. package/mcp-server/dist/tools/gsc/experience.js +351 -0
  356. package/mcp-server/dist/tools/gsc/experience.js.map +1 -0
  357. package/mcp-server/dist/tools/gsc/helpers.d.ts +78 -0
  358. package/mcp-server/dist/tools/gsc/helpers.d.ts.map +1 -0
  359. package/mcp-server/dist/tools/gsc/helpers.js +258 -0
  360. package/mcp-server/dist/tools/gsc/helpers.js.map +1 -0
  361. package/mcp-server/dist/tools/gsc/indexing.d.ts +121 -0
  362. package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -0
  363. package/mcp-server/dist/tools/gsc/indexing.js +357 -0
  364. package/mcp-server/dist/tools/gsc/indexing.js.map +1 -0
  365. package/mcp-server/dist/tools/gsc/inspect.d.ts +78 -0
  366. package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -0
  367. package/mcp-server/dist/tools/gsc/inspect.js +321 -0
  368. package/mcp-server/dist/tools/gsc/inspect.js.map +1 -0
  369. package/mcp-server/dist/tools/gsc/navigate.d.ts +44 -0
  370. package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -0
  371. package/mcp-server/dist/tools/gsc/navigate.js +197 -0
  372. package/mcp-server/dist/tools/gsc/navigate.js.map +1 -0
  373. package/mcp-server/dist/tools/gsc/performance.d.ts +84 -0
  374. package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -0
  375. package/mcp-server/dist/tools/gsc/performance.js +274 -0
  376. package/mcp-server/dist/tools/gsc/performance.js.map +1 -0
  377. package/mcp-server/dist/tools/gsc/settings.d.ts +153 -0
  378. package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -0
  379. package/mcp-server/dist/tools/gsc/settings.js +425 -0
  380. package/mcp-server/dist/tools/gsc/settings.js.map +1 -0
  381. package/mcp-server/dist/tools/gsc.d.ts +7 -0
  382. package/mcp-server/dist/tools/gsc.d.ts.map +1 -0
  383. package/mcp-server/dist/tools/gsc.js +51 -0
  384. package/mcp-server/dist/tools/gsc.js.map +1 -0
  385. package/mcp-server/dist/tools/image-tools.d.ts +24 -0
  386. package/mcp-server/dist/tools/image-tools.d.ts.map +1 -0
  387. package/mcp-server/dist/tools/image-tools.js +80 -0
  388. package/mcp-server/dist/tools/image-tools.js.map +1 -0
  389. package/mcp-server/dist/tools/image.d.ts +10 -0
  390. package/mcp-server/dist/tools/image.d.ts.map +1 -0
  391. package/mcp-server/dist/tools/image.js +14 -0
  392. package/mcp-server/dist/tools/image.js.map +1 -0
  393. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +97 -0
  394. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -0
  395. package/mcp-server/dist/tools/leonardo-browser-tools.js +228 -0
  396. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -0
  397. package/mcp-server/dist/tools/leonardo.d.ts +13 -0
  398. package/mcp-server/dist/tools/leonardo.d.ts.map +1 -0
  399. package/mcp-server/dist/tools/leonardo.js +21 -0
  400. package/mcp-server/dist/tools/leonardo.js.map +1 -0
  401. package/mcp-server/dist/tools/loop.d.ts +30 -0
  402. package/mcp-server/dist/tools/loop.d.ts.map +1 -0
  403. package/mcp-server/dist/tools/loop.js +401 -0
  404. package/mcp-server/dist/tools/loop.js.map +1 -0
  405. package/mcp-server/dist/tools/memories.d.ts +56 -0
  406. package/mcp-server/dist/tools/memories.d.ts.map +1 -0
  407. package/mcp-server/dist/tools/memories.js +171 -0
  408. package/mcp-server/dist/tools/memories.js.map +1 -0
  409. package/mcp-server/dist/tools/morelogin.d.ts +24 -0
  410. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -0
  411. package/mcp-server/dist/tools/morelogin.js +79 -0
  412. package/mcp-server/dist/tools/morelogin.js.map +1 -0
  413. package/mcp-server/dist/tools/profile.d.ts +17 -0
  414. package/mcp-server/dist/tools/profile.d.ts.map +1 -0
  415. package/mcp-server/dist/tools/profile.js +114 -0
  416. package/mcp-server/dist/tools/profile.js.map +1 -0
  417. package/mcp-server/dist/tools/recall.d.ts +71 -0
  418. package/mcp-server/dist/tools/recall.d.ts.map +1 -0
  419. package/mcp-server/dist/tools/recall.js +147 -0
  420. package/mcp-server/dist/tools/recall.js.map +1 -0
  421. package/mcp-server/dist/tools/reflect.d.ts +56 -0
  422. package/mcp-server/dist/tools/reflect.d.ts.map +1 -0
  423. package/mcp-server/dist/tools/reflect.js +157 -0
  424. package/mcp-server/dist/tools/reflect.js.map +1 -0
  425. package/mcp-server/dist/tools/remember.d.ts +62 -0
  426. package/mcp-server/dist/tools/remember.d.ts.map +1 -0
  427. package/mcp-server/dist/tools/remember.js +201 -0
  428. package/mcp-server/dist/tools/remember.js.map +1 -0
  429. package/mcp-server/dist/tools/response.d.ts +23 -0
  430. package/mcp-server/dist/tools/response.d.ts.map +1 -0
  431. package/mcp-server/dist/tools/response.js +24 -0
  432. package/mcp-server/dist/tools/response.js.map +1 -0
  433. package/mcp-server/dist/tools/restore.d.ts +14 -0
  434. package/mcp-server/dist/tools/restore.d.ts.map +1 -0
  435. package/mcp-server/dist/tools/restore.js +23 -0
  436. package/mcp-server/dist/tools/restore.js.map +1 -0
  437. package/mcp-server/dist/tools/style-guide-tools.d.ts +51 -0
  438. package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -0
  439. package/mcp-server/dist/tools/style-guide-tools.js +231 -0
  440. package/mcp-server/dist/tools/style-guide-tools.js.map +1 -0
  441. package/mcp-server/dist/tools/style-guide.d.ts +8 -0
  442. package/mcp-server/dist/tools/style-guide.d.ts.map +1 -0
  443. package/mcp-server/dist/tools/style-guide.js +12 -0
  444. package/mcp-server/dist/tools/style-guide.js.map +1 -0
  445. package/mcp-server/dist/tools/sync.d.ts +20 -0
  446. package/mcp-server/dist/tools/sync.d.ts.map +1 -0
  447. package/mcp-server/dist/tools/sync.js +156 -0
  448. package/mcp-server/dist/tools/sync.js.map +1 -0
  449. package/mcp-server/dist/tools/tictactoe-tools.d.ts +18 -0
  450. package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -0
  451. package/mcp-server/dist/tools/tictactoe-tools.js +78 -0
  452. package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -0
  453. package/mcp-server/dist/tools/tictactoe.d.ts +7 -0
  454. package/mcp-server/dist/tools/tictactoe.d.ts.map +1 -0
  455. package/mcp-server/dist/tools/tictactoe.js +11 -0
  456. package/mcp-server/dist/tools/tictactoe.js.map +1 -0
  457. package/mcp-server/dist/tools/utils.d.ts +19 -0
  458. package/mcp-server/dist/tools/utils.d.ts.map +1 -0
  459. package/mcp-server/dist/tools/utils.js +54 -0
  460. package/mcp-server/dist/tools/utils.js.map +1 -0
  461. package/mcp-server/dist/tools/whiteboard-format.d.ts +88 -0
  462. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -0
  463. package/mcp-server/dist/tools/whiteboard-format.js +337 -0
  464. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -0
  465. package/mcp-server/dist/tools/whiteboard-tools.d.ts +326 -0
  466. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -0
  467. package/mcp-server/dist/tools/whiteboard-tools.js +222 -0
  468. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -0
  469. package/mcp-server/dist/tools/whiteboard.d.ts +8 -0
  470. package/mcp-server/dist/tools/whiteboard.d.ts.map +1 -0
  471. package/mcp-server/dist/tools/whiteboard.js +16 -0
  472. package/mcp-server/dist/tools/whiteboard.js.map +1 -0
  473. package/mcp-server/dist/tools/youtube/analytics.d.ts +46 -0
  474. package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -0
  475. package/mcp-server/dist/tools/youtube/analytics.js +83 -0
  476. package/mcp-server/dist/tools/youtube/analytics.js.map +1 -0
  477. package/mcp-server/dist/tools/youtube/dedup.d.ts +35 -0
  478. package/mcp-server/dist/tools/youtube/dedup.d.ts.map +1 -0
  479. package/mcp-server/dist/tools/youtube/dedup.js +56 -0
  480. package/mcp-server/dist/tools/youtube/dedup.js.map +1 -0
  481. package/mcp-server/dist/tools/youtube/download.d.ts +31 -0
  482. package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -0
  483. package/mcp-server/dist/tools/youtube/download.js +30 -0
  484. package/mcp-server/dist/tools/youtube/download.js.map +1 -0
  485. package/mcp-server/dist/tools/youtube/helpers.d.ts +66 -0
  486. package/mcp-server/dist/tools/youtube/helpers.d.ts.map +1 -0
  487. package/mcp-server/dist/tools/youtube/helpers.js +143 -0
  488. package/mcp-server/dist/tools/youtube/helpers.js.map +1 -0
  489. package/mcp-server/dist/tools/youtube/media.d.ts +43 -0
  490. package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -0
  491. package/mcp-server/dist/tools/youtube/media.js +97 -0
  492. package/mcp-server/dist/tools/youtube/media.js.map +1 -0
  493. package/mcp-server/dist/tools/youtube/metadata.d.ts +33 -0
  494. package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -0
  495. package/mcp-server/dist/tools/youtube/metadata.js +106 -0
  496. package/mcp-server/dist/tools/youtube/metadata.js.map +1 -0
  497. package/mcp-server/dist/tools/youtube/navigate.d.ts +30 -0
  498. package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -0
  499. package/mcp-server/dist/tools/youtube/navigate.js +71 -0
  500. package/mcp-server/dist/tools/youtube/navigate.js.map +1 -0
  501. package/mcp-server/dist/tools/youtube/playlist.d.ts +29 -0
  502. package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -0
  503. package/mcp-server/dist/tools/youtube/playlist.js +128 -0
  504. package/mcp-server/dist/tools/youtube/playlist.js.map +1 -0
  505. package/mcp-server/dist/tools/youtube/schedule.d.ts +31 -0
  506. package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -0
  507. package/mcp-server/dist/tools/youtube/schedule.js +147 -0
  508. package/mcp-server/dist/tools/youtube/schedule.js.map +1 -0
  509. package/mcp-server/dist/tools/youtube/source.d.ts +36 -0
  510. package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -0
  511. package/mcp-server/dist/tools/youtube/source.js +85 -0
  512. package/mcp-server/dist/tools/youtube/source.js.map +1 -0
  513. package/mcp-server/dist/tools/youtube/upload.d.ts +53 -0
  514. package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -0
  515. package/mcp-server/dist/tools/youtube/upload.js +255 -0
  516. package/mcp-server/dist/tools/youtube/upload.js.map +1 -0
  517. package/mcp-server/dist/tools/youtube.d.ts +12 -0
  518. package/mcp-server/dist/tools/youtube.d.ts.map +1 -0
  519. package/mcp-server/dist/tools/youtube.js +38 -0
  520. package/mcp-server/dist/tools/youtube.js.map +1 -0
  521. package/mcp-server/dist/tui.d.ts +3 -0
  522. package/mcp-server/dist/tui.d.ts.map +1 -0
  523. package/mcp-server/dist/tui.js +806 -0
  524. package/mcp-server/dist/tui.js.map +1 -0
  525. package/mcp-server/dist/types.d.ts +77 -0
  526. package/mcp-server/dist/types.d.ts.map +1 -0
  527. package/mcp-server/dist/types.js +2 -0
  528. package/mcp-server/dist/types.js.map +1 -0
  529. package/mcp-server/package-lock.json +4798 -0
  530. package/mcp-server/package.json +55 -38
  531. package/mcp-server/run.mjs +12 -2
  532. package/mcp-server/src/config.ts +48 -3
  533. package/mcp-server/src/http.ts +296 -93
  534. package/mcp-server/src/index.ts +546 -203
  535. package/mcp-server/src/preload-http.ts +19 -18
  536. package/mcp-server/src/preload.ts +19 -18
  537. package/mcp-server/src/scripts/setup-embeddings.ts +9 -0
  538. package/mcp-server/src/services/assistant-judgments.ts +157 -0
  539. package/mcp-server/src/services/browser-assist-gate.ts +383 -0
  540. package/mcp-server/src/services/browser-assist.ts +267 -0
  541. package/mcp-server/src/services/browser-bench.ts +477 -0
  542. package/mcp-server/src/services/browser-judgments.ts +414 -0
  543. package/mcp-server/src/services/browser-risk.ts +484 -0
  544. package/mcp-server/src/services/categories.ts +36 -19
  545. package/mcp-server/src/services/codex-config-heal.ts +403 -0
  546. package/mcp-server/src/services/desktop-assist-gate.ts +251 -0
  547. package/mcp-server/src/services/desktop-assist.ts +308 -0
  548. package/mcp-server/src/services/desktop-bench.ts +372 -0
  549. package/mcp-server/src/services/desktop-client.ts +76 -0
  550. package/mcp-server/src/services/desktop-judgments.ts +218 -0
  551. package/mcp-server/src/services/desktop-risk.ts +743 -0
  552. package/mcp-server/src/services/edit-stale.ts +299 -0
  553. package/mcp-server/src/services/embedding-service.ts +108 -0
  554. package/mcp-server/src/services/embedding-worker.ts +46 -0
  555. package/mcp-server/src/services/fb-regions.ts +221 -0
  556. package/mcp-server/src/services/file-checksums.ts +26 -9
  557. package/mcp-server/src/services/file-excerpt.ts +59 -0
  558. package/mcp-server/src/services/identity.ts +291 -0
  559. package/mcp-server/src/services/local-embeddings.ts +2 -77
  560. package/mcp-server/src/services/memory-client.ts +23 -0
  561. package/mcp-server/src/services/memory-judge-backfill.ts +462 -0
  562. package/mcp-server/src/services/memory-judgments.ts +901 -0
  563. package/mcp-server/src/services/memory-maintenance.ts +360 -0
  564. package/mcp-server/src/services/memory-retrieval.ts +349 -0
  565. package/mcp-server/src/services/memory-schema.ts +280 -0
  566. package/mcp-server/src/services/memory-sessions.ts +87 -0
  567. package/mcp-server/src/services/memory-triage.ts +182 -0
  568. package/mcp-server/src/services/memory-verification.ts +68 -0
  569. package/mcp-server/src/services/memory-writer.ts +125 -0
  570. package/mcp-server/src/services/neural-interface.ts +1217 -73
  571. package/mcp-server/src/services/profiles.ts +428 -0
  572. package/mcp-server/src/services/secret-gate.ts +52 -0
  573. package/mcp-server/src/services/server-instructions.ts +122 -0
  574. package/mcp-server/src/services/sqlite.ts +1456 -823
  575. package/mcp-server/src/services/typesafe-bench.ts +247 -0
  576. package/mcp-server/src/services/typesafe-config.ts +790 -0
  577. package/mcp-server/src/services/typesafe.ts +390 -0
  578. package/mcp-server/src/services/vector-cache.ts +255 -0
  579. package/mcp-server/src/services/whiteboard-geometry.ts +711 -0
  580. package/mcp-server/src/tools/agents.ts +539 -0
  581. package/mcp-server/src/tools/bluesky.ts +1186 -0
  582. package/mcp-server/src/tools/browser-advanced.ts +15 -6
  583. package/mcp-server/src/tools/browser-batch.ts +178 -0
  584. package/mcp-server/src/tools/browser-cheatsheet.ts +155 -0
  585. package/mcp-server/src/tools/browser-interact.ts +362 -255
  586. package/mcp-server/src/tools/browser-navigate.ts +164 -77
  587. package/mcp-server/src/tools/browser-observe.ts +2222 -1330
  588. package/mcp-server/src/tools/browser.ts +181 -107
  589. package/mcp-server/src/tools/card.ts +7 -5
  590. package/mcp-server/src/tools/choice.ts +103 -0
  591. package/mcp-server/src/tools/computer.ts +190 -0
  592. package/mcp-server/src/tools/discord.ts +10 -23
  593. package/mcp-server/src/tools/fb-groups.ts +387 -0
  594. package/mcp-server/src/tools/forget.ts +1 -1
  595. package/mcp-server/src/tools/git.ts +3 -1
  596. package/mcp-server/src/tools/gsc/experience.ts +440 -0
  597. package/mcp-server/src/tools/gsc/helpers.ts +288 -0
  598. package/mcp-server/src/tools/gsc/indexing.ts +495 -0
  599. package/mcp-server/src/tools/gsc/inspect.ts +391 -0
  600. package/mcp-server/src/tools/gsc/navigate.ts +236 -0
  601. package/mcp-server/src/tools/gsc/performance.ts +352 -0
  602. package/mcp-server/src/tools/gsc/settings.ts +564 -0
  603. package/mcp-server/src/tools/gsc.ts +95 -0
  604. package/mcp-server/src/tools/image.ts +3 -1
  605. package/mcp-server/src/tools/leonardo-browser-tools.ts +47 -37
  606. package/mcp-server/src/tools/leonardo.ts +7 -5
  607. package/mcp-server/src/tools/loop.ts +118 -25
  608. package/mcp-server/src/tools/memories.ts +65 -5
  609. package/mcp-server/src/tools/morelogin.ts +81 -0
  610. package/mcp-server/src/tools/profile.ts +122 -0
  611. package/mcp-server/src/tools/recall.ts +105 -261
  612. package/mcp-server/src/tools/reflect.ts +171 -145
  613. package/mcp-server/src/tools/remember.ts +223 -115
  614. package/mcp-server/src/tools/style-guide-tools.ts +250 -0
  615. package/mcp-server/src/tools/style-guide.ts +16 -0
  616. package/mcp-server/src/tools/sync.ts +66 -9
  617. package/mcp-server/src/tools/tictactoe.ts +3 -1
  618. package/mcp-server/src/tools/utils.ts +22 -0
  619. package/mcp-server/src/tools/whiteboard-format.ts +394 -0
  620. package/mcp-server/src/tools/whiteboard-tools.ts +191 -183
  621. package/mcp-server/src/tools/whiteboard.ts +7 -5
  622. package/mcp-server/src/tools/youtube/analytics.ts +106 -0
  623. package/mcp-server/src/tools/youtube/dedup.ts +57 -0
  624. package/mcp-server/src/tools/youtube/download.ts +41 -0
  625. package/mcp-server/src/tools/youtube/helpers.ts +183 -0
  626. package/mcp-server/src/tools/youtube/media.ts +109 -0
  627. package/mcp-server/src/tools/youtube/metadata.ts +112 -0
  628. package/mcp-server/src/tools/youtube/navigate.ts +81 -0
  629. package/mcp-server/src/tools/youtube/playlist.ts +134 -0
  630. package/mcp-server/src/tools/youtube/schedule.ts +158 -0
  631. package/mcp-server/src/tools/youtube/source.ts +101 -0
  632. package/mcp-server/src/tools/youtube/upload.ts +296 -0
  633. package/mcp-server/src/tools/youtube.ts +47 -0
  634. package/mcp-server/src/tui.ts +8 -9
  635. package/neural-interface/games/TicTacToe/1.svg +1 -0
  636. package/neural-interface/games/TicTacToe/2.svg +1 -0
  637. package/neural-interface/games/TicTacToe/3.svg +1 -0
  638. package/neural-interface/games/TicTacToe/4.svg +1 -0
  639. package/neural-interface/games/TicTacToe/5.svg +1 -0
  640. package/neural-interface/games/TicTacToe/6.svg +1 -0
  641. package/neural-interface/games/TicTacToe/7.svg +1 -0
  642. package/neural-interface/games/TicTacToe/8.svg +1 -0
  643. package/neural-interface/games/TicTacToe/9.svg +1 -0
  644. package/neural-interface/games/TicTacToe/Board.svg +1 -0
  645. package/neural-interface/games/TicTacToe/Circle.svg +1 -0
  646. package/neural-interface/games/TicTacToe/Cross.svg +1 -0
  647. package/neural-interface/i18n/en.json +6983 -0
  648. package/neural-interface/i18n/pt-BR.json +6987 -0
  649. package/neural-interface/lib/assistant-api.js +1005 -0
  650. package/neural-interface/lib/assistant-attachments.js +121 -0
  651. package/neural-interface/lib/assistant-brains/claude.js +207 -0
  652. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +43 -0
  653. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +56 -0
  654. package/neural-interface/lib/assistant-brains/codex.js +213 -0
  655. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +47 -0
  656. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +62 -0
  657. package/neural-interface/lib/assistant-brains/opencode.js +320 -0
  658. package/neural-interface/lib/assistant-budget.js +318 -0
  659. package/neural-interface/lib/assistant-catalog.js +731 -0
  660. package/neural-interface/lib/assistant-clarify.js +664 -0
  661. package/neural-interface/lib/assistant-config.js +232 -0
  662. package/neural-interface/lib/assistant-dispatch.js +2744 -0
  663. package/neural-interface/lib/assistant-envelope.js +579 -0
  664. package/neural-interface/lib/assistant-evidence.js +236 -0
  665. package/neural-interface/lib/assistant-hidden-models.js +272 -0
  666. package/neural-interface/lib/assistant-jev.js +117 -0
  667. package/neural-interface/lib/assistant-judgments.js +111 -0
  668. package/neural-interface/lib/assistant-media.js +335 -0
  669. package/neural-interface/lib/assistant-memory.js +398 -0
  670. package/neural-interface/lib/assistant-persona.js +444 -0
  671. package/neural-interface/lib/assistant-plan-permissions.js +448 -0
  672. package/neural-interface/lib/assistant-playbooks/design.md +87 -0
  673. package/neural-interface/lib/assistant-playbooks.js +72 -0
  674. package/neural-interface/lib/assistant-pricing.js +159 -0
  675. package/neural-interface/lib/assistant-route-gate-codex.js +163 -0
  676. package/neural-interface/lib/assistant-route-gate.js +212 -0
  677. package/neural-interface/lib/assistant-router.js +1324 -0
  678. package/neural-interface/lib/assistant-runtime.js +3337 -0
  679. package/neural-interface/lib/assistant-task-prompt.js +472 -0
  680. package/neural-interface/lib/assistant-usage.js +1688 -0
  681. package/neural-interface/lib/augmented-path.js +50 -0
  682. package/neural-interface/lib/automation-storage-migration.js +54 -0
  683. package/neural-interface/lib/backup-service.js +851 -0
  684. package/neural-interface/lib/backup-zip-reader.js +262 -0
  685. package/neural-interface/lib/browser-assist-api.js +41 -0
  686. package/neural-interface/lib/browser-console.js +176 -0
  687. package/neural-interface/lib/browser-execution.js +241 -0
  688. package/neural-interface/lib/browser-extraction.js +191 -0
  689. package/neural-interface/lib/browser-screenshot.js +399 -0
  690. package/neural-interface/lib/browser-semantic-context.js +639 -0
  691. package/neural-interface/lib/browser-snapshots.js +192 -0
  692. package/neural-interface/lib/browser-tab-recovery.js +119 -0
  693. package/neural-interface/lib/browser-targets.js +70 -0
  694. package/neural-interface/lib/browser-tool-policy.js +926 -0
  695. package/neural-interface/lib/claude-accounts.js +230 -0
  696. package/neural-interface/lib/claude-agent-bridge.js +3296 -0
  697. package/neural-interface/lib/claude-bypass-policy.js +99 -0
  698. package/neural-interface/lib/claude-history.js +429 -0
  699. package/neural-interface/lib/claude-model-catalog.js +483 -0
  700. package/neural-interface/lib/claude-panel-requests.js +165 -0
  701. package/neural-interface/lib/claude-panel-session.js +272 -0
  702. package/neural-interface/lib/claude-permission-rules.js +153 -0
  703. package/neural-interface/lib/claude-session-cleanup.js +71 -0
  704. package/neural-interface/lib/claude-session-list.js +82 -0
  705. package/neural-interface/lib/claude-session-ops.js +140 -0
  706. package/neural-interface/lib/claude-settings-view.js +51 -0
  707. package/neural-interface/lib/claude-skin-connect.js +79 -0
  708. package/neural-interface/lib/claude-stall-policy.js +7 -0
  709. package/neural-interface/lib/claude-temporary.js +435 -0
  710. package/neural-interface/lib/cli-update-planner.js +312 -0
  711. package/neural-interface/lib/codex-capabilities.d.ts +41 -0
  712. package/neural-interface/lib/codex-capabilities.js +148 -0
  713. package/neural-interface/lib/codex-collaboration-mode.js +17 -0
  714. package/neural-interface/lib/codex-compat-rpc.js +241 -0
  715. package/neural-interface/lib/codex-mcp-approvals.js +56 -0
  716. package/neural-interface/lib/codex-mcp-apps.js +47 -0
  717. package/neural-interface/lib/codex-model-context.js +202 -0
  718. package/neural-interface/lib/codex-plan-store.js +71 -0
  719. package/neural-interface/lib/codex-request-journal.js +242 -0
  720. package/neural-interface/lib/codex-runtime-path.js +213 -0
  721. package/neural-interface/lib/codex-session-catalog.js +231 -0
  722. package/neural-interface/lib/codex-session-settings.js +46 -0
  723. package/neural-interface/lib/codex-sidepanel-permissions.js +110 -0
  724. package/neural-interface/lib/codex-thread-history.js +165 -0
  725. package/neural-interface/lib/codex-user-verification.js +34 -0
  726. package/neural-interface/lib/codex-writer-lifecycle.js +152 -0
  727. package/neural-interface/lib/confined-fs.js +256 -0
  728. package/neural-interface/lib/db.js +922 -0
  729. package/neural-interface/lib/design-md.js +9 -0
  730. package/neural-interface/lib/desktop/api.js +92 -0
  731. package/neural-interface/lib/desktop/audit.js +62 -0
  732. package/neural-interface/lib/desktop/build.js +423 -0
  733. package/neural-interface/lib/desktop/config.js +606 -0
  734. package/neural-interface/lib/desktop/coords.js +76 -0
  735. package/neural-interface/lib/desktop/fake-helper.js +1192 -0
  736. package/neural-interface/lib/desktop/frames.js +77 -0
  737. package/neural-interface/lib/desktop/grants.js +84 -0
  738. package/neural-interface/lib/desktop/guards.js +170 -0
  739. package/neural-interface/lib/desktop/helper/SynabunDesktop.swift +3056 -0
  740. package/neural-interface/lib/desktop/lease.js +51 -0
  741. package/neural-interface/lib/desktop/manager.js +545 -0
  742. package/neural-interface/lib/desktop/press-contexts.js +103 -0
  743. package/neural-interface/lib/desktop/protocol.js +495 -0
  744. package/neural-interface/lib/desktop/service.js +1202 -0
  745. package/neural-interface/lib/effort-levels.js +148 -0
  746. package/neural-interface/lib/event-loop-monitor.js +67 -0
  747. package/neural-interface/lib/exec-loop-command.js +209 -0
  748. package/neural-interface/lib/folder-picker.ps1 +77 -0
  749. package/neural-interface/lib/http-guards.js +287 -0
  750. package/neural-interface/lib/jsonl-lines.js +94 -0
  751. package/neural-interface/lib/loop-logger.js +127 -0
  752. package/neural-interface/lib/mcp-client-config.js +133 -0
  753. package/neural-interface/lib/mcp-installer.js +487 -0
  754. package/neural-interface/lib/mcp-profile-refresh-coordinator.js +78 -0
  755. package/neural-interface/lib/mcp-profile-servers.js +120 -0
  756. package/neural-interface/lib/memo-cache.js +84 -0
  757. package/neural-interface/lib/memory-api.js +758 -0
  758. package/neural-interface/lib/memory-map-api.js +1150 -0
  759. package/neural-interface/lib/memory-map-layout.js +872 -0
  760. package/neural-interface/lib/memory-map-worker.js +165 -0
  761. package/neural-interface/lib/memory-session-capture.js +81 -0
  762. package/neural-interface/lib/memory-timers.js +62 -0
  763. package/neural-interface/lib/morelogin.js +301 -0
  764. package/neural-interface/lib/native-binary-runtime.js +650 -0
  765. package/neural-interface/lib/native-loop-goal.js +33 -0
  766. package/neural-interface/lib/native-loop-providers.js +1016 -0
  767. package/neural-interface/lib/native-loop-runtime.js +747 -0
  768. package/neural-interface/lib/opencode-hidden-models.js +113 -0
  769. package/neural-interface/lib/opencode-history.js +253 -0
  770. package/neural-interface/lib/opencode-runtime-config.js +58 -0
  771. package/neural-interface/lib/opencode-v2-client.js +486 -0
  772. package/neural-interface/lib/opencode-v2-ws-requests.js +955 -0
  773. package/neural-interface/lib/path-confine.js +213 -0
  774. package/neural-interface/lib/plugin-installer.js +264 -0
  775. package/neural-interface/lib/project-storage.js +766 -0
  776. package/neural-interface/lib/pty-host/core.js +603 -0
  777. package/neural-interface/lib/pty-host/flow.js +43 -0
  778. package/neural-interface/lib/pty-host/host.js +47 -0
  779. package/neural-interface/lib/pty-host/manager.js +360 -0
  780. package/neural-interface/lib/pty-host/protocol.js +81 -0
  781. package/neural-interface/lib/pty-host/snapshot.js +133 -0
  782. package/neural-interface/lib/remote-policy.js +582 -0
  783. package/neural-interface/lib/rulesets/api.js +175 -0
  784. package/neural-interface/lib/rulesets/fs-safe.js +245 -0
  785. package/neural-interface/lib/rulesets/installer.js +1453 -0
  786. package/neural-interface/lib/rulesets/json-edit.js +186 -0
  787. package/neural-interface/lib/rulesets/lock.js +170 -0
  788. package/neural-interface/lib/rulesets/managed-text.js +314 -0
  789. package/neural-interface/lib/rulesets/normalise.js +24 -0
  790. package/neural-interface/lib/rulesets/render.js +84 -0
  791. package/neural-interface/lib/schedule-launch-intent.js +40 -0
  792. package/neural-interface/lib/session-cache-builder.js +524 -0
  793. package/neural-interface/lib/session-chunker.js +344 -0
  794. package/neural-interface/lib/session-indexer.js +327 -0
  795. package/neural-interface/lib/session-title-generator.js +227 -0
  796. package/neural-interface/lib/skill-prompt-bridge.js +11 -0
  797. package/neural-interface/lib/style-guide/api.js +375 -0
  798. package/neural-interface/lib/style-guide/color.js +352 -0
  799. package/neural-interface/lib/style-guide/export-css.js +99 -0
  800. package/neural-interface/lib/style-guide/export-dtcg.js +209 -0
  801. package/neural-interface/lib/style-guide/export-tailwind.js +102 -0
  802. package/neural-interface/lib/style-guide/fonts.json +227 -0
  803. package/neural-interface/lib/style-guide/import.js +1268 -0
  804. package/neural-interface/lib/style-guide/pointers.js +103 -0
  805. package/neural-interface/lib/style-guide/presets.js +232 -0
  806. package/neural-interface/lib/style-guide/render-design-md.js +319 -0
  807. package/neural-interface/lib/style-guide/schema.js +848 -0
  808. package/neural-interface/lib/style-guide/security.js +43 -0
  809. package/neural-interface/lib/style-guide/store.js +491 -0
  810. package/neural-interface/lib/style-guide/summary.js +106 -0
  811. package/neural-interface/lib/style-guide/tokens.js +170 -0
  812. package/neural-interface/lib/synabun-update-plan.js +305 -0
  813. package/neural-interface/lib/synabun-version.js +179 -0
  814. package/neural-interface/lib/system-restore.js +99 -0
  815. package/neural-interface/lib/terminal-env.js +86 -0
  816. package/neural-interface/lib/ui-blob-store.js +106 -0
  817. package/neural-interface/lib/vector-cache.js +2 -0
  818. package/neural-interface/lib/virtual-socket.js +60 -0
  819. package/neural-interface/lib/whatsapp/api.js +146 -0
  820. package/neural-interface/lib/whatsapp/auth-store.js +389 -0
  821. package/neural-interface/lib/whatsapp/baileys-adapter.js +457 -0
  822. package/neural-interface/lib/whatsapp/brain.js +128 -0
  823. package/neural-interface/lib/whatsapp/bridge.js +1499 -0
  824. package/neural-interface/lib/whatsapp/cards.js +519 -0
  825. package/neural-interface/lib/whatsapp/commands.js +92 -0
  826. package/neural-interface/lib/whatsapp/config.js +291 -0
  827. package/neural-interface/lib/whatsapp/connector/entry.mjs +25 -0
  828. package/neural-interface/lib/whatsapp/connector/manifest.json +6 -0
  829. package/neural-interface/lib/whatsapp/connector/npm-shrinkwrap.json +717 -0
  830. package/neural-interface/lib/whatsapp/connector/package.json +8 -0
  831. package/neural-interface/lib/whatsapp/fake-baileys.js +444 -0
  832. package/neural-interface/lib/whatsapp/format.js +552 -0
  833. package/neural-interface/lib/whatsapp/host-core.js +1225 -0
  834. package/neural-interface/lib/whatsapp/host.js +119 -0
  835. package/neural-interface/lib/whatsapp/identity.js +288 -0
  836. package/neural-interface/lib/whatsapp/inbound.js +149 -0
  837. package/neural-interface/lib/whatsapp/installer.js +562 -0
  838. package/neural-interface/lib/whatsapp/manager.js +638 -0
  839. package/neural-interface/lib/whatsapp/paths.js +81 -0
  840. package/neural-interface/lib/whatsapp/protocol.js +327 -0
  841. package/neural-interface/lib/whatsapp/qr-svg.js +57 -0
  842. package/neural-interface/lib/whatsapp/redact.js +130 -0
  843. package/neural-interface/lib/whatsapp/service.js +1305 -0
  844. package/neural-interface/lib/whatsapp/vendor/qrcodegen.js +848 -0
  845. package/neural-interface/package-lock.json +4682 -0
  846. package/neural-interface/package.json +58 -27
  847. package/neural-interface/public/apple-touch-icon.png +0 -0
  848. package/neural-interface/public/category-logos/synabun.png +0 -0
  849. package/neural-interface/public/claude.svg +1 -0
  850. package/neural-interface/public/favicon-16x16.png +0 -0
  851. package/neural-interface/public/favicon-32x32.png +0 -0
  852. package/neural-interface/public/icon-192.png +0 -0
  853. package/neural-interface/public/icon-512.png +0 -0
  854. package/neural-interface/public/index.html +32 -182
  855. package/neural-interface/public/index2d.html +2 -2
  856. package/neural-interface/public/logo-synabun.png +0 -0
  857. package/neural-interface/public/logoHD.png +0 -0
  858. package/neural-interface/public/mcp.svg +4 -0
  859. package/neural-interface/public/offline.html +335 -299
  860. package/neural-interface/public/onboarding.html +692 -155
  861. package/neural-interface/public/opencode-logo-dark-square.svg +1 -0
  862. package/neural-interface/public/shared/agent-runtime-options.js +596 -0
  863. package/neural-interface/public/shared/api.js +339 -28
  864. package/neural-interface/public/shared/assistant/asst-accounts.js +318 -0
  865. package/neural-interface/public/shared/assistant/asst-agents-dock.js +296 -0
  866. package/neural-interface/public/shared/assistant/asst-api.js +270 -0
  867. package/neural-interface/public/shared/assistant/asst-brain-picker.js +744 -0
  868. package/neural-interface/public/shared/assistant/asst-budget.js +333 -0
  869. package/neural-interface/public/shared/assistant/asst-composer.js +656 -0
  870. package/neural-interface/public/shared/assistant/asst-computer.js +803 -0
  871. package/neural-interface/public/shared/assistant/asst-control.js +1018 -0
  872. package/neural-interface/public/shared/assistant/asst-hosts.js +262 -0
  873. package/neural-interface/public/shared/assistant/asst-mascot.js +311 -0
  874. package/neural-interface/public/shared/assistant/asst-menu.js +375 -0
  875. package/neural-interface/public/shared/assistant/asst-panel.js +1845 -0
  876. package/neural-interface/public/shared/assistant/asst-rack-styles.js +589 -0
  877. package/neural-interface/public/shared/assistant/asst-render.js +3296 -0
  878. package/neural-interface/public/shared/assistant/asst-route.js +1653 -0
  879. package/neural-interface/public/shared/assistant/asst-roving.js +75 -0
  880. package/neural-interface/public/shared/assistant/asst-sanitize.js +117 -0
  881. package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +488 -0
  882. package/neural-interface/public/shared/assistant/asst-sidepanel.js +675 -0
  883. package/neural-interface/public/shared/assistant/asst-slash.js +258 -0
  884. package/neural-interface/public/shared/assistant/asst-state.js +727 -0
  885. package/neural-interface/public/shared/assistant/asst-styles.js +1684 -0
  886. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +1017 -0
  887. package/neural-interface/public/shared/assistant/asst-usage.js +444 -0
  888. package/neural-interface/public/shared/assistant/asst-ws.js +175 -0
  889. package/neural-interface/public/shared/automation-context.js +75 -0
  890. package/neural-interface/public/shared/blob-store.js +99 -0
  891. package/neural-interface/public/shared/cdx/cdx-capabilities.js +118 -0
  892. package/neural-interface/public/shared/cdx/cdx-cards.js +37 -0
  893. package/neural-interface/public/shared/cdx/cdx-commands.js +171 -0
  894. package/neural-interface/public/shared/cdx/cdx-context-menu.js +402 -0
  895. package/neural-interface/public/shared/cdx/cdx-context-model.js +220 -0
  896. package/neural-interface/public/shared/cdx/cdx-features.js +408 -0
  897. package/neural-interface/public/shared/cdx/cdx-icons.js +89 -0
  898. package/neural-interface/public/shared/cdx/cdx-mcp-app-host.js +414 -0
  899. package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.html +6 -0
  900. package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.js +56 -0
  901. package/neural-interface/public/shared/cdx/cdx-mcp-app.js +178 -0
  902. package/neural-interface/public/shared/cdx/cdx-model-catalog.js +120 -0
  903. package/neural-interface/public/shared/cdx/cdx-output-model.js +261 -0
  904. package/neural-interface/public/shared/cdx/cdx-output.js +382 -0
  905. package/neural-interface/public/shared/cdx/cdx-panel.js +1372 -0
  906. package/neural-interface/public/shared/cdx/cdx-plan.js +266 -0
  907. package/neural-interface/public/shared/cdx/cdx-protocol.js +682 -0
  908. package/neural-interface/public/shared/cdx/cdx-render.js +3381 -0
  909. package/neural-interface/public/shared/cdx/cdx-requests.js +1136 -0
  910. package/neural-interface/public/shared/cdx/cdx-styles.js +3251 -0
  911. package/neural-interface/public/shared/cdx/cdx-tabs.js +7992 -0
  912. package/neural-interface/public/shared/cdx/cdx-ws.js +363 -0
  913. package/neural-interface/public/shared/cli-status.js +169 -0
  914. package/neural-interface/public/shared/constants.js +22 -5
  915. package/neural-interface/public/shared/cp/cp-agents.js +186 -0
  916. package/neural-interface/public/shared/cp/cp-bash.js +252 -0
  917. package/neural-interface/public/shared/cp/cp-compose.js +159 -0
  918. package/neural-interface/public/shared/cp/cp-context-menu.js +309 -0
  919. package/neural-interface/public/shared/cp/cp-context-model.js +157 -0
  920. package/neural-interface/public/shared/cp/cp-context-window.js +80 -0
  921. package/neural-interface/public/shared/cp/cp-ctx.js +11 -0
  922. package/neural-interface/public/shared/cp/cp-diff.js +255 -0
  923. package/neural-interface/public/shared/cp/cp-event-rows.js +637 -0
  924. package/neural-interface/public/shared/cp/cp-events.js +846 -0
  925. package/neural-interface/public/shared/cp/cp-markdown.js +104 -0
  926. package/neural-interface/public/shared/cp/cp-permission-model.js +905 -0
  927. package/neural-interface/public/shared/cp/cp-permissions.js +626 -0
  928. package/neural-interface/public/shared/cp/cp-rehydrate.js +113 -0
  929. package/neural-interface/public/shared/cp/cp-restore.js +224 -0
  930. package/neural-interface/public/shared/cp/cp-session-model.js +338 -0
  931. package/neural-interface/public/shared/cp/cp-session-settings.js +254 -0
  932. package/neural-interface/public/shared/cp/cp-sessions.js +227 -0
  933. package/neural-interface/public/shared/cp/cp-statusline.js +153 -0
  934. package/neural-interface/public/shared/cp/cp-styles.js +349 -0
  935. package/neural-interface/public/shared/cp/cp-tasks-model.js +282 -0
  936. package/neural-interface/public/shared/cp/cp-tasks.js +107 -0
  937. package/neural-interface/public/shared/cp/cp-temporary-view.js +56 -0
  938. package/neural-interface/public/shared/cp/cp-temporary.js +231 -0
  939. package/neural-interface/public/shared/cp/cp-tool-cards.js +326 -0
  940. package/neural-interface/public/shared/cp/cp-tool-results.js +618 -0
  941. package/neural-interface/public/shared/cp/cp-usage-model.js +124 -0
  942. package/neural-interface/public/shared/graph-activity.js +68 -0
  943. package/neural-interface/public/shared/html-shell.js +107 -12
  944. package/neural-interface/public/shared/i18n.js +132 -34
  945. package/neural-interface/public/shared/node-positions-store.js +44 -0
  946. package/neural-interface/public/shared/ocp-hidden-models.js +116 -0
  947. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +355 -0
  948. package/neural-interface/public/shared/ocp-v2/ocp-v2-autoaccept-button.js +35 -0
  949. package/neural-interface/public/shared/ocp-v2/ocp-v2-automation-ownership.js +72 -0
  950. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +280 -0
  951. package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +67 -0
  952. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +179 -0
  953. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes.js +164 -0
  954. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +725 -0
  955. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +75 -0
  956. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +1204 -0
  957. package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm-logic.js +117 -0
  958. package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm.js +59 -0
  959. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-gauge.js +252 -0
  960. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +478 -0
  961. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +179 -0
  962. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +233 -0
  963. package/neural-interface/public/shared/ocp-v2/ocp-v2-icons.js +30 -0
  964. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +1065 -0
  965. package/neural-interface/public/shared/ocp-v2/ocp-v2-mention-hints.js +182 -0
  966. package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +655 -0
  967. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +2636 -0
  968. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +601 -0
  969. package/neural-interface/public/shared/ocp-v2/ocp-v2-profile-inheritance.js +78 -0
  970. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +649 -0
  971. package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +35 -0
  972. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +357 -0
  973. package/neural-interface/public/shared/ocp-v2/ocp-v2-render-logic.js +189 -0
  974. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +1869 -0
  975. package/neural-interface/public/shared/ocp-v2/ocp-v2-select.js +42 -0
  976. package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +117 -0
  977. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +1714 -0
  978. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +468 -0
  979. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-widgets.js +63 -0
  980. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +366 -0
  981. package/neural-interface/public/shared/ocp-v2/ocp-v2-settings-link.js +19 -0
  982. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +343 -0
  983. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +746 -0
  984. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +347 -0
  985. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +338 -0
  986. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +3543 -0
  987. package/neural-interface/public/shared/ocp-v2/ocp-v2-subagents-logic.js +482 -0
  988. package/neural-interface/public/shared/ocp-v2/ocp-v2-tools-logic.js +351 -0
  989. package/neural-interface/public/shared/ocp-v2/ocp-v2-tools.js +168 -0
  990. package/neural-interface/public/shared/ocp-v2/ocp-v2-variantpicker.js +315 -0
  991. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +545 -0
  992. package/neural-interface/public/shared/provider-icons.js +30 -0
  993. package/neural-interface/public/shared/session-title.js +100 -0
  994. package/neural-interface/public/shared/settings/settings-ia.js +389 -0
  995. package/neural-interface/public/shared/settings/settings-kit.js +234 -0
  996. package/neural-interface/public/shared/settings/settings-search.js +463 -0
  997. package/neural-interface/public/shared/settings/settings-shell.js +570 -0
  998. package/neural-interface/public/shared/state.js +5 -0
  999. package/neural-interface/public/shared/storage.js +50 -7
  1000. package/neural-interface/public/shared/styleguide/sg-agents.js +42 -0
  1001. package/neural-interface/public/shared/styleguide/sg-brand.js +4 -0
  1002. package/neural-interface/public/shared/styleguide/sg-color-client.js +388 -0
  1003. package/neural-interface/public/shared/styleguide/sg-colors.js +148 -0
  1004. package/neural-interface/public/shared/styleguide/sg-components.js +35 -0
  1005. package/neural-interface/public/shared/styleguide/sg-history.js +41 -0
  1006. package/neural-interface/public/shared/styleguide/sg-icons-logo.js +38 -0
  1007. package/neural-interface/public/shared/styleguide/sg-imagery.js +4 -0
  1008. package/neural-interface/public/shared/styleguide/sg-import-export.js +47 -0
  1009. package/neural-interface/public/shared/styleguide/sg-kit.js +281 -0
  1010. package/neural-interface/public/shared/styleguide/sg-labels.js +318 -0
  1011. package/neural-interface/public/shared/styleguide/sg-layout.js +4 -0
  1012. package/neural-interface/public/shared/styleguide/sg-motion.js +5 -0
  1013. package/neural-interface/public/shared/styleguide/sg-panel.js +229 -0
  1014. package/neural-interface/public/shared/styleguide/sg-preview.js +138 -0
  1015. package/neural-interface/public/shared/styleguide/sg-rules.js +9 -0
  1016. package/neural-interface/public/shared/styleguide/sg-shape.js +24 -0
  1017. package/neural-interface/public/shared/styleguide/sg-state.js +132 -0
  1018. package/neural-interface/public/shared/styleguide/sg-typography.js +124 -0
  1019. package/neural-interface/public/shared/styles.css +7883 -1155
  1020. package/neural-interface/public/shared/synabun-mascot.js +1625 -0
  1021. package/neural-interface/public/shared/synabun-ticker.js +376 -0
  1022. package/neural-interface/public/shared/term-renderer.js +343 -0
  1023. package/neural-interface/public/shared/ui-assistant-panel.js +10 -0
  1024. package/neural-interface/public/shared/ui-assistant.js +77 -0
  1025. package/neural-interface/public/shared/ui-automation-studio.js +5105 -3573
  1026. package/neural-interface/public/shared/ui-claude-panel.js +11685 -6333
  1027. package/neural-interface/public/shared/ui-codex-panel.js +12 -0
  1028. package/neural-interface/public/shared/ui-cost-widget.js +55 -34
  1029. package/neural-interface/public/shared/ui-detail.js +77 -14
  1030. package/neural-interface/public/shared/ui-explorer.js +360 -181
  1031. package/neural-interface/public/shared/ui-file-explorer.js +485 -107
  1032. package/neural-interface/public/shared/ui-help.js +2 -2
  1033. package/neural-interface/public/shared/ui-image-gallery.js +45 -21
  1034. package/neural-interface/public/shared/ui-judgments.js +1346 -0
  1035. package/neural-interface/public/shared/ui-keybinds.js +3 -2
  1036. package/neural-interface/public/shared/ui-link.js +105 -51
  1037. package/neural-interface/public/shared/ui-loading.js +4 -4
  1038. package/neural-interface/public/shared/ui-memory-maintenance.js +111 -0
  1039. package/neural-interface/public/shared/ui-menubar.js +89 -4
  1040. package/neural-interface/public/shared/ui-native-loop-router-state.js +94 -0
  1041. package/neural-interface/public/shared/ui-native-loop-router.js +493 -0
  1042. package/neural-interface/public/shared/ui-native-window-id.js +7 -0
  1043. package/neural-interface/public/shared/ui-navbar.js +357 -222
  1044. package/neural-interface/public/shared/ui-notifications.js +58 -12
  1045. package/neural-interface/public/shared/ui-opencode-panel-v2.js +17 -0
  1046. package/neural-interface/public/shared/ui-panels.js +15 -7
  1047. package/neural-interface/public/shared/ui-resume.js +823 -653
  1048. package/neural-interface/public/shared/ui-schedule-queue.js +172 -0
  1049. package/neural-interface/public/shared/ui-schedules-studio.js +1882 -0
  1050. package/neural-interface/public/shared/ui-scroll-follow.js +194 -0
  1051. package/neural-interface/public/shared/ui-sessions.js +789 -34
  1052. package/neural-interface/public/shared/ui-settings.js +5793 -2190
  1053. package/neural-interface/public/shared/ui-sidepanel-layout.js +109 -0
  1054. package/neural-interface/public/shared/ui-sidepanel-runtime.js +19 -0
  1055. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +40 -0
  1056. package/neural-interface/public/shared/ui-sidepanel-sessions.js +221 -0
  1057. package/neural-interface/public/shared/ui-sidepanel-state.js +131 -0
  1058. package/neural-interface/public/shared/ui-sidepanel-tray.js +547 -0
  1059. package/neural-interface/public/shared/ui-sidepanel-windows.js +387 -0
  1060. package/neural-interface/public/shared/ui-skills.js +18 -32
  1061. package/neural-interface/public/shared/ui-styleguide.js +35 -0
  1062. package/neural-interface/public/shared/ui-sync.js +87 -0
  1063. package/neural-interface/public/shared/ui-terminal.js +7877 -6385
  1064. package/neural-interface/public/shared/ui-tool-updates.js +292 -0
  1065. package/neural-interface/public/shared/ui-tooltip.js +156 -15
  1066. package/neural-interface/public/shared/ui-tutorial-draw.js +119 -683
  1067. package/neural-interface/public/shared/ui-tutorial-layout.js +135 -0
  1068. package/neural-interface/public/shared/ui-tutorial-steps.js +59 -2209
  1069. package/neural-interface/public/shared/ui-tutorial.css +102 -0
  1070. package/neural-interface/public/shared/ui-tutorial.js +557 -1076
  1071. package/neural-interface/public/shared/ui-update.js +420 -68
  1072. package/neural-interface/public/shared/ui-whatsapp.js +941 -0
  1073. package/neural-interface/public/shared/ui-whiteboard.js +1076 -233
  1074. package/neural-interface/public/shared/ui-workspaces.js +2 -1
  1075. package/neural-interface/public/shared/utils.js +58 -0
  1076. package/neural-interface/public/shared/vterm-buffer.js +15 -5
  1077. package/neural-interface/public/shared/whatsapp/wa-phone.js +65 -0
  1078. package/neural-interface/public/shared/whatsapp/wa-view.js +411 -0
  1079. package/neural-interface/public/sidepanel-session.html +18 -0
  1080. package/neural-interface/public/sw.js +8 -2
  1081. package/neural-interface/public/synabun.png +0 -0
  1082. package/neural-interface/public/variant/2d/graph.js +1707 -1635
  1083. package/neural-interface/public/variant/2d/lasso.js +2 -1
  1084. package/neural-interface/public/variant/2d/layout.js +595 -594
  1085. package/neural-interface/public/variant/2d/main.js +556 -521
  1086. package/neural-interface/public/variant/2d/settings-gfx.js +18 -24
  1087. package/neural-interface/public/variant/3d/main.js +516 -500
  1088. package/neural-interface/public/variant/3d/map-controls.js +144 -0
  1089. package/neural-interface/public/variant/3d/map-data.js +251 -0
  1090. package/neural-interface/public/variant/3d/map-labels.js +241 -0
  1091. package/neural-interface/public/variant/3d/map-pick.js +90 -0
  1092. package/neural-interface/public/variant/3d/map-renderer.js +521 -0
  1093. package/neural-interface/public/variant/3d/map-shaders.js +158 -0
  1094. package/neural-interface/public/variant/3d/map-view.js +618 -0
  1095. package/neural-interface/public/vendor/three/manifest.json +3 -0
  1096. package/neural-interface/public/vendor/three/three-0.169.0.min.js +3844 -0
  1097. package/neural-interface/public/vendor/xterm/manifest.json +3 -0
  1098. package/neural-interface/public/vendor/xterm/xterm-6.0.0.css +285 -0
  1099. package/neural-interface/public/vendor/xterm/xterm-6.0.0.min.js +192 -0
  1100. package/neural-interface/scripts/build-vendor.mjs +64 -0
  1101. package/neural-interface/scripts/codex-protocol-fixture.mjs +83 -0
  1102. package/neural-interface/scripts/rebuild-pty.js +37 -23
  1103. package/neural-interface/scripts/vendor-three-entry.js +24 -0
  1104. package/neural-interface/scripts/vendor-xterm-entry.js +8 -0
  1105. package/neural-interface/server.js +33948 -15000
  1106. package/neural-interface/skins/default/skin.css +90 -0
  1107. package/neural-interface/skins/default/skin.json +8 -0
  1108. package/neural-interface/templates/rulesets/README.md +9 -0
  1109. package/neural-interface/templates/rulesets/claude.md +3 -0
  1110. package/neural-interface/templates/rulesets/codex.md +2 -0
  1111. package/neural-interface/templates/rulesets/coexistence.md +6 -0
  1112. package/neural-interface/templates/rulesets/core.md +26 -0
  1113. package/neural-interface/templates/rulesets/cursor.md +2 -0
  1114. package/neural-interface/templates/rulesets/gemini.md +2 -0
  1115. package/neural-interface/templates/rulesets/legacy-hashes.json +227 -0
  1116. package/neural-interface/templates/rulesets/manifest.json +12 -0
  1117. package/neural-interface/templates/rulesets/opencode.md +2 -0
  1118. package/package.json +119 -53
  1119. package/postinstall.js +125 -26
  1120. package/preuninstall.js +187 -0
  1121. package/scripts/audit-claude-hook-usage.mjs +12 -0
  1122. package/scripts/audit-memory-duplicates.mjs +44 -0
  1123. package/scripts/measure-claude-hook-overhead.mjs +77 -0
  1124. package/scripts/recover-user-config.mjs +254 -0
  1125. package/scripts/restore-data-home-from-backup.mjs +239 -0
  1126. package/setup.js +804 -260
  1127. package/skills/leonardo/SKILL.md +19 -10
  1128. package/skills/leonardo/modules/image-prompter.md +18 -12
  1129. package/skills/leonardo/modules/video-prompter.md +19 -13
  1130. package/skills/synabun/SKILL.md +209 -185
  1131. package/skills/synabun/icon.png +0 -0
  1132. package/skills/synabun/modules/audit.md +380 -374
  1133. package/skills/synabun/modules/changelog.md +15 -6
  1134. package/skills/synabun/modules/idea.md +148 -144
  1135. package/skills/synabun/modules/memorize.md +13 -4
  1136. package/skills/synabun/modules/schedule.md +198 -0
  1137. package/skills/synabun/synabunicon.png +0 -0
  1138. package/updater.cmd +31 -0
  1139. package/updater.mjs +382 -0
  1140. package/updater.sh +29 -0
  1141. package/hooks/claude-code/test-user-learning.mjs +0 -531
  1142. package/neural-interface/public/claude-chat.css +0 -878
  1143. package/neural-interface/public/claude-chat.html +0 -92
  1144. package/neural-interface/public/claude-chat.js +0 -1168
  1145. package/neural-interface/public/index-legacy.html +0 -14677
  1146. package/neural-interface/public/index2d-legacy.html +0 -8193
  1147. package/neural-interface/public/shared/html-term-renderer.js +0 -1022
  1148. package/neural-interface/public/variant/3d/background.js +0 -884
  1149. package/neural-interface/public/variant/3d/camera.js +0 -661
  1150. package/neural-interface/public/variant/3d/gfx.js +0 -116
  1151. package/neural-interface/public/variant/3d/graph.js +0 -2399
  1152. package/neural-interface/public/variant/3d/settings-gfx.js +0 -228
  1153. package/neural-interface/templates/CLAUDE-template.md +0 -211
@@ -1,1117 +1,598 @@
1
- // ═══════════════════════════════════════════
2
- // TUTORIAL RUNTIME — Animated onboarding system
3
- // ═══════════════════════════════════════════
4
- //
5
- // Orchestrates the tutorial experience. Two rendering modes:
6
- //
7
- // 1. WHITEBOARD MODE (whiteboardMode: true) — renders hand-drawn animated
8
- // elements directly on the whiteboard in focus mode. No modals, no overlays.
9
- // Steps use a render() function for full control.
10
- //
11
- // 2. OVERLAY MODE (legacy) — renders an SVG overlay + card panel on top of
12
- // the app. Used for non-whiteboard steps or when restarting from ? button.
13
- //
14
- // Drawing is delegated to ui-tutorial-draw.js.
15
- // Step content comes from ui-tutorial-steps.js.
16
-
1
+ // A reversible, viewport-based tour shared by both variants. It annotates the
2
+ // user's current view: no config writes, forced focus mode or session creation.
3
+ // What it changes to show a step (an open menu, the Assistant panel) it puts back.
17
4
  import { storage, flushStorage } from './storage.js';
18
- import { emit, on } from './state.js';
5
+ import { state, emit, on } from './state.js';
19
6
  import { KEYS } from './constants.js';
20
- import { registerMenuItem, registerHelpSection } from './registry.js';
21
- import { loadIfaceConfig, saveIfaceConfig, applyIfaceConfig } from './ui-settings.js';
22
- import { TUTORIAL_STEPS } from './ui-tutorial-steps.js';
23
- import {
24
- createAnimatedArrow,
25
- createWobblyCircle,
26
- createHandDrawnUnderline,
27
- typewriterText,
28
- handwrittenLabel,
29
- createDoodle,
30
- createSpotlight,
31
- resolveTargetRect,
32
- resolveAnchorPoint,
33
- resolveRelativePoint,
34
- AnimationSequencer,
35
- } from './ui-tutorial-draw.js';
36
-
37
- const SVG_NS = 'http://www.w3.org/2000/svg';
38
-
39
- // ── Internal state ─────────────────────────
40
- let _steps = [];
41
- let _currentStep = -1;
42
- let _active = false;
43
- let _sequencer = null;
44
- let _resizeTimer = null;
45
- let _keyHandler = null;
46
-
47
- // Overlay mode state (legacy)
48
- let _spotlight = null;
49
- let _overlayEl = null;
50
- let _cardEl = null;
51
- let _pulseEl = null;
52
- let _annotationGroup = null;
53
- let _advanceCleanup = null;
54
- let _domAnnotationLayer = null;
55
-
56
- // Whiteboard mode state
57
- let _wbTutorialSvg = null;
58
- let _wbTutorialDom = null;
59
- let _isFocusModeForced = false;
60
- let _originalVizEnabled = true;
61
- let _isSkipAnimating = false;
62
- let _clickInterceptor = null;
63
- let _adhdMessageTimer = null;
64
-
65
-
66
- // ═══════════════════════════════════════════
67
- // INITIALIZATION
68
- // ═══════════════════════════════════════════
69
-
70
- export function initTutorial() {
71
- _steps = TUTORIAL_STEPS;
72
- if (!_steps || _steps.length === 0) return;
73
-
74
- // Register menu item to restart
75
- registerMenuItem({
76
- menu: 'Help',
77
- order: 50,
78
- type: 'item',
79
- id: 'restart-tutorial',
80
- label: 'Restart Tutorial',
81
- init(el) { el.addEventListener('click', () => startTutorial(true)); },
82
- });
83
-
84
- // Register help section
85
- registerHelpSection({
86
- order: 95,
87
- html: `<div class="help-section">
88
- <div class="help-section-title">Tutorial</div>
89
- <div class="help-row"><span class="help-desc">Restart the guided tour from Help &rarr; Restart Tutorial</span></div>
90
- </div>`,
91
- });
92
-
93
- // Auto-start only on true first visit (never seen tutorial at all)
94
- const completed = storage.getItem(KEYS.TUTORIAL_COMPLETED);
95
- const skipped = storage.getItem(KEYS.TUTORIAL_SKIPPED);
96
- const started = storage.getItem(KEYS.TUTORIAL_STARTED);
97
-
98
- if (!completed && !skipped && !started) {
99
- // Force focus mode BEFORE boot() reads the config
100
- _forceFocusForTutorial();
101
-
102
- on('data-loaded', () => {
103
- setTimeout(() => {
104
- if (!_active) startTutorial(false);
105
- }, 500);
106
- });
7
+ import { t } from './i18n.js';
8
+ import { registerHelpSection, getVariant } from './registry.js';
9
+ import { TUTORIAL_STEPS, FEATURE_STEPS, SKIP_HINT, CHAPTERS, buildExplorePrompt, resumeIndex } from './ui-tutorial-steps.js';
10
+ import { CLI_PROFILES, ensureModelsForProfile, modelSelectorValue, formatModelOptionLabel } from './agent-runtime-options.js';
11
+ import { isAssistantPanelOpen, toggleAssistantPanel, assistantPanelPeekable } from './assistant/asst-sidepanel.js';
12
+ import { createOutline, createAnimatedArrow, createHandDrawnUnderline, createDoodle } from './ui-tutorial-draw.js';
13
+ import { visibleRect, unionRect, outlineShape, outlineRect, placeNote, arrowPoints } from './ui-tutorial-layout.js';
14
+
15
+ const NS = 'http://www.w3.org/2000/svg';
16
+ const INK = '#6da4ff'; // target outline, arrow, underline (Style Guide dark primary)
17
+ const CHALK = 'rgba(240, 243, 247, 0.62)'; // the note's own outline
18
+ const DRAW = 250; // one stroke (Style Guide motion "normal")
19
+ const ERASE = 120; // the previous step's strokes fading out
20
+ const SETTLE_MAX = 600; // longest wait for an opening menu or panel to stop moving
21
+ const GUARDED = ['pointerdown', 'pointerup', 'mousedown', 'mouseup', 'click', 'dblclick', 'contextmenu',
22
+ 'touchstart', 'dragstart', 'pointerover', 'mouseover', 'mouseenter', 'mousemove'];
23
+ // Chrome the note leaves visible when there is free space.
24
+ const KEEP_CLEAR = ['#title-bar', '#topright-controls', '#term-minimized-tray', '#wb-toolbar'];
25
+ const PEER_PANEL_BUTTONS = ['#topright-claude-panel-btn', '#topright-codex-panel-btn', '#topright-opencode-panel-btn'];
26
+ // Names the copy mentions, read off the control on screen so the text matches it
27
+ // in every locale; the i18n key covers a control that is not in the DOM.
28
+ const NAMES = {
29
+ explorer: ['#topright-memory-explorer-btn', 'tutorial.names.explorer'],
30
+ focus: ['#titlebar-viz-toggle', 'tooltip.toggleViz'],
31
+ apps: ['[data-menu="apps"] > .menubar-label', 'nav.apps'],
32
+ browser: ['#menu-terminal-browser', 'menu.apps.browser'],
33
+ studio: ['#menu-open-automation-studio', 'menu.automations.studio'],
34
+ schedules: ['#menu-automations-schedules', 'tutorial.names.schedules'],
35
+ keybinds: ['#topright-keybinds-btn', 'tutorial.names.keybinds'],
36
+ settings: ['#menubar-settings-btn', 'nav.settings'],
37
+ projects: [null, 'settings.redesign.nav.projects.label'],
38
+ computer: [null, 'assistant.computer.toggle'],
39
+ more: [null, 'assistant.toolbar.more'],
40
+ budget: [null, 'assistant.budget.title'],
41
+ };
42
+ const WELCOME = TUTORIAL_STEPS.findIndex(s => s.id === 'welcome');
43
+
44
+ let active = false, initialized = false, index = WELCOME, firstRun = false, skipHint = false, resumed = false;
45
+ let svg, dom, note, ui, observer, targetObserver, previousFocus, nextButton;
46
+ let inks = {}; // the strokes on screen, by part: { g, key }
47
+ let menuState = [], panelPeek = null, passthrough = false, placed = false, lastBox = null;
48
+ let onScreen = null; // the step whose text is in the note: the next one is drawn only once its target holds still
49
+ let timers = new Set(), generation = 0, resizeFrame = 0, stepAbort = null;
50
+ let offLoaded = null, autoTimer = null, lastGeometry = '', beforeAdvance = null, onPrimary = null, onLater = null, ready = null;
51
+
52
+ const reduced = () => matchMedia('(prefers-reduced-motion: reduce)').matches;
53
+ const tr = (key, params) => t(`tutorial.${key}`, params);
54
+ const node = (tag, cls, text) => {
55
+ const el = document.createElement(tag);
56
+ if (cls) el.className = cls;
57
+ if (text != null) el.textContent = text;
58
+ return el;
59
+ };
60
+ const currentStep = () => (skipHint ? SKIP_HINT : TUTORIAL_STEPS[index]);
61
+
62
+ function later(fn, ms) {
63
+ const id = setTimeout(() => { timers.delete(id); fn(); }, ms);
64
+ timers.add(id);
65
+ return id;
66
+ }
67
+ function clearStep() {
68
+ generation++;
69
+ for (const id of timers) clearTimeout(id);
70
+ timers.clear();
71
+ stepAbort?.abort(); stepAbort = null;
72
+ }
73
+
74
+ // ── What the copy and the annotations read from the live UI ──
75
+
76
+ function names() {
77
+ const out = {};
78
+ for (const [name, [selector, key]] of Object.entries(NAMES)) {
79
+ const el = selector && document.querySelector(selector);
80
+ const label = el && (el.querySelector('.menu-text')?.textContent || el.dataset.tooltip || el.textContent);
81
+ // A tooltip may end in its shortcut: "Focus Mode (V)".
82
+ out[name] = label?.replace(/\s*\([^)]*\)\s*$/, '').trim() || t(key);
83
+ }
84
+ out.menu = document.querySelector('[data-menu="graph"] > .menubar-label')?.textContent.trim()
85
+ || t(getVariant() === '2d' ? 'nav.graph' : 'nav.map');
86
+ out.view = out.menu.toLocaleLowerCase();
87
+ return out;
88
+ }
89
+ // A dropdown the tour opened is still fading in when its item is first measured.
90
+ const shown = (el) => !el.checkVisibility
91
+ || el.checkVisibility({ checkOpacity: !el.closest('.menubar-item.open, #assistant-panel.open'), checkVisibilityCSS: true });
92
+ function targetRect(selector, lastSelector) {
93
+ for (const el of document.querySelectorAll(selector)) {
94
+ if (!shown(el)) continue;
95
+ const last = lastSelector && document.querySelector(lastSelector);
96
+ const rect = unionRect([el.getBoundingClientRect(), last && shown(last) ? last.getBoundingClientRect() : null]);
97
+ if (visibleRect(rect, innerWidth, innerHeight)) return rect;
107
98
  }
99
+ return null;
108
100
  }
109
-
110
-
111
- // ═══════════════════════════════════════════
112
- // FOCUS MODE FORCING
113
- // ═══════════════════════════════════════════
114
-
115
- function _forceFocusForTutorial() {
116
- const cfg = loadIfaceConfig();
117
- _originalVizEnabled = cfg.visualizationEnabled !== false;
118
- if (cfg.visualizationEnabled !== false) {
119
- cfg.visualizationEnabled = false;
120
- saveIfaceConfig(cfg);
121
- _isFocusModeForced = true;
101
+ // The first alternative on screen. A hidden toolbar (or a guest's missing control) leaves `missing`.
102
+ function resolveStep(step) {
103
+ const targets = step.targets || [];
104
+ for (let i = 0; i < targets.length; i++) {
105
+ const [selector, copy = 'body', lastSelector] = targets[i];
106
+ const rect = targetRect(selector, lastSelector);
107
+ if (rect) return { rect, alternative: i, copy: i === 0 && step.copy?.[getVariant()] || copy, missing: false };
122
108
  }
109
+ return { rect: null, alternative: -1, copy: step.copy?.[getVariant()] || 'body', missing: targets.length > 0 };
123
110
  }
124
111
 
125
- function _ensureFocusMode() {
126
- const staticBg = document.getElementById('static-bg');
127
- if (!staticBg?.classList.contains('visible')) {
128
- document.getElementById('titlebar-viz-toggle')?.click();
129
- }
130
- }
112
+ // ── What the tour changes to show a step, and puts back ──
131
113
 
132
- function _restoreFocusMode() {
133
- if (_isFocusModeForced) {
134
- const cfg = loadIfaceConfig();
135
- cfg.visualizationEnabled = _originalVizEnabled;
136
- saveIfaceConfig(cfg);
137
- applyIfaceConfig(cfg);
138
- _isFocusModeForced = false;
114
+ function showStage(step) {
115
+ for (const [el, open] of menuState) {
116
+ if (el.isConnected) el.classList.toggle('open', step.menu ? el.dataset.menu === step.menu : open);
139
117
  }
118
+ if (step.panel !== 'assistant') { hidePanelPeek(); return; }
119
+ // With no session tab, opening the Assistant starts a session: its button is annotated instead.
120
+ if (panelPeek || isAssistantPanelOpen() || !assistantPanelPeekable()) return;
121
+ panelPeek = {
122
+ peers: PEER_PANEL_BUTTONS.map(s => document.querySelector(s)).filter(b => b?.classList.contains('active')),
123
+ lastActivePanel: state.lastActivePanel, lastActiveSidepanel: state.lastActiveSidepanel,
124
+ };
125
+ toggleAssistantPanel();
140
126
  }
141
-
142
-
143
- // ═══════════════════════════════════════════
144
- // WHITEBOARD LAYER MANAGEMENT
145
- // ═══════════════════════════════════════════
146
-
147
- function _createWhiteboardLayers() {
148
- if (_wbTutorialSvg) return;
149
-
150
- // Append to document.body with z-index above the titlebar (50000)
151
- // so tutorial annotations render above dropdowns and navbar elements.
152
- // Coordinates are viewport-based, so placement is identical.
153
-
154
- // SVG layer for hand-drawn elements
155
- _wbTutorialSvg = document.createElementNS(SVG_NS, 'svg');
156
- _wbTutorialSvg.id = 'wb-tutorial';
157
- _wbTutorialSvg.style.cssText = 'position:fixed;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible;z-index:60000;';
158
- document.body.appendChild(_wbTutorialSvg);
159
-
160
- // DOM layer for clickable interactive elements
161
- _wbTutorialDom = document.createElement('div');
162
- _wbTutorialDom.id = 'wb-tutorial-dom';
163
- _wbTutorialDom.style.cssText = 'position:fixed;inset:0;pointer-events:none;z-index:60001;';
164
- document.body.appendChild(_wbTutorialDom);
165
- }
166
-
167
- function _destroyWhiteboardLayers() {
168
- if (_wbTutorialSvg) { _wbTutorialSvg.remove(); _wbTutorialSvg = null; }
169
- if (_wbTutorialDom) { _wbTutorialDom.remove(); _wbTutorialDom = null; }
170
- }
171
-
172
-
173
- // ═══════════════════════════════════════════
174
- // UI HELPERS
175
- // ═══════════════════════════════════════════
176
-
177
- function _hideStaticBgLogo(hide) {
178
- const logo = document.querySelector('#static-bg .static-bg-logo');
179
- const breathe = document.querySelector('#static-bg .focus-breathe');
180
- if (logo) logo.classList.toggle('tutorial-hidden', hide);
181
- if (breathe) breathe.classList.toggle('tutorial-hidden', hide);
182
- }
183
-
184
- function _hideWhiteboardToolbar(hide) {
185
- const toolbar = document.getElementById('wb-toolbar');
186
- if (toolbar) toolbar.classList.toggle('tutorial-hidden', hide);
127
+ function hidePanelPeek() {
128
+ if (!panelPeek) return;
129
+ const peek = panelPeek; panelPeek = null;
130
+ if (isAssistantPanelOpen()) toggleAssistantPanel();
131
+ // Showing the Assistant hid the docked panel that was open: bring it back.
132
+ passthrough = true;
133
+ for (const button of peek.peers) if (!button.classList.contains('active')) button.click();
134
+ passthrough = false;
135
+ state.lastActivePanel = peek.lastActivePanel; state.lastActiveSidepanel = peek.lastActiveSidepanel;
187
136
  }
188
-
189
- function _hideTopControls(hide) {
190
- const top = document.getElementById('topright-controls');
191
- if (top) top.classList.toggle('tutorial-hidden', hide);
137
+ function restoreStage() {
138
+ for (const [el, open] of menuState) if (el.isConnected) el.classList.toggle('open', open);
139
+ hidePanelPeek();
192
140
  }
193
141
 
194
-
195
- // ═══════════════════════════════════════════
196
- // HAND-DRAWN BUTTON (DOM, Caveat font, clickable)
197
- // ═══════════════════════════════════════════
198
-
199
- function _createHandDrawnButton(container, text, { x, y, color = 'rgba(255,255,255,0.5)', fontSize = 26, onClick }) {
200
- const el = document.createElement('div');
201
- el.className = 'wb-tutorial-btn';
202
- el.textContent = text;
203
- el.style.cssText = `
204
- position: absolute;
205
- left: ${x}px;
206
- top: ${y}px;
207
- transform: translate(-50%, 0);
208
- font-family: 'Caveat', cursive;
209
- font-size: ${fontSize}px;
210
- color: ${color};
211
- pointer-events: auto;
212
- opacity: 0;
213
- `;
214
- container.appendChild(el);
215
-
216
- // Animate in
217
- requestAnimationFrame(() => { el.style.opacity = '1'; });
218
-
219
- // Hover effect
220
- el.addEventListener('mouseenter', () => {
221
- el.style.color = 'rgba(255, 255, 255, 0.85)';
222
- el.style.transform = 'translate(-50%, 0) scale(1.08)';
223
- });
224
- el.addEventListener('mouseleave', () => {
225
- el.style.color = color;
226
- el.style.transform = 'translate(-50%, 0) scale(1)';
227
- });
228
-
229
- el.addEventListener('click', onClick);
230
- return el;
142
+ export function initTutorial() {
143
+ if (initialized) return;
144
+ initialized = true;
145
+ const css = node('link'); css.rel = 'stylesheet'; css.href = '/shared/ui-tutorial.css'; css.id = 'tutorial-styles';
146
+ // The first note is measured with its stylesheet and handwriting font in place.
147
+ ready = Promise.race([
148
+ Promise.all([new Promise(done => { css.onload = css.onerror = done; }),
149
+ document.fonts?.load("700 34px 'Caveat'").catch(() => {}), document.fonts?.load("26px 'Caveat'").catch(() => {})]),
150
+ new Promise(done => setTimeout(done, 1200)),
151
+ ]);
152
+ document.head.append(css);
153
+ const opener = document.querySelector('#titlebar-tutorial-btn');
154
+ if (opener) {
155
+ opener.dataset.tooltip = tr('title');
156
+ opener.setAttribute('aria-label', tr('title'));
157
+ opener.setAttribute('aria-pressed', 'false');
158
+ }
159
+ // No HTML interpolation of translations: help registration accepts static HTML.
160
+ const help = node('div', 'help-section');
161
+ help.append(node('div', 'help-section-title', tr('title')), node('div', 'help-row', tr('helpDescription')));
162
+ registerHelpSection({ order: 95, html: help.outerHTML });
163
+ if (![KEYS.TUTORIAL_COMPLETED, KEYS.TUTORIAL_SKIPPED, KEYS.TUTORIAL_STARTED].some(k => storage.getItem(k))) {
164
+ offLoaded = on('data-loaded', () => {
165
+ offLoaded?.(); offLoaded = null;
166
+ autoTimer = setTimeout(() => { autoTimer = null; if (!active) startTutorial(false); }, 500);
167
+ });
168
+ }
231
169
  }
232
170
 
171
+ export { resumeIndex } from './ui-tutorial-steps.js';
233
172
 
234
- // ═══════════════════════════════════════════
235
- // START / STOP
236
- // ═══════════════════════════════════════════
237
-
238
- export function startTutorial(fromBeginning = false) {
239
- if (_active) destroyTutorial();
240
-
241
- _active = true;
242
- _currentStep = 0;
243
-
244
- // Always start from step 0 — no mid-tutorial resume on refresh
245
- if (fromBeginning) {
246
- storage.removeItem(KEYS.TUTORIAL_COMPLETED);
247
- storage.removeItem(KEYS.TUTORIAL_SKIPPED);
248
- storage.removeItem(KEYS.TUTORIAL_STARTED);
249
- storage.removeItem(KEYS.ONBOARDING_EXPLORE);
250
- storage.removeItem(KEYS.ONBOARDING_CLI);
251
- storage.removeItem(KEYS.ONBOARDING_MODEL);
252
- storage.removeItem(KEYS.ONBOARDING_PROJECT);
253
- }
254
- storage.removeItem(KEYS.TUTORIAL_STEP);
255
-
256
- // Mark that tutorial has been seen — refresh mid-tutorial won't re-trigger
257
- // Flush immediately (bypass 500ms debounce) so the flag survives a quick refresh
173
+ // Navbar calls startTutorial(true): it is a toggle, preserving every choice.
174
+ export function startTutorial(manual = false) {
175
+ if (autoTimer) { clearTimeout(autoTimer); autoTimer = null; }
176
+ offLoaded?.(); offLoaded = null;
177
+ if (active) { destroyTutorial(); return; }
178
+ firstRun = !manual && !storage.getItem(KEYS.TUTORIAL_COMPLETED) && !storage.getItem(KEYS.TUTORIAL_SKIPPED);
179
+ index = resumeIndex(storage.getItem(KEYS.TUTORIAL_STEP), firstRun);
180
+ resumed = index > WELCOME + 1;
181
+ active = true; skipHint = false; placed = false; onScreen = null; lastBox = null; lastGeometry = ''; previousFocus = document.activeElement;
182
+ menuState = [...document.querySelectorAll('.menubar-item')].map(el => [el, el.classList.contains('open')]);
258
183
  storage.setItem(KEYS.TUTORIAL_STARTED, 'true');
259
- flushStorage();
260
-
261
- const step = _steps[_currentStep];
262
-
263
- if (step?.whiteboardMode) {
264
- // Whiteboard-based rendering
265
- _ensureFocusMode();
266
- _hideStaticBgLogo(true);
267
- _hideWhiteboardToolbar(true);
268
- _hideTopControls(true);
269
- _createWhiteboardLayers();
270
- } else {
271
- // Legacy overlay + card rendering
272
- _createOverlay();
273
- _createCard();
274
- }
275
-
276
- _installKeyHandler();
277
- _installClickInterceptor();
278
- _installResizeHandler();
279
-
280
- emit('tutorial:start');
281
- _renderStep(_currentStep);
282
- }
283
-
284
- function skipTutorial() {
285
- storage.setItem(KEYS.TUTORIAL_SKIPPED, 'true');
286
- storage.removeItem(KEYS.TUTORIAL_STEP);
287
- _exitStep(() => {
288
- _restoreFocusMode();
289
- destroyTutorial();
290
- emit('tutorial:skip');
184
+ svg = document.createElementNS(NS, 'svg'); svg.id = 'wb-tutorial'; svg.setAttribute('aria-hidden', 'true');
185
+ dom = node('div'); dom.id = 'wb-tutorial-dom';
186
+ buildNote();
187
+ // Keep showcase menus and the underlying board from handling tour controls.
188
+ for (const event of ['click', 'pointerdown', 'wheel']) dom.addEventListener(event, e => e.stopPropagation());
189
+ document.body.append(dom, svg);
190
+ document.querySelector('#titlebar-tutorial-btn')?.setAttribute('aria-pressed', 'true');
191
+ window.addEventListener('keydown', keyHandler, true);
192
+ for (const event of GUARDED) window.addEventListener(event, guardPointer, true);
193
+ window.addEventListener('wheel', guardWheel, { capture: true, passive: false });
194
+ window.addEventListener('focusin', guardFocus, true);
195
+ window.addEventListener('resize', scheduleLayout);
196
+ window.visualViewport?.addEventListener('resize', scheduleLayout);
197
+ document.addEventListener('transitionend', onSettled, true);
198
+ window.addEventListener('pagehide', destroyTutorial);
199
+ observer = new ResizeObserver(scheduleLayout);
200
+ observer.observe(note);
201
+ targetObserver = new MutationObserver(records => {
202
+ if (records.some(r => !r.target.closest?.('#wb-tutorial, #wb-tutorial-dom'))) scheduleLayout();
291
203
  });
292
- }
293
-
294
- function completeTutorial() {
295
- storage.setItem(KEYS.TUTORIAL_COMPLETED, 'true');
296
- storage.removeItem(KEYS.TUTORIAL_STEP);
297
- _exitStep(() => _animateCompletion());
298
- }
299
-
300
- async function _animateCompletion() {
301
- // ── 1. Fade out tutorial layers ──
302
- if (_wbTutorialSvg) {
303
- _wbTutorialSvg.style.transition = 'opacity 0.6s ease';
304
- _wbTutorialSvg.style.opacity = '0';
305
- }
306
- if (_wbTutorialDom) {
307
- _wbTutorialDom.style.transition = 'opacity 0.6s ease';
308
- _wbTutorialDom.style.opacity = '0';
309
- }
310
-
311
- await new Promise(r => setTimeout(r, 400));
312
-
313
- // ── 2. Reveal logo with scale + fade entrance ──
314
- const logo = document.querySelector('#static-bg .static-bg-logo');
315
- const breathe = document.querySelector('#static-bg .focus-breathe');
316
-
317
- if (logo) {
318
- logo.style.transition = 'none';
319
- logo.style.transform = 'translate(-50%, -50%) scale(0.7)';
320
- logo.style.opacity = '0';
321
- logo.classList.remove('tutorial-hidden');
322
- logo.offsetHeight; // force reflow
323
- logo.style.transition = 'opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1), transform 0.8s cubic-bezier(0.22, 1, 0.36, 1)';
324
- logo.style.opacity = ''; // back to CSS default (0.18)
325
- logo.style.transform = '';
326
- }
327
- if (breathe) {
328
- breathe.style.transition = 'none';
329
- breathe.style.opacity = '0';
330
- breathe.classList.remove('tutorial-hidden');
331
- breathe.offsetHeight;
332
- breathe.style.transition = 'opacity 1.2s ease 0.3s';
333
- breathe.style.opacity = '';
334
- }
335
-
336
- // ── 3. Slide toolbar in from left (staggered) ──
337
- const toolbar = document.getElementById('wb-toolbar');
338
- if (toolbar) {
339
- toolbar.style.transition = 'none';
340
- toolbar.style.transform = 'translateX(-30px)';
341
- toolbar.style.opacity = '0';
342
- toolbar.style.pointerEvents = '';
343
- toolbar.classList.remove('tutorial-hidden');
344
- toolbar.offsetHeight;
345
- toolbar.style.transition = 'opacity 0.5s ease 0.2s, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.2s';
346
- toolbar.style.opacity = '';
347
- toolbar.style.transform = '';
204
+ targetObserver.observe(document.body, { attributes: true, attributeFilter: ['class', 'hidden'], childList: true, subtree: true });
205
+ emit('tutorial:start');
206
+ const token = ++generation;
207
+ (ready || Promise.resolve()).then(() => { if (active && token === generation) renderStep(); });
208
+ }
209
+
210
+ export function destroyTutorial() {
211
+ if (!active) return;
212
+ clearStep(); active = false;
213
+ cancelAnimationFrame(resizeFrame); resizeFrame = 0;
214
+ observer?.disconnect(); observer = null;
215
+ targetObserver?.disconnect(); targetObserver = null;
216
+ svg?.remove(); dom?.remove(); svg = dom = note = ui = nextButton = null; inks = {};
217
+ window.removeEventListener('keydown', keyHandler, true);
218
+ for (const event of GUARDED) window.removeEventListener(event, guardPointer, true);
219
+ window.removeEventListener('wheel', guardWheel, true);
220
+ window.removeEventListener('focusin', guardFocus, true);
221
+ window.removeEventListener('resize', scheduleLayout);
222
+ window.visualViewport?.removeEventListener('resize', scheduleLayout);
223
+ document.removeEventListener('transitionend', onSettled, true);
224
+ window.removeEventListener('pagehide', destroyTutorial);
225
+ restoreStage(); menuState = [];
226
+ document.querySelector('#titlebar-tutorial-btn')?.setAttribute('aria-pressed', 'false');
227
+ if (previousFocus?.isConnected) previousFocus.focus({ preventScroll: true });
228
+ previousFocus = null;
229
+ flushStorage(); emit('tutorial:exit');
230
+ }
231
+
232
+ // ── Input: the tour is modal. Nothing reaches the board, the graph or the panels behind it ──
233
+
234
+ const allowed = (el) => !!el?.closest?.('#wb-tutorial-dom, #titlebar-tutorial-btn');
235
+ function guardPointer(e) {
236
+ if (passthrough || allowed(e.target)) return;
237
+ if (e.cancelable) e.preventDefault();
238
+ e.stopImmediatePropagation();
239
+ }
240
+ function guardWheel(e) { if (!e.target.closest?.('.tour-note')) { e.preventDefault(); e.stopImmediatePropagation(); } }
241
+ // The Assistant panel focuses its composer when it opens: the keyboard stays on the tour.
242
+ function guardFocus(e) { if (!passthrough && !allowed(e.target)) focusDefault(); }
243
+ function focusDefault() {
244
+ const launch = !skipHint && TUTORIAL_STEPS[index].kind === 'launch';
245
+ (nextButton && !nextButton.disabled && !launch ? nextButton : note)?.focus({ preventScroll: true });
246
+ }
247
+ function keyHandler(e) {
248
+ if (!active) return;
249
+ if (e.key === 'Escape') { e.preventDefault(); e.stopImmediatePropagation(); destroyTutorial(); return; }
250
+ if (e.key === 'Tab') {
251
+ const controls = [...dom.querySelectorAll('button:not(:disabled):not([hidden]), select:not(:disabled)')];
252
+ const pos = controls.indexOf(document.activeElement);
253
+ if (pos < 0 || (!e.shiftKey && pos === controls.length - 1) || (e.shiftKey && pos === 0)) {
254
+ e.preventDefault(); (e.shiftKey ? controls.at(-1) : controls[0])?.focus();
255
+ }
256
+ e.stopImmediatePropagation(); return;
348
257
  }
349
-
350
- // ── 4. Slide top controls in from top (staggered) ──
351
- const topControls = document.getElementById('topright-controls');
352
- if (topControls) {
353
- topControls.style.transition = 'none';
354
- topControls.style.transform = 'translateY(-20px)';
355
- topControls.style.opacity = '0';
356
- topControls.classList.remove('tutorial-hidden');
357
- topControls.offsetHeight;
358
- topControls.style.transition = 'opacity 0.5s ease 0.35s, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.35s';
359
- topControls.style.opacity = '';
360
- topControls.style.transform = '';
258
+ if (e.target.matches?.('select')) { e.stopImmediatePropagation(); return; }
259
+ if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
260
+ e.preventDefault(); e.stopImmediatePropagation();
261
+ if (e.key === 'ArrowLeft') back(); else if (!nextButton.disabled) advance();
262
+ return;
361
263
  }
362
-
363
- // ── 5. Wait for all transitions, then clean up ──
364
- await new Promise(r => setTimeout(r, 1000));
365
-
366
- // Clean inline styles
367
- if (logo) { logo.style.transition = ''; logo.style.transform = ''; logo.style.opacity = ''; }
368
- if (breathe) { breathe.style.transition = ''; breathe.style.opacity = ''; }
369
- if (toolbar) { toolbar.style.transition = ''; toolbar.style.transform = ''; toolbar.style.opacity = ''; }
370
- if (topControls) { topControls.style.transition = ''; topControls.style.transform = ''; topControls.style.opacity = ''; }
371
-
372
- _restoreFocusMode();
373
- destroyTutorial();
374
- emit('tutorial:complete');
375
- }
376
-
377
- function destroyTutorial() {
378
- _active = false;
379
- _currentStep = -1;
380
- _isSkipAnimating = false;
381
- if (_sequencer) { _sequencer.cancel(); _sequencer = null; }
382
-
383
- // Overlay mode cleanup
384
- if (_spotlight) { _spotlight.destroy(); _spotlight = null; }
385
- if (_overlayEl) { _overlayEl.remove(); _overlayEl = null; }
386
- if (_cardEl) { _cardEl.remove(); _cardEl = null; }
387
- if (_pulseEl) { _pulseEl.remove(); _pulseEl = null; }
388
- if (_advanceCleanup) { _advanceCleanup(); _advanceCleanup = null; }
389
- if (_domAnnotationLayer) { _domAnnotationLayer.remove(); _domAnnotationLayer = null; }
390
-
391
- // Whiteboard mode cleanup
392
- _destroyWhiteboardLayers();
393
- _hideStaticBgLogo(false);
394
- _hideWhiteboardToolbar(false);
395
- _hideTopControls(false);
396
-
397
- // Close any open menubar dropdowns opened by tutorial
398
- const openMenu = document.querySelector('.menubar-item.open');
399
- if (openMenu) openMenu.classList.remove('open');
400
-
401
- // Handlers
402
- if (_keyHandler) { document.removeEventListener('keydown', _keyHandler, true); _keyHandler = null; }
403
- _removeClickInterceptor();
404
- if (_resizeTimer) { clearTimeout(_resizeTimer); _resizeTimer = null; }
405
- window.removeEventListener('resize', _onResize);
406
- }
407
-
408
-
409
- // ═══════════════════════════════════════════
410
- // STEP NAVIGATION
411
- // ═══════════════════════════════════════════
412
-
413
- function nextStep() {
414
- if (_isSkipAnimating) return;
415
- if (_currentStep >= _steps.length - 1) {
416
- completeTutorial();
264
+ if (e.key === 'Enter' && !e.target.closest?.('button')) {
265
+ e.preventDefault(); e.stopImmediatePropagation();
266
+ if (!nextButton.disabled) advance();
417
267
  return;
418
268
  }
419
- _exitStep(() => {
420
- _currentStep++;
421
- emit('tutorial:step', { index: _currentStep, id: _steps[_currentStep].id });
422
- _renderStep(_currentStep);
423
- });
424
- }
425
-
426
- function prevStep() {
427
- if (_isSkipAnimating) return;
428
- if (_currentStep <= 0) return;
429
- _exitStep(() => {
430
- _currentStep--;
431
- emit('tutorial:step', { index: _currentStep, id: _steps[_currentStep].id });
432
- _renderStep(_currentStep);
433
- });
434
- }
435
-
436
- function goToStep(targetIndex) {
437
- if (_isSkipAnimating) return;
438
- if (targetIndex < 0 || targetIndex >= _steps.length) return;
439
- _exitStep(() => {
440
- _currentStep = targetIndex;
441
- emit('tutorial:step', { index: _currentStep, id: _steps[_currentStep].id });
442
- _renderStep(_currentStep);
443
- });
269
+ // Native button Enter/Space still activate; product shortcuts never leak out.
270
+ e.stopImmediatePropagation();
444
271
  }
445
272
 
273
+ // ── Navigation ──
446
274
 
447
- // ═══════════════════════════════════════════
448
- // STEP RENDERING (ROUTER)
449
- // ═══════════════════════════════════════════
450
-
451
- function _renderStep(index) {
452
- const step = _steps[index];
453
- if (!step) return;
454
-
455
- step.onEnter?.({ nextStep, prevStep, skipTutorial, emit });
456
-
457
- // If step has onEnter, delay render to let CSS transitions settle (panels slide 0.3s)
458
- const renderDelay = step.onEnter ? 380 : 0;
459
-
460
- if (step.whiteboardMode) {
461
- if (renderDelay > 0) {
462
- setTimeout(() => _renderWhiteboardStep(step, index), renderDelay);
463
- } else {
464
- _renderWhiteboardStep(step, index);
465
- }
466
- } else {
467
- // Legacy overlay mode
468
- if (step.focusModeRequired) {
469
- const staticBg = document.getElementById('static-bg');
470
- if (!staticBg?.classList.contains('visible')) {
471
- document.getElementById('titlebar-viz-toggle')?.click();
472
- setTimeout(() => _renderOverlayStep(step, index), 600);
473
- return;
474
- }
475
- }
476
- _renderOverlayStep(step, index);
477
- }
275
+ function go(next) {
276
+ if (!active || next < (firstRun ? 0 : WELCOME) || next >= TUTORIAL_STEPS.length) return;
277
+ index = next; skipHint = false; renderStep();
478
278
  }
479
-
480
-
481
- // ═══════════════════════════════════════════
482
- // WHITEBOARD MODE RENDERING
483
- // ═══════════════════════════════════════════
484
-
485
- function _renderWhiteboardStep(step, index) {
486
- // Clean previous step content
487
- if (_sequencer) { _sequencer.cancel(); _sequencer = null; }
488
- if (_wbTutorialSvg) _wbTutorialSvg.innerHTML = '';
489
- if (_wbTutorialDom) _wbTutorialDom.innerHTML = '';
490
-
491
- if (!step.render) return;
492
-
493
- _sequencer = new AnimationSequencer();
494
- step.render({
495
- svg: _wbTutorialSvg,
496
- dom: _wbTutorialDom,
497
- seq: _sequencer,
498
- vw: window.innerWidth,
499
- vh: window.innerHeight,
500
- nextStep,
501
- prevStep,
502
- goToStep,
503
- skipTutorial,
504
- onSkipWithArrow: _animateSkipArrow,
505
- createButton: _createHandDrawnButton,
506
- });
507
- _sequencer.play();
279
+ function back() {
280
+ if (skipHint) { skipHint = false; renderStep(); return; }
281
+ go(index - 1);
508
282
  }
509
-
510
-
511
- // ═══════════════════════════════════════════
512
- // SKIP ARROW ANIMATION ("I'll be here")
513
- // ═══════════════════════════════════════════
514
-
515
- async function _animateSkipArrow() {
516
- if (_isSkipAnimating) return;
517
- _isSkipAnimating = true;
518
-
519
- // Clear current content
520
- if (_sequencer) { _sequencer.cancel(); _sequencer = null; }
521
- if (_wbTutorialSvg) _wbTutorialSvg.innerHTML = '';
522
- if (_wbTutorialDom) _wbTutorialDom.innerHTML = '';
523
-
524
- // Find the ? button
525
- const tutBtn = document.getElementById('titlebar-tutorial-btn');
526
- const btnRect = tutBtn?.getBoundingClientRect();
527
- if (!btnRect || !_wbTutorialSvg) { _finishSkip(); return; }
528
-
529
- // Arrow tip: below the ? button, clear of the toolbar
530
- const toX = btnRect.left + btnRect.width / 2;
531
- const toY = btnRect.bottom + 16;
532
-
533
- // Arrow start: well below the toolbar so nothing overlaps
534
- const fromX = toX - 50;
535
- const fromY = toY + 120;
536
-
537
- const seq = new AnimationSequencer();
538
- _sequencer = seq;
539
-
540
- // "I'll be here" handwritten text — appears first, then arrow points up from it
541
- seq.add(() => handwrittenLabel(_wbTutorialSvg, "I'll be here", {
542
- x: fromX - 30,
543
- y: fromY + 28,
544
- color: 'rgba(255, 255, 255, 0.45)',
545
- fontSize: 20,
546
- duration: 500,
547
- }), 200);
548
-
549
- // Small curvy arrow from text area up to the ? button
550
- seq.add(() => createAnimatedArrow(_wbTutorialSvg, {
551
- from: { x: fromX, y: fromY },
552
- to: { x: toX, y: toY },
553
- color: 'rgba(255, 255, 255, 0.35)',
554
- wobbleSeed: 'skip-arrow',
555
- duration: 600,
556
- delay: 0,
557
- }), 300);
558
-
559
- // Tiny sparkle near the button
560
- seq.add(() => createDoodle(_wbTutorialSvg, 'sparkle', {
561
- x: toX + 18,
562
- y: toY + 6,
563
- scale: 0.6,
564
- color: 'rgba(255, 255, 255, 0.3)',
565
- duration: 400,
566
- }), 400);
567
-
568
- await seq.play();
569
-
570
- // Hold for 2 seconds so the user can read it
571
- await new Promise(r => setTimeout(r, 2000));
572
- if (!_active) return;
573
-
574
- // ── Graceful exit: fade arrow, fade in logo, slide in toolbar ──
575
-
576
- // 1. Fade out the tutorial drawings
577
- if (_wbTutorialSvg) {
578
- _wbTutorialSvg.style.transition = 'opacity 0.5s ease';
579
- _wbTutorialSvg.style.opacity = '0';
580
- }
581
- if (_wbTutorialDom) {
582
- _wbTutorialDom.style.transition = 'opacity 0.5s ease';
583
- _wbTutorialDom.style.opacity = '0';
283
+ function advance() {
284
+ if (skipHint) { destroyTutorial(); return; }
285
+ const step = TUTORIAL_STEPS[index];
286
+ beforeAdvance?.();
287
+ if (step.kind === 'explore') {
288
+ storage.setItem(KEYS.ONBOARDING_EXPLORE, 'no'); go(WELCOME); return;
584
289
  }
585
-
586
- await new Promise(r => setTimeout(r, 300));
587
- if (!_active) return;
588
-
589
- // 2. Fade in the center logo (remove tutorial-hidden — CSS transition handles fade)
590
- _hideStaticBgLogo(false);
591
-
592
- // 3. Slide toolbar in from left
593
- const toolbar = document.getElementById('wb-toolbar');
594
- if (toolbar) {
595
- toolbar.style.transition = 'none';
596
- toolbar.style.transform = 'translateX(-30px)';
597
- toolbar.style.opacity = '0';
598
- toolbar.style.pointerEvents = '';
599
- toolbar.classList.remove('tutorial-hidden');
600
- toolbar.offsetHeight; // eslint-disable-line no-unused-expressions
601
- toolbar.style.transition = 'opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1)';
602
- toolbar.style.opacity = '';
603
- toolbar.style.transform = '';
290
+ if (step.kind === 'launch') return; // Only the explicit launch button starts work.
291
+ if (index === TUTORIAL_STEPS.length - 1) {
292
+ storage.setItem(KEYS.TUTORIAL_COMPLETED, 'true'); storage.removeItem(KEYS.TUTORIAL_STEP);
293
+ destroyTutorial(); emit('tutorial:complete'); return;
604
294
  }
605
-
606
- // 4. Slide top controls in from top
607
- const topControls = document.getElementById('topright-controls');
608
- if (topControls) {
609
- topControls.style.transition = 'none';
610
- topControls.style.transform = 'translateY(-20px)';
611
- topControls.style.opacity = '0';
612
- topControls.classList.remove('tutorial-hidden');
613
- topControls.offsetHeight; // eslint-disable-line no-unused-expressions
614
- topControls.style.transition = 'opacity 0.5s ease 0.1s, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.1s';
615
- topControls.style.opacity = '';
616
- topControls.style.transform = '';
617
- }
618
-
619
- // Wait for transitions to finish
620
- await new Promise(r => setTimeout(r, 700));
621
- if (!_active) return;
622
-
623
- // Clean up inline styles
624
- if (toolbar) {
625
- toolbar.style.transition = '';
626
- toolbar.style.transform = '';
627
- toolbar.style.opacity = '';
628
- }
629
- if (topControls) {
630
- topControls.style.transition = '';
631
- topControls.style.transform = '';
632
- topControls.style.opacity = '';
633
- }
634
-
635
- _finishSkip();
295
+ go(index + 1);
636
296
  }
637
-
638
- function _finishSkip() {
297
+ function skip() {
639
298
  storage.setItem(KEYS.TUTORIAL_SKIPPED, 'true');
640
- storage.removeItem(KEYS.TUTORIAL_STEP);
641
- _hideStaticBgLogo(false);
642
- _hideWhiteboardToolbar(false);
643
- _hideTopControls(false);
644
- _restoreFocusMode();
645
- destroyTutorial();
646
- emit('tutorial:skip');
647
- }
648
-
649
-
650
- // ═══════════════════════════════════════════
651
- // OVERLAY MODE RENDERING (LEGACY)
652
- // ═══════════════════════════════════════════
653
-
654
- function _createOverlay() {
655
- if (_overlayEl) return;
656
- _overlayEl = document.createElementNS(SVG_NS, 'svg');
657
- _overlayEl.id = 'tutorial-overlay';
658
- _overlayEl.setAttribute('viewBox', `0 0 ${window.innerWidth} ${window.innerHeight}`);
659
- document.body.appendChild(_overlayEl);
660
- }
661
-
662
- function _createCard() {
663
- if (_cardEl) return;
664
- _cardEl = document.createElement('div');
665
- _cardEl.className = 'tutorial-card';
666
- _cardEl.innerHTML = `
667
- <div class="tutorial-title"></div>
668
- <div class="tutorial-body"></div>
669
- <div class="tutorial-nav">
670
- <button class="tutorial-nav-btn tutorial-btn-back">Back</button>
671
- <span class="tutorial-step-counter"></span>
672
- <button class="tutorial-nav-btn primary tutorial-btn-next">Next</button>
673
- </div>
674
- <span class="tutorial-skip">Skip tutorial</span>
675
- `;
676
- document.body.appendChild(_cardEl);
677
- _cardEl.querySelector('.tutorial-btn-next').addEventListener('click', nextStep);
678
- _cardEl.querySelector('.tutorial-btn-back').addEventListener('click', prevStep);
679
- _cardEl.querySelector('.tutorial-skip').addEventListener('click', skipTutorial);
299
+ skipHint = true; renderStep(); emit('tutorial:skip');
300
+ }
301
+
302
+ // ── The note: one element for the whole tour, so nothing blinks between steps ──
303
+
304
+ function button(text, fn, cls = '') {
305
+ const el = node('button', cls, text); el.type = 'button'; el.addEventListener('click', fn); return el;
306
+ }
307
+ function buildNote() {
308
+ note = node('section', 'tour-note tour-snap'); note.tabIndex = -1;
309
+ note.setAttribute('role', 'dialog'); note.setAttribute('aria-modal', 'true');
310
+ note.setAttribute('aria-labelledby', 'tour-heading'); note.setAttribute('aria-describedby', 'tour-copy');
311
+ const progress = node('div', 'tour-progress');
312
+ const dots = node('span', 'tour-dots'); dots.setAttribute('role', 'img');
313
+ for (const chapter of CHAPTERS) { const dot = node('span'); dot.dataset.chapter = chapter; dots.append(dot); }
314
+ ui = {
315
+ label: node('span'), dots,
316
+ restart: button(tr('restart'), () => { resumed = false; go(WELCOME); }, 'tour-link'),
317
+ body: node('div', 'tour-body'),
318
+ prev: button(tr('back'), back),
319
+ skip: button('', () => (onLater || skip)(), 'tour-link tour-skip'),
320
+ };
321
+ nextButton = button('', () => (onPrimary || advance)(), 'primary');
322
+ progress.append(ui.label, ui.restart, dots);
323
+ const nav = node('nav', 'tour-nav'); nav.setAttribute('aria-label', tr('navigation'));
324
+ nav.append(ui.prev, nextButton, ui.skip);
325
+ note.append(progress, ui.body, nav, node('p', 'tour-key-hint', tr('keys')));
326
+ dom.append(note);
327
+ }
328
+ // Handwriting appears word by word; the text itself is ordinary DOM text.
329
+ function write(el, text, start) {
330
+ if (reduced()) { el.textContent = text; return; }
331
+ const words = text.split(' ');
332
+ const pace = Math.min(26, 400 / words.length);
333
+ el.replaceChildren();
334
+ words.forEach((word, i) => {
335
+ const span = node('span', 'tour-word', word);
336
+ span.style.animationDelay = `${Math.round(start + i * pace)}ms`;
337
+ el.append(span);
338
+ if (i < words.length - 1) el.append(' ');
339
+ });
680
340
  }
681
-
682
- function _renderOverlayStep(step, index) {
683
- const targetRect = resolveTargetRect(step.target);
684
-
685
- // Spotlight
686
- if (_spotlight) { _spotlight.destroy(); _spotlight = null; }
687
- if (step.spotlight !== false) {
688
- _spotlight = createSpotlight(_overlayEl, targetRect, {
689
- padding: step.spotlightPadding || 16,
690
- wobbleSeed: step.id + '-spot',
341
+ function renderStep() {
342
+ clearStep();
343
+ const step = currentStep();
344
+ if (!skipHint) storage.setItem(KEYS.TUTORIAL_STEP, step.id);
345
+ flushStorage();
346
+ const show = () => { showStage(step); settle(step, () => { fillNote(step); layout(true); keepFocus(step); }); };
347
+ // Holding an arrow key runs through the steps: only the one it stops on moves the Assistant panel.
348
+ const panelMoves = panelPeek ? step.panel !== 'assistant'
349
+ : step.panel === 'assistant' && !isAssistantPanelOpen() && assistantPanelPeekable();
350
+ if (panelMoves) later(show, 150); else show();
351
+ emit('tutorial:step', { index, id: step.id });
352
+ }
353
+ // A menu or panel the tour just opened is still moving: draw once the target holds still.
354
+ function settle(step, done) {
355
+ const staged = !!step.menu || (step.panel === 'assistant' && isAssistantPanelOpen());
356
+ // Staged, the target is the control inside the menu or panel, not the fallback outside it.
357
+ const inside = step.targets ? step.targets.length - (step.panel ? 1 : 0) : 0;
358
+ const started = performance.now();
359
+ let last = null;
360
+ const tick = () => {
361
+ const found = resolveStep(step);
362
+ const now = found.rect ? [found.alternative, found.rect.left, found.rect.top, found.rect.width, found.rect.height].map(Math.round).join() : '';
363
+ const arrived = !staged || (found.alternative >= 0 && found.alternative < inside);
364
+ if ((now === last && arrived) || performance.now() - started > SETTLE_MAX) { done(); return; }
365
+ last = now; later(tick, 32);
366
+ };
367
+ tick();
368
+ }
369
+ function fillNote(step) {
370
+ onScreen = step; beforeAdvance = onPrimary = onLater = null;
371
+ const found = resolveStep(step);
372
+ const featureIndex = FEATURE_STEPS.indexOf(step);
373
+ const setup = !!step.kind && step.kind !== 'welcome';
374
+ note.dataset.step = step.id;
375
+ ui.label.textContent = setup ? tr('setupProgress', { n: index + 1, total: WELCOME })
376
+ : featureIndex >= 0 ? `${tr(`chapters.${step.chapter}`)} · ${tr('progress', { n: featureIndex + 1, total: FEATURE_STEPS.length })}`
377
+ : tr('title');
378
+ ui.dots.hidden = !step.chapter;
379
+ ui.dots.setAttribute('aria-label', step.chapter ? tr(`chapters.${step.chapter}`) : '');
380
+ for (const dot of ui.dots.children) dot.classList.toggle('current', dot.dataset.chapter === step.chapter);
381
+ ui.restart.hidden = !(resumed && featureIndex > 0);
382
+
383
+ const heading = node('h2'); heading.id = 'tour-heading';
384
+ const copy = node('p', 'tour-copy'); copy.id = 'tour-copy'; copy.dataset.copy = found.copy;
385
+ // After the target's outline and the arrow; at once when there is no target.
386
+ const base = found.rect ? 350 : 100;
387
+ write(heading, tr(`steps.${step.id}.title`), base);
388
+ write(copy, tr(`steps.${step.id}.${found.copy}`, names()), base + 150);
389
+ const unavailable = node('p', 'tour-status tour-unavailable', tr('unavailable')); unavailable.hidden = !found.missing;
390
+ const extra = node('div', 'tour-extra');
391
+ ui.body.replaceChildren(heading, copy, unavailable, extra);
392
+
393
+ ui.prev.disabled = !skipHint && index <= (firstRun ? 0 : WELCOME);
394
+ ui.skip.hidden = skipHint || index === TUTORIAL_STEPS.length - 1;
395
+ // Past the first setup screen the way out of the exploration is "later": the tour itself is skipped from its welcome.
396
+ const postpone = setup && step.kind !== 'explore';
397
+ ui.skip.textContent = postpone ? tr('later') : tr('skip');
398
+ if (postpone) onLater = () => go(WELCOME);
399
+ nextButton.disabled = false;
400
+ nextButton.textContent = skipHint ? tr('close') : step.kind === 'welcome' ? tr('start') : step.kind === 'explore' ? tr('later')
401
+ : index === TUTORIAL_STEPS.length - 1 ? tr('finish') : tr('next');
402
+ if (setup) renderOnboarding(step, extra);
403
+ }
404
+ // Focus stays on the button the user is working with; it moves only when that button is gone.
405
+ function keepFocus(step) {
406
+ const focused = document.activeElement;
407
+ if (!dom.contains(focused) || focused === note || focused.disabled || focused.hidden || (step.kind === 'launch' && focused === nextButton)) focusDefault();
408
+ }
409
+ function scheduleLayout() {
410
+ if (!active || resizeFrame) return;
411
+ resizeFrame = requestAnimationFrame(() => { resizeFrame = 0; layout(false); });
412
+ }
413
+ function onSettled(e) { if (!e.target.closest?.('#wb-tutorial, #wb-tutorial-dom')) scheduleLayout(); }
414
+ function lastLine(el, origin) {
415
+ const range = document.createRange(); range.selectNodeContents(el);
416
+ const rects = [...range.getClientRects()].filter(r => r.width > 0);
417
+ const bottom = Math.max(...rects.map(r => r.bottom));
418
+ const line = unionRect(rects.filter(r => r.bottom > bottom - 8));
419
+ return { left: line.left - origin.left, bottom: line.bottom - origin.top, width: line.width };
420
+ }
421
+ // One part of the drawing (the target's strokes, the note's) is redrawn only when its geometry changed.
422
+ function redraw(part, key, motion, draw) {
423
+ const old = inks[part];
424
+ if (old?.key === key) return;
425
+ if (old) {
426
+ if (motion) { old.g.classList.add('tour-leaving'); setTimeout(() => old.g.remove(), ERASE); } else old.g.remove();
427
+ }
428
+ const g = document.createElementNS(NS, 'g'); svg.append(g);
429
+ inks[part] = { g, key };
430
+ draw(g);
431
+ }
432
+ function layout(animate) {
433
+ // A relayout follows the step on screen; the one being prepared is not drawn early.
434
+ const step = onScreen;
435
+ if (!active || !note || !step) return;
436
+ const found = resolveStep(step);
437
+ // The view changed under an open step (the whiteboard toolbar appeared): its copy follows.
438
+ const copy = ui.body.querySelector('#tour-copy');
439
+ if (copy.dataset.copy !== found.copy) { copy.dataset.copy = found.copy; copy.textContent = tr(`steps.${step.id}.${found.copy}`, names()); }
440
+ ui.body.querySelector('.tour-unavailable').hidden = !found.missing;
441
+
442
+ const rects = (selectors) => selectors.flatMap(s => [...document.querySelectorAll(s)])
443
+ .filter(shown).map(el => el.getBoundingClientRect()).filter(r => r.width > 0 && r.height > 0);
444
+ const avoid = rects(['.menubar-item.open .menubar-dropdown']), keep = rects(KEEP_CLEAR);
445
+ const key = (...values) => values.map(v => Math.round(v)).join(',');
446
+ const flat = (list) => list.flatMap(r => [r.left, r.top, r.width, r.height]);
447
+ // The app redraws itself all the time: nothing the note depends on moved, nothing to do.
448
+ const geometry = key(innerWidth, innerHeight, note.offsetWidth, note.scrollHeight, ...flat(found.rect ? [found.rect] : []), -1, ...flat(avoid), -1, ...flat(keep));
449
+ if (geometry === lastGeometry && !animate) return;
450
+ const moved = geometry !== lastGeometry;
451
+ lastGeometry = geometry;
452
+ note.style.maxHeight = '';
453
+ const box = placeNote(found.rect, innerWidth, innerHeight, note.offsetWidth, note.offsetHeight, { avoid, keep, near: lastBox });
454
+ note.style.maxHeight = `${box.height}px`;
455
+
456
+ const motion = animate && !reduced();
457
+ const glide = motion && placed && moved ? DRAW : 0;
458
+ const stroke = (ms) => (motion ? ms : 0);
459
+ note.classList.toggle('tour-snap', !glide);
460
+ note.style.transform = `translate(${Math.round(box.left)}px, ${Math.round(box.top)}px)`;
461
+ note.classList.add('tour-placed');
462
+ placed = true; lastBox = box;
463
+ svg.setAttribute('viewBox', `0 0 ${innerWidth} ${innerHeight}`);
464
+
465
+ // Order: the target's outline, the arrow, then the note with its text.
466
+ let at = 0, arrowFrom = null;
467
+ if (found.rect) {
468
+ const shape = outlineShape(found.rect);
469
+ const ring = outlineRect(found.rect, innerWidth, innerHeight, shape);
470
+ const arrow = arrowPoints(box, ring, 6);
471
+ arrowFrom = arrow.from;
472
+ redraw('target', key(ring.left, ring.top, ring.width, ring.height, arrow.from.x, arrow.from.y, arrow.to.x, arrow.to.y), motion, (g) => {
473
+ createOutline(g, ring, { shape, color: INK, strokeWidth: 2.5, wobbleSeed: step.id, duration: stroke(DRAW) });
474
+ createAnimatedArrow(g, { ...arrow, color: INK, strokeWidth: 2.5, wobbleSeed: step.id,
475
+ duration: stroke(DRAW), delay: stroke(Math.max(200, glide)) });
476
+ at = stroke(350);
691
477
  });
692
- }
693
-
694
- // Card
695
- _updateCard(step, index, targetRect);
696
-
697
- // Annotations
698
- if (_annotationGroup) _annotationGroup.remove();
699
- _annotationGroup = document.createElementNS(SVG_NS, 'g');
700
- _annotationGroup.classList.add('tutorial-annotations');
701
- _overlayEl.appendChild(_annotationGroup);
702
-
703
- if (_sequencer) _sequencer.cancel();
704
- _sequencer = new AnimationSequencer();
705
- for (const ann of (step.annotations || [])) {
706
- _sequencer.add(() => _renderAnnotation(ann, step, targetRect), ann.delay || 0);
707
- }
708
- _sequencer.play();
709
-
710
- _setupAdvanceTrigger(step, targetRect);
711
- _updatePulseRing(step, targetRect);
712
- }
713
-
714
- function _updateCard(step, index, targetRect) {
715
- _cardEl.querySelector('.tutorial-title').textContent = step.title || '';
716
- _cardEl.querySelector('.tutorial-body').textContent = step.body || '';
717
- _cardEl.querySelector('.tutorial-step-counter').textContent = `${index + 1} of ${_steps.length}`;
718
- _cardEl.querySelector('.tutorial-btn-back').style.display = index === 0 ? 'none' : '';
719
- _cardEl.querySelector('.tutorial-btn-next').textContent = index === _steps.length - 1 ? 'Finish' : 'Next';
720
-
721
- _positionCard(step.cardPosition || 'auto', targetRect);
722
- _cardEl.classList.remove('exit');
723
- requestAnimationFrame(() => { _cardEl.classList.add('visible'); });
724
- }
725
-
726
- function _positionCard(position, targetRect) {
727
- const cardW = 380;
728
- const cardH = _cardEl.offsetHeight || 200;
729
- const margin = 24;
730
- const vw = window.innerWidth;
731
- const vh = window.innerHeight;
732
- let left, top;
733
-
734
- if (position === 'center' || !targetRect) {
735
- left = (vw - cardW) / 2;
736
- top = (vh - cardH) / 2;
737
- } else if (position === 'auto') {
738
- const cx = targetRect.left + targetRect.width / 2;
739
- const cy = targetRect.top + targetRect.height / 2;
740
- left = cx < vw / 2
741
- ? Math.min(targetRect.right + margin + 20, vw - cardW - margin)
742
- : Math.max(targetRect.left - cardW - margin - 20, margin);
743
- top = cy < vh / 2
744
- ? Math.max(targetRect.bottom + margin, margin)
745
- : Math.max(targetRect.top - cardH - margin, margin);
746
- left = Math.max(margin, Math.min(left, vw - cardW - margin));
747
- top = Math.max(margin, Math.min(top, vh - cardH - margin));
748
- } else {
749
- const positions = {
750
- 'top-left': { left: margin, top: margin },
751
- 'top-right': { left: vw - cardW - margin, top: margin },
752
- 'bottom-left': { left: margin, top: vh - cardH - margin },
753
- 'bottom-right': { left: vw - cardW - margin, top: vh - cardH - margin },
754
- 'top-center': { left: (vw - cardW) / 2, top: margin },
755
- 'bottom-center': { left: (vw - cardW) / 2, top: vh - cardH - margin },
756
- };
757
- const pos = positions[position] || positions['top-right'];
758
- left = pos.left;
759
- top = pos.top;
760
- }
761
- _cardEl.style.left = `${left}px`;
762
- _cardEl.style.top = `${top}px`;
763
- }
764
-
765
- function _renderAnnotation(ann, step, targetRect) {
766
- const svg = _annotationGroup;
767
-
768
- switch (ann.type) {
769
- case 'arrow': {
770
- const from = _resolveAnnotationPoint(ann.from, targetRect);
771
- const to = _resolveAnnotationPoint(ann.to, targetRect, step.targetAnchor);
772
- if (!from || !to) return null;
773
- return createAnimatedArrow(svg, {
774
- from, to,
775
- color: ann.color || 'rgba(255,255,255,0.35)',
776
- wobbleSeed: step.id + '-arrow',
777
- duration: ann.duration || 800,
778
- arrowheadSize: ann.arrowheadSize || 14,
779
- });
780
- }
781
- case 'circle': {
782
- const rect = ann.target === 'inherit' ? targetRect : resolveTargetRect(ann.target);
783
- if (!rect) return null;
784
- return createWobblyCircle(svg, rect, {
785
- color: ann.color || 'rgba(255,255,255,0.3)',
786
- padding: ann.padding || 12,
787
- wobbleSeed: step.id + '-circle',
788
- duration: ann.duration || 700,
789
- });
790
- }
791
- case 'underline': {
792
- const rect = ann.target === 'inherit' ? targetRect : resolveTargetRect(ann.target);
793
- if (!rect) return null;
794
- return createHandDrawnUnderline(svg, rect, {
795
- color: ann.color || 'rgba(255,255,255,0.3)',
796
- wobbleSeed: step.id + '-underline',
797
- duration: ann.duration || 500,
798
- });
799
- }
800
- case 'text': {
801
- if (ann.style === 'handwritten') {
802
- const pos = _resolveAnnotationPoint(ann.position, targetRect);
803
- if (!pos) return null;
804
- return handwrittenLabel(svg, ann.text, {
805
- x: pos.x, y: pos.y,
806
- color: ann.color || 'rgba(255,255,255,0.4)',
807
- fontSize: ann.fontSize || 18,
808
- textAnchor: ann.textAnchor,
809
- duration: ann.duration || 400,
810
- });
811
- }
812
- const container = _getOrCreateDomAnnotationLayer();
813
- return typewriterText(container, ann.text, {
814
- charDelay: ann.charDelay || 35,
815
- font: ann.font || 'sans',
816
- color: ann.color || 'rgba(255,255,255,0.6)',
817
- });
818
- }
819
- case 'doodle': {
820
- const pos = _resolveAnnotationPoint(ann.position, targetRect);
821
- if (!pos) return null;
822
- return createDoodle(svg, ann.doodleId, {
823
- x: pos.x, y: pos.y,
824
- scale: ann.scale || 1,
825
- color: ann.color || 'rgba(255,255,255,0.3)',
826
- duration: ann.duration || 600,
827
- });
828
- }
829
- default:
830
- return null;
831
- }
832
- }
833
-
834
- function _resolveAnnotationPoint(value, targetRect, defaultAnchor) {
835
- if (!value) return null;
836
- if (value === 'target') {
837
- if (!targetRect) return null;
838
- return resolveAnchorPoint(targetRect, defaultAnchor || 'center');
839
- }
840
- if (typeof value === 'object' && 'x' in value && 'y' in value) {
841
- if (value.x <= 1 && value.y <= 1 && value.x >= 0 && value.y >= 0) {
842
- return resolveRelativePoint(value);
843
- }
844
- return value;
845
- }
846
- return null;
847
- }
848
-
849
- function _getOrCreateDomAnnotationLayer() {
850
- if (_domAnnotationLayer && _domAnnotationLayer.parentNode) return _domAnnotationLayer;
851
- _domAnnotationLayer = document.createElement('div');
852
- _domAnnotationLayer.style.cssText = 'position:fixed;inset:0;z-index:9998;pointer-events:none;display:flex;align-items:center;justify-content:center;padding:20px;';
853
- document.body.appendChild(_domAnnotationLayer);
854
- return _domAnnotationLayer;
478
+ } else redraw('target', '', motion, () => {});
479
+ // The underline is SVG, the heading is not: natural wrapping, reliable font
480
+ // metrics and semantic copy for screen readers.
481
+ const origin = note.getBoundingClientRect();
482
+ const line = lastLine(ui.body.querySelector('h2'), origin);
483
+ redraw('note', key(box.left, box.top, box.width, box.height, line.left, line.bottom, line.width, arrowFrom?.x || 0), motion, (g) => {
484
+ const edge = { left: box.left - 5, top: box.top - 5, right: box.right + 5, bottom: box.bottom + 5, width: box.width + 10, height: box.height + 10 };
485
+ createOutline(g, edge, { shape: 'box', radius: 18, wobble: 2.4, color: CHALK, strokeWidth: 1.6,
486
+ wobbleSeed: `${step.id}-note`, duration: stroke(DRAW + 100), delay: Math.max(at, glide) });
487
+ createHandDrawnUnderline(g, { left: box.left + line.left, bottom: box.top + line.bottom, width: line.width },
488
+ { color: INK, wobbleSeed: step.id, duration: stroke(200), delay: Math.max(at, glide) + stroke(300), offset: 3 });
489
+ // The flourish sits on the note's top corner, the one the arrow does not leave from.
490
+ const corner = arrowFrom && arrowFrom.x > box.left + box.width / 2 && arrowFrom.y < box.top + 60 ? box.left - 8 : box.right - 22;
491
+ createDoodle(g, step.kind === 'warning' ? 'alert' : 'sparkle', { x: corner, y: Math.max(4, box.top - 20),
492
+ scale: 0.7, color: INK, duration: stroke(200), delay: Math.max(at, glide) + stroke(400) });
493
+ });
855
494
  }
856
495
 
857
- function _setupAdvanceTrigger(step, targetRect) {
858
- if (_advanceCleanup) { _advanceCleanup(); _advanceCleanup = null; }
859
- const advanceOn = step.advanceOn || 'click';
860
-
861
- if (advanceOn === 'click') return;
496
+ // ── First-run setup: the optional project exploration ──
862
497
 
863
- if (advanceOn === 'target-click' && step.target) {
864
- const targetEl = document.querySelector(step.target);
865
- if (targetEl) {
866
- const handler = () => nextStep();
867
- targetEl.addEventListener('click', handler, { once: true });
868
- _advanceCleanup = () => targetEl.removeEventListener('click', handler);
498
+ function renderOnboarding(step, content) {
499
+ const token = generation;
500
+ const fresh = () => active && generation === token && content.isConnected;
501
+ const saveChoice = (key, value) => { storage.setItem(key, value); flushStorage(); };
502
+ const field = (labelText) => {
503
+ const label = node('label', 'tour-field', labelText);
504
+ const select = node('select'); label.append(select); content.append(label); return select;
505
+ };
506
+ const option = (select, label, value) => { const o = node('option', '', label); o.value = value; select.append(o); };
507
+ const status = (text = tr('loading')) => { const el = node('p', 'tour-status', text); el.setAttribute('role', 'status'); content.append(el); return el; };
508
+ const retry = () => content.append(button(tr('retry'), () => renderStep()));
509
+ if (step.kind === 'explore') {
510
+ content.append(button(tr('explore'), () => { saveChoice(KEYS.ONBOARDING_EXPLORE, 'yes'); go(index + 1); }));
511
+ } else if (step.kind === 'cli') {
512
+ const choices = node('div', 'tour-options'); content.append(choices);
513
+ nextButton.disabled = !CLI_PROFILES.some(c => c.id === storage.getItem(KEYS.ONBOARDING_CLI));
514
+ for (const cli of CLI_PROFILES) {
515
+ const choice = button(cli.label, () => {
516
+ if (storage.getItem(KEYS.ONBOARDING_CLI) !== cli.id) storage.removeItem(KEYS.ONBOARDING_MODEL);
517
+ saveChoice(KEYS.ONBOARDING_CLI, cli.id); go(index + 1);
518
+ }, 'tour-choice');
519
+ choice.setAttribute('aria-pressed', String(storage.getItem(KEYS.ONBOARDING_CLI) === cli.id)); choices.append(choice);
869
520
  }
870
- return;
871
- }
872
- if (advanceOn.startsWith('key:')) {
873
- const key = advanceOn.slice(4).toLowerCase();
874
- const handler = (e) => {
875
- if (e.key.toLowerCase() === key) { nextStep(); document.removeEventListener('keydown', handler); }
521
+ } else if (step.kind === 'model') {
522
+ const select = field(tr('model')); select.disabled = true; nextButton.disabled = true;
523
+ const loading = status(); let settled = false;
524
+ const finish = (models) => {
525
+ if (!fresh() || settled) return;
526
+ settled = true; clearTimeout(timeout); timers.delete(timeout);
527
+ option(select, tr('cliDefault'), '');
528
+ for (const m of models) option(select, formatModelOptionLabel(m, { includeService: true }), modelSelectorValue(m));
529
+ select.value = storage.getItem(KEYS.ONBOARDING_MODEL) || '';
530
+ if (select.selectedIndex < 0) select.value = '';
531
+ select.disabled = false; nextButton.disabled = false;
532
+ loading.textContent = models.length ? tr('catalog') : tr('catalogUnavailable');
533
+ select.addEventListener('change', () => saveChoice(KEYS.ONBOARDING_MODEL, select.value));
534
+ beforeAdvance = () => saveChoice(KEYS.ONBOARDING_MODEL, select.value);
535
+ if (!models.length) retry();
876
536
  };
877
- document.addEventListener('keydown', handler);
878
- _advanceCleanup = () => document.removeEventListener('keydown', handler);
879
- return;
880
- }
881
- if (advanceOn.startsWith('auto:')) {
882
- const ms = parseInt(advanceOn.slice(5), 10) || 3000;
883
- const timer = setTimeout(nextStep, ms);
884
- _advanceCleanup = () => clearTimeout(timer);
885
- }
886
- }
887
-
888
- function _updatePulseRing(step, targetRect) {
889
- if (_pulseEl) { _pulseEl.remove(); _pulseEl = null; }
890
- if (step.advanceOn === 'target-click' && targetRect) {
891
- _pulseEl = document.createElement('div');
892
- _pulseEl.className = 'tutorial-pulse-ring';
893
- _pulseEl.style.left = `${targetRect.left - 4}px`;
894
- _pulseEl.style.top = `${targetRect.top - 4}px`;
895
- _pulseEl.style.width = `${targetRect.width + 8}px`;
896
- _pulseEl.style.height = `${targetRect.height + 8}px`;
897
- document.body.appendChild(_pulseEl);
898
- }
899
- }
900
-
901
-
902
- // ═══════════════════════════════════════════
903
- // STEP EXIT
904
- // ═══════════════════════════════════════════
905
-
906
- function _exitStep(callback) {
907
- const step = _steps[_currentStep];
908
- if (step) step.onExit?.({ nextStep, prevStep, skipTutorial, emit });
909
-
910
- if (_sequencer) { _sequencer.cancel(); _sequencer = null; }
911
- if (_advanceCleanup) { _advanceCleanup(); _advanceCleanup = null; }
912
- if (_pulseEl) { _pulseEl.remove(); _pulseEl = null; }
913
-
914
- if (step?.whiteboardMode) {
915
- // Whiteboard mode: just clear the layers
916
- if (_wbTutorialSvg) _wbTutorialSvg.innerHTML = '';
917
- if (_wbTutorialDom) _wbTutorialDom.innerHTML = '';
918
- callback?.();
919
- } else {
920
- // Overlay mode: fade out annotations + card
921
- if (_annotationGroup) {
922
- _annotationGroup.style.transition = 'opacity 0.2s ease';
923
- _annotationGroup.style.opacity = '0';
924
- }
925
- if (_cardEl) {
926
- _cardEl.classList.remove('visible');
927
- _cardEl.classList.add('exit');
928
- }
929
- if (_spotlight) {
930
- _spotlight.fadeOut(() => {
931
- if (_spotlight) { _spotlight.destroy(); _spotlight = null; }
537
+ const timeout = later(() => finish([]), 8000);
538
+ ensureModelsForProfile(storage.getItem(KEYS.ONBOARDING_CLI)).then(m => finish(Array.isArray(m) ? m : [])).catch(() => finish([]));
539
+ } else if (step.kind === 'project') {
540
+ const select = field(tr('project')); select.disabled = true; nextButton.disabled = true;
541
+ const loading = status();
542
+ stepAbort = new AbortController();
543
+ const abort = stepAbort;
544
+ const timeout = later(() => abort.abort(), 8000);
545
+ fetch('/api/terminal/profiles', { signal: abort.signal }).then(r => { if (!r.ok) throw new Error('profiles'); return r.json(); }).then(data => {
546
+ if (!fresh()) return;
547
+ const projects = (data.projects || []).filter(p => p.path);
548
+ const name = (p) => p.label || p.path.split(/[\\/]/).filter(Boolean).pop();
549
+ option(select, tr('chooseProject'), '');
550
+ projects.forEach((p, i) => option(select, name(p), String(i)));
551
+ let prior = null; try { prior = JSON.parse(storage.getItem(KEYS.ONBOARDING_PROJECT) || 'null'); } catch { /* choose again */ }
552
+ const existing = projects.findIndex(p => p.path === prior?.path);
553
+ select.value = existing >= 0 ? String(existing) : '';
554
+ select.disabled = !projects.length; nextButton.disabled = existing < 0;
555
+ loading.textContent = projects.length ? tr('projectHint') : tr('noProjects');
556
+ select.addEventListener('change', () => {
557
+ const project = projects[Number(select.value)];
558
+ nextButton.disabled = select.value === '';
559
+ if (select.value !== '' && project) saveChoice(KEYS.ONBOARDING_PROJECT, JSON.stringify({ path: project.path, label: name(project) }));
932
560
  });
933
- }
934
- if (_domAnnotationLayer) {
935
- _domAnnotationLayer.remove();
936
- _domAnnotationLayer = null;
937
- }
938
- setTimeout(() => {
939
- if (_annotationGroup) { _annotationGroup.remove(); _annotationGroup = null; }
940
- callback?.();
941
- }, 300);
942
- }
943
- }
944
-
945
-
946
- // ═══════════════════════════════════════════
947
- // KEYBOARD HANDLER
948
- // ═══════════════════════════════════════════
949
-
950
- function _installKeyHandler() {
951
- if (_keyHandler) return;
952
- _keyHandler = (e) => {
953
- if (!_active) return;
954
-
955
- const step = _steps[_currentStep];
956
-
957
- // Block V key during whiteboard steps to prevent exiting focus mode
958
- if ((e.key === 'v' || e.key === 'V') && step?.whiteboardMode) {
959
- e.stopPropagation();
960
- e.preventDefault();
961
- return;
962
- }
963
-
964
- if (e.key === 'Escape') {
965
- e.stopPropagation();
966
- if (_isSkipAnimating) return;
967
- if (step?.id === 'welcome' && step?.whiteboardMode) {
968
- _animateSkipArrow();
969
- } else if (_currentStep <= 5) {
970
- skipTutorial();
971
- } else {
972
- prevStep();
973
- }
974
- return;
975
- }
976
-
977
- if (e.key === 'ArrowRight' || e.key === 'Enter' || e.key === ' ') {
978
- e.stopPropagation();
979
- e.preventDefault();
980
- nextStep();
981
- return;
982
- }
983
-
984
- if (e.key === 'ArrowLeft') {
985
- e.stopPropagation();
986
- prevStep();
987
- }
988
- };
989
- document.addEventListener('keydown', _keyHandler, true);
990
- }
991
-
992
-
993
- // ═══════════════════════════════════════════
994
- // TOOLBAR CLICK INTERCEPTOR (ADHD protection)
995
- // ═══════════════════════════════════════════
996
-
997
- const _interceptedBtnIds = [
998
- 'titlebar-viz-toggle',
999
- 'titlebar-fullscreen-btn',
1000
- ];
1001
-
1002
- function _installClickInterceptor() {
1003
- if (_clickInterceptor) return;
1004
- _clickInterceptor = (e) => {
1005
- if (!_active || _isSkipAnimating) return;
1006
- const step = _steps[_currentStep];
1007
- if (!step?.whiteboardMode) return;
1008
-
1009
- // Check if the click target is one of the intercepted buttons or menu items
1010
- const btn = e.target.closest('#titlebar-viz-toggle, #titlebar-fullscreen-btn, #topright-keybinds-btn, .menubar-dropdown .menu-item, .menubar-label');
1011
- if (!btn) return;
1012
-
1013
- e.stopPropagation();
1014
- e.preventDefault();
1015
- _showAdhdMessage();
1016
- };
1017
- document.addEventListener('click', _clickInterceptor, true);
1018
- }
1019
-
1020
- function _removeClickInterceptor() {
1021
- if (_clickInterceptor) {
1022
- document.removeEventListener('click', _clickInterceptor, true);
1023
- _clickInterceptor = null;
1024
- }
1025
- if (_adhdMessageTimer) {
1026
- clearTimeout(_adhdMessageTimer);
1027
- _adhdMessageTimer = null;
561
+ }).catch(() => {
562
+ if (!fresh()) return;
563
+ loading.textContent = tr('projectsUnavailable'); retry();
564
+ }).finally(() => { clearTimeout(timeout); timers.delete(timeout); });
565
+ content.append(button(tr('addProject', names()), async () => {
566
+ // Explicit user action hands off to the existing Projects settings page.
567
+ destroyTutorial(); const { openSettingsModal } = await import('./ui-settings.js');
568
+ await openSettingsModal({ tab: 'projects', expand: ['stg-sec-workspaces'] });
569
+ }));
570
+ } else if (step.kind === 'launch') {
571
+ nextButton.textContent = tr('begin');
572
+ // A second click meant for the previous screen must not start the CLI.
573
+ nextButton.disabled = true; later(() => { nextButton.disabled = false; }, 600);
574
+ const loading = status('');
575
+ let busy = false;
576
+ onPrimary = () => {
577
+ if (busy || !fresh()) return;
578
+ let project = null; try { project = JSON.parse(storage.getItem(KEYS.ONBOARDING_PROJECT) || 'null'); } catch { /* handled below */ }
579
+ const cli = storage.getItem(KEYS.ONBOARDING_CLI);
580
+ if (!project?.path || !CLI_PROFILES.some(c => c.id === cli)) { loading.textContent = tr('selectionMissing'); return; }
581
+ busy = true; nextButton.disabled = true; loading.textContent = tr('launching');
582
+ // The same category slug Settings → Projects gives an exploration.
583
+ const slug = (project.label || project.path.split(/[\\/]/).filter(Boolean).pop() || 'project').toLowerCase().replace(/[^a-z0-9]+/g, '');
584
+ const model = storage.getItem(KEYS.ONBOARDING_MODEL);
585
+ const finish = (err) => {
586
+ if (!fresh()) return;
587
+ clearTimeout(timeout); timers.delete(timeout);
588
+ if (err) { busy = false; nextButton.disabled = false; loading.textContent = tr('launchFailed'); }
589
+ else { firstRun = false; go(WELCOME); } // setup is done: Back from the welcome does not return to it
590
+ };
591
+ const timeout = later(() => finish(new Error('timeout')), 15000);
592
+ try {
593
+ emit('terminal:launch-floating', { profile: cli, cwd: project.path, createOpts: model ? { model } : {},
594
+ initialMessage: buildExplorePrompt(slug), autoSubmit: true, onDone: finish });
595
+ } catch (err) { finish(err); }
596
+ };
1028
597
  }
1029
598
  }
1030
-
1031
- function _showAdhdMessage() {
1032
- if (!_wbTutorialSvg || !_wbTutorialDom) return;
1033
-
1034
- // Cancel the step's sequencer so pending tasks don't re-add elements
1035
- if (_sequencer) { _sequencer.cancel(); _sequencer = null; }
1036
-
1037
- // Save current step content and replace with ADHD message
1038
- const savedSvg = _wbTutorialSvg.innerHTML;
1039
- const savedDom = _wbTutorialDom.innerHTML;
1040
- _wbTutorialSvg.innerHTML = '';
1041
- _wbTutorialDom.innerHTML = '';
1042
-
1043
- if (_adhdMessageTimer) clearTimeout(_adhdMessageTimer);
1044
-
1045
- const seq = new AnimationSequencer();
1046
- const cx = window.innerWidth / 2;
1047
- const cy = window.innerHeight / 2 - 20;
1048
-
1049
- seq.add(() => handwrittenLabel(_wbTutorialSvg, 'Wait bro... gee', {
1050
- x: cx, y: cy - 10,
1051
- textAnchor: 'middle',
1052
- color: 'rgba(255, 255, 255, 0.55)',
1053
- fontSize: 28, duration: 400,
1054
- }), 100);
1055
-
1056
- seq.add(() => handwrittenLabel(_wbTutorialSvg, 'You can click shit later.', {
1057
- x: cx, y: cy + 30,
1058
- textAnchor: 'middle',
1059
- color: 'rgba(255, 255, 255, 0.35)',
1060
- fontSize: 20, duration: 400,
1061
- }), 400);
1062
-
1063
- // OK button to dismiss and return to the step
1064
- seq.add(() => {
1065
- const okEl = _createHandDrawnButton(_wbTutorialDom, 'Ok', {
1066
- x: cx, y: cy + 100, fontSize: 24,
1067
- color: 'rgba(255, 255, 255, 0.45)',
1068
- onClick: () => {
1069
- if (!_wbTutorialSvg || !_wbTutorialDom || !_active) return;
1070
- _wbTutorialSvg.innerHTML = '';
1071
- _wbTutorialDom.innerHTML = '';
1072
- const step = _steps[_currentStep];
1073
- if (step) _renderWhiteboardStep(step, _currentStep);
1074
- },
1075
- });
1076
- return { destroy() { okEl.remove(); } };
1077
- }, 700);
1078
-
1079
- seq.play();
1080
- }
1081
-
1082
-
1083
- // ═══════════════════════════════════════════
1084
- // RESIZE HANDLER
1085
- // ═══════════════════════════════════════════
1086
-
1087
- function _onResize() {
1088
- if (_resizeTimer) clearTimeout(_resizeTimer);
1089
- _resizeTimer = setTimeout(() => {
1090
- if (!_active || _currentStep < 0) return;
1091
-
1092
- const step = _steps[_currentStep];
1093
- if (!step) return;
1094
-
1095
- if (step.whiteboardMode && !_isSkipAnimating) {
1096
- // Re-render the whiteboard step to re-center
1097
- _renderWhiteboardStep(step, _currentStep);
1098
- } else if (!step.whiteboardMode) {
1099
- if (_overlayEl) {
1100
- _overlayEl.setAttribute('viewBox', `0 0 ${window.innerWidth} ${window.innerHeight}`);
1101
- }
1102
- const targetRect = resolveTargetRect(step.target);
1103
- if (_spotlight) _spotlight.update(targetRect);
1104
- if (_cardEl) _positionCard(step.cardPosition || 'auto', targetRect);
1105
- if (_pulseEl && targetRect) {
1106
- _pulseEl.style.left = `${targetRect.left - 4}px`;
1107
- _pulseEl.style.top = `${targetRect.top - 4}px`;
1108
- _pulseEl.style.width = `${targetRect.width + 8}px`;
1109
- _pulseEl.style.height = `${targetRect.height + 8}px`;
1110
- }
1111
- }
1112
- }, 300);
1113
- }
1114
-
1115
- function _installResizeHandler() {
1116
- window.addEventListener('resize', _onResize);
1117
- }