synabun 1.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1163) hide show
  1. package/CHANGELOG.md +205 -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 +136 -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/whatsapp.md +325 -0
  20. package/hooks/claude-code/post-plan.mjs +613 -391
  21. package/hooks/claude-code/post-remember.mjs +246 -122
  22. package/hooks/claude-code/pre-compact.mjs +171 -110
  23. package/hooks/claude-code/pre-task.mjs +133 -0
  24. package/hooks/claude-code/pre-websearch.mjs +15 -4
  25. package/hooks/claude-code/prompt-origin.mjs +94 -0
  26. package/hooks/claude-code/prompt-submit.mjs +1244 -861
  27. package/hooks/claude-code/session-start.mjs +114 -156
  28. package/hooks/claude-code/shared.mjs +1228 -368
  29. package/hooks/claude-code/state.mjs +167 -0
  30. package/hooks/claude-code/stop.mjs +515 -140
  31. package/hooks/claude-code/subagent-start.mjs +154 -0
  32. package/hooks/claude-code/subagent-stop.mjs +102 -0
  33. package/hooks/claude-code/task-gate.mjs +150 -0
  34. package/launcher.mjs +40 -0
  35. package/lib/claude-hooks.js +137 -0
  36. package/lib/claude-usage-audit.js +141 -0
  37. package/lib/client-config-repair.js +145 -0
  38. package/lib/data-home-migration.js +502 -0
  39. package/lib/desktop-pwa.js +206 -0
  40. package/lib/external-tools.js +221 -0
  41. package/lib/first-launch-protection.js +245 -0
  42. package/lib/packaged-runtime.js +110 -0
  43. package/lib/paths.d.ts +21 -0
  44. package/lib/paths.js +103 -0
  45. package/lib/start-launcher.js +1309 -0
  46. package/mcp-server/dist/config.d.ts +22 -0
  47. package/mcp-server/dist/config.d.ts.map +1 -0
  48. package/mcp-server/dist/config.js +109 -0
  49. package/mcp-server/dist/config.js.map +1 -0
  50. package/mcp-server/dist/http.d.ts +30 -0
  51. package/mcp-server/dist/http.d.ts.map +1 -0
  52. package/mcp-server/dist/http.js +276 -0
  53. package/mcp-server/dist/http.js.map +1 -0
  54. package/mcp-server/dist/index.d.ts +48 -0
  55. package/mcp-server/dist/index.d.ts.map +1 -0
  56. package/mcp-server/dist/index.js +538 -0
  57. package/mcp-server/dist/index.js.map +1 -0
  58. package/mcp-server/dist/preload-http.d.ts +3 -0
  59. package/mcp-server/dist/preload-http.d.ts.map +1 -0
  60. package/mcp-server/dist/preload-http.js +28 -0
  61. package/mcp-server/dist/preload-http.js.map +1 -0
  62. package/mcp-server/dist/preload.d.ts +3 -0
  63. package/mcp-server/dist/preload.d.ts.map +1 -0
  64. package/mcp-server/dist/preload.js +32 -0
  65. package/mcp-server/dist/preload.js.map +1 -0
  66. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts +19 -0
  67. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.d.ts.map +1 -0
  68. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js +403 -0
  69. package/mcp-server/dist/scripts/migrate-qdrant-to-sqlite.js.map +1 -0
  70. package/mcp-server/dist/scripts/setup-embeddings.d.ts +3 -0
  71. package/mcp-server/dist/scripts/setup-embeddings.d.ts.map +1 -0
  72. package/mcp-server/dist/scripts/setup-embeddings.js +15 -0
  73. package/mcp-server/dist/scripts/setup-embeddings.js.map +1 -0
  74. package/mcp-server/dist/services/assistant-judgments.d.ts +79 -0
  75. package/mcp-server/dist/services/assistant-judgments.d.ts.map +1 -0
  76. package/mcp-server/dist/services/assistant-judgments.js +128 -0
  77. package/mcp-server/dist/services/assistant-judgments.js.map +1 -0
  78. package/mcp-server/dist/services/browser-assist-gate.d.ts +314 -0
  79. package/mcp-server/dist/services/browser-assist-gate.d.ts.map +1 -0
  80. package/mcp-server/dist/services/browser-assist-gate.js +344 -0
  81. package/mcp-server/dist/services/browser-assist-gate.js.map +1 -0
  82. package/mcp-server/dist/services/browser-assist.d.ts +104 -0
  83. package/mcp-server/dist/services/browser-assist.d.ts.map +1 -0
  84. package/mcp-server/dist/services/browser-assist.js +282 -0
  85. package/mcp-server/dist/services/browser-assist.js.map +1 -0
  86. package/mcp-server/dist/services/browser-bench.d.ts +772 -0
  87. package/mcp-server/dist/services/browser-bench.d.ts.map +1 -0
  88. package/mcp-server/dist/services/browser-bench.js +424 -0
  89. package/mcp-server/dist/services/browser-bench.js.map +1 -0
  90. package/mcp-server/dist/services/browser-judgments.d.ts +196 -0
  91. package/mcp-server/dist/services/browser-judgments.d.ts.map +1 -0
  92. package/mcp-server/dist/services/browser-judgments.js +363 -0
  93. package/mcp-server/dist/services/browser-judgments.js.map +1 -0
  94. package/mcp-server/dist/services/browser-risk.d.ts +166 -0
  95. package/mcp-server/dist/services/browser-risk.d.ts.map +1 -0
  96. package/mcp-server/dist/services/browser-risk.js +458 -0
  97. package/mcp-server/dist/services/browser-risk.js.map +1 -0
  98. package/mcp-server/dist/services/categories.d.ts +61 -0
  99. package/mcp-server/dist/services/categories.d.ts.map +1 -0
  100. package/mcp-server/dist/services/categories.js +377 -0
  101. package/mcp-server/dist/services/categories.js.map +1 -0
  102. package/mcp-server/dist/services/codex-config-heal.d.ts +49 -0
  103. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -0
  104. package/mcp-server/dist/services/codex-config-heal.js +346 -0
  105. package/mcp-server/dist/services/codex-config-heal.js.map +1 -0
  106. package/mcp-server/dist/services/desktop-assist-gate.d.ts +198 -0
  107. package/mcp-server/dist/services/desktop-assist-gate.d.ts.map +1 -0
  108. package/mcp-server/dist/services/desktop-assist-gate.js +202 -0
  109. package/mcp-server/dist/services/desktop-assist-gate.js.map +1 -0
  110. package/mcp-server/dist/services/desktop-assist.d.ts +104 -0
  111. package/mcp-server/dist/services/desktop-assist.d.ts.map +1 -0
  112. package/mcp-server/dist/services/desktop-assist.js +266 -0
  113. package/mcp-server/dist/services/desktop-assist.js.map +1 -0
  114. package/mcp-server/dist/services/desktop-bench.d.ts +553 -0
  115. package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -0
  116. package/mcp-server/dist/services/desktop-bench.js +311 -0
  117. package/mcp-server/dist/services/desktop-bench.js.map +1 -0
  118. package/mcp-server/dist/services/desktop-client.d.ts +23 -0
  119. package/mcp-server/dist/services/desktop-client.d.ts.map +1 -0
  120. package/mcp-server/dist/services/desktop-client.js +79 -0
  121. package/mcp-server/dist/services/desktop-client.js.map +1 -0
  122. package/mcp-server/dist/services/desktop-judgments.d.ts +125 -0
  123. package/mcp-server/dist/services/desktop-judgments.d.ts.map +1 -0
  124. package/mcp-server/dist/services/desktop-judgments.js +177 -0
  125. package/mcp-server/dist/services/desktop-judgments.js.map +1 -0
  126. package/mcp-server/dist/services/desktop-risk.d.ts +283 -0
  127. package/mcp-server/dist/services/desktop-risk.d.ts.map +1 -0
  128. package/mcp-server/dist/services/desktop-risk.js +605 -0
  129. package/mcp-server/dist/services/desktop-risk.js.map +1 -0
  130. package/mcp-server/dist/services/discord.d.ts +112 -0
  131. package/mcp-server/dist/services/discord.d.ts.map +1 -0
  132. package/mcp-server/dist/services/discord.js +477 -0
  133. package/mcp-server/dist/services/discord.js.map +1 -0
  134. package/mcp-server/dist/services/edit-stale.d.ts +81 -0
  135. package/mcp-server/dist/services/edit-stale.d.ts.map +1 -0
  136. package/mcp-server/dist/services/edit-stale.js +358 -0
  137. package/mcp-server/dist/services/edit-stale.js.map +1 -0
  138. package/mcp-server/dist/services/embedding-service.d.ts +16 -0
  139. package/mcp-server/dist/services/embedding-service.d.ts.map +1 -0
  140. package/mcp-server/dist/services/embedding-service.js +126 -0
  141. package/mcp-server/dist/services/embedding-service.js.map +1 -0
  142. package/mcp-server/dist/services/embedding-worker.d.ts +2 -0
  143. package/mcp-server/dist/services/embedding-worker.d.ts.map +1 -0
  144. package/mcp-server/dist/services/embedding-worker.js +52 -0
  145. package/mcp-server/dist/services/embedding-worker.js.map +1 -0
  146. package/mcp-server/dist/services/fb-regions.d.ts +71 -0
  147. package/mcp-server/dist/services/fb-regions.d.ts.map +1 -0
  148. package/mcp-server/dist/services/fb-regions.js +211 -0
  149. package/mcp-server/dist/services/fb-regions.js.map +1 -0
  150. package/mcp-server/dist/services/file-checksums.d.ts +22 -0
  151. package/mcp-server/dist/services/file-checksums.d.ts.map +1 -0
  152. package/mcp-server/dist/services/file-checksums.js +55 -0
  153. package/mcp-server/dist/services/file-checksums.js.map +1 -0
  154. package/mcp-server/dist/services/file-excerpt.d.ts +24 -0
  155. package/mcp-server/dist/services/file-excerpt.d.ts.map +1 -0
  156. package/mcp-server/dist/services/file-excerpt.js +65 -0
  157. package/mcp-server/dist/services/file-excerpt.js.map +1 -0
  158. package/mcp-server/dist/services/identity.d.ts +124 -0
  159. package/mcp-server/dist/services/identity.d.ts.map +1 -0
  160. package/mcp-server/dist/services/identity.js +241 -0
  161. package/mcp-server/dist/services/identity.js.map +1 -0
  162. package/mcp-server/dist/services/local-embeddings.d.ts +2 -0
  163. package/mcp-server/dist/services/local-embeddings.d.ts.map +1 -0
  164. package/mcp-server/dist/services/local-embeddings.js +3 -0
  165. package/mcp-server/dist/services/local-embeddings.js.map +1 -0
  166. package/mcp-server/dist/services/memory-client.d.ts +4 -0
  167. package/mcp-server/dist/services/memory-client.d.ts.map +1 -0
  168. package/mcp-server/dist/services/memory-client.js +27 -0
  169. package/mcp-server/dist/services/memory-client.js.map +1 -0
  170. package/mcp-server/dist/services/memory-judge-backfill.d.ts +135 -0
  171. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -0
  172. package/mcp-server/dist/services/memory-judge-backfill.js +510 -0
  173. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -0
  174. package/mcp-server/dist/services/memory-judgments.d.ts +362 -0
  175. package/mcp-server/dist/services/memory-judgments.d.ts.map +1 -0
  176. package/mcp-server/dist/services/memory-judgments.js +674 -0
  177. package/mcp-server/dist/services/memory-judgments.js.map +1 -0
  178. package/mcp-server/dist/services/memory-maintenance.d.ts +108 -0
  179. package/mcp-server/dist/services/memory-maintenance.d.ts.map +1 -0
  180. package/mcp-server/dist/services/memory-maintenance.js +403 -0
  181. package/mcp-server/dist/services/memory-maintenance.js.map +1 -0
  182. package/mcp-server/dist/services/memory-retrieval.d.ts +66 -0
  183. package/mcp-server/dist/services/memory-retrieval.d.ts.map +1 -0
  184. package/mcp-server/dist/services/memory-retrieval.js +412 -0
  185. package/mcp-server/dist/services/memory-retrieval.js.map +1 -0
  186. package/mcp-server/dist/services/memory-schema.d.ts +16 -0
  187. package/mcp-server/dist/services/memory-schema.d.ts.map +1 -0
  188. package/mcp-server/dist/services/memory-schema.js +282 -0
  189. package/mcp-server/dist/services/memory-schema.js.map +1 -0
  190. package/mcp-server/dist/services/memory-sessions.d.ts +24 -0
  191. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -0
  192. package/mcp-server/dist/services/memory-sessions.js +110 -0
  193. package/mcp-server/dist/services/memory-sessions.js.map +1 -0
  194. package/mcp-server/dist/services/memory-triage.d.ts +60 -0
  195. package/mcp-server/dist/services/memory-triage.d.ts.map +1 -0
  196. package/mcp-server/dist/services/memory-triage.js +189 -0
  197. package/mcp-server/dist/services/memory-triage.js.map +1 -0
  198. package/mcp-server/dist/services/memory-verification.d.ts +24 -0
  199. package/mcp-server/dist/services/memory-verification.d.ts.map +1 -0
  200. package/mcp-server/dist/services/memory-verification.js +92 -0
  201. package/mcp-server/dist/services/memory-verification.js.map +1 -0
  202. package/mcp-server/dist/services/memory-writer.d.ts +26 -0
  203. package/mcp-server/dist/services/memory-writer.d.ts.map +1 -0
  204. package/mcp-server/dist/services/memory-writer.js +126 -0
  205. package/mcp-server/dist/services/memory-writer.js.map +1 -0
  206. package/mcp-server/dist/services/neural-interface.d.ts +439 -0
  207. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -0
  208. package/mcp-server/dist/services/neural-interface.js +1135 -0
  209. package/mcp-server/dist/services/neural-interface.js.map +1 -0
  210. package/mcp-server/dist/services/profiles.d.ts +120 -0
  211. package/mcp-server/dist/services/profiles.d.ts.map +1 -0
  212. package/mcp-server/dist/services/profiles.js +387 -0
  213. package/mcp-server/dist/services/profiles.js.map +1 -0
  214. package/mcp-server/dist/services/secret-gate.d.ts +29 -0
  215. package/mcp-server/dist/services/secret-gate.d.ts.map +1 -0
  216. package/mcp-server/dist/services/secret-gate.js +43 -0
  217. package/mcp-server/dist/services/secret-gate.js.map +1 -0
  218. package/mcp-server/dist/services/server-instructions.d.ts +10 -0
  219. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -0
  220. package/mcp-server/dist/services/server-instructions.js +101 -0
  221. package/mcp-server/dist/services/server-instructions.js.map +1 -0
  222. package/mcp-server/dist/services/sqlite.d.ts +235 -0
  223. package/mcp-server/dist/services/sqlite.d.ts.map +1 -0
  224. package/mcp-server/dist/services/sqlite.js +1185 -0
  225. package/mcp-server/dist/services/sqlite.js.map +1 -0
  226. package/mcp-server/dist/services/typesafe-bench.d.ts +99 -0
  227. package/mcp-server/dist/services/typesafe-bench.d.ts.map +1 -0
  228. package/mcp-server/dist/services/typesafe-bench.js +218 -0
  229. package/mcp-server/dist/services/typesafe-bench.js.map +1 -0
  230. package/mcp-server/dist/services/typesafe-config.d.ts +342 -0
  231. package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -0
  232. package/mcp-server/dist/services/typesafe-config.js +746 -0
  233. package/mcp-server/dist/services/typesafe-config.js.map +1 -0
  234. package/mcp-server/dist/services/typesafe.d.ts +213 -0
  235. package/mcp-server/dist/services/typesafe.d.ts.map +1 -0
  236. package/mcp-server/dist/services/typesafe.js +330 -0
  237. package/mcp-server/dist/services/typesafe.js.map +1 -0
  238. package/mcp-server/dist/services/vector-cache.d.ts +68 -0
  239. package/mcp-server/dist/services/vector-cache.d.ts.map +1 -0
  240. package/mcp-server/dist/services/vector-cache.js +271 -0
  241. package/mcp-server/dist/services/vector-cache.js.map +1 -0
  242. package/mcp-server/dist/services/whiteboard-geometry.d.ts +305 -0
  243. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -0
  244. package/mcp-server/dist/services/whiteboard-geometry.js +666 -0
  245. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -0
  246. package/mcp-server/dist/tools/agents.d.ts +212 -0
  247. package/mcp-server/dist/tools/agents.d.ts.map +1 -0
  248. package/mcp-server/dist/tools/agents.js +407 -0
  249. package/mcp-server/dist/tools/agents.js.map +1 -0
  250. package/mcp-server/dist/tools/bluesky.d.ts +39 -0
  251. package/mcp-server/dist/tools/bluesky.d.ts.map +1 -0
  252. package/mcp-server/dist/tools/bluesky.js +1144 -0
  253. package/mcp-server/dist/tools/bluesky.js.map +1 -0
  254. package/mcp-server/dist/tools/browser-advanced.d.ts +58 -0
  255. package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -0
  256. package/mcp-server/dist/tools/browser-advanced.js +106 -0
  257. package/mcp-server/dist/tools/browser-advanced.js.map +1 -0
  258. package/mcp-server/dist/tools/browser-batch.d.ts +99 -0
  259. package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -0
  260. package/mcp-server/dist/tools/browser-batch.js +187 -0
  261. package/mcp-server/dist/tools/browser-batch.js.map +1 -0
  262. package/mcp-server/dist/tools/browser-cheatsheet.d.ts +21 -0
  263. package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -0
  264. package/mcp-server/dist/tools/browser-cheatsheet.js +144 -0
  265. package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -0
  266. package/mcp-server/dist/tools/browser-interact.d.ts +239 -0
  267. package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -0
  268. package/mcp-server/dist/tools/browser-interact.js +300 -0
  269. package/mcp-server/dist/tools/browser-interact.js.map +1 -0
  270. package/mcp-server/dist/tools/browser-navigate.d.ts +90 -0
  271. package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -0
  272. package/mcp-server/dist/tools/browser-navigate.js +142 -0
  273. package/mcp-server/dist/tools/browser-navigate.js.map +1 -0
  274. package/mcp-server/dist/tools/browser-observe.d.ts +561 -0
  275. package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -0
  276. package/mcp-server/dist/tools/browser-observe.js +2009 -0
  277. package/mcp-server/dist/tools/browser-observe.js.map +1 -0
  278. package/mcp-server/dist/tools/browser.d.ts +34 -0
  279. package/mcp-server/dist/tools/browser.d.ts.map +1 -0
  280. package/mcp-server/dist/tools/browser.js +112 -0
  281. package/mcp-server/dist/tools/browser.js.map +1 -0
  282. package/mcp-server/dist/tools/card-tools.d.ts +82 -0
  283. package/mcp-server/dist/tools/card-tools.d.ts.map +1 -0
  284. package/mcp-server/dist/tools/card-tools.js +137 -0
  285. package/mcp-server/dist/tools/card-tools.js.map +1 -0
  286. package/mcp-server/dist/tools/card.d.ts +8 -0
  287. package/mcp-server/dist/tools/card.d.ts.map +1 -0
  288. package/mcp-server/dist/tools/card.js +16 -0
  289. package/mcp-server/dist/tools/card.js.map +1 -0
  290. package/mcp-server/dist/tools/category.d.ts +32 -0
  291. package/mcp-server/dist/tools/category.d.ts.map +1 -0
  292. package/mcp-server/dist/tools/category.js +290 -0
  293. package/mcp-server/dist/tools/category.js.map +1 -0
  294. package/mcp-server/dist/tools/choice.d.ts +160 -0
  295. package/mcp-server/dist/tools/choice.d.ts.map +1 -0
  296. package/mcp-server/dist/tools/choice.js +80 -0
  297. package/mcp-server/dist/tools/choice.js.map +1 -0
  298. package/mcp-server/dist/tools/computer.d.ts +71 -0
  299. package/mcp-server/dist/tools/computer.d.ts.map +1 -0
  300. package/mcp-server/dist/tools/computer.js +174 -0
  301. package/mcp-server/dist/tools/computer.js.map +1 -0
  302. package/mcp-server/dist/tools/discord-channel.d.ts +44 -0
  303. package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -0
  304. package/mcp-server/dist/tools/discord-channel.js +236 -0
  305. package/mcp-server/dist/tools/discord-channel.js.map +1 -0
  306. package/mcp-server/dist/tools/discord-guild.d.ts +20 -0
  307. package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -0
  308. package/mcp-server/dist/tools/discord-guild.js +138 -0
  309. package/mcp-server/dist/tools/discord-guild.js.map +1 -0
  310. package/mcp-server/dist/tools/discord-member.d.ts +26 -0
  311. package/mcp-server/dist/tools/discord-member.d.ts.map +1 -0
  312. package/mcp-server/dist/tools/discord-member.js +122 -0
  313. package/mcp-server/dist/tools/discord-member.js.map +1 -0
  314. package/mcp-server/dist/tools/discord-message.d.ts +36 -0
  315. package/mcp-server/dist/tools/discord-message.d.ts.map +1 -0
  316. package/mcp-server/dist/tools/discord-message.js +184 -0
  317. package/mcp-server/dist/tools/discord-message.js.map +1 -0
  318. package/mcp-server/dist/tools/discord-onboarding.d.ts +32 -0
  319. package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -0
  320. package/mcp-server/dist/tools/discord-onboarding.js +179 -0
  321. package/mcp-server/dist/tools/discord-onboarding.js.map +1 -0
  322. package/mcp-server/dist/tools/discord-role.d.ts +34 -0
  323. package/mcp-server/dist/tools/discord-role.d.ts.map +1 -0
  324. package/mcp-server/dist/tools/discord-role.js +178 -0
  325. package/mcp-server/dist/tools/discord-role.js.map +1 -0
  326. package/mcp-server/dist/tools/discord-thread.d.ts +28 -0
  327. package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -0
  328. package/mcp-server/dist/tools/discord-thread.js +88 -0
  329. package/mcp-server/dist/tools/discord-thread.js.map +1 -0
  330. package/mcp-server/dist/tools/discord-webhook.d.ts +32 -0
  331. package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -0
  332. package/mcp-server/dist/tools/discord-webhook.js +154 -0
  333. package/mcp-server/dist/tools/discord-webhook.js.map +1 -0
  334. package/mcp-server/dist/tools/discord.d.ts +7 -0
  335. package/mcp-server/dist/tools/discord.d.ts.map +1 -0
  336. package/mcp-server/dist/tools/discord.js +25 -0
  337. package/mcp-server/dist/tools/discord.js.map +1 -0
  338. package/mcp-server/dist/tools/fb-groups.d.ts +98 -0
  339. package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -0
  340. package/mcp-server/dist/tools/fb-groups.js +369 -0
  341. package/mcp-server/dist/tools/fb-groups.js.map +1 -0
  342. package/mcp-server/dist/tools/forget.d.ts +14 -0
  343. package/mcp-server/dist/tools/forget.d.ts.map +1 -0
  344. package/mcp-server/dist/tools/forget.js +26 -0
  345. package/mcp-server/dist/tools/forget.js.map +1 -0
  346. package/mcp-server/dist/tools/git-tools.d.ts +24 -0
  347. package/mcp-server/dist/tools/git-tools.d.ts.map +1 -0
  348. package/mcp-server/dist/tools/git-tools.js +107 -0
  349. package/mcp-server/dist/tools/git-tools.js.map +1 -0
  350. package/mcp-server/dist/tools/git.d.ts +7 -0
  351. package/mcp-server/dist/tools/git.d.ts.map +1 -0
  352. package/mcp-server/dist/tools/git.js +11 -0
  353. package/mcp-server/dist/tools/git.js.map +1 -0
  354. package/mcp-server/dist/tools/gsc/experience.d.ts +135 -0
  355. package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -0
  356. package/mcp-server/dist/tools/gsc/experience.js +351 -0
  357. package/mcp-server/dist/tools/gsc/experience.js.map +1 -0
  358. package/mcp-server/dist/tools/gsc/helpers.d.ts +78 -0
  359. package/mcp-server/dist/tools/gsc/helpers.d.ts.map +1 -0
  360. package/mcp-server/dist/tools/gsc/helpers.js +258 -0
  361. package/mcp-server/dist/tools/gsc/helpers.js.map +1 -0
  362. package/mcp-server/dist/tools/gsc/indexing.d.ts +121 -0
  363. package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -0
  364. package/mcp-server/dist/tools/gsc/indexing.js +357 -0
  365. package/mcp-server/dist/tools/gsc/indexing.js.map +1 -0
  366. package/mcp-server/dist/tools/gsc/inspect.d.ts +78 -0
  367. package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -0
  368. package/mcp-server/dist/tools/gsc/inspect.js +321 -0
  369. package/mcp-server/dist/tools/gsc/inspect.js.map +1 -0
  370. package/mcp-server/dist/tools/gsc/navigate.d.ts +44 -0
  371. package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -0
  372. package/mcp-server/dist/tools/gsc/navigate.js +197 -0
  373. package/mcp-server/dist/tools/gsc/navigate.js.map +1 -0
  374. package/mcp-server/dist/tools/gsc/performance.d.ts +84 -0
  375. package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -0
  376. package/mcp-server/dist/tools/gsc/performance.js +274 -0
  377. package/mcp-server/dist/tools/gsc/performance.js.map +1 -0
  378. package/mcp-server/dist/tools/gsc/settings.d.ts +153 -0
  379. package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -0
  380. package/mcp-server/dist/tools/gsc/settings.js +425 -0
  381. package/mcp-server/dist/tools/gsc/settings.js.map +1 -0
  382. package/mcp-server/dist/tools/gsc.d.ts +7 -0
  383. package/mcp-server/dist/tools/gsc.d.ts.map +1 -0
  384. package/mcp-server/dist/tools/gsc.js +51 -0
  385. package/mcp-server/dist/tools/gsc.js.map +1 -0
  386. package/mcp-server/dist/tools/image-tools.d.ts +24 -0
  387. package/mcp-server/dist/tools/image-tools.d.ts.map +1 -0
  388. package/mcp-server/dist/tools/image-tools.js +80 -0
  389. package/mcp-server/dist/tools/image-tools.js.map +1 -0
  390. package/mcp-server/dist/tools/image.d.ts +10 -0
  391. package/mcp-server/dist/tools/image.d.ts.map +1 -0
  392. package/mcp-server/dist/tools/image.js +14 -0
  393. package/mcp-server/dist/tools/image.js.map +1 -0
  394. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +97 -0
  395. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -0
  396. package/mcp-server/dist/tools/leonardo-browser-tools.js +228 -0
  397. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -0
  398. package/mcp-server/dist/tools/leonardo.d.ts +13 -0
  399. package/mcp-server/dist/tools/leonardo.d.ts.map +1 -0
  400. package/mcp-server/dist/tools/leonardo.js +21 -0
  401. package/mcp-server/dist/tools/leonardo.js.map +1 -0
  402. package/mcp-server/dist/tools/loop.d.ts +30 -0
  403. package/mcp-server/dist/tools/loop.d.ts.map +1 -0
  404. package/mcp-server/dist/tools/loop.js +401 -0
  405. package/mcp-server/dist/tools/loop.js.map +1 -0
  406. package/mcp-server/dist/tools/memories.d.ts +56 -0
  407. package/mcp-server/dist/tools/memories.d.ts.map +1 -0
  408. package/mcp-server/dist/tools/memories.js +171 -0
  409. package/mcp-server/dist/tools/memories.js.map +1 -0
  410. package/mcp-server/dist/tools/morelogin.d.ts +24 -0
  411. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -0
  412. package/mcp-server/dist/tools/morelogin.js +79 -0
  413. package/mcp-server/dist/tools/morelogin.js.map +1 -0
  414. package/mcp-server/dist/tools/profile.d.ts +17 -0
  415. package/mcp-server/dist/tools/profile.d.ts.map +1 -0
  416. package/mcp-server/dist/tools/profile.js +114 -0
  417. package/mcp-server/dist/tools/profile.js.map +1 -0
  418. package/mcp-server/dist/tools/recall.d.ts +71 -0
  419. package/mcp-server/dist/tools/recall.d.ts.map +1 -0
  420. package/mcp-server/dist/tools/recall.js +147 -0
  421. package/mcp-server/dist/tools/recall.js.map +1 -0
  422. package/mcp-server/dist/tools/reflect.d.ts +56 -0
  423. package/mcp-server/dist/tools/reflect.d.ts.map +1 -0
  424. package/mcp-server/dist/tools/reflect.js +157 -0
  425. package/mcp-server/dist/tools/reflect.js.map +1 -0
  426. package/mcp-server/dist/tools/remember.d.ts +62 -0
  427. package/mcp-server/dist/tools/remember.d.ts.map +1 -0
  428. package/mcp-server/dist/tools/remember.js +201 -0
  429. package/mcp-server/dist/tools/remember.js.map +1 -0
  430. package/mcp-server/dist/tools/response.d.ts +23 -0
  431. package/mcp-server/dist/tools/response.d.ts.map +1 -0
  432. package/mcp-server/dist/tools/response.js +24 -0
  433. package/mcp-server/dist/tools/response.js.map +1 -0
  434. package/mcp-server/dist/tools/restore.d.ts +14 -0
  435. package/mcp-server/dist/tools/restore.d.ts.map +1 -0
  436. package/mcp-server/dist/tools/restore.js +23 -0
  437. package/mcp-server/dist/tools/restore.js.map +1 -0
  438. package/mcp-server/dist/tools/style-guide-tools.d.ts +51 -0
  439. package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -0
  440. package/mcp-server/dist/tools/style-guide-tools.js +231 -0
  441. package/mcp-server/dist/tools/style-guide-tools.js.map +1 -0
  442. package/mcp-server/dist/tools/style-guide.d.ts +8 -0
  443. package/mcp-server/dist/tools/style-guide.d.ts.map +1 -0
  444. package/mcp-server/dist/tools/style-guide.js +12 -0
  445. package/mcp-server/dist/tools/style-guide.js.map +1 -0
  446. package/mcp-server/dist/tools/sync.d.ts +20 -0
  447. package/mcp-server/dist/tools/sync.d.ts.map +1 -0
  448. package/mcp-server/dist/tools/sync.js +156 -0
  449. package/mcp-server/dist/tools/sync.js.map +1 -0
  450. package/mcp-server/dist/tools/tictactoe-tools.d.ts +18 -0
  451. package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -0
  452. package/mcp-server/dist/tools/tictactoe-tools.js +78 -0
  453. package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -0
  454. package/mcp-server/dist/tools/tictactoe.d.ts +7 -0
  455. package/mcp-server/dist/tools/tictactoe.d.ts.map +1 -0
  456. package/mcp-server/dist/tools/tictactoe.js +11 -0
  457. package/mcp-server/dist/tools/tictactoe.js.map +1 -0
  458. package/mcp-server/dist/tools/utils.d.ts +19 -0
  459. package/mcp-server/dist/tools/utils.d.ts.map +1 -0
  460. package/mcp-server/dist/tools/utils.js +54 -0
  461. package/mcp-server/dist/tools/utils.js.map +1 -0
  462. package/mcp-server/dist/tools/whiteboard-format.d.ts +88 -0
  463. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -0
  464. package/mcp-server/dist/tools/whiteboard-format.js +337 -0
  465. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -0
  466. package/mcp-server/dist/tools/whiteboard-tools.d.ts +326 -0
  467. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -0
  468. package/mcp-server/dist/tools/whiteboard-tools.js +222 -0
  469. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -0
  470. package/mcp-server/dist/tools/whiteboard.d.ts +8 -0
  471. package/mcp-server/dist/tools/whiteboard.d.ts.map +1 -0
  472. package/mcp-server/dist/tools/whiteboard.js +16 -0
  473. package/mcp-server/dist/tools/whiteboard.js.map +1 -0
  474. package/mcp-server/dist/tools/youtube/analytics.d.ts +46 -0
  475. package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -0
  476. package/mcp-server/dist/tools/youtube/analytics.js +83 -0
  477. package/mcp-server/dist/tools/youtube/analytics.js.map +1 -0
  478. package/mcp-server/dist/tools/youtube/dedup.d.ts +35 -0
  479. package/mcp-server/dist/tools/youtube/dedup.d.ts.map +1 -0
  480. package/mcp-server/dist/tools/youtube/dedup.js +56 -0
  481. package/mcp-server/dist/tools/youtube/dedup.js.map +1 -0
  482. package/mcp-server/dist/tools/youtube/download.d.ts +31 -0
  483. package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -0
  484. package/mcp-server/dist/tools/youtube/download.js +30 -0
  485. package/mcp-server/dist/tools/youtube/download.js.map +1 -0
  486. package/mcp-server/dist/tools/youtube/helpers.d.ts +66 -0
  487. package/mcp-server/dist/tools/youtube/helpers.d.ts.map +1 -0
  488. package/mcp-server/dist/tools/youtube/helpers.js +143 -0
  489. package/mcp-server/dist/tools/youtube/helpers.js.map +1 -0
  490. package/mcp-server/dist/tools/youtube/media.d.ts +43 -0
  491. package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -0
  492. package/mcp-server/dist/tools/youtube/media.js +97 -0
  493. package/mcp-server/dist/tools/youtube/media.js.map +1 -0
  494. package/mcp-server/dist/tools/youtube/metadata.d.ts +33 -0
  495. package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -0
  496. package/mcp-server/dist/tools/youtube/metadata.js +106 -0
  497. package/mcp-server/dist/tools/youtube/metadata.js.map +1 -0
  498. package/mcp-server/dist/tools/youtube/navigate.d.ts +30 -0
  499. package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -0
  500. package/mcp-server/dist/tools/youtube/navigate.js +71 -0
  501. package/mcp-server/dist/tools/youtube/navigate.js.map +1 -0
  502. package/mcp-server/dist/tools/youtube/playlist.d.ts +29 -0
  503. package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -0
  504. package/mcp-server/dist/tools/youtube/playlist.js +128 -0
  505. package/mcp-server/dist/tools/youtube/playlist.js.map +1 -0
  506. package/mcp-server/dist/tools/youtube/schedule.d.ts +31 -0
  507. package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -0
  508. package/mcp-server/dist/tools/youtube/schedule.js +147 -0
  509. package/mcp-server/dist/tools/youtube/schedule.js.map +1 -0
  510. package/mcp-server/dist/tools/youtube/source.d.ts +36 -0
  511. package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -0
  512. package/mcp-server/dist/tools/youtube/source.js +85 -0
  513. package/mcp-server/dist/tools/youtube/source.js.map +1 -0
  514. package/mcp-server/dist/tools/youtube/upload.d.ts +53 -0
  515. package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -0
  516. package/mcp-server/dist/tools/youtube/upload.js +255 -0
  517. package/mcp-server/dist/tools/youtube/upload.js.map +1 -0
  518. package/mcp-server/dist/tools/youtube.d.ts +12 -0
  519. package/mcp-server/dist/tools/youtube.d.ts.map +1 -0
  520. package/mcp-server/dist/tools/youtube.js +38 -0
  521. package/mcp-server/dist/tools/youtube.js.map +1 -0
  522. package/mcp-server/dist/tui.d.ts +3 -0
  523. package/mcp-server/dist/tui.d.ts.map +1 -0
  524. package/mcp-server/dist/tui.js +806 -0
  525. package/mcp-server/dist/tui.js.map +1 -0
  526. package/mcp-server/dist/types.d.ts +77 -0
  527. package/mcp-server/dist/types.d.ts.map +1 -0
  528. package/mcp-server/dist/types.js +2 -0
  529. package/mcp-server/dist/types.js.map +1 -0
  530. package/mcp-server/package-lock.json +4798 -0
  531. package/mcp-server/package.json +55 -38
  532. package/mcp-server/run.mjs +12 -2
  533. package/mcp-server/src/config.ts +48 -3
  534. package/mcp-server/src/http.ts +296 -93
  535. package/mcp-server/src/index.ts +546 -203
  536. package/mcp-server/src/preload-http.ts +19 -18
  537. package/mcp-server/src/preload.ts +19 -18
  538. package/mcp-server/src/scripts/setup-embeddings.ts +9 -0
  539. package/mcp-server/src/services/assistant-judgments.ts +157 -0
  540. package/mcp-server/src/services/browser-assist-gate.ts +383 -0
  541. package/mcp-server/src/services/browser-assist.ts +267 -0
  542. package/mcp-server/src/services/browser-bench.ts +477 -0
  543. package/mcp-server/src/services/browser-judgments.ts +414 -0
  544. package/mcp-server/src/services/browser-risk.ts +484 -0
  545. package/mcp-server/src/services/categories.ts +36 -19
  546. package/mcp-server/src/services/codex-config-heal.ts +403 -0
  547. package/mcp-server/src/services/desktop-assist-gate.ts +251 -0
  548. package/mcp-server/src/services/desktop-assist.ts +308 -0
  549. package/mcp-server/src/services/desktop-bench.ts +372 -0
  550. package/mcp-server/src/services/desktop-client.ts +76 -0
  551. package/mcp-server/src/services/desktop-judgments.ts +218 -0
  552. package/mcp-server/src/services/desktop-risk.ts +743 -0
  553. package/mcp-server/src/services/edit-stale.ts +299 -0
  554. package/mcp-server/src/services/embedding-service.ts +108 -0
  555. package/mcp-server/src/services/embedding-worker.ts +46 -0
  556. package/mcp-server/src/services/fb-regions.ts +221 -0
  557. package/mcp-server/src/services/file-checksums.ts +26 -9
  558. package/mcp-server/src/services/file-excerpt.ts +59 -0
  559. package/mcp-server/src/services/identity.ts +291 -0
  560. package/mcp-server/src/services/local-embeddings.ts +2 -77
  561. package/mcp-server/src/services/memory-client.ts +23 -0
  562. package/mcp-server/src/services/memory-judge-backfill.ts +462 -0
  563. package/mcp-server/src/services/memory-judgments.ts +901 -0
  564. package/mcp-server/src/services/memory-maintenance.ts +360 -0
  565. package/mcp-server/src/services/memory-retrieval.ts +349 -0
  566. package/mcp-server/src/services/memory-schema.ts +280 -0
  567. package/mcp-server/src/services/memory-sessions.ts +87 -0
  568. package/mcp-server/src/services/memory-triage.ts +182 -0
  569. package/mcp-server/src/services/memory-verification.ts +68 -0
  570. package/mcp-server/src/services/memory-writer.ts +125 -0
  571. package/mcp-server/src/services/neural-interface.ts +1217 -73
  572. package/mcp-server/src/services/profiles.ts +428 -0
  573. package/mcp-server/src/services/secret-gate.ts +52 -0
  574. package/mcp-server/src/services/server-instructions.ts +122 -0
  575. package/mcp-server/src/services/sqlite.ts +1456 -823
  576. package/mcp-server/src/services/typesafe-bench.ts +247 -0
  577. package/mcp-server/src/services/typesafe-config.ts +790 -0
  578. package/mcp-server/src/services/typesafe.ts +390 -0
  579. package/mcp-server/src/services/vector-cache.ts +255 -0
  580. package/mcp-server/src/services/whiteboard-geometry.ts +711 -0
  581. package/mcp-server/src/tools/agents.ts +539 -0
  582. package/mcp-server/src/tools/bluesky.ts +1186 -0
  583. package/mcp-server/src/tools/browser-advanced.ts +15 -6
  584. package/mcp-server/src/tools/browser-batch.ts +178 -0
  585. package/mcp-server/src/tools/browser-cheatsheet.ts +155 -0
  586. package/mcp-server/src/tools/browser-interact.ts +362 -255
  587. package/mcp-server/src/tools/browser-navigate.ts +164 -77
  588. package/mcp-server/src/tools/browser-observe.ts +2222 -1330
  589. package/mcp-server/src/tools/browser.ts +181 -107
  590. package/mcp-server/src/tools/card.ts +7 -5
  591. package/mcp-server/src/tools/choice.ts +103 -0
  592. package/mcp-server/src/tools/computer.ts +190 -0
  593. package/mcp-server/src/tools/discord.ts +10 -23
  594. package/mcp-server/src/tools/fb-groups.ts +387 -0
  595. package/mcp-server/src/tools/forget.ts +1 -1
  596. package/mcp-server/src/tools/git.ts +3 -1
  597. package/mcp-server/src/tools/gsc/experience.ts +440 -0
  598. package/mcp-server/src/tools/gsc/helpers.ts +288 -0
  599. package/mcp-server/src/tools/gsc/indexing.ts +495 -0
  600. package/mcp-server/src/tools/gsc/inspect.ts +391 -0
  601. package/mcp-server/src/tools/gsc/navigate.ts +236 -0
  602. package/mcp-server/src/tools/gsc/performance.ts +352 -0
  603. package/mcp-server/src/tools/gsc/settings.ts +564 -0
  604. package/mcp-server/src/tools/gsc.ts +95 -0
  605. package/mcp-server/src/tools/image.ts +3 -1
  606. package/mcp-server/src/tools/leonardo-browser-tools.ts +47 -37
  607. package/mcp-server/src/tools/leonardo.ts +7 -5
  608. package/mcp-server/src/tools/loop.ts +118 -25
  609. package/mcp-server/src/tools/memories.ts +65 -5
  610. package/mcp-server/src/tools/morelogin.ts +81 -0
  611. package/mcp-server/src/tools/profile.ts +122 -0
  612. package/mcp-server/src/tools/recall.ts +105 -261
  613. package/mcp-server/src/tools/reflect.ts +171 -145
  614. package/mcp-server/src/tools/remember.ts +223 -115
  615. package/mcp-server/src/tools/style-guide-tools.ts +250 -0
  616. package/mcp-server/src/tools/style-guide.ts +16 -0
  617. package/mcp-server/src/tools/sync.ts +66 -9
  618. package/mcp-server/src/tools/tictactoe.ts +3 -1
  619. package/mcp-server/src/tools/utils.ts +22 -0
  620. package/mcp-server/src/tools/whiteboard-format.ts +394 -0
  621. package/mcp-server/src/tools/whiteboard-tools.ts +191 -183
  622. package/mcp-server/src/tools/whiteboard.ts +7 -5
  623. package/mcp-server/src/tools/youtube/analytics.ts +106 -0
  624. package/mcp-server/src/tools/youtube/dedup.ts +57 -0
  625. package/mcp-server/src/tools/youtube/download.ts +41 -0
  626. package/mcp-server/src/tools/youtube/helpers.ts +183 -0
  627. package/mcp-server/src/tools/youtube/media.ts +109 -0
  628. package/mcp-server/src/tools/youtube/metadata.ts +112 -0
  629. package/mcp-server/src/tools/youtube/navigate.ts +81 -0
  630. package/mcp-server/src/tools/youtube/playlist.ts +134 -0
  631. package/mcp-server/src/tools/youtube/schedule.ts +158 -0
  632. package/mcp-server/src/tools/youtube/source.ts +101 -0
  633. package/mcp-server/src/tools/youtube/upload.ts +296 -0
  634. package/mcp-server/src/tools/youtube.ts +47 -0
  635. package/mcp-server/src/tui.ts +8 -9
  636. package/neural-interface/games/TicTacToe/1.svg +1 -0
  637. package/neural-interface/games/TicTacToe/2.svg +1 -0
  638. package/neural-interface/games/TicTacToe/3.svg +1 -0
  639. package/neural-interface/games/TicTacToe/4.svg +1 -0
  640. package/neural-interface/games/TicTacToe/5.svg +1 -0
  641. package/neural-interface/games/TicTacToe/6.svg +1 -0
  642. package/neural-interface/games/TicTacToe/7.svg +1 -0
  643. package/neural-interface/games/TicTacToe/8.svg +1 -0
  644. package/neural-interface/games/TicTacToe/9.svg +1 -0
  645. package/neural-interface/games/TicTacToe/Board.svg +1 -0
  646. package/neural-interface/games/TicTacToe/Circle.svg +1 -0
  647. package/neural-interface/games/TicTacToe/Cross.svg +1 -0
  648. package/neural-interface/i18n/en.json +7022 -0
  649. package/neural-interface/i18n/pt-BR.json +7026 -0
  650. package/neural-interface/lib/assistant-api.js +1005 -0
  651. package/neural-interface/lib/assistant-attachments.js +121 -0
  652. package/neural-interface/lib/assistant-brains/claude.js +207 -0
  653. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +43 -0
  654. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +56 -0
  655. package/neural-interface/lib/assistant-brains/codex.js +213 -0
  656. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +47 -0
  657. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +62 -0
  658. package/neural-interface/lib/assistant-brains/opencode.js +320 -0
  659. package/neural-interface/lib/assistant-budget.js +318 -0
  660. package/neural-interface/lib/assistant-catalog.js +731 -0
  661. package/neural-interface/lib/assistant-clarify.js +664 -0
  662. package/neural-interface/lib/assistant-config.js +232 -0
  663. package/neural-interface/lib/assistant-dispatch.js +2744 -0
  664. package/neural-interface/lib/assistant-envelope.js +582 -0
  665. package/neural-interface/lib/assistant-evidence.js +236 -0
  666. package/neural-interface/lib/assistant-hidden-models.js +272 -0
  667. package/neural-interface/lib/assistant-jev.js +117 -0
  668. package/neural-interface/lib/assistant-judgments.js +111 -0
  669. package/neural-interface/lib/assistant-media.js +335 -0
  670. package/neural-interface/lib/assistant-memory.js +398 -0
  671. package/neural-interface/lib/assistant-persona.js +444 -0
  672. package/neural-interface/lib/assistant-plan-permissions.js +448 -0
  673. package/neural-interface/lib/assistant-playbooks/design.md +87 -0
  674. package/neural-interface/lib/assistant-playbooks.js +72 -0
  675. package/neural-interface/lib/assistant-pricing.js +159 -0
  676. package/neural-interface/lib/assistant-route-gate-codex.js +163 -0
  677. package/neural-interface/lib/assistant-route-gate.js +212 -0
  678. package/neural-interface/lib/assistant-router.js +1324 -0
  679. package/neural-interface/lib/assistant-runtime.js +3337 -0
  680. package/neural-interface/lib/assistant-task-prompt.js +472 -0
  681. package/neural-interface/lib/assistant-usage.js +1688 -0
  682. package/neural-interface/lib/augmented-path.js +70 -0
  683. package/neural-interface/lib/automation-storage-migration.js +54 -0
  684. package/neural-interface/lib/backup-service.js +851 -0
  685. package/neural-interface/lib/backup-zip-reader.js +262 -0
  686. package/neural-interface/lib/browser-assist-api.js +41 -0
  687. package/neural-interface/lib/browser-console.js +176 -0
  688. package/neural-interface/lib/browser-execution.js +241 -0
  689. package/neural-interface/lib/browser-extraction.js +191 -0
  690. package/neural-interface/lib/browser-language.js +83 -0
  691. package/neural-interface/lib/browser-screenshot.js +399 -0
  692. package/neural-interface/lib/browser-semantic-context.js +639 -0
  693. package/neural-interface/lib/browser-snapshots.js +192 -0
  694. package/neural-interface/lib/browser-tab-recovery.js +119 -0
  695. package/neural-interface/lib/browser-targets.js +70 -0
  696. package/neural-interface/lib/browser-tool-policy.js +926 -0
  697. package/neural-interface/lib/claude-accounts.js +230 -0
  698. package/neural-interface/lib/claude-agent-bridge.js +3203 -0
  699. package/neural-interface/lib/claude-bypass-policy.js +99 -0
  700. package/neural-interface/lib/claude-executable.js +241 -0
  701. package/neural-interface/lib/claude-history.js +429 -0
  702. package/neural-interface/lib/claude-model-catalog.js +444 -0
  703. package/neural-interface/lib/claude-panel-requests.js +165 -0
  704. package/neural-interface/lib/claude-panel-session.js +272 -0
  705. package/neural-interface/lib/claude-permission-rules.js +153 -0
  706. package/neural-interface/lib/claude-session-cleanup.js +71 -0
  707. package/neural-interface/lib/claude-session-list.js +82 -0
  708. package/neural-interface/lib/claude-session-ops.js +140 -0
  709. package/neural-interface/lib/claude-settings-view.js +51 -0
  710. package/neural-interface/lib/claude-skin-connect.js +79 -0
  711. package/neural-interface/lib/claude-stall-policy.js +7 -0
  712. package/neural-interface/lib/claude-temporary.js +435 -0
  713. package/neural-interface/lib/cli-update-planner.js +312 -0
  714. package/neural-interface/lib/codex-capabilities.d.ts +41 -0
  715. package/neural-interface/lib/codex-capabilities.js +148 -0
  716. package/neural-interface/lib/codex-collaboration-mode.js +17 -0
  717. package/neural-interface/lib/codex-compat-rpc.js +241 -0
  718. package/neural-interface/lib/codex-mcp-approvals.js +56 -0
  719. package/neural-interface/lib/codex-mcp-apps.js +47 -0
  720. package/neural-interface/lib/codex-model-context.js +202 -0
  721. package/neural-interface/lib/codex-plan-store.js +71 -0
  722. package/neural-interface/lib/codex-request-journal.js +242 -0
  723. package/neural-interface/lib/codex-runtime-path.js +213 -0
  724. package/neural-interface/lib/codex-session-catalog.js +231 -0
  725. package/neural-interface/lib/codex-session-settings.js +46 -0
  726. package/neural-interface/lib/codex-sidepanel-permissions.js +110 -0
  727. package/neural-interface/lib/codex-thread-history.js +165 -0
  728. package/neural-interface/lib/codex-user-verification.js +34 -0
  729. package/neural-interface/lib/codex-writer-lifecycle.js +152 -0
  730. package/neural-interface/lib/confined-fs.js +256 -0
  731. package/neural-interface/lib/db.js +922 -0
  732. package/neural-interface/lib/design-md.js +9 -0
  733. package/neural-interface/lib/desktop/api.js +92 -0
  734. package/neural-interface/lib/desktop/audit.js +62 -0
  735. package/neural-interface/lib/desktop/build.js +423 -0
  736. package/neural-interface/lib/desktop/config.js +606 -0
  737. package/neural-interface/lib/desktop/coords.js +76 -0
  738. package/neural-interface/lib/desktop/fake-helper.js +1192 -0
  739. package/neural-interface/lib/desktop/frames.js +77 -0
  740. package/neural-interface/lib/desktop/grants.js +84 -0
  741. package/neural-interface/lib/desktop/guards.js +170 -0
  742. package/neural-interface/lib/desktop/helper/SynabunDesktop.swift +3056 -0
  743. package/neural-interface/lib/desktop/lease.js +51 -0
  744. package/neural-interface/lib/desktop/manager.js +545 -0
  745. package/neural-interface/lib/desktop/press-contexts.js +103 -0
  746. package/neural-interface/lib/desktop/protocol.js +495 -0
  747. package/neural-interface/lib/desktop/service.js +1202 -0
  748. package/neural-interface/lib/effort-levels.js +148 -0
  749. package/neural-interface/lib/event-loop-monitor.js +67 -0
  750. package/neural-interface/lib/exec-loop-command.js +209 -0
  751. package/neural-interface/lib/folder-picker.ps1 +77 -0
  752. package/neural-interface/lib/http-guards.js +287 -0
  753. package/neural-interface/lib/jsonl-lines.js +94 -0
  754. package/neural-interface/lib/loop-logger.js +127 -0
  755. package/neural-interface/lib/mcp-client-config.js +133 -0
  756. package/neural-interface/lib/mcp-installer.js +487 -0
  757. package/neural-interface/lib/mcp-profile-refresh-coordinator.js +78 -0
  758. package/neural-interface/lib/mcp-profile-servers.js +120 -0
  759. package/neural-interface/lib/memo-cache.js +84 -0
  760. package/neural-interface/lib/memory-api.js +758 -0
  761. package/neural-interface/lib/memory-map-api.js +1150 -0
  762. package/neural-interface/lib/memory-map-layout.js +872 -0
  763. package/neural-interface/lib/memory-map-worker.js +165 -0
  764. package/neural-interface/lib/memory-session-capture.js +81 -0
  765. package/neural-interface/lib/memory-timers.js +62 -0
  766. package/neural-interface/lib/morelogin.js +301 -0
  767. package/neural-interface/lib/native-binary-runtime.js +382 -0
  768. package/neural-interface/lib/native-loop-goal.js +33 -0
  769. package/neural-interface/lib/native-loop-providers.js +1002 -0
  770. package/neural-interface/lib/native-loop-runtime.js +747 -0
  771. package/neural-interface/lib/offline-page.js +54 -0
  772. package/neural-interface/lib/opencode-hidden-models.js +113 -0
  773. package/neural-interface/lib/opencode-history.js +253 -0
  774. package/neural-interface/lib/opencode-runtime-config.js +58 -0
  775. package/neural-interface/lib/opencode-v2-client.js +486 -0
  776. package/neural-interface/lib/opencode-v2-ws-requests.js +955 -0
  777. package/neural-interface/lib/path-confine.js +213 -0
  778. package/neural-interface/lib/plugin-installer.js +264 -0
  779. package/neural-interface/lib/project-storage.js +766 -0
  780. package/neural-interface/lib/pty-host/core.js +603 -0
  781. package/neural-interface/lib/pty-host/flow.js +43 -0
  782. package/neural-interface/lib/pty-host/host.js +47 -0
  783. package/neural-interface/lib/pty-host/manager.js +360 -0
  784. package/neural-interface/lib/pty-host/protocol.js +81 -0
  785. package/neural-interface/lib/pty-host/snapshot.js +133 -0
  786. package/neural-interface/lib/remote-policy.js +582 -0
  787. package/neural-interface/lib/rulesets/api.js +175 -0
  788. package/neural-interface/lib/rulesets/fs-safe.js +245 -0
  789. package/neural-interface/lib/rulesets/installer.js +1453 -0
  790. package/neural-interface/lib/rulesets/json-edit.js +186 -0
  791. package/neural-interface/lib/rulesets/lock.js +170 -0
  792. package/neural-interface/lib/rulesets/managed-text.js +314 -0
  793. package/neural-interface/lib/rulesets/normalise.js +24 -0
  794. package/neural-interface/lib/rulesets/render.js +84 -0
  795. package/neural-interface/lib/schedule-launch-intent.js +40 -0
  796. package/neural-interface/lib/session-cache-builder.js +524 -0
  797. package/neural-interface/lib/session-chunker.js +344 -0
  798. package/neural-interface/lib/session-indexer.js +327 -0
  799. package/neural-interface/lib/session-title-generator.js +232 -0
  800. package/neural-interface/lib/skill-prompt-bridge.js +11 -0
  801. package/neural-interface/lib/style-guide/api.js +375 -0
  802. package/neural-interface/lib/style-guide/color.js +352 -0
  803. package/neural-interface/lib/style-guide/export-css.js +99 -0
  804. package/neural-interface/lib/style-guide/export-dtcg.js +209 -0
  805. package/neural-interface/lib/style-guide/export-tailwind.js +102 -0
  806. package/neural-interface/lib/style-guide/fonts.json +227 -0
  807. package/neural-interface/lib/style-guide/import.js +1268 -0
  808. package/neural-interface/lib/style-guide/pointers.js +103 -0
  809. package/neural-interface/lib/style-guide/presets.js +232 -0
  810. package/neural-interface/lib/style-guide/render-design-md.js +319 -0
  811. package/neural-interface/lib/style-guide/schema.js +848 -0
  812. package/neural-interface/lib/style-guide/security.js +43 -0
  813. package/neural-interface/lib/style-guide/store.js +491 -0
  814. package/neural-interface/lib/style-guide/summary.js +106 -0
  815. package/neural-interface/lib/style-guide/tokens.js +170 -0
  816. package/neural-interface/lib/synabun-update-plan.js +324 -0
  817. package/neural-interface/lib/synabun-version.js +179 -0
  818. package/neural-interface/lib/system-restore.js +99 -0
  819. package/neural-interface/lib/terminal-env.js +86 -0
  820. package/neural-interface/lib/ui-blob-store.js +106 -0
  821. package/neural-interface/lib/vector-cache.js +2 -0
  822. package/neural-interface/lib/virtual-socket.js +60 -0
  823. package/neural-interface/lib/whatsapp/api.js +146 -0
  824. package/neural-interface/lib/whatsapp/auth-store.js +389 -0
  825. package/neural-interface/lib/whatsapp/baileys-adapter.js +457 -0
  826. package/neural-interface/lib/whatsapp/brain.js +128 -0
  827. package/neural-interface/lib/whatsapp/bridge.js +1499 -0
  828. package/neural-interface/lib/whatsapp/cards.js +519 -0
  829. package/neural-interface/lib/whatsapp/commands.js +92 -0
  830. package/neural-interface/lib/whatsapp/config.js +291 -0
  831. package/neural-interface/lib/whatsapp/connector/entry.mjs +25 -0
  832. package/neural-interface/lib/whatsapp/connector/manifest.json +6 -0
  833. package/neural-interface/lib/whatsapp/connector/npm-shrinkwrap.json +717 -0
  834. package/neural-interface/lib/whatsapp/connector/package.json +8 -0
  835. package/neural-interface/lib/whatsapp/fake-baileys.js +444 -0
  836. package/neural-interface/lib/whatsapp/format.js +552 -0
  837. package/neural-interface/lib/whatsapp/host-core.js +1225 -0
  838. package/neural-interface/lib/whatsapp/host.js +119 -0
  839. package/neural-interface/lib/whatsapp/identity.js +288 -0
  840. package/neural-interface/lib/whatsapp/inbound.js +149 -0
  841. package/neural-interface/lib/whatsapp/installer.js +562 -0
  842. package/neural-interface/lib/whatsapp/manager.js +638 -0
  843. package/neural-interface/lib/whatsapp/paths.js +81 -0
  844. package/neural-interface/lib/whatsapp/protocol.js +327 -0
  845. package/neural-interface/lib/whatsapp/qr-svg.js +57 -0
  846. package/neural-interface/lib/whatsapp/redact.js +130 -0
  847. package/neural-interface/lib/whatsapp/service.js +1305 -0
  848. package/neural-interface/lib/whatsapp/vendor/qrcodegen.js +848 -0
  849. package/neural-interface/package-lock.json +4431 -0
  850. package/neural-interface/package.json +58 -27
  851. package/neural-interface/public/apple-touch-icon.png +0 -0
  852. package/neural-interface/public/category-logos/synabun.png +0 -0
  853. package/neural-interface/public/claude.svg +1 -0
  854. package/neural-interface/public/favicon-16x16.png +0 -0
  855. package/neural-interface/public/favicon-32x32.png +0 -0
  856. package/neural-interface/public/icon-192.png +0 -0
  857. package/neural-interface/public/icon-512.png +0 -0
  858. package/neural-interface/public/index.html +32 -182
  859. package/neural-interface/public/index2d.html +2 -2
  860. package/neural-interface/public/install-app.html +31 -0
  861. package/neural-interface/public/logo-synabun.png +0 -0
  862. package/neural-interface/public/logoHD.png +0 -0
  863. package/neural-interface/public/manifest.json +2 -0
  864. package/neural-interface/public/mcp.svg +4 -0
  865. package/neural-interface/public/offline.html +670 -299
  866. package/neural-interface/public/onboarding.html +804 -161
  867. package/neural-interface/public/opencode-logo-dark-square.svg +1 -0
  868. package/neural-interface/public/shared/agent-runtime-options.js +596 -0
  869. package/neural-interface/public/shared/api.js +339 -28
  870. package/neural-interface/public/shared/assistant/asst-accounts.js +318 -0
  871. package/neural-interface/public/shared/assistant/asst-agents-dock.js +296 -0
  872. package/neural-interface/public/shared/assistant/asst-api.js +270 -0
  873. package/neural-interface/public/shared/assistant/asst-brain-picker.js +744 -0
  874. package/neural-interface/public/shared/assistant/asst-budget.js +333 -0
  875. package/neural-interface/public/shared/assistant/asst-composer.js +656 -0
  876. package/neural-interface/public/shared/assistant/asst-computer.js +803 -0
  877. package/neural-interface/public/shared/assistant/asst-control.js +1018 -0
  878. package/neural-interface/public/shared/assistant/asst-hosts.js +262 -0
  879. package/neural-interface/public/shared/assistant/asst-mascot.js +313 -0
  880. package/neural-interface/public/shared/assistant/asst-menu.js +375 -0
  881. package/neural-interface/public/shared/assistant/asst-panel.js +1845 -0
  882. package/neural-interface/public/shared/assistant/asst-rack-styles.js +586 -0
  883. package/neural-interface/public/shared/assistant/asst-render.js +3305 -0
  884. package/neural-interface/public/shared/assistant/asst-route.js +1653 -0
  885. package/neural-interface/public/shared/assistant/asst-roving.js +75 -0
  886. package/neural-interface/public/shared/assistant/asst-sanitize.js +117 -0
  887. package/neural-interface/public/shared/assistant/asst-sidepanel-styles.js +488 -0
  888. package/neural-interface/public/shared/assistant/asst-sidepanel.js +675 -0
  889. package/neural-interface/public/shared/assistant/asst-slash.js +258 -0
  890. package/neural-interface/public/shared/assistant/asst-state.js +727 -0
  891. package/neural-interface/public/shared/assistant/asst-styles.js +1686 -0
  892. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +1017 -0
  893. package/neural-interface/public/shared/assistant/asst-usage.js +444 -0
  894. package/neural-interface/public/shared/assistant/asst-ws.js +175 -0
  895. package/neural-interface/public/shared/automation-context.js +75 -0
  896. package/neural-interface/public/shared/blob-store.js +99 -0
  897. package/neural-interface/public/shared/cdx/cdx-capabilities.js +118 -0
  898. package/neural-interface/public/shared/cdx/cdx-cards.js +37 -0
  899. package/neural-interface/public/shared/cdx/cdx-commands.js +171 -0
  900. package/neural-interface/public/shared/cdx/cdx-context-menu.js +402 -0
  901. package/neural-interface/public/shared/cdx/cdx-context-model.js +220 -0
  902. package/neural-interface/public/shared/cdx/cdx-features.js +408 -0
  903. package/neural-interface/public/shared/cdx/cdx-icons.js +89 -0
  904. package/neural-interface/public/shared/cdx/cdx-mcp-app-host.js +414 -0
  905. package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.html +6 -0
  906. package/neural-interface/public/shared/cdx/cdx-mcp-app-proxy.js +56 -0
  907. package/neural-interface/public/shared/cdx/cdx-mcp-app.js +178 -0
  908. package/neural-interface/public/shared/cdx/cdx-model-catalog.js +120 -0
  909. package/neural-interface/public/shared/cdx/cdx-output-model.js +261 -0
  910. package/neural-interface/public/shared/cdx/cdx-output.js +382 -0
  911. package/neural-interface/public/shared/cdx/cdx-panel.js +1372 -0
  912. package/neural-interface/public/shared/cdx/cdx-plan.js +266 -0
  913. package/neural-interface/public/shared/cdx/cdx-protocol.js +682 -0
  914. package/neural-interface/public/shared/cdx/cdx-render.js +3381 -0
  915. package/neural-interface/public/shared/cdx/cdx-requests.js +1136 -0
  916. package/neural-interface/public/shared/cdx/cdx-styles.js +3251 -0
  917. package/neural-interface/public/shared/cdx/cdx-tabs.js +7992 -0
  918. package/neural-interface/public/shared/cdx/cdx-ws.js +363 -0
  919. package/neural-interface/public/shared/cli-status.js +169 -0
  920. package/neural-interface/public/shared/command-runner-model.js +30 -0
  921. package/neural-interface/public/shared/constants.js +22 -5
  922. package/neural-interface/public/shared/cp/cp-agents.js +186 -0
  923. package/neural-interface/public/shared/cp/cp-bash.js +252 -0
  924. package/neural-interface/public/shared/cp/cp-compose.js +159 -0
  925. package/neural-interface/public/shared/cp/cp-context-menu.js +309 -0
  926. package/neural-interface/public/shared/cp/cp-context-model.js +157 -0
  927. package/neural-interface/public/shared/cp/cp-context-window.js +80 -0
  928. package/neural-interface/public/shared/cp/cp-ctx.js +11 -0
  929. package/neural-interface/public/shared/cp/cp-diff.js +255 -0
  930. package/neural-interface/public/shared/cp/cp-event-rows.js +637 -0
  931. package/neural-interface/public/shared/cp/cp-events.js +846 -0
  932. package/neural-interface/public/shared/cp/cp-markdown.js +104 -0
  933. package/neural-interface/public/shared/cp/cp-permission-model.js +905 -0
  934. package/neural-interface/public/shared/cp/cp-permissions.js +626 -0
  935. package/neural-interface/public/shared/cp/cp-rehydrate.js +113 -0
  936. package/neural-interface/public/shared/cp/cp-restore.js +224 -0
  937. package/neural-interface/public/shared/cp/cp-session-model.js +338 -0
  938. package/neural-interface/public/shared/cp/cp-session-settings.js +254 -0
  939. package/neural-interface/public/shared/cp/cp-sessions.js +227 -0
  940. package/neural-interface/public/shared/cp/cp-statusline.js +153 -0
  941. package/neural-interface/public/shared/cp/cp-styles.js +349 -0
  942. package/neural-interface/public/shared/cp/cp-tasks-model.js +282 -0
  943. package/neural-interface/public/shared/cp/cp-tasks.js +107 -0
  944. package/neural-interface/public/shared/cp/cp-temporary-view.js +56 -0
  945. package/neural-interface/public/shared/cp/cp-temporary.js +231 -0
  946. package/neural-interface/public/shared/cp/cp-tool-cards.js +326 -0
  947. package/neural-interface/public/shared/cp/cp-tool-results.js +618 -0
  948. package/neural-interface/public/shared/cp/cp-usage-model.js +124 -0
  949. package/neural-interface/public/shared/graph-activity.js +68 -0
  950. package/neural-interface/public/shared/html-shell.js +116 -17
  951. package/neural-interface/public/shared/i18n.js +132 -34
  952. package/neural-interface/public/shared/node-positions-store.js +44 -0
  953. package/neural-interface/public/shared/ocp-hidden-models.js +116 -0
  954. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +355 -0
  955. package/neural-interface/public/shared/ocp-v2/ocp-v2-autoaccept-button.js +35 -0
  956. package/neural-interface/public/shared/ocp-v2/ocp-v2-automation-ownership.js +72 -0
  957. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +280 -0
  958. package/neural-interface/public/shared/ocp-v2/ocp-v2-caps.js +67 -0
  959. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +179 -0
  960. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes.js +164 -0
  961. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +725 -0
  962. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +75 -0
  963. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +1204 -0
  964. package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm-logic.js +117 -0
  965. package/neural-interface/public/shared/ocp-v2/ocp-v2-confirm.js +59 -0
  966. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-gauge.js +252 -0
  967. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +478 -0
  968. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +179 -0
  969. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +233 -0
  970. package/neural-interface/public/shared/ocp-v2/ocp-v2-icons.js +30 -0
  971. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +1065 -0
  972. package/neural-interface/public/shared/ocp-v2/ocp-v2-mention-hints.js +182 -0
  973. package/neural-interface/public/shared/ocp-v2/ocp-v2-modelpicker.js +655 -0
  974. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +2636 -0
  975. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +601 -0
  976. package/neural-interface/public/shared/ocp-v2/ocp-v2-profile-inheritance.js +78 -0
  977. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +649 -0
  978. package/neural-interface/public/shared/ocp-v2/ocp-v2-providers.js +35 -0
  979. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +357 -0
  980. package/neural-interface/public/shared/ocp-v2/ocp-v2-render-logic.js +189 -0
  981. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +1869 -0
  982. package/neural-interface/public/shared/ocp-v2/ocp-v2-select.js +42 -0
  983. package/neural-interface/public/shared/ocp-v2/ocp-v2-send-logic.js +117 -0
  984. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +1714 -0
  985. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +468 -0
  986. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-widgets.js +63 -0
  987. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +366 -0
  988. package/neural-interface/public/shared/ocp-v2/ocp-v2-settings-link.js +19 -0
  989. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +343 -0
  990. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +746 -0
  991. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +347 -0
  992. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +338 -0
  993. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +3543 -0
  994. package/neural-interface/public/shared/ocp-v2/ocp-v2-subagents-logic.js +482 -0
  995. package/neural-interface/public/shared/ocp-v2/ocp-v2-tools-logic.js +351 -0
  996. package/neural-interface/public/shared/ocp-v2/ocp-v2-tools.js +168 -0
  997. package/neural-interface/public/shared/ocp-v2/ocp-v2-variantpicker.js +315 -0
  998. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +545 -0
  999. package/neural-interface/public/shared/provider-icons.js +30 -0
  1000. package/neural-interface/public/shared/pwa-install-page.js +34 -0
  1001. package/neural-interface/public/shared/pwa-install.css +12 -0
  1002. package/neural-interface/public/shared/pwa-install.js +28 -0
  1003. package/neural-interface/public/shared/session-title.js +100 -0
  1004. package/neural-interface/public/shared/settings/settings-ia.js +389 -0
  1005. package/neural-interface/public/shared/settings/settings-kit.js +234 -0
  1006. package/neural-interface/public/shared/settings/settings-rules.js +160 -0
  1007. package/neural-interface/public/shared/settings/settings-search.js +463 -0
  1008. package/neural-interface/public/shared/settings/settings-shell.js +570 -0
  1009. package/neural-interface/public/shared/start-bridge.js +583 -0
  1010. package/neural-interface/public/shared/state.js +5 -0
  1011. package/neural-interface/public/shared/storage.js +50 -7
  1012. package/neural-interface/public/shared/styleguide/sg-agents.js +42 -0
  1013. package/neural-interface/public/shared/styleguide/sg-brand.js +4 -0
  1014. package/neural-interface/public/shared/styleguide/sg-color-client.js +388 -0
  1015. package/neural-interface/public/shared/styleguide/sg-colors.js +151 -0
  1016. package/neural-interface/public/shared/styleguide/sg-components.js +35 -0
  1017. package/neural-interface/public/shared/styleguide/sg-history.js +41 -0
  1018. package/neural-interface/public/shared/styleguide/sg-icons-logo.js +38 -0
  1019. package/neural-interface/public/shared/styleguide/sg-imagery.js +4 -0
  1020. package/neural-interface/public/shared/styleguide/sg-import-export.js +48 -0
  1021. package/neural-interface/public/shared/styleguide/sg-kit.js +284 -0
  1022. package/neural-interface/public/shared/styleguide/sg-labels.js +318 -0
  1023. package/neural-interface/public/shared/styleguide/sg-layout.js +4 -0
  1024. package/neural-interface/public/shared/styleguide/sg-motion.js +5 -0
  1025. package/neural-interface/public/shared/styleguide/sg-panel.js +237 -0
  1026. package/neural-interface/public/shared/styleguide/sg-preview.js +138 -0
  1027. package/neural-interface/public/shared/styleguide/sg-rules.js +9 -0
  1028. package/neural-interface/public/shared/styleguide/sg-shape.js +24 -0
  1029. package/neural-interface/public/shared/styleguide/sg-state.js +132 -0
  1030. package/neural-interface/public/shared/styleguide/sg-typography.js +125 -0
  1031. package/neural-interface/public/shared/styles.css +8614 -1477
  1032. package/neural-interface/public/shared/synabun-mascot.js +1625 -0
  1033. package/neural-interface/public/shared/synabun-ticker.js +376 -0
  1034. package/neural-interface/public/shared/term-ready.js +307 -0
  1035. package/neural-interface/public/shared/term-renderer.js +343 -0
  1036. package/neural-interface/public/shared/ui-assistant-panel.js +10 -0
  1037. package/neural-interface/public/shared/ui-assistant.js +77 -0
  1038. package/neural-interface/public/shared/ui-automation-studio.js +5105 -3573
  1039. package/neural-interface/public/shared/ui-claude-panel.js +11685 -6333
  1040. package/neural-interface/public/shared/ui-codex-panel.js +12 -0
  1041. package/neural-interface/public/shared/ui-command-runner.js +251 -468
  1042. package/neural-interface/public/shared/ui-cost-widget.js +55 -34
  1043. package/neural-interface/public/shared/ui-detail.js +77 -14
  1044. package/neural-interface/public/shared/ui-explorer.js +360 -181
  1045. package/neural-interface/public/shared/ui-file-explorer.js +485 -107
  1046. package/neural-interface/public/shared/ui-help.js +2 -2
  1047. package/neural-interface/public/shared/ui-image-gallery.js +45 -21
  1048. package/neural-interface/public/shared/ui-judgments.js +1346 -0
  1049. package/neural-interface/public/shared/ui-keybinds.js +3 -2
  1050. package/neural-interface/public/shared/ui-link.js +105 -51
  1051. package/neural-interface/public/shared/ui-loading.js +222 -11
  1052. package/neural-interface/public/shared/ui-memory-maintenance.js +111 -0
  1053. package/neural-interface/public/shared/ui-menubar.js +100 -31
  1054. package/neural-interface/public/shared/ui-native-loop-router-state.js +94 -0
  1055. package/neural-interface/public/shared/ui-native-loop-router.js +493 -0
  1056. package/neural-interface/public/shared/ui-native-window-id.js +7 -0
  1057. package/neural-interface/public/shared/ui-navbar.js +357 -222
  1058. package/neural-interface/public/shared/ui-notifications.js +58 -12
  1059. package/neural-interface/public/shared/ui-opencode-panel-v2.js +17 -0
  1060. package/neural-interface/public/shared/ui-panels.js +15 -7
  1061. package/neural-interface/public/shared/ui-resume.js +823 -653
  1062. package/neural-interface/public/shared/ui-schedule-queue.js +172 -0
  1063. package/neural-interface/public/shared/ui-schedules-studio.js +1882 -0
  1064. package/neural-interface/public/shared/ui-scroll-follow.js +194 -0
  1065. package/neural-interface/public/shared/ui-sessions.js +789 -34
  1066. package/neural-interface/public/shared/ui-settings.js +5774 -2194
  1067. package/neural-interface/public/shared/ui-sidepanel-layout.js +109 -0
  1068. package/neural-interface/public/shared/ui-sidepanel-runtime.js +19 -0
  1069. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +40 -0
  1070. package/neural-interface/public/shared/ui-sidepanel-sessions.js +221 -0
  1071. package/neural-interface/public/shared/ui-sidepanel-state.js +131 -0
  1072. package/neural-interface/public/shared/ui-sidepanel-tray.js +547 -0
  1073. package/neural-interface/public/shared/ui-sidepanel-windows.js +387 -0
  1074. package/neural-interface/public/shared/ui-skills.js +18 -32
  1075. package/neural-interface/public/shared/ui-styleguide.js +35 -0
  1076. package/neural-interface/public/shared/ui-sync.js +87 -0
  1077. package/neural-interface/public/shared/ui-terminal.js +7863 -6385
  1078. package/neural-interface/public/shared/ui-tool-updates.js +292 -0
  1079. package/neural-interface/public/shared/ui-tooltip.js +156 -15
  1080. package/neural-interface/public/shared/ui-tutorial-draw.js +119 -683
  1081. package/neural-interface/public/shared/ui-tutorial-layout.js +135 -0
  1082. package/neural-interface/public/shared/ui-tutorial-steps.js +59 -2209
  1083. package/neural-interface/public/shared/ui-tutorial.css +102 -0
  1084. package/neural-interface/public/shared/ui-tutorial.js +557 -1076
  1085. package/neural-interface/public/shared/ui-update.js +420 -68
  1086. package/neural-interface/public/shared/ui-whatsapp.js +941 -0
  1087. package/neural-interface/public/shared/ui-whiteboard.js +1076 -233
  1088. package/neural-interface/public/shared/ui-workspaces.js +2 -1
  1089. package/neural-interface/public/shared/utils.js +58 -0
  1090. package/neural-interface/public/shared/vterm-buffer.js +15 -5
  1091. package/neural-interface/public/shared/whatsapp/wa-phone.js +65 -0
  1092. package/neural-interface/public/shared/whatsapp/wa-view.js +411 -0
  1093. package/neural-interface/public/sidepanel-session.html +18 -0
  1094. package/neural-interface/public/sw.js +10 -2
  1095. package/neural-interface/public/synabun.png +0 -0
  1096. package/neural-interface/public/variant/2d/graph.js +1707 -1635
  1097. package/neural-interface/public/variant/2d/lasso.js +2 -1
  1098. package/neural-interface/public/variant/2d/layout.js +595 -594
  1099. package/neural-interface/public/variant/2d/main.js +557 -521
  1100. package/neural-interface/public/variant/2d/settings-gfx.js +18 -24
  1101. package/neural-interface/public/variant/3d/main.js +517 -500
  1102. package/neural-interface/public/variant/3d/map-controls.js +144 -0
  1103. package/neural-interface/public/variant/3d/map-data.js +251 -0
  1104. package/neural-interface/public/variant/3d/map-labels.js +241 -0
  1105. package/neural-interface/public/variant/3d/map-pick.js +90 -0
  1106. package/neural-interface/public/variant/3d/map-renderer.js +521 -0
  1107. package/neural-interface/public/variant/3d/map-shaders.js +158 -0
  1108. package/neural-interface/public/variant/3d/map-view.js +618 -0
  1109. package/neural-interface/public/vendor/three/manifest.json +3 -0
  1110. package/neural-interface/public/vendor/three/three-0.169.0.min.js +3844 -0
  1111. package/neural-interface/public/vendor/xterm/manifest.json +3 -0
  1112. package/neural-interface/public/vendor/xterm/xterm-6.0.0.css +285 -0
  1113. package/neural-interface/public/vendor/xterm/xterm-6.0.0.min.js +192 -0
  1114. package/neural-interface/scripts/build-vendor.mjs +64 -0
  1115. package/neural-interface/scripts/codex-protocol-fixture.mjs +83 -0
  1116. package/neural-interface/scripts/rebuild-pty.js +39 -22
  1117. package/neural-interface/scripts/vendor-three-entry.js +24 -0
  1118. package/neural-interface/scripts/vendor-xterm-entry.js +8 -0
  1119. package/neural-interface/server.js +33983 -15000
  1120. package/neural-interface/skins/default/skin.css +90 -0
  1121. package/neural-interface/skins/default/skin.json +8 -0
  1122. package/neural-interface/templates/rulesets/README.md +9 -0
  1123. package/neural-interface/templates/rulesets/claude.md +3 -0
  1124. package/neural-interface/templates/rulesets/codex.md +2 -0
  1125. package/neural-interface/templates/rulesets/coexistence.md +6 -0
  1126. package/neural-interface/templates/rulesets/core.md +26 -0
  1127. package/neural-interface/templates/rulesets/cursor.md +2 -0
  1128. package/neural-interface/templates/rulesets/gemini.md +2 -0
  1129. package/neural-interface/templates/rulesets/legacy-hashes.json +227 -0
  1130. package/neural-interface/templates/rulesets/manifest.json +12 -0
  1131. package/neural-interface/templates/rulesets/opencode.md +2 -0
  1132. package/package.json +131 -53
  1133. package/postinstall.js +55 -26
  1134. package/preuninstall.js +187 -0
  1135. package/scripts/restore-data-home-from-backup.mjs +239 -0
  1136. package/setup.js +872 -260
  1137. package/skills/leonardo/SKILL.md +19 -10
  1138. package/skills/leonardo/modules/image-prompter.md +18 -12
  1139. package/skills/leonardo/modules/video-prompter.md +19 -13
  1140. package/skills/synabun/SKILL.md +209 -185
  1141. package/skills/synabun/icon.png +0 -0
  1142. package/skills/synabun/modules/audit.md +380 -374
  1143. package/skills/synabun/modules/changelog.md +15 -6
  1144. package/skills/synabun/modules/idea.md +148 -144
  1145. package/skills/synabun/modules/memorize.md +13 -4
  1146. package/skills/synabun/modules/schedule.md +198 -0
  1147. package/skills/synabun/synabunicon.png +0 -0
  1148. package/updater.cmd +31 -0
  1149. package/updater.mjs +382 -0
  1150. package/updater.sh +29 -0
  1151. package/hooks/claude-code/test-user-learning.mjs +0 -531
  1152. package/neural-interface/public/claude-chat.css +0 -878
  1153. package/neural-interface/public/claude-chat.html +0 -92
  1154. package/neural-interface/public/claude-chat.js +0 -1168
  1155. package/neural-interface/public/index-legacy.html +0 -14677
  1156. package/neural-interface/public/index2d-legacy.html +0 -8193
  1157. package/neural-interface/public/shared/html-term-renderer.js +0 -1022
  1158. package/neural-interface/public/variant/3d/background.js +0 -884
  1159. package/neural-interface/public/variant/3d/camera.js +0 -661
  1160. package/neural-interface/public/variant/3d/gfx.js +0 -116
  1161. package/neural-interface/public/variant/3d/graph.js +0 -2399
  1162. package/neural-interface/public/variant/3d/settings-gfx.js +0 -228
  1163. package/neural-interface/templates/CLAUDE-template.md +0 -211
@@ -0,0 +1,1268 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun — Style Guide importers
3
+ // ═══════════════════════════════════════════
4
+ //
5
+ // Everything a guide can be filled from: a DESIGN.md (ours, Stitch's or one of the
6
+ // community collection's: YAML frontmatter read by the small parser below, no
7
+ // dependency), a W3C design-tokens file, CSS custom properties, a Tailwind theme as
8
+ // JSON, the project's own files, or a community DESIGN.md fetched by slug.
9
+ //
10
+ // Each importer is pure and returns { patch, warnings }: `patch` is a partial v2
11
+ // config, applied as a JSON merge patch by buildImport (`merge`) or over the
12
+ // defaults (`replace`). The two functions that touch the outside take it injected:
13
+ // scanCodebase(root, { fs }) and fetchCommunityDesignMd(slug, { fetchImpl }).
14
+
15
+ import * as nodeFs from 'node:fs';
16
+ import { basename, join, relative, sep } from 'node:path';
17
+ import { PALETTE_STEPS, relativeLuminance, rgbToHex, scaleFromBase, toHex } from './color.js';
18
+ import { walkDtcg } from './export-dtcg.js';
19
+ import {
20
+ CORE_PALETTES, SEMANTIC_ROLES, STATUS_KEYS, THEMES,
21
+ applyMergePatch, defaultStyleGuide, diffConfigs, isAlias, isPlainObject, kebab, normalizeStyleGuide, resolveAlias, resolveText, tokenKey,
22
+ } from './schema.js';
23
+ import { roleFromName } from './tokens.js';
24
+ import { containedPath } from './security.js';
25
+
26
+ export const IMPORT_KINDS = Object.freeze(['design-md', 'dtcg', 'css', 'tailwind-json', 'codebase', 'community']);
27
+ export const COMMUNITY_SLUG_RE = /^[a-z0-9.-]{1,40}$/;
28
+ export const COMMUNITY_BASE_URL = 'https://raw.githubusercontent.com/VoltAgent/awesome-design-md/main/design-md';
29
+ export const COMMUNITY_ATTRIBUTION = 'From the community collection github.com/VoltAgent/awesome-design-md: a description of a public design, not an official brand asset.';
30
+ export const SCAN_MAX_FILES = 400;
31
+ const SCAN_MAX_BYTES = 1024 * 1024;
32
+ const SCAN_SKIP_DIRS = new Set(['node_modules', 'dist', 'build', '.git', '.synabun', '.next', '.nuxt', '.cache', '.turbo', 'coverage', 'vendor', 'out', 'target', '.venv', '__pycache__']);
33
+ const MAX_IMPORT_BYTES = 2 * 1024 * 1024;
34
+ const MAX_EXTRA_PALETTES = 8;
35
+ const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype', 'toString', 'valueOf']);
36
+ const MAX_DEPTH = 64;
37
+
38
+ function checkText(text) {
39
+ if (Buffer.byteLength(String(text ?? '')) > MAX_IMPORT_BYTES) throw new ImportError('TOO_LARGE', 'That file is too large to import.', 413);
40
+ }
41
+ function checkTree(value) {
42
+ const pending = [[value, 0]];
43
+ let count = 0;
44
+ while (pending.length) {
45
+ const [node, depth] = pending.pop();
46
+ if (depth > MAX_DEPTH || ++count > 100000) throw new ImportError('BAD_JSON', 'Import nesting or node count exceeds the limit.');
47
+ if (node && typeof node === 'object') for (const [key, item] of Object.entries(node)) {
48
+ if (UNSAFE_KEYS.has(key)) throw new ImportError('BAD_JSON', `Unsafe import key: ${key}`);
49
+ pending.push([item, depth + 1]);
50
+ }
51
+ }
52
+ }
53
+
54
+ export class ImportError extends Error {
55
+ constructor(code, message, status = 400) {
56
+ super(message);
57
+ this.name = 'ImportError';
58
+ this.code = code;
59
+ this.status = status;
60
+ }
61
+ }
62
+
63
+ // ── YAML subset ─────────────────────────────────────────────────────────────
64
+
65
+ /** Cut a trailing comment: a `#` at the start or after whitespace, outside quotes. */
66
+ function stripComment(line) {
67
+ let quote = null;
68
+ for (let i = 0; i < line.length; i++) {
69
+ const ch = line[i];
70
+ if (quote) {
71
+ if (ch === '\\' && quote === '"') i++;
72
+ else if (ch === quote) quote = null;
73
+ continue;
74
+ }
75
+ if (ch === '"' || ch === "'") { quote = ch; continue; }
76
+ if (ch === '#' && (i === 0 || /\s/.test(line[i - 1]))) {
77
+ // `color: #fff` is a hex color far more often than an empty value with a comment.
78
+ if (/:\s*$/.test(line.slice(0, i)) && /^#[0-9a-fA-F]{3,8}\s*(#.*)?$/.test(line.slice(i))) { i += line.slice(i).search(/\s|$/) - 1; continue; }
79
+ return line.slice(0, i);
80
+ }
81
+ }
82
+ return line;
83
+ }
84
+
85
+ function parseScalar(raw, depth = 0) {
86
+ if (depth > MAX_DEPTH) throw new ImportError('BAD_YAML', 'YAML nesting exceeds 64 levels');
87
+ const text = String(raw).trim();
88
+ if (text === '') return null;
89
+ if (text[0] === '"' && text.endsWith('"') && text.length >= 2) {
90
+ try { return JSON.parse(text); } catch { return text.slice(1, -1).replace(/\\(["\\])/g, '$1'); }
91
+ }
92
+ if (text[0] === "'" && text.endsWith("'") && text.length >= 2) return text.slice(1, -1).replace(/''/g, "'");
93
+ if (text[0] === '[' && text.endsWith(']')) return splitFlow(text.slice(1, -1)).map((part) => parseScalar(part, depth + 1));
94
+ if (text === '{}') return {};
95
+ if (text[0] === '{' && text.endsWith('}') && /:/.test(text)) {
96
+ const out = {};
97
+ for (const part of splitFlow(text.slice(1, -1))) {
98
+ const at = splitKey(part);
99
+ if (at && !UNSAFE_KEYS.has(at.key)) out[at.key] = parseScalar(at.rest, depth + 1);
100
+ }
101
+ return out;
102
+ }
103
+ if (/^(true|yes)$/i.test(text)) return true;
104
+ if (/^(false|no)$/i.test(text)) return false;
105
+ if (/^(null|~)$/i.test(text)) return null;
106
+ if (/^-?(\d+\.?\d*|\.\d+)(e[+-]?\d+)?$/i.test(text)) return Number(text);
107
+ return text;
108
+ }
109
+
110
+ /** Split "a, b, c" on commas outside quotes and brackets. */
111
+ function splitFlow(text) {
112
+ const out = [];
113
+ let depth = 0; let quote = null; let start = 0;
114
+ for (let i = 0; i < text.length; i++) {
115
+ const ch = text[i];
116
+ if (quote) { if (ch === quote) quote = null; continue; }
117
+ if (ch === '"' || ch === "'") quote = ch;
118
+ else if (ch === '[' || ch === '{' || ch === '(') depth++;
119
+ else if (ch === ']' || ch === '}' || ch === ')') depth--;
120
+ else if (ch === ',' && depth === 0) { out.push(text.slice(start, i)); start = i + 1; }
121
+ }
122
+ out.push(text.slice(start));
123
+ return out.map((part) => part.trim()).filter((part) => part !== '');
124
+ }
125
+
126
+ /** "key: rest" → { key, rest }, or null when the line is not a mapping entry. */
127
+ function splitKey(text) {
128
+ const line = text.trim();
129
+ let match = /^"((?:[^"\\]|\\.)*)"\s*:(?:\s+(.*))?$/.exec(line) || /^'((?:[^']|'')*)'\s*:(?:\s+(.*))?$/.exec(line);
130
+ if (match) return { key: match[1], rest: match[2] ?? '' };
131
+ match = /^([^\s:#\-[{"'][^:]*?)\s*:(?:\s+(.*))?$/.exec(line);
132
+ if (!match) return null;
133
+ // A URL or a time is a scalar, not a key.
134
+ if (/^[a-z]+$/i.test(match[1]) && /^\/\//.test(match[2] ?? '')) return null;
135
+ return { key: match[1].trim(), rest: match[2] ?? '' };
136
+ }
137
+
138
+ /**
139
+ * A small YAML subset, enough for a DESIGN.md frontmatter: maps, nested maps, block lists (of scalars
140
+ * or of maps), flow lists and maps on one line, quoted and plain scalars, `|` and `>` block text,
141
+ * comments. Anchors, tags and multi-document streams are not read. Throws ImportError('BAD_YAML').
142
+ */
143
+ export function parseYamlSubset(text) {
144
+ checkText(text);
145
+ const lines = [];
146
+ for (const raw of String(text ?? '').replace(/\r\n?/g, '\n').split('\n')) {
147
+ const expanded = raw.replace(/^\t+/, (tabs) => ' '.repeat(tabs.length));
148
+ const content = stripComment(expanded).replace(/\s+$/, '');
149
+ lines.push({ indent: content.length - content.trimStart().length, text: content.trim(), raw: expanded });
150
+ }
151
+ let index = 0;
152
+ let nesting = 0;
153
+ const skipBlank = () => { while (index < lines.length && lines[index].text === '') index++; };
154
+ const blockText = (parentIndent, folded) => {
155
+ const collected = [];
156
+ let base = null;
157
+ while (index < lines.length) {
158
+ const line = lines[index];
159
+ if (line.raw.trim() === '') { collected.push(''); index++; continue; }
160
+ const indent = line.raw.length - line.raw.trimStart().length;
161
+ if (indent <= parentIndent) break;
162
+ if (base === null) base = indent;
163
+ collected.push(line.raw.slice(Math.min(base, indent)).replace(/\s+$/, ''));
164
+ index++;
165
+ }
166
+ while (collected.length && collected[collected.length - 1] === '') collected.pop();
167
+ return folded ? collected.join(' ').replace(/\s+/g, ' ').trim() : collected.join('\n');
168
+ };
169
+ const valueAfter = (rest, indent) => {
170
+ if (rest === '|' || rest === '|-' || rest === '>' || rest === '>-') return blockText(indent, rest[0] === '>');
171
+ if (rest !== '') return parseScalar(rest);
172
+ skipBlank();
173
+ if (index < lines.length && (lines[index].indent > indent || (lines[index].indent === indent && lines[index].text.startsWith('- ')))) return parseNode(lines[index].indent);
174
+ return null;
175
+ };
176
+ function parseNode(indent) {
177
+ if (++nesting > MAX_DEPTH) throw new ImportError('BAD_YAML', 'YAML nesting exceeds 64 levels');
178
+ try { return parseNodeInner(indent); } finally { nesting--; }
179
+ }
180
+ function parseNodeInner(indent) {
181
+ skipBlank();
182
+ if (index >= lines.length) return null;
183
+ if (lines[index].text === '-' || lines[index].text.startsWith('- ')) {
184
+ const list = [];
185
+ while (index < lines.length) {
186
+ skipBlank();
187
+ if (index >= lines.length || lines[index].indent !== indent || !(lines[index].text === '-' || lines[index].text.startsWith('- '))) break;
188
+ const body = lines[index].text.slice(1).trim();
189
+ const entry = body ? splitKey(body) : null;
190
+ if (body === '') { index++; list.push(valueAfter('', indent)); continue; }
191
+ if (!entry) { index++; list.push(parseScalar(body)); continue; }
192
+ // "- key: value" opens a map whose other keys sit two columns in.
193
+ const item = {};
194
+ const itemIndent = indent + 2;
195
+ index++;
196
+ const first = valueAfter(entry.rest, itemIndent);
197
+ if (!UNSAFE_KEYS.has(entry.key)) item[entry.key] = first;
198
+ skipBlank();
199
+ if (index < lines.length && lines[index].indent === itemIndent && !lines[index].text.startsWith('- ')) Object.assign(item, parseNode(itemIndent));
200
+ list.push(item);
201
+ }
202
+ return list;
203
+ }
204
+ const map = {};
205
+ while (index < lines.length) {
206
+ skipBlank();
207
+ if (index >= lines.length || lines[index].indent < indent) break;
208
+ if (lines[index].indent > indent) throw new ImportError('BAD_YAML', `Unexpected indentation on line ${index + 1}`);
209
+ const entry = splitKey(lines[index].text);
210
+ if (!entry) throw new ImportError('BAD_YAML', `Cannot read line ${index + 1}: "${lines[index].text.slice(0, 60)}"`);
211
+ index++;
212
+ if (UNSAFE_KEYS.has(entry.key)) { valueAfter(entry.rest, indent); continue; }
213
+ map[entry.key] = valueAfter(entry.rest, indent);
214
+ }
215
+ return map;
216
+ }
217
+ skipBlank();
218
+ if (index >= lines.length) return {};
219
+ const value = parseNode(lines[index].indent);
220
+ skipBlank();
221
+ if (index < lines.length) throw new ImportError('BAD_YAML', `Cannot read line ${index + 1}: "${lines[index].text.slice(0, 60)}"`);
222
+ return value;
223
+ }
224
+
225
+ /** A Markdown file → { data (frontmatter object or null), body, hasFrontmatter }. */
226
+ export function splitFrontmatter(markdown) {
227
+ checkText(markdown);
228
+ const text = String(markdown ?? '').replace(/^\uFEFF/, '').replace(/\r\n?/g, '\n');
229
+ const match = /^---[ \t]*\n([\s\S]*?)\n(?:---|\.\.\.)[ \t]*(?:\n|$)/.exec(text);
230
+ if (!match) return { data: null, body: text, hasFrontmatter: false };
231
+ return { data: parseYamlSubset(match[1]), body: text.slice(match[0].length), hasFrontmatter: true };
232
+ }
233
+
234
+ // ── shared readers ──────────────────────────────────────────────────────────
235
+
236
+ /** "24px" | "1.5rem" | 24 → 24 (px), or null. */
237
+ export function toPx(value, { base = 16 } = {}) {
238
+ if (typeof value === 'number') return Number.isFinite(value) ? value : null;
239
+ const text = String(value ?? '').trim().toLowerCase();
240
+ if (text === 'full') return 9999;
241
+ const match = /^(-?(?:\d+\.?\d*|\.\d+))(px|rem|em|pt)?$/.exec(text);
242
+ if (!match) return null;
243
+ const n = parseFloat(match[1]);
244
+ if (match[2] === 'rem' || match[2] === 'em') return Math.round(n * base * 1000) / 1000;
245
+ if (match[2] === 'pt') return Math.round(n * (4 / 3) * 1000) / 1000;
246
+ return n;
247
+ }
248
+
249
+ const WEIGHT_NAMES = Object.freeze({ thin: 100, extralight: 200, light: 300, normal: 400, regular: 400, book: 400, medium: 500, semibold: 600, demibold: 600, bold: 700, extrabold: 800, black: 900, heavy: 900 });
250
+ function toWeight(value) {
251
+ if (typeof value === 'number') return value;
252
+ const text = String(value ?? '').trim().toLowerCase().replace(/[\s-]/g, '');
253
+ if (WEIGHT_NAMES[text]) return WEIGHT_NAMES[text];
254
+ const n = parseFloat(text);
255
+ return Number.isFinite(n) ? n : null;
256
+ }
257
+ function toLineHeight(value, size) {
258
+ if (typeof value === 'number') return value > 4 && size ? Math.round((value / size) * 1000) / 1000 : value;
259
+ const text = String(value ?? '').trim().toLowerCase();
260
+ if (text === 'normal') return 1.5;
261
+ if (text.endsWith('%')) return Math.round(parseFloat(text)) / 100;
262
+ const px = /px|rem|pt/.test(text) ? toPx(text) : null;
263
+ if (px !== null && size) return Math.round((px / size) * 1000) / 1000;
264
+ const n = parseFloat(text);
265
+ return Number.isFinite(n) ? n : null;
266
+ }
267
+ function toLetterSpacing(value, size) {
268
+ if (typeof value === 'number') return Math.abs(value) < 1 ? value : (size ? Math.round((value / size) * 10000) / 10000 : 0);
269
+ const text = String(value ?? '').trim().toLowerCase();
270
+ if (text === 'normal' || text === '0') return 0;
271
+ if (text.endsWith('em') && !text.endsWith('rem')) return parseFloat(text);
272
+ if (text.endsWith('%')) return parseFloat(text) / 100;
273
+ const px = toPx(text);
274
+ if (px !== null && size) return Math.round((px / size) * 10000) / 10000;
275
+ return null;
276
+ }
277
+ function toMs(value) {
278
+ if (typeof value === 'number') return value;
279
+ const text = String(value ?? '').trim().toLowerCase();
280
+ const n = parseFloat(text);
281
+ if (!Number.isFinite(n)) return null;
282
+ return text.endsWith('ms') ? n : text.endsWith('s') ? n * 1000 : n;
283
+ }
284
+
285
+ /** `"Space Grotesk", system-ui, sans-serif` → { family, fallback }. */
286
+ export function splitFontStack(value) {
287
+ const parts = (Array.isArray(value) ? value.map(String) : splitFlow(String(value ?? ''))).map((part) => part.trim().replace(/^["']|["']$/g, '')).filter(Boolean);
288
+ if (!parts.length) return null;
289
+ return { family: parts[0], fallback: parts.slice(1).join(', ') };
290
+ }
291
+ function fontCategory(family, id = '') {
292
+ if (/mono|code|courier|consol|menlo/i.test(family) || /(^|-)(code|mono)(-|$)/.test(id)) return 'mono';
293
+ if (/serif|georgia|times|garamond|playfair|merriweather|lora|fraunces/i.test(family) && !/sans/i.test(family)) return 'serif';
294
+ return 'sans';
295
+ }
296
+ const FALLBACKS = Object.freeze({ mono: 'ui-monospace, monospace', serif: 'Georgia, serif', sans: 'system-ui, sans-serif' });
297
+
298
+ function makeFont(family, fallback, { googleFonts = null, weights = null } = {}) {
299
+ const system = /^(system-ui|sans-serif|serif|monospace|ui-monospace|ui-sans-serif|ui-serif|-apple-system|arial|helvetica|georgia|times new roman|courier new|verdana|tahoma|segoe ui)$/i.test(family);
300
+ const font = { family, fallback: fallback || FALLBACKS[fontCategory(family)] };
301
+ // Without the list of Google families the source is not known: the guide's own value stays.
302
+ if (system) font.source = 'system';
303
+ else if (googleFonts) font.source = googleFonts.has(family.toLowerCase()) ? 'google' : 'other';
304
+ if (weights?.length) font.weights = [...new Set(weights)].sort((a, b) => a - b);
305
+ return font;
306
+ }
307
+
308
+ const STATUS_SYNONYMS = Object.freeze({ error: 'danger', destructive: 'danger', negative: 'danger', critical: 'danger', warn: 'warning', caution: 'warning', positive: 'success', information: 'info', informative: 'info' });
309
+ const PALETTE_SYNONYMS = Object.freeze({ brand: 'primary', tertiary: 'accent', gray: 'neutral', grey: 'neutral' });
310
+ const ROLE_SYNONYMS = Object.freeze({
311
+ background: 'background', bg: 'background', canvas: 'background', page: 'background',
312
+ surface: 'surface', card: 'surface', panel: 'surface', 'surface-container': 'surface',
313
+ 'surface-raised': 'surfaceRaised', 'surface-elevated': 'surfaceRaised', elevated: 'surfaceRaised', popover: 'surfaceRaised',
314
+ text: 'text', foreground: 'text', fg: 'text', ink: 'text', 'on-background': 'text', 'on-surface': 'text', 'text-primary': 'text', 'text-default': 'text',
315
+ 'text-muted': 'textMuted', 'muted-foreground': 'textMuted', 'text-secondary': 'textMuted', 'on-surface-variant': 'textMuted', 'text-subtle': 'textMuted', subtle: 'textMuted',
316
+ border: 'border', outline: 'border', divider: 'border', hairline: 'border', input: 'border',
317
+ 'on-primary': 'onPrimary', 'primary-foreground': 'onPrimary',
318
+ 'on-secondary': 'onSecondary', 'secondary-foreground': 'onSecondary',
319
+ 'on-accent': 'onAccent', 'accent-foreground': 'onAccent',
320
+ link: 'link', focus: 'focus', ring: 'focus', 'focus-ring': 'focus',
321
+ });
322
+
323
+ /**
324
+ * Sort named colors into the config. `entries` is [[name, value, theme?]]: a value is any CSS color or
325
+ * one of our aliases; `theme` says a flat name belongs to that theme (a `.dark` block). Names:
326
+ * <palette>-<step> · <theme>-<role> · a status · primary | secondary | accent | neutral (a base)
327
+ * background, surface, text, border, on-primary, … (flat semantic names) · anything else (a new palette)
328
+ * Returns { colors, extraPalettes } and pushes to `warnings`.
329
+ */
330
+ function sortColors(entries, warnings, { realias = false } = {}) {
331
+ const palettes = {};
332
+ const semantic = { light: {}, dark: {} };
333
+ const status = {};
334
+ const flat = [];
335
+ const extraPalettes = new Set();
336
+ const colorOf = (value) => (typeof value === 'string' && /^\{[a-z0-9-]+\.[a-z0-9-]+\}$/i.test(value.trim()) ? value.trim() : toHex(value));
337
+ const palette = (key) => (palettes[key] ||= { explicit: {}, base: null });
338
+ // `brand` stands for `primary` (and `gray` for `neutral`) only in a file that has no palette of that name itself.
339
+ const named = new Set(entries.map(([rawName]) => kebab(rawName).replace(/-(50|100|200|300|400|500|600|700|800|900|950)$/, '')));
340
+ const core = (name) => (CORE_PALETTES.includes(name) ? name : (PALETTE_SYNONYMS[name] && !named.has(PALETTE_SYNONYMS[name]) ? PALETTE_SYNONYMS[name] : null));
341
+ for (const [rawName, rawValue, theme = null] of entries) {
342
+ const name = kebab(rawName);
343
+ const value = colorOf(rawValue);
344
+ if (!name || !value) { if (name && rawValue !== null && rawValue !== undefined && rawValue !== '') warnings.push(`Not a color: ${rawName}: ${String(rawValue).slice(0, 40)}`); continue; }
345
+ const themed = /^(light|dark)-(.+)$/.exec(name);
346
+ if (themed && !PALETTE_STEPS.includes(themed[2])) { semantic[themed[1]][roleFromName(themed[2])] = value; continue; }
347
+ const stepped = /^(.+)-(50|100|200|300|400|500|600|700|800|900|950)$/.exec(name);
348
+ if (stepped && !theme) {
349
+ const key = core(stepped[1]) || stepped[1];
350
+ if (value.startsWith('#')) palette(key).explicit[stepped[2]] = value.slice(0, 7);
351
+ continue;
352
+ }
353
+ const statusKey = STATUS_KEYS.includes(name) ? name : STATUS_SYNONYMS[name];
354
+ if (statusKey && value.startsWith('#')) { if (!theme) status[statusKey] = value; continue; }
355
+ flat.push([name, value, theme]);
356
+ }
357
+ // Flat names describe one theme: the one the block says, else the one the background's lightness says.
358
+ const background = flat.find(([name, , theme]) => !theme && ROLE_SYNONYMS[name] === 'background');
359
+ const flatTheme = background && background[1].startsWith('#') && relativeLuminance(background[1]) < 0.2 ? 'dark' : 'light';
360
+ let sawFlatRole = false;
361
+ for (const [name, value, theme] of flat) {
362
+ const target = theme || flatTheme;
363
+ const key = core(name);
364
+ if (key) {
365
+ if (theme) semantic[theme][key === 'neutral' ? 'textMuted' : key] = value;
366
+ else if (value.startsWith('#')) { palette(key).base = value.slice(0, 7); if (target === 'dark' && key !== 'neutral') semantic.dark[key] = `{${key}.500}`; }
367
+ continue;
368
+ }
369
+ // shadcn's `muted` is a quiet surface, `accent` a hover surface: only the first is useful here.
370
+ const role = ROLE_SYNONYMS[name] || (name === 'muted' ? 'surface' : null) || (SEMANTIC_ROLES.includes(roleFromName(name)) ? roleFromName(name) : null);
371
+ if (role) {
372
+ if (name === 'muted' && semantic[target].surface) continue;
373
+ semantic[target][role] = value;
374
+ if (!theme) sawFlatRole = true;
375
+ continue;
376
+ }
377
+ if (theme) continue;
378
+ if (!value.startsWith('#')) continue;
379
+ if (extraPalettes.size >= MAX_EXTRA_PALETTES && !palettes[name]) { warnings.push(`Color "${name}" was not imported: more than ${MAX_EXTRA_PALETTES} extra palettes`); continue; }
380
+ palette(name).base = value.slice(0, 7);
381
+ extraPalettes.add(name);
382
+ }
383
+ const colors = {};
384
+ for (const [key, entry] of Object.entries(palettes)) {
385
+ const steps = Object.keys(entry.explicit);
386
+ const base = entry.explicit['500'] || entry.base || entry.explicit[steps[Math.floor(steps.length / 2)]];
387
+ if (!base) continue;
388
+ if (!CORE_PALETTES.includes(key)) extraPalettes.add(key);
389
+ (colors.palettes ||= {})[key] = { base, steps: { ...scaleFromBase(base), ...entry.explicit } };
390
+ }
391
+ if (realias && colors.palettes) {
392
+ // A format that only carries resolved colors: a role whose color is exactly a palette step points at it again.
393
+ const steps = new Map();
394
+ for (const [key, entry] of Object.entries(colors.palettes)) for (const [step, hex] of Object.entries(entry.steps)) if (!steps.has(hex)) steps.set(hex, `{${key}.${step}}`);
395
+ for (const theme of THEMES) for (const [role, value] of Object.entries(semantic[theme])) if (steps.has(value)) semantic[theme][role] = steps.get(value);
396
+ }
397
+ for (const theme of THEMES) if (Object.keys(semantic[theme]).length) (colors.semantic ||= {})[theme] = semantic[theme];
398
+ if (Object.keys(status).length) colors.status = status;
399
+ // Flat names on a dark background describe a dark-only design; anything else leaves the themes alone.
400
+ const themedBoth = Object.keys(semantic.light).length && Object.keys(semantic.dark).length;
401
+ if (sawFlatRole && !themedBoth && flatTheme === 'dark') colors.themes = { default: 'dark', supports: ['dark'] };
402
+ else if (themedBoth) colors.themes = { supports: ['light', 'dark'] };
403
+ return { colors, extraPalettes };
404
+ }
405
+
406
+ /** A token name in someone's frontmatter ("{colors.x}") → our alias, or null. */
407
+ function colorAliasFor(name, known) {
408
+ const key = kebab(name);
409
+ const themed = /^(light|dark)-(.+)$/.exec(key);
410
+ if (themed && !PALETTE_STEPS.includes(themed[2])) return `{semantic.${roleFromName(themed[2])}}`;
411
+ const stepped = /^(.+)-(50|100|200|300|400|500|600|700|800|900|950)$/.exec(key);
412
+ if (stepped) return `{${PALETTE_SYNONYMS[stepped[1]] || stepped[1]}.${stepped[2]}}`;
413
+ if (STATUS_KEYS.includes(key) || STATUS_SYNONYMS[key]) return `{status.${STATUS_SYNONYMS[key] || key}}`;
414
+ if (CORE_PALETTES.includes(key) || PALETTE_SYNONYMS[key]) return `{semantic.${PALETTE_SYNONYMS[key] || key}}`.replace('{semantic.neutral}', '{neutral.500}');
415
+ const role = ROLE_SYNONYMS[key] || (SEMANTIC_ROLES.includes(roleFromName(key)) ? roleFromName(key) : null);
416
+ if (role) return `{semantic.${role}}`;
417
+ return known.has(key) ? `{${key}.500}` : null;
418
+ }
419
+
420
+ /** Text styles + fonts from a map of { id: { fontFamily, fontSize, fontWeight, lineHeight, letterSpacing } }. */
421
+ function sortTypography(styleMap, { googleFonts = null } = {}, warnings = []) {
422
+ const styles = {};
423
+ const families = new Map(); // family → { ids, fallback, weights }
424
+ for (const [rawId, raw] of Object.entries(styleMap || {})) {
425
+ const id = kebab(rawId);
426
+ if (!id || !isPlainObject(raw)) continue;
427
+ const size = toPx(raw.fontSize ?? raw.size);
428
+ if (size === null) { warnings.push(`Text style "${rawId}" has no readable font size`); continue; }
429
+ const stack = raw.fontFamily ? splitFontStack(raw.fontFamily) : null;
430
+ const style = { size };
431
+ const weight = toWeight(raw.fontWeight ?? raw.weight);
432
+ if (weight !== null) style.weight = weight;
433
+ const lineHeight = toLineHeight(raw.lineHeight, size);
434
+ if (lineHeight !== null) style.lineHeight = lineHeight;
435
+ const letterSpacing = raw.letterSpacing === undefined || raw.letterSpacing === null ? null : toLetterSpacing(raw.letterSpacing, size);
436
+ if (letterSpacing !== null) style.letterSpacing = letterSpacing;
437
+ const transform = String(raw.textTransform ?? raw.transform ?? '').toLowerCase();
438
+ if (['uppercase', 'lowercase', 'capitalize', 'none'].includes(transform)) style.transform = transform;
439
+ if (toPx(raw.mobileSize) !== null) style.mobileSize = toPx(raw.mobileSize);
440
+ if (typeof raw.usage === 'string') style.usage = raw.usage;
441
+ styles[id] = style;
442
+ if (stack) {
443
+ const entry = families.get(stack.family) || { ids: [], fallback: stack.fallback, weights: [], features: '' };
444
+ entry.ids.push(id);
445
+ if (weight !== null) entry.weights.push(weight);
446
+ if (typeof raw.fontFeature === 'string') entry.features = raw.fontFeature;
447
+ families.set(stack.family, entry);
448
+ style._family = stack.family;
449
+ }
450
+ }
451
+ if (!Object.keys(styles).length) return null;
452
+ const fonts = {};
453
+ const score = (ids, re) => ids.filter((id) => re.test(id)).length;
454
+ const pick = (re, taken) => [...families.entries()].filter(([family]) => !taken.includes(family)).sort((a, b) => score(b[1].ids, re) - score(a[1].ids, re))[0];
455
+ const make = (family) => ({ ...makeFont(family, families.get(family).fallback, { googleFonts, weights: families.get(family).weights }), ...(families.get(family).features ? { features: families.get(family).features } : {}) });
456
+ const taken = [];
457
+ const mono = [...families.keys()].find((family) => fontCategory(family, families.get(family).ids.join('-')) === 'mono');
458
+ if (mono) { fonts.mono = make(mono); taken.push(mono); }
459
+ const HEADING_RE = /display|headline|heading|title|hero|^h[1-6]$/;
460
+ const BODY_RE = /body|paragraph|text|label|caption|button|overline|small/;
461
+ const heading = pick(HEADING_RE, taken);
462
+ const body = [...families.entries()].filter(([family]) => !taken.includes(family)).sort((a, b) => score(b[1].ids, BODY_RE) - score(a[1].ids, BODY_RE))[0];
463
+ if (body && score(body[1].ids, BODY_RE) > 0) { fonts.body = make(body[0]); taken.push(body[0]); }
464
+ if (heading && score(heading[1].ids, HEADING_RE) > 0) { fonts.heading = make(heading[0]); taken.push(heading[0]); }
465
+ const rest = [...families.keys()].filter((family) => !taken.includes(family));
466
+ if (!fonts.body && rest.length) { fonts.body = make(rest[0]); taken.push(rest.shift()); }
467
+ // Keep the patch partial: a body family alone does not define the heading role.
468
+ if (!fonts.heading && rest.length) fonts.heading = make(rest.shift());
469
+ if (rest.length) fonts.display = make(rest.shift());
470
+ if (rest.length) warnings.push(`More than four font families: ${rest.join(', ')} mapped to the body font`);
471
+ const keyOf = (family) => Object.entries(fonts).find(([, font]) => font?.family === family)?.[0];
472
+ for (const [id, style] of Object.entries(styles)) {
473
+ const family = style._family;
474
+ delete style._family;
475
+ const role = HEADING_RE.test(id) ? 'heading' : /code|mono/.test(id) ? 'mono' : 'body';
476
+ style.font = (family && (fonts[role]?.family === family ? role : keyOf(family))) || role;
477
+ }
478
+ const typography = { styles };
479
+ if (Object.values(fonts).some(Boolean)) typography.fonts = Object.fromEntries(Object.entries(fonts).filter(([, font]) => font));
480
+ return typography;
481
+ }
482
+
483
+ function dimensionMap(map, warnings, label) {
484
+ const out = {};
485
+ for (const [rawKey, value] of Object.entries(map || {})) {
486
+ const key = tokenKey(rawKey);
487
+ const n = toPx(value);
488
+ if (!key) continue;
489
+ if (n === null) { warnings.push(`${label} "${rawKey}" is not a length: ${String(value).slice(0, 30)}`); continue; }
490
+ out[key] = n;
491
+ }
492
+ return Object.keys(out).length ? out : null;
493
+ }
494
+
495
+ const RADIUS_ROLE_NAMES = Object.freeze(['button', 'card', 'input', 'badge', 'modal']);
496
+ /**
497
+ * `rounded-button` and friends are roles, not steps: each one that has the size of a step of the scale is taken
498
+ * out of `radius` (mutated) and returned as { role: step }.
499
+ */
500
+ function splitRadiusRoles(radius) {
501
+ const roles = {};
502
+ for (const role of RADIUS_ROLE_NAMES) {
503
+ if (!(role in radius)) continue;
504
+ const step = Object.keys(radius).find((key) => !RADIUS_ROLE_NAMES.includes(key) && radius[key] === radius[role]);
505
+ if (step) { roles[role] = step; delete radius[role]; }
506
+ }
507
+ return roles;
508
+ }
509
+
510
+ const COMPONENT_PROPS = Object.freeze({ backgroundColor: 'background', background: 'background', textColor: 'text', color: 'text', rounded: 'radius', borderRadius: 'radius', boxShadow: 'shadow' });
511
+ function componentCategory(id) {
512
+ if (/button|btn|cta/.test(id)) return 'button';
513
+ if (/input|field|select|textarea|checkbox|radio|switch|search|form/.test(id)) return 'input';
514
+ if (/modal|dialog|drawer|popover|sheet|overlay/.test(id)) return 'overlay';
515
+ if (/card|tile|panel/.test(id)) return 'card';
516
+ if (/nav|menu|tab|header|footer|sidebar|breadcrumb/.test(id)) return 'navigation';
517
+ if (/alert|toast|banner|badge|tag|pill|chip|tooltip|progress/.test(id)) return 'feedback';
518
+ if (/table|list|chart|stat|avatar/.test(id)) return 'data';
519
+ return 'other';
520
+ }
521
+
522
+ // ── DESIGN.md ───────────────────────────────────────────────────────────────
523
+
524
+ /** "## Heading" sections of a Markdown body: [{ title, text, subs: [{ title, text }] }]. */
525
+ export function markdownSections(body) {
526
+ const sections = [];
527
+ let current = null; let sub = null; let fence = false;
528
+ for (const line of String(body ?? '').split('\n')) {
529
+ if (/^\s*(```|~~~)/.test(line)) fence = !fence;
530
+ const h2 = !fence && /^##\s+(.+?)\s*#*\s*$/.exec(line);
531
+ const h3 = !fence && /^###\s+(.+?)\s*#*\s*$/.exec(line);
532
+ if (h2) { current = { title: h2[1].trim(), lines: [], subs: [] }; sections.push(current); sub = null; continue; }
533
+ if (h3 && current) { sub = { title: h3[1].trim(), lines: [] }; current.subs.push(sub); continue; }
534
+ (sub || current)?.lines.push(line);
535
+ }
536
+ const text = (lines) => lines.join('\n').trim();
537
+ return sections.map((s) => ({ title: s.title, text: text(s.lines), subs: s.subs.map((x) => ({ title: x.title, text: text(x.lines) })) }));
538
+ }
539
+ const bulletsOf = (text) => String(text ?? '').split('\n').map((line) => /^\s*[-*•]\s+(.*)$/.exec(line)?.[1]?.trim()).filter(Boolean).map((item) => item.replace(/\*\*/g, ''));
540
+ const proseOf = (text) => String(text ?? '').split(/\n{2,}/).map((p) => p.trim()).filter((p) => p && !/^[-*•|>#]/.test(p) && !/^\*\*[^*]+:\*\*/.test(p)).map((p) => p.replace(/\s*\n\s*/g, ' ').replace(/\*\*/g, ''));
541
+ const sectionNamed = (sections, re) => sections.find((s) => re.test(s.title.replace(/^\d+[.)]\s*/, '')));
542
+
543
+ const OUR_DEFAULT_RULES = new Set([
544
+ 'Use the semantic color roles and the type styles above.', 'Keep spacing on the scale.',
545
+ 'Invent colors, fonts or radii the guide does not define.', 'Convey meaning with color alone.',
546
+ ]);
547
+
548
+ function frontmatterToPatch(data, patch, warnings, options) {
549
+ if (typeof data.name === 'string' && data.name.trim()) (patch.brand ||= {}).name = data.name.trim();
550
+ if (typeof data.description === 'string' && data.description.trim()) (patch.brand ||= {}).description = data.description.trim();
551
+ const known = new Set();
552
+ if (isPlainObject(data.colors)) {
553
+ const entries = [];
554
+ const flatten = (map, prefix) => {
555
+ for (const [key, value] of Object.entries(map)) {
556
+ if (isPlainObject(value)) flatten(value, `${prefix}${key}-`);
557
+ else entries.push([`${prefix}${key}`, value]);
558
+ }
559
+ };
560
+ flatten(data.colors, '');
561
+ const sorted = sortColors(entries, warnings, { realias: true });
562
+ if (Object.keys(sorted.colors).length) patch.colors = sorted.colors;
563
+ for (const key of sorted.extraPalettes) known.add(key);
564
+ }
565
+ if (isPlainObject(data.typography)) {
566
+ const typography = sortTypography(data.typography, options, warnings);
567
+ if (typography) patch.typography = typography;
568
+ }
569
+ const radius = dimensionMap(data.rounded ?? data.radius, warnings, 'Radius');
570
+ if (radius) (patch.shape ||= {}).radius = radius;
571
+ const spacing = dimensionMap(data.spacing, warnings, 'Spacing');
572
+ if (spacing) ((patch.layout ||= {}).spacing ||= {}).scale = spacing;
573
+ if (isPlainObject(data.components)) {
574
+ const components = [];
575
+ const translate = (value) => String(value).replace(/\{([a-zA-Z]+)\.([^{}]+)\}/g, (match, group, name) => {
576
+ if (group === 'colors' || group === 'color') return colorAliasFor(name, known) || match;
577
+ if (group === 'rounded' || group === 'radius') return `{radius.${tokenKey(name)}}`;
578
+ if (group === 'typography') return `{typography.${kebab(name)}}`;
579
+ if (group === 'spacing') return `{spacing.${tokenKey(name)}}`;
580
+ return match;
581
+ });
582
+ for (const [rawId, props] of Object.entries(data.components)) {
583
+ const id = kebab(rawId);
584
+ if (!id || !isPlainObject(props)) continue;
585
+ const tokens = {};
586
+ const states = {};
587
+ for (const [key, value] of Object.entries(props)) {
588
+ if (isPlainObject(value)) { states[tokenKey(key)] = Object.entries(value).map(([k, v]) => `${COMPONENT_PROPS[k] || k} ${translate(v)}`).join(', '); continue; }
589
+ if (value === null || value === undefined || value === '') continue;
590
+ tokens[COMPONENT_PROPS[key] || tokenKey(key)] = translate(value);
591
+ }
592
+ components.push({ id, name: rawId.replace(/[-_]+/g, ' ').replace(/^./, (ch) => ch.toUpperCase()), category: componentCategory(id), tokens, states, notes: '' });
593
+ }
594
+ if (components.length) patch.components = components;
595
+ }
596
+ }
597
+
598
+ function bodyToPatch(body, patch, { ours = false } = {}) {
599
+ const sections = markdownSections(body);
600
+ const rules = sectionNamed(sections, /^do['’]?s?\s+(and|&)\s+don['’]?ts?/i);
601
+ if (rules) {
602
+ const dos = []; const donts = [];
603
+ for (const sub of rules.subs) (/don['’]?t|avoid|never/i.test(sub.title) ? donts : dos).push(...bulletsOf(sub.text));
604
+ for (const item of bulletsOf(rules.text)) {
605
+ const dont = /^(don['’]?t|avoid|never|❌)[:\s]+(.*)$/i.exec(item);
606
+ const doIt = /^(do|✅)[:\s]+(.*)$/i.exec(item);
607
+ if (dont) donts.push(dont[2]); else if (doIt) dos.push(doIt[2]); else dos.push(item);
608
+ }
609
+ const keep = (items) => items.filter((item) => !OUR_DEFAULT_RULES.has(item));
610
+ if (keep(dos).length) (patch.rules ||= {}).dos = keep(dos);
611
+ if (keep(donts).length) (patch.rules ||= {}).donts = keep(donts);
612
+ }
613
+ // Our own file holds the user's free Markdown between these two headings, headings of its own included.
614
+ const own = ours ? /(?:^|\n)## Project Rules\n([\s\S]*?)\n## Agent Instructions(?:\n|$)/.exec(String(body ?? '')) : null;
615
+ const custom = own ? null : (sectionNamed(sections, /^project rules$/i) || (!ours && sectionNamed(sections, /^iteration guide$/i)));
616
+ if (own && own[1].trim()) (patch.rules ||= {}).custom = own[1].trim();
617
+ if (custom && (custom.text || custom.subs.length)) {
618
+ const text = [custom.text, ...custom.subs.map((s) => `### ${s.title}\n\n${s.text}`)].filter(Boolean).join('\n\n');
619
+ (patch.rules ||= {}).custom = /^project rules$/i.test(custom.title) ? text : `## ${custom.title}\n\n${text}`;
620
+ }
621
+ // The rest of our own file is rendered from fields the frontmatter already carries.
622
+ if (ours) return;
623
+ const overview = sectionNamed(sections, /^(overview|visual theme)/i);
624
+ if (overview) {
625
+ const prose = proseOf(overview.text);
626
+ if (prose.length) (patch.brand ||= {}).vibe = prose.join('\n\n').slice(0, 1200);
627
+ const key = overview.subs.find((s) => /key characteristics/i.test(s.title));
628
+ if (key && bulletsOf(key.text).length) (patch.brand ||= {}).keyCharacteristics = bulletsOf(key.text).slice(0, 12);
629
+ }
630
+ const typography = sectionNamed(sections, /^typography/i);
631
+ const principles = typography?.subs.find((s) => /principles/i.test(s.title));
632
+ if (principles && bulletsOf(principles.text).length) (patch.typography ||= {}).principles = bulletsOf(principles.text).slice(0, 20);
633
+ const layout = sectionNamed(sections, /^layout/i);
634
+ const whitespace = layout?.subs.find((s) => /whitespace/i.test(s.title));
635
+ if (whitespace) {
636
+ const items = bulletsOf(whitespace.text).length ? bulletsOf(whitespace.text) : proseOf(whitespace.text);
637
+ if (items.length) (patch.layout ||= {}).principles = items.slice(0, 20);
638
+ }
639
+ const responsive = sectionNamed(sections, /^responsive/i);
640
+ if (responsive) {
641
+ const items = [...bulletsOf(responsive.text), ...responsive.subs.flatMap((s) => bulletsOf(s.text).map((item) => `${s.title}: ${item}`))];
642
+ if (items.length) patch.responsive = { notes: items.slice(0, 20) };
643
+ }
644
+ }
645
+
646
+ /** A DESIGN.md (ours, Stitch's or a community one) → { patch, warnings }. */
647
+ export function importDesignMd(text, options = {}) {
648
+ const warnings = [];
649
+ const patch = {};
650
+ let parts;
651
+ try { parts = splitFrontmatter(text); } catch (error) {
652
+ if (!(error instanceof ImportError)) throw error;
653
+ warnings.push(`The frontmatter could not be read (${error.message}); only the prose was imported.`);
654
+ parts = { data: null, body: String(text ?? '').replace(/^---[\s\S]*?\n---[ \t]*\n/, ''), hasFrontmatter: false };
655
+ }
656
+ if (isPlainObject(parts.data)) frontmatterToPatch(parts.data, patch, warnings, options);
657
+ else if (!warnings.length) warnings.push('No YAML frontmatter: tokens were not imported, only the prose.');
658
+ bodyToPatch(parts.body, patch, { ours: /Generated by SynaBun Style Guide/.test(parts.body) });
659
+ return { patch, warnings };
660
+ }
661
+
662
+ // ── DTCG ────────────────────────────────────────────────────────────────────
663
+
664
+ function dtcgColorValue(value) {
665
+ if (typeof value === 'string') return toHex(value);
666
+ if (!isPlainObject(value)) return null;
667
+ if (typeof value.hex === 'string' && toHex(value.hex)) {
668
+ const hex = toHex(value.hex).slice(0, 7);
669
+ return Number.isFinite(value.alpha) && value.alpha < 1 ? `${hex}${Math.round(value.alpha * 255).toString(16).padStart(2, '0')}` : hex;
670
+ }
671
+ if (Array.isArray(value.components) && value.components.length >= 3 && (!value.colorSpace || value.colorSpace === 'srgb')) {
672
+ const [r, g, b] = value.components.map((c) => Number(c) * 255);
673
+ return rgbToHex({ r, g, b, a: Number.isFinite(value.alpha) ? value.alpha : 1 });
674
+ }
675
+ return null;
676
+ }
677
+ function dtcgPx(value) {
678
+ if (isPlainObject(value) && Number.isFinite(Number(value.value))) return value.unit === 'rem' ? Number(value.value) * 16 : Number(value.value);
679
+ return toPx(value);
680
+ }
681
+ function dtcgShadowCss(value) {
682
+ const layers = (Array.isArray(value) ? value : [value]).filter(isPlainObject);
683
+ if (!layers.length) return null;
684
+ return layers.map((layer) => {
685
+ const color = dtcgColorValue(layer.color) || '#000000';
686
+ const n = (v) => { const p = dtcgPx(v) ?? 0; return p === 0 ? '0' : `${p}px`; };
687
+ return `${layer.inset ? 'inset ' : ''}${n(layer.offsetX)} ${n(layer.offsetY)} ${n(layer.blur)} ${n(layer.spread)} ${color}`;
688
+ }).join(', ');
689
+ }
690
+
691
+ /** A fontFamily token → a font, with the source, weights and features our own files record in $extensions. */
692
+ function namedFont(stack, options) {
693
+ const font = makeFont(stack.family, stack.fallback, options);
694
+ if (typeof stack.source === 'string') font.source = stack.source;
695
+ if (Array.isArray(stack.weights) && stack.weights.length) font.weights = stack.weights;
696
+ if (typeof stack.features === 'string') font.features = stack.features;
697
+ return font;
698
+ }
699
+
700
+ /** A W3C design-tokens document (text or object) → { patch, warnings }. */
701
+ export function importDtcg(input, options = {}) {
702
+ const warnings = [];
703
+ let doc = input;
704
+ if (typeof input === 'string') {
705
+ checkText(input);
706
+ try { doc = JSON.parse(input); } catch (error) { throw new ImportError('BAD_JSON', `Not valid JSON: ${error.message}`); }
707
+ }
708
+ checkTree(doc);
709
+ if (!isPlainObject(doc)) throw new ImportError('BAD_JSON', 'A design-tokens file is a JSON object');
710
+ const { tokens } = walkDtcg(doc);
711
+ const byPath = new Map(tokens.map((entry) => [entry.path.join('.'), entry]));
712
+ const deref = (entry, depth = 0) => (entry?.alias && depth < 8 ? deref(byPath.get(entry.alias), depth + 1) : entry);
713
+ const patch = {};
714
+ const colorEntries = [];
715
+ const styleMap = {};
716
+ const fontFamilies = {};
717
+ const ourAlias = (alias) => {
718
+ const parts = alias.split('.');
719
+ if (parts[0] !== 'color') return null;
720
+ if (parts[1] === 'semantic' && parts.length === 4) return `{semantic.${parts[3]}}`;
721
+ if (parts[1] === 'status' && parts.length === 3) return `{status.${parts[2]}}`;
722
+ return parts.length === 3 ? `{${kebab(parts[1])}.${parts[2]}}` : null;
723
+ };
724
+ for (const entry of tokens) {
725
+ const [head, ...rest] = entry.path;
726
+ const leaf = rest[rest.length - 1];
727
+ const target = deref(entry);
728
+ if (!target) { warnings.push(`${entry.path.join('.')}: alias {${entry.alias}} names no token`); continue; }
729
+ const value = target.value;
730
+ if (entry.type === 'color') {
731
+ const parts = head === 'color' || head === 'colors' ? rest : entry.path;
732
+ if (parts[0] === 'semantic' && THEMES.includes(parts[1]) && parts.length === 3) {
733
+ colorEntries.push([`${parts[1]}-${kebab(parts[2])}`, (entry.alias && ourAlias(entry.alias)) || dtcgColorValue(value)]);
734
+ } else if (parts[0] === 'status' && parts.length === 2) colorEntries.push([parts[1], dtcgColorValue(value)]);
735
+ else colorEntries.push([parts.join('-'), dtcgColorValue(value)]);
736
+ } else if (entry.type === 'fontFamily') {
737
+ const stack = splitFontStack(value);
738
+ if (stack && leaf) fontFamilies[leaf] = { ...stack, source: entry.extension?.source, weights: entry.extension?.weights, features: entry.extension?.features };
739
+ } else if (entry.type === 'typography' && isPlainObject(value)) {
740
+ const family = typeof value.fontFamily === 'string' && /^\{[^{}]+\}$/.test(value.fontFamily) ? deref(byPath.get(value.fontFamily.slice(1, -1)))?.value : value.fontFamily;
741
+ const size = dtcgPx(value.fontSize);
742
+ const spacing = dtcgPx(value.letterSpacing);
743
+ styleMap[leaf] = {
744
+ fontFamily: family, fontSize: size, fontWeight: value.fontWeight, lineHeight: isPlainObject(value.lineHeight) ? `${dtcgPx(value.lineHeight)}px` : value.lineHeight,
745
+ letterSpacing: spacing !== null && size ? `${Math.round((spacing / size) * 10000) / 10000}em` : 0, usage: entry.description,
746
+ mobileSize: entry.extension?.mobileSize, transform: entry.extension?.transform,
747
+ };
748
+ } else if (entry.type === 'dimension') {
749
+ const n = dtcgPx(value);
750
+ const key = tokenKey(leaf);
751
+ if (n === null || !key) continue;
752
+ if (/^(spacing|space)$/i.test(head)) (((patch.layout ||= {}).spacing ||= {}).scale ||= {})[key] = n;
753
+ else if (/^radius ?role/i.test(head)) { if (entry.alias?.startsWith('radius.')) ((patch.shape ||= {}).radiusRoles ||= {})[key] = entry.alias.slice(7); }
754
+ else if (/^(radius|rounded|borderradius)$/i.test(head)) ((patch.shape ||= {}).radius ||= {})[key] = n;
755
+ else if (/^(breakpoint|breakpoints|screens)$/i.test(head)) ((patch.layout ||= {}).breakpoints ||= {})[key] = n;
756
+ else if (/^(border|borderwidth)$/i.test(head)) ((patch.shape ||= {}).borders ||= {})[key] = n;
757
+ } else if (entry.type === 'shadow') {
758
+ // Our own files keep the CSS as it was written beside the structured value.
759
+ const css = typeof entry.extension?.css === 'string' ? entry.extension.css : dtcgShadowCss(value);
760
+ const none = isPlainObject(value) && dtcgColorValue(value.color)?.endsWith('00') && !dtcgPx(value.blur) && !dtcgPx(value.offsetY);
761
+ if (css) ((patch.shape ||= {}).elevation ||= {})[tokenKey(leaf)] = { shadow: none ? 'none' : css, usage: entry.description || '' };
762
+ } else if (entry.type === 'duration') {
763
+ const ms = isPlainObject(value) ? (value.unit === 's' ? Number(value.value) * 1000 : Number(value.value)) : toMs(value);
764
+ if (Number.isFinite(ms)) ((patch.motion ||= {}).durations ||= {})[tokenKey(leaf)] = ms;
765
+ } else if (entry.type === 'cubicBezier' && Array.isArray(value) && value.length === 4) {
766
+ ((patch.motion ||= {}).easings ||= {})[tokenKey(leaf)] = `cubic-bezier(${value.join(', ')})`;
767
+ } else if (entry.type === 'number' && /^z-?index$/i.test(head) && Number.isFinite(Number(value))) {
768
+ ((patch.layout ||= {}).zIndex ||= {})[tokenKey(leaf)] = Number(value);
769
+ }
770
+ }
771
+ const sorted = sortColors(colorEntries, warnings);
772
+ if (Object.keys(sorted.colors).length) patch.colors = sorted.colors;
773
+ const typography = sortTypography(styleMap, options, warnings);
774
+ if (typography) {
775
+ patch.typography = typography;
776
+ // Our own files name the families: keep those names instead of guessing from the style ids.
777
+ const named = Object.entries(fontFamilies).filter(([key]) => ['heading', 'body', 'mono', 'display'].includes(key));
778
+ if (named.length) {
779
+ typography.fonts = Object.fromEntries(named.map(([key, stack]) => [key, namedFont(stack, options)]));
780
+ for (const [id, style] of Object.entries(typography.styles)) {
781
+ const family = splitFontStack(styleMap[id]?.fontFamily)?.family;
782
+ style.font = named.find(([, stack]) => stack.family === family)?.[0] || style.font;
783
+ }
784
+ }
785
+ } else if (Object.keys(fontFamilies).length) {
786
+ const fonts = {};
787
+ for (const [key, stack] of Object.entries(fontFamilies)) {
788
+ const slot = ['heading', 'body', 'mono', 'display'].includes(key) ? key : /mono|code/.test(key) ? 'mono' : /head|display|title/.test(key) ? 'heading' : 'body';
789
+ fonts[slot] ||= namedFont(stack, options);
790
+ }
791
+ patch.typography = { fonts };
792
+ }
793
+ if (!tokens.length) warnings.push('No tokens found: a token is an object with a $value.');
794
+ return { patch, warnings };
795
+ }
796
+
797
+ // ── CSS custom properties ───────────────────────────────────────────────────
798
+
799
+ /** Every custom property in a stylesheet: [{ name, value, scope: 'root' | 'light' | 'dark' }] (comments removed). */
800
+ export function parseCssVars(css) {
801
+ const text = String(css ?? '').replace(/\/\*[\s\S]*?\*\//g, '');
802
+ const out = [];
803
+ const stack = [];
804
+ let buffer = '';
805
+ const scope = () => {
806
+ const context = stack.join(' ').toLowerCase();
807
+ if (/prefers-color-scheme:\s*dark|\.dark\b|theme=["']?dark|\bdark\b/.test(context)) return 'dark';
808
+ if (/prefers-color-scheme:\s*light|\.light\b|theme=["']?light/.test(context)) return 'light';
809
+ return 'root';
810
+ };
811
+ const declaration = (chunk) => {
812
+ const match = /^\s*(--[A-Za-z0-9_-]+|\$[A-Za-z0-9_-]+|color-scheme)\s*:\s*([\s\S]+?)\s*(?:!default\s*)?$/.exec(chunk);
813
+ if (match) out.push({ name: match[1].startsWith('$') ? `--${match[1].slice(1)}` : match[1], value: match[2].trim(), scope: scope() });
814
+ };
815
+ for (let i = 0; i < text.length; i++) {
816
+ const ch = text[i];
817
+ if (ch === '{') { stack.push(buffer.trim()); buffer = ''; }
818
+ else if (ch === '}') { declaration(buffer); buffer = ''; stack.pop(); }
819
+ else if (ch === ';') { declaration(buffer); buffer = ''; }
820
+ else buffer += ch;
821
+ }
822
+ declaration(buffer);
823
+ return out;
824
+ }
825
+
826
+ const VAR_RE = /^var\(\s*--([A-Za-z0-9_-]+)\s*(?:,\s*([\s\S]+))?\)$/;
827
+
828
+ /** CSS custom properties (any stylesheet, a Tailwind v4 `@theme` included) → { patch, warnings }. */
829
+ export function importCssVars(css, options = {}) {
830
+ checkText(css);
831
+ const warnings = [];
832
+ const vars = parseCssVars(css);
833
+ const patch = {};
834
+ const colorEntries = [];
835
+ const styleMap = {};
836
+ const fonts = {};
837
+ const rootScheme = vars.find((v) => v.name === 'color-scheme' && v.scope === 'root')?.value;
838
+ const themeOf = (v) => (v.scope === 'root' ? null : v.scope);
839
+ const colorAlias = (name) => {
840
+ const key = name.replace(/^color-/, '');
841
+ const stepped = /^(.+)-(50|100|200|300|400|500|600|700|800|900|950)$/.exec(key);
842
+ if (stepped) return `{${stepped[1]}.${stepped[2]}}`;
843
+ if (STATUS_KEYS.includes(key)) return `{status.${key}}`;
844
+ return null;
845
+ };
846
+ const style = (id) => (styleMap[id] ||= {});
847
+ for (const v of vars) {
848
+ if (v.name === 'color-scheme') continue;
849
+ const name = v.name.slice(2).toLowerCase();
850
+ const ref = VAR_RE.exec(v.value);
851
+ const value = ref ? (colorAlias(ref[1]) ? null : ref[2]?.trim() ?? null) : v.value;
852
+ let m;
853
+ if ((m = /^font-(heading|body|mono|display|sans|serif)$/.exec(name))) {
854
+ const stack = splitFontStack(v.value);
855
+ const slot = m[1] === 'sans' || m[1] === 'serif' ? 'body' : m[1];
856
+ if (stack && !(slot === 'body' && fonts.body && m[1] !== 'body')) fonts[slot] = makeFont(stack.family, stack.fallback, options);
857
+ } else if ((m = /^text-([a-z0-9-]+?)--(line-height|font-weight|letter-spacing)$/.exec(name)) || (m = /^text-([a-z0-9]+(?:-[a-z0-9]+)*?)-(size-mobile|size|weight|line-height|letter-spacing)$/.exec(name))) {
858
+ const field = { size: 'fontSize', 'size-mobile': 'mobileSize', weight: 'fontWeight', 'font-weight': 'fontWeight', 'line-height': 'lineHeight', 'letter-spacing': 'letterSpacing' }[m[2]];
859
+ style(m[1])[field] = v.value;
860
+ } else if ((m = /^text-([a-z0-9]+(?:-[a-z0-9]+)*?)-font$/.exec(name))) {
861
+ const font = /^var\(--font-(heading|body|mono|display)\)$/.exec(v.value);
862
+ if (font) style(m[1])._font = font[1];
863
+ } else if ((m = /^text-([a-z0-9-]+)$/.exec(name)) && toPx(v.value) !== null) {
864
+ style(m[1]).fontSize = v.value;
865
+ } else if (name === 'spacing' && toPx(v.value) !== null) {
866
+ ((patch.layout ||= {}).spacing ||= {}).base = toPx(v.value);
867
+ } else if ((m = /^(?:space|spacing)-([a-z0-9-]+)$/.exec(name)) && toPx(v.value) !== null) {
868
+ (((patch.layout ||= {}).spacing ||= {}).scale ||= {})[m[1]] = toPx(v.value);
869
+ } else if ((m = /^radius(?:-([a-z0-9-]+))?$/.exec(name))) {
870
+ const target = /^var\(--radius-([a-z0-9-]+)\)$/.exec(v.value);
871
+ if (target && m[1]) ((patch.shape ||= {}).radiusRoles ||= {})[m[1]] = target[1];
872
+ else if (toPx(v.value) !== null) ((patch.shape ||= {}).radius ||= {})[m[1] || 'md'] = toPx(v.value);
873
+ } else if ((m = /^border-([a-z0-9-]+)$/.exec(name)) && toPx(v.value) !== null) {
874
+ ((patch.shape ||= {}).borders ||= {})[m[1]] = toPx(v.value);
875
+ } else if ((m = /^shadow-([a-z0-9-]+)$/.exec(name))) {
876
+ ((patch.shape ||= {}).elevation ||= {})[m[1]] = { shadow: v.value === '0 0 #0000' ? 'none' : v.value };
877
+ } else if ((m = /^duration-([a-z0-9-]+)$/.exec(name))) {
878
+ // The reduced-motion block zeroes the durations: that is not the token's value.
879
+ if (toMs(v.value) !== null && !(patch.motion?.durations && m[1] in patch.motion.durations)) ((patch.motion ||= {}).durations ||= {})[m[1]] = toMs(v.value);
880
+ } else if ((m = /^ease-([a-z0-9-]+)$/.exec(name))) {
881
+ ((patch.motion ||= {}).easings ||= {})[m[1]] = v.value;
882
+ } else if ((m = /^breakpoint-([a-z0-9-]+)$/.exec(name)) && toPx(v.value) !== null) {
883
+ ((patch.layout ||= {}).breakpoints ||= {})[m[1]] = toPx(v.value);
884
+ } else if ((m = /^z-([a-z0-9-]+)$/.exec(name)) && Number.isFinite(Number(v.value))) {
885
+ ((patch.layout ||= {}).zIndex ||= {})[m[1]] = Number(v.value);
886
+ } else if (name === 'container-max' && toPx(v.value) !== null) ((patch.layout ||= {}).container ||= {}).maxWidth = toPx(v.value);
887
+ else if (name === 'container-padding' && toPx(v.value) !== null) ((patch.layout ||= {}).container ||= {}).padding = toPx(v.value);
888
+ else if (name === 'grid-columns' && Number.isFinite(Number(v.value))) ((patch.layout ||= {}).grid ||= {}).columns = Number(v.value);
889
+ else if (name === 'grid-gutter' && toPx(v.value) !== null) ((patch.layout ||= {}).grid ||= {}).gutter = toPx(v.value);
890
+ else if ((m = /^gradient-([a-z0-9-]+)$/.exec(name))) {
891
+ ((patch.colors ||= {}).gradients ||= []).push({ name: m[1], css: v.value, usage: '' });
892
+ } else {
893
+ const key = name.replace(/^color-/, '');
894
+ const alias = ref ? colorAlias(ref[1]) : null;
895
+ const color = alias || (value ? toHex(value) : null);
896
+ if (color) colorEntries.push([key, color, themeOf(v)]);
897
+ }
898
+ }
899
+ if (patch.shape?.radius) {
900
+ const roles = splitRadiusRoles(patch.shape.radius);
901
+ if (Object.keys(roles).length) patch.shape.radiusRoles = { ...roles, ...(patch.shape.radiusRoles || {}) };
902
+ if (!Object.keys(patch.shape.radius).length) delete patch.shape.radius;
903
+ }
904
+ // A root block that declares itself dark holds the dark theme's flat names.
905
+ const entries = rootScheme === 'dark' ? colorEntries.map(([key, color, theme]) => [key, color, theme || (ROLE_SYNONYMS[key] || SEMANTIC_ROLES.includes(roleFromName(key)) ? 'dark' : null)]) : colorEntries;
906
+ const sorted = sortColors(entries, warnings);
907
+ const gradients = patch.colors?.gradients;
908
+ if (Object.keys(sorted.colors).length) patch.colors = { ...sorted.colors, ...(gradients ? { gradients } : {}) };
909
+ if (rootScheme === 'dark' && patch.colors?.semantic?.dark && !patch.colors.semantic.light) patch.colors.themes = { default: 'dark', supports: ['dark'] };
910
+ const preset = Object.fromEntries(Object.entries(styleMap).map(([id, raw]) => [id, raw._font]));
911
+ for (const raw of Object.values(styleMap)) delete raw._font;
912
+ const typography = sortTypography(styleMap, options, warnings);
913
+ if (typography) {
914
+ for (const [id, s] of Object.entries(typography.styles)) if (preset[id]) s.font = preset[id];
915
+ delete typography.fonts;
916
+ patch.typography = typography;
917
+ }
918
+ if (Object.keys(fonts).length) (patch.typography ||= {}).fonts = fonts;
919
+ if (!vars.length) warnings.push('No CSS custom properties found.');
920
+ return { patch, warnings };
921
+ }
922
+
923
+ // ── Tailwind theme (JSON) ───────────────────────────────────────────────────
924
+
925
+ /** A Tailwind theme as JSON ({ theme: { extend } }, { theme }, { extend } or the theme itself) → { patch, warnings }. */
926
+ export function importTailwindTheme(input, options = {}) {
927
+ const warnings = [];
928
+ let doc = input;
929
+ if (typeof input === 'string') {
930
+ checkText(input);
931
+ try { doc = JSON.parse(input); } catch (error) { throw new ImportError('BAD_JSON', `Not valid JSON: ${error.message}`); }
932
+ }
933
+ checkTree(doc);
934
+ if (!isPlainObject(doc)) throw new ImportError('BAD_JSON', 'A Tailwind theme is a JSON object');
935
+ const base = isPlainObject(doc.theme) ? doc.theme : doc;
936
+ const theme = { ...base, ...(isPlainObject(base.extend) ? base.extend : {}) };
937
+ const patch = {};
938
+ if (isPlainObject(theme.colors)) {
939
+ const entries = [];
940
+ const literal = (value) => { const ref = typeof value === 'string' ? VAR_RE.exec(value.trim()) : null; return ref ? ref[2]?.trim() : value; };
941
+ for (const [name, value] of Object.entries(theme.colors)) {
942
+ if (isPlainObject(value)) {
943
+ for (const [step, color] of Object.entries(value)) {
944
+ if (step === 'DEFAULT') { if (!value['500']) entries.push([name, literal(color)]); } else entries.push([`${name}-${step}`, literal(color)]);
945
+ }
946
+ } else entries.push([name, literal(value)]);
947
+ }
948
+ const sorted = sortColors(entries.filter(([, value]) => typeof value === 'string' && toHex(value)), warnings, { realias: true });
949
+ if (Object.keys(sorted.colors).length) patch.colors = sorted.colors;
950
+ }
951
+ if (isPlainObject(theme.fontFamily)) {
952
+ const fonts = {};
953
+ for (const [key, value] of Object.entries(theme.fontFamily)) {
954
+ const stack = splitFontStack(value);
955
+ if (!stack) continue;
956
+ const slot = ['heading', 'body', 'mono', 'display'].includes(key) ? key : key === 'sans' || key === 'serif' ? 'body' : /mono|code/.test(key) ? 'mono' : /head|title/.test(key) ? 'heading' : null;
957
+ if (slot && !(fonts[slot] && (key === 'sans' || key === 'serif'))) fonts[slot] = makeFont(stack.family, stack.fallback, options);
958
+ }
959
+ if (Object.keys(fonts).length) patch.typography = { fonts };
960
+ }
961
+ if (isPlainObject(theme.fontSize)) {
962
+ const styleMap = {};
963
+ for (const [id, value] of Object.entries(theme.fontSize)) {
964
+ const [size, extra] = Array.isArray(value) ? value : [value, {}];
965
+ const more = isPlainObject(extra) ? extra : { lineHeight: extra };
966
+ styleMap[id] = { fontSize: size, lineHeight: more.lineHeight, letterSpacing: more.letterSpacing ?? 0, fontWeight: more.fontWeight };
967
+ }
968
+ const typography = sortTypography(styleMap, options, warnings);
969
+ if (typography) patch.typography = { ...(patch.typography || {}), styles: typography.styles };
970
+ }
971
+ const dims = (map, label) => dimensionMap(Object.fromEntries(Object.entries(map || {}).filter(([key]) => key !== 'DEFAULT')), warnings, label);
972
+ const spacing = isPlainObject(theme.spacing) ? dims(theme.spacing, 'Spacing') : null;
973
+ if (spacing) ((patch.layout ||= {}).spacing ||= {}).scale = Object.fromEntries(Object.entries(spacing).slice(0, 24));
974
+ const radius = isPlainObject(theme.borderRadius) ? dims(theme.borderRadius, 'Radius') : null;
975
+ if (radius) {
976
+ const roles = splitRadiusRoles(radius);
977
+ if (Object.keys(radius).length) (patch.shape ||= {}).radius = radius;
978
+ if (Object.keys(roles).length) (patch.shape ||= {}).radiusRoles = roles;
979
+ }
980
+ const borders = isPlainObject(theme.borderWidth) ? dims(theme.borderWidth, 'Border') : null;
981
+ if (borders) (patch.shape ||= {}).borders = borders;
982
+ const screens = isPlainObject(theme.screens) ? dims(theme.screens, 'Breakpoint') : null;
983
+ if (screens) (patch.layout ||= {}).breakpoints = screens;
984
+ if (isPlainObject(theme.boxShadow)) {
985
+ const elevation = {};
986
+ for (const [key, value] of Object.entries(theme.boxShadow)) if (typeof value === 'string' && tokenKey(key) && key !== 'DEFAULT') elevation[tokenKey(key)] = { shadow: value };
987
+ if (Object.keys(elevation).length) (patch.shape ||= {}).elevation = elevation;
988
+ }
989
+ if (isPlainObject(theme.zIndex)) {
990
+ const zIndex = Object.fromEntries(Object.entries(theme.zIndex).filter(([key, value]) => tokenKey(key) && Number.isFinite(Number(value))).map(([key, value]) => [tokenKey(key), Number(value)]));
991
+ if (Object.keys(zIndex).length) (patch.layout ||= {}).zIndex = zIndex;
992
+ }
993
+ if (isPlainObject(theme.transitionTimingFunction)) {
994
+ const easings = Object.fromEntries(Object.entries(theme.transitionTimingFunction).filter(([key, value]) => key !== 'DEFAULT' && typeof value === 'string').map(([key, value]) => [tokenKey(key), value]));
995
+ if (Object.keys(easings).length) (patch.motion ||= {}).easings = easings;
996
+ }
997
+ if (isPlainObject(theme.transitionDuration)) {
998
+ const durations = Object.fromEntries(Object.entries(theme.transitionDuration).filter(([key, value]) => key !== 'DEFAULT' && toMs(value) !== null).map(([key, value]) => [/^\d/.test(key) ? `d${key}` : tokenKey(key), toMs(value)]));
999
+ if (Object.keys(durations).length) (patch.motion ||= {}).durations = durations;
1000
+ }
1001
+ if (!Object.keys(patch).length) warnings.push('No theme values found: expected colors, fontFamily, fontSize, spacing, borderRadius, boxShadow or screens.');
1002
+ return { patch, warnings };
1003
+ }
1004
+
1005
+ // ── codebase scan ───────────────────────────────────────────────────────────
1006
+
1007
+ /** The object literal after `key:` in JS source, as text (braces matched, strings skipped), or null. */
1008
+ function objectLiteralAfter(source, key) {
1009
+ const match = new RegExp(`(?:^|[\\s,{])["']?${key}["']?\\s*:\\s*\\{`).exec(source);
1010
+ if (!match) return null;
1011
+ const start = match.index + match[0].length - 1;
1012
+ let depth = 0; let quote = null;
1013
+ for (let i = start; i < source.length; i++) {
1014
+ const ch = source[i];
1015
+ if (quote) { if (ch === '\\') i++; else if (ch === quote) quote = null; continue; }
1016
+ if (ch === '"' || ch === "'" || ch === '`') quote = ch;
1017
+ else if (ch === '{') depth++;
1018
+ else if (ch === '}' && --depth === 0) return source.slice(start, i + 1);
1019
+ }
1020
+ return null;
1021
+ }
1022
+
1023
+ /** A JS object literal of plain values → an object, or null: quotes the keys, drops comments and trailing commas. */
1024
+ function looseObject(literal) {
1025
+ if (!literal) return null;
1026
+ const json = literal
1027
+ .replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:"'])\/\/[^\n]*/g, '$1')
1028
+ .replace(/'((?:[^'\\]|\\.)*)'/g, (_, body) => JSON.stringify(body.replace(/\\'/g, "'")))
1029
+ .replace(/([{,]\s*)([A-Za-z_$][\w$-]*|\d+)\s*:/g, '$1"$2":')
1030
+ .replace(/,(\s*[}\]])/g, '$1');
1031
+ try { return JSON.parse(json); } catch { return null; }
1032
+ }
1033
+
1034
+ /** What a tailwind.config.* file says about the theme, read as text (the file is never executed). */
1035
+ export function tailwindConfigTheme(source) {
1036
+ const theme = {};
1037
+ for (const key of ['colors', 'fontFamily', 'fontSize', 'borderRadius', 'boxShadow', 'screens', 'spacing']) {
1038
+ const value = looseObject(objectLiteralAfter(String(source ?? ''), key));
1039
+ if (isPlainObject(value)) theme[key] = value;
1040
+ }
1041
+ return theme;
1042
+ }
1043
+
1044
+ /**
1045
+ * Read the project's own styling: `*.css`, `*.scss`, `tailwind.config.*` and a hand-written DESIGN.md,
1046
+ * skipping node_modules, dist, build, .git and SynaBun's own output, at most `maxFiles` files of
1047
+ * 1 MB each. Later sources win: DESIGN.md, then the Tailwind config, then the stylesheets.
1048
+ * `fs` needs readdirSync (withFileTypes), readFileSync and statSync. → { patch, warnings, files }.
1049
+ */
1050
+ export function scanCodebase(root, { fs = nodeFs, maxFiles = SCAN_MAX_FILES, googleFonts = null } = {}) {
1051
+ maxFiles = Math.min(SCAN_MAX_FILES, Math.max(1, Math.floor(Number(maxFiles) || SCAN_MAX_FILES)));
1052
+ const warnings = [];
1053
+ const found = [];
1054
+ const queue = [root];
1055
+ let capped = false;
1056
+ let dirs = 0;
1057
+ while (queue.length && !capped) {
1058
+ const dir = queue.shift();
1059
+ if (++dirs > 4000) { warnings.push('Stopped after 4000 directories.'); break; }
1060
+ if (fs === nodeFs && !containedPath(root, dir, { noSymlinks: true })) continue;
1061
+ let entries = [];
1062
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { continue; }
1063
+ entries.sort((a, b) => a.name.localeCompare(b.name));
1064
+ for (const entry of entries) {
1065
+ const path = join(dir, entry.name);
1066
+ if (entry.isSymbolicLink?.()) continue;
1067
+ if (entry.isDirectory()) { if (!SCAN_SKIP_DIRS.has(entry.name)) queue.push(path); continue; }
1068
+ if (!entry.isFile()) continue;
1069
+ const kind = /^tailwind\.config\.(js|cjs|mjs|ts)$/.test(entry.name) ? 'tailwind' : /\.(css|scss)$/i.test(entry.name) && !/\.min\.css$/i.test(entry.name) ? 'css' : (entry.name === 'DESIGN.md' && dir === root) ? 'design-md' : null;
1070
+ if (!kind) continue;
1071
+ if (found.length >= maxFiles) { capped = true; break; }
1072
+ found.push({ path, kind });
1073
+ }
1074
+ }
1075
+ if (capped) warnings.push(`Stopped after ${maxFiles} files: the rest of the project was not read.`);
1076
+ const read = (path) => {
1077
+ try {
1078
+ if (fs === nodeFs && !containedPath(root, path, { noSymlinks: true })) return null;
1079
+ if (fs.statSync(path).size > SCAN_MAX_BYTES) return null;
1080
+ const text = fs.readFileSync(path, 'utf8');
1081
+ return Buffer.byteLength(text) <= SCAN_MAX_BYTES ? text : null;
1082
+ } catch { return null; }
1083
+ };
1084
+ const options = { googleFonts };
1085
+ let patch = {};
1086
+ const files = [];
1087
+ const add = (file, result) => {
1088
+ for (const warning of result.warnings) if (!/^No (CSS custom properties|theme values|YAML frontmatter)/.test(warning)) warnings.push(`${file}: ${warning}`);
1089
+ if (!Object.keys(result.patch).length) return;
1090
+ patch = applyMergePatch(patch, result.patch);
1091
+ files.push(file);
1092
+ };
1093
+ const rel = (path) => relative(root, path).split(sep).join('/');
1094
+ for (const kind of ['design-md', 'tailwind', 'css']) {
1095
+ for (const file of found.filter((entry) => entry.kind === kind)) {
1096
+ const text = read(file.path);
1097
+ if (text === null) continue;
1098
+ try {
1099
+ if (kind === 'design-md') { if (!/Generated by SynaBun Style Guide/.test(text)) add(rel(file.path), importDesignMd(text, options)); }
1100
+ else if (kind === 'tailwind') add(rel(file.path), importTailwindTheme(tailwindConfigTheme(text), options));
1101
+ else if (/--[A-Za-z]|\$[A-Za-z][\w-]*\s*:/.test(text)) add(rel(file.path), importCssVars(text, options));
1102
+ } catch (error) { warnings.push(`${rel(file.path)}: ${error.message}`); }
1103
+ }
1104
+ }
1105
+ if (!files.length) warnings.push('No design tokens found in this project (looked for CSS custom properties, a Tailwind config and a DESIGN.md).');
1106
+ return { patch, warnings, files, scanned: found.length };
1107
+ }
1108
+
1109
+ // ── community ───────────────────────────────────────────────────────────────
1110
+
1111
+ /**
1112
+ * Fetch `design-md/<slug>/DESIGN.md` from the community collection. The slug is checked against
1113
+ * COMMUNITY_SLUG_RE before any request; the request stops after `timeoutMs`. Throws ImportError.
1114
+ */
1115
+ export async function fetchCommunityDesignMd(slug, { fetchImpl = globalThis.fetch, timeoutMs = 10000, maxBytes = MAX_IMPORT_BYTES } = {}) {
1116
+ const name = String(slug ?? '').trim().toLowerCase();
1117
+ if (!COMMUNITY_SLUG_RE.test(name) || name.includes('..') || name.startsWith('.') || name.endsWith('.')) throw new ImportError('BAD_SLUG', 'A community slug is 1 to 40 characters: a-z, 0-9, "." and "-".');
1118
+ if (typeof fetchImpl !== 'function') throw new ImportError('FETCH_UNAVAILABLE', 'No fetch available', 500);
1119
+ const url = `${COMMUNITY_BASE_URL}/${name}/DESIGN.md`;
1120
+ const controller = new AbortController();
1121
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
1122
+ try {
1123
+ const response = await fetchImpl(url, { signal: controller.signal, redirect: 'error', headers: { Accept: 'text/plain' } });
1124
+ if (response.status === 404) throw new ImportError('NOT_FOUND', `No community DESIGN.md named "${name}".`, 404);
1125
+ if (!response.ok) throw new ImportError('FETCH_FAILED', `The community collection answered HTTP ${response.status}.`, 502);
1126
+ if (response.redirected || (response.url && response.url !== url)) throw new ImportError('FETCH_FAILED', 'Community redirects are not allowed.', 502);
1127
+ if (Number(response.headers?.get('content-length')) > maxBytes) {
1128
+ controller.abort();
1129
+ throw new ImportError('TOO_LARGE', 'That DESIGN.md is too large to import.', 413);
1130
+ }
1131
+ let text;
1132
+ if (response.body?.getReader) {
1133
+ const reader = response.body.getReader();
1134
+ const decoder = new TextDecoder();
1135
+ const chunks = [];
1136
+ let bytes = 0;
1137
+ try {
1138
+ while (true) {
1139
+ const { done, value } = await reader.read();
1140
+ if (done) break;
1141
+ bytes += value.byteLength;
1142
+ if (bytes > maxBytes) {
1143
+ controller.abort();
1144
+ await reader.cancel().catch(() => {});
1145
+ throw new ImportError('TOO_LARGE', 'That DESIGN.md is too large to import.', 413);
1146
+ }
1147
+ chunks.push(decoder.decode(value, { stream: true }));
1148
+ }
1149
+ text = chunks.join('') + decoder.decode();
1150
+ } finally { reader.releaseLock(); }
1151
+ } else text = await response.text(); // Injected test adapters without a response stream.
1152
+ if (Buffer.byteLength(text) > maxBytes) throw new ImportError('TOO_LARGE', 'That DESIGN.md is too large to import.', 413);
1153
+ return { text, url, slug: name };
1154
+ } catch (error) {
1155
+ if (error instanceof ImportError) throw error;
1156
+ if (controller.signal.aborted) throw new ImportError('TIMEOUT', `The community collection did not answer within ${Math.round(timeoutMs / 1000)} s.`, 504);
1157
+ throw new ImportError('FETCH_FAILED', `Could not reach the community collection: ${error?.message || error}`, 502);
1158
+ } finally {
1159
+ clearTimeout(timer);
1160
+ }
1161
+ }
1162
+
1163
+ // ── applying an import ──────────────────────────────────────────────────────
1164
+
1165
+ // Maps an import replaces whole in `replace` mode (otherwise the defaults' entries would stay beside the imported ones).
1166
+ const REPLACED_MAPS = Object.freeze([
1167
+ ['typography', 'styles'], ['layout', 'spacing', 'scale'], ['layout', 'breakpoints'], ['layout', 'zIndex'],
1168
+ ['shape', 'radius'], ['shape', 'elevation'], ['shape', 'borders'], ['motion', 'durations'], ['motion', 'easings'],
1169
+ ]);
1170
+ const at = (object, path) => path.reduce((node, key) => (isPlainObject(node) ? node[key] : undefined), object);
1171
+
1172
+ /**
1173
+ * The config an import produces. `merge`: the patch over the current guide. `replace`: the patch over
1174
+ * the defaults, keeping what is not a design decision (the project, the revision, the logo files, the
1175
+ * agent and export settings). Missing font roles keep their stored values in merge and use the
1176
+ * schema defaults in replace (including the default heading family). → { config, diff (against `base`) }.
1177
+ */
1178
+ export function buildImport(base, patch, { merge = 'merge' } = {}) {
1179
+ const current = normalizeStyleGuide(base);
1180
+ let start = current;
1181
+ if (merge === 'replace') {
1182
+ start = defaultStyleGuide(current.projectPath);
1183
+ Object.assign(start, { revision: current.revision, updatedAt: current.updatedAt, logo: current.logo, agents: current.agents, exports: current.exports });
1184
+ for (const path of REPLACED_MAPS) {
1185
+ if (isPlainObject(at(patch, path))) at(start, path.slice(0, -1))[path[path.length - 1]] = {};
1186
+ }
1187
+ if (isPlainObject(patch?.colors?.semantic)) for (const theme of THEMES) if (patch.colors.semantic[theme]) start.colors.semantic[theme] = {};
1188
+ }
1189
+ const { components, ...rest } = isPlainObject(patch) ? patch : {};
1190
+ // A guide without a brand name is rendered under its folder's name: reading that back is not a brand name.
1191
+ if (!current.brand.name && rest.brand?.name && rest.brand.name === basename(current.projectPath.replace(/[\\/]+$/, ''))) {
1192
+ const { name: _folder, ...brand } = rest.brand;
1193
+ rest.brand = brand;
1194
+ }
1195
+ const gradients = rest.colors?.gradients;
1196
+ const body = gradients ? { ...rest, colors: { ...rest.colors } } : { ...rest };
1197
+ if (gradients) delete body.colors.gradients;
1198
+ if (merge === 'merge' && isPlainObject(body.typography?.fonts)) {
1199
+ // The same family keeps the weights the guide lists: an import only knows the ones its text styles use.
1200
+ body.typography = { ...body.typography, fonts: Object.fromEntries(Object.entries(body.typography.fonts).map(([key, font]) => {
1201
+ if (!isPlainObject(font) || font.family !== current.typography.fonts[key]?.family) return [key, font];
1202
+ const { weights: _weights, fallback: _fallback, ...kept } = font;
1203
+ return [key, kept];
1204
+ })) };
1205
+ }
1206
+ const merged = applyMergePatch(start, body);
1207
+ // Arrays are replaced whole by a merge patch; components and gradients merge by id / name instead.
1208
+ const same = (a, b) => resolveText(current, a).text.replace(/\s+/g, '') === resolveText(current, b).text.replace(/\s+/g, '')
1209
+ || (isAlias(a) && isAlias(b) && resolveAlias(current, a).ok && JSON.stringify(resolveAlias(current, a).value) === JSON.stringify(resolveAlias(current, b).value));
1210
+ if (Array.isArray(components)) {
1211
+ if (merge === 'replace') merged.components = components;
1212
+ else {
1213
+ const list = merged.components.map((component) => ({ ...component, tokens: { ...component.tokens }, states: { ...component.states } }));
1214
+ for (const incoming of components) {
1215
+ const existing = list.find((component) => component.id === incoming.id);
1216
+ if (!existing) { list.push(incoming); continue; }
1217
+ for (const [key, value] of Object.entries(incoming.tokens || {})) if (!(key in existing.tokens) || !same(existing.tokens[key], value)) existing.tokens[key] = value;
1218
+ for (const [key, value] of Object.entries(incoming.states || {})) if (value) existing.states[key] = value;
1219
+ }
1220
+ merged.components = list;
1221
+ }
1222
+ }
1223
+ if (Array.isArray(gradients)) {
1224
+ if (merge === 'replace') merged.colors.gradients = gradients;
1225
+ else {
1226
+ const list = merged.colors.gradients.map((gradient) => ({ ...gradient }));
1227
+ for (const incoming of gradients) {
1228
+ const existing = list.find((gradient) => gradient.name === incoming.name);
1229
+ if (!existing) list.push(incoming);
1230
+ else if (!same(existing.css, incoming.css)) existing.css = incoming.css;
1231
+ }
1232
+ merged.colors.gradients = list;
1233
+ }
1234
+ }
1235
+ const config = normalizeStyleGuide(merged, { projectPath: current.projectPath });
1236
+ return { config, diff: diffConfigs(current, config) };
1237
+ }
1238
+
1239
+ /**
1240
+ * One import, start to finish. `deps`: { fs, fetchImpl, googleFonts, projectRoot }.
1241
+ * → { config, diff, warnings, patch, files?, source? }. Throws ImportError for a bad request.
1242
+ */
1243
+ export async function runImport({ kind, text = '', slug = '', base, merge = 'merge', deps = {} } = {}) {
1244
+ if (!IMPORT_KINDS.includes(kind)) throw new ImportError('BAD_KIND', `kind must be one of: ${IMPORT_KINDS.join(', ')}`);
1245
+ if (!['merge', 'replace'].includes(merge)) throw new ImportError('BAD_MERGE', 'merge must be "merge" or "replace"');
1246
+ if (typeof text === 'string' && Buffer.byteLength(text) > MAX_IMPORT_BYTES) throw new ImportError('TOO_LARGE', 'That file is too large to import.', 413);
1247
+ const options = { googleFonts: deps.googleFonts || null };
1248
+ let result;
1249
+ const extra = {};
1250
+ if (kind === 'codebase') {
1251
+ if (!deps.projectRoot) throw new ImportError('NO_PROJECT', 'A codebase scan needs the project root.');
1252
+ result = scanCodebase(deps.projectRoot, { fs: deps.fs || nodeFs, googleFonts: options.googleFonts });
1253
+ extra.files = result.files;
1254
+ } else if (kind === 'community') {
1255
+ const fetched = await fetchCommunityDesignMd(slug, { fetchImpl: deps.fetchImpl || globalThis.fetch, timeoutMs: deps.timeoutMs || 10000 });
1256
+ result = importDesignMd(fetched.text, options);
1257
+ result.warnings.unshift(COMMUNITY_ATTRIBUTION);
1258
+ extra.source = fetched.url;
1259
+ } else {
1260
+ if (typeof text !== 'string' || !text.trim()) throw new ImportError('NO_TEXT', 'text is required for this kind of import.');
1261
+ if (kind === 'design-md') result = importDesignMd(text, options);
1262
+ else if (kind === 'dtcg') result = importDtcg(text, options);
1263
+ else if (kind === 'css') result = importCssVars(text, options);
1264
+ else result = importTailwindTheme(text, options);
1265
+ }
1266
+ const built = buildImport(base, result.patch, { merge });
1267
+ return { ...built, warnings: result.warnings, patch: result.patch, ...extra };
1268
+ }