synabun 2.0.10 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (656) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/README.md +25 -2
  3. package/THIRD-PARTY-LICENSES.md +22 -0
  4. package/bin/synabun.js +71 -24
  5. package/docs/whatsapp.md +13 -13
  6. package/hooks/claude-code/pre-websearch.mjs +12 -1
  7. package/hooks/claude-code/shared.mjs +5 -0
  8. package/hooks/claude-code/stop.mjs +1 -1
  9. package/lib/claude-hooks.js +172 -18
  10. package/lib/client-config-repair.js +30 -17
  11. package/lib/desktop-app.js +7 -1
  12. package/lib/external-tools.js +7 -6
  13. package/lib/first-launch-protection.js +57 -12
  14. package/lib/mcp-dist.js +176 -0
  15. package/lib/release-npm-ci.mjs +138 -0
  16. package/lib/release-publish.mjs +91 -0
  17. package/lib/release-scan.mjs +50 -0
  18. package/lib/server-crash-record.js +123 -0
  19. package/lib/server-exit.js +318 -0
  20. package/lib/server-supervisor.js +508 -0
  21. package/lib/start-launcher.js +37 -4
  22. package/lib/tools-cli.js +45 -0
  23. package/lib/update-snapshot.js +302 -0
  24. package/lib/virustotal.mjs +203 -0
  25. package/lib/windows-crash-event.js +269 -0
  26. package/mcp-server/dist/http.d.ts +20 -1
  27. package/mcp-server/dist/http.d.ts.map +1 -1
  28. package/mcp-server/dist/http.js +59 -12
  29. package/mcp-server/dist/http.js.map +1 -1
  30. package/mcp-server/dist/index.d.ts +33 -27
  31. package/mcp-server/dist/index.d.ts.map +1 -1
  32. package/mcp-server/dist/index.js +128 -143
  33. package/mcp-server/dist/index.js.map +1 -1
  34. package/mcp-server/dist/preload.js +1 -1
  35. package/mcp-server/dist/preload.js.map +1 -1
  36. package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
  37. package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
  38. package/mcp-server/dist/services/budget-judgments.js +5 -3
  39. package/mcp-server/dist/services/budget-judgments.js.map +1 -1
  40. package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
  41. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  42. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  43. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  44. package/mcp-server/dist/services/identity.d.ts +2 -2
  45. package/mcp-server/dist/services/identity.js +2 -2
  46. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  47. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  48. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  49. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  50. package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
  51. package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
  52. package/mcp-server/dist/services/memory-sessions.js +28 -2
  53. package/mcp-server/dist/services/memory-sessions.js.map +1 -1
  54. package/mcp-server/dist/services/neural-interface.d.ts +18 -11
  55. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  56. package/mcp-server/dist/services/neural-interface.js +67 -11
  57. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  58. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  59. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  60. package/mcp-server/dist/services/server-instructions.js +22 -63
  61. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  62. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  63. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  64. package/mcp-server/dist/services/tool-catalog.js +339 -0
  65. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  66. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  67. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  68. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  69. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  70. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  71. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  72. package/mcp-server/dist/services/tool-list.js +334 -0
  73. package/mcp-server/dist/services/tool-list.js.map +1 -0
  74. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  75. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  76. package/mcp-server/dist/services/tool-runtime.js +400 -0
  77. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  78. package/mcp-server/dist/services/typesafe-config.js +1 -1
  79. package/mcp-server/dist/services/typesafe-config.js.map +1 -1
  80. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  81. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  82. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  83. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  84. package/mcp-server/dist/tools/agents.d.ts +14 -14
  85. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  86. package/mcp-server/dist/tools/agents.js +29 -19
  87. package/mcp-server/dist/tools/agents.js.map +1 -1
  88. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  89. package/mcp-server/dist/tools/choice.d.ts +6 -0
  90. package/mcp-server/dist/tools/choice.d.ts.map +1 -1
  91. package/mcp-server/dist/tools/choice.js +18 -13
  92. package/mcp-server/dist/tools/choice.js.map +1 -1
  93. package/mcp-server/dist/tools/git-tools.js +2 -2
  94. package/mcp-server/dist/tools/git-tools.js.map +1 -1
  95. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  96. package/mcp-server/dist/tools/image-tools.js +1 -1
  97. package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
  98. package/mcp-server/dist/tools/morelogin.js +9 -6
  99. package/mcp-server/dist/tools/morelogin.js.map +1 -1
  100. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  101. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  102. package/mcp-server/dist/tools/skill-tools.js +642 -0
  103. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  104. package/mcp-server/dist/tools/skill.d.ts +7 -0
  105. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  106. package/mcp-server/dist/tools/skill.js +11 -0
  107. package/mcp-server/dist/tools/skill.js.map +1 -0
  108. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  109. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  110. package/mcp-server/dist/tools/tool-groups.js +147 -0
  111. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  112. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  113. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  114. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  115. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  116. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  117. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  118. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  119. package/mcp-server/package-lock.json +2 -2
  120. package/mcp-server/package.json +1 -1
  121. package/mcp-server/src/http.ts +75 -12
  122. package/mcp-server/src/index.ts +147 -154
  123. package/mcp-server/src/preload.ts +12 -12
  124. package/mcp-server/src/services/budget-judgments.ts +5 -3
  125. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  126. package/mcp-server/src/services/identity.ts +2 -2
  127. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  128. package/mcp-server/src/services/memory-sessions.ts +24 -3
  129. package/mcp-server/src/services/neural-interface.ts +81 -21
  130. package/mcp-server/src/services/server-instructions.ts +29 -64
  131. package/mcp-server/src/services/tool-catalog.ts +403 -0
  132. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  133. package/mcp-server/src/services/tool-list.ts +410 -0
  134. package/mcp-server/src/services/tool-runtime.ts +457 -0
  135. package/mcp-server/src/services/typesafe-config.ts +1 -1
  136. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  137. package/mcp-server/src/tools/agents.ts +29 -20
  138. package/mcp-server/src/tools/choice.ts +17 -12
  139. package/mcp-server/src/tools/git-tools.ts +2 -2
  140. package/mcp-server/src/tools/image-tools.ts +1 -1
  141. package/mcp-server/src/tools/morelogin.ts +6 -4
  142. package/mcp-server/src/tools/skill-tools.ts +592 -0
  143. package/mcp-server/src/tools/skill.ts +13 -0
  144. package/mcp-server/src/tools/tool-groups.ts +164 -0
  145. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  146. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  147. package/neural-interface/i18n/en.json +3953 -228
  148. package/neural-interface/i18n/pt-BR.json +3901 -179
  149. package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
  150. package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
  151. package/neural-interface/lib/antigravity/acp-connection.js +299 -0
  152. package/neural-interface/lib/antigravity/bypass.js +100 -0
  153. package/neural-interface/lib/antigravity/catalog.js +273 -0
  154. package/neural-interface/lib/antigravity/home.js +260 -0
  155. package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
  156. package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
  157. package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
  158. package/neural-interface/lib/antigravity/policy.js +74 -0
  159. package/neural-interface/lib/antigravity/tool-call.js +178 -0
  160. package/neural-interface/lib/antigravity/transcripts.js +252 -0
  161. package/neural-interface/lib/antigravity/usage.js +43 -0
  162. package/neural-interface/lib/assistant-api.js +128 -28
  163. package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
  164. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  165. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  166. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  167. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  168. package/neural-interface/lib/assistant-brains/opencode.js +120 -54
  169. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
  170. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
  171. package/neural-interface/lib/assistant-budget-planner.js +7 -3
  172. package/neural-interface/lib/assistant-budget-split.js +42 -15
  173. package/neural-interface/lib/assistant-catalog.js +81 -15
  174. package/neural-interface/lib/assistant-config.js +6 -3
  175. package/neural-interface/lib/assistant-dispatch.js +1073 -200
  176. package/neural-interface/lib/assistant-envelope.js +156 -2
  177. package/neural-interface/lib/assistant-evidence.js +80 -0
  178. package/neural-interface/lib/assistant-hidden-models.js +7 -5
  179. package/neural-interface/lib/assistant-persona.js +93 -19
  180. package/neural-interface/lib/assistant-plan-permissions.js +25 -9
  181. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  182. package/neural-interface/lib/assistant-route-gate.js +6 -4
  183. package/neural-interface/lib/assistant-router.js +245 -38
  184. package/neural-interface/lib/assistant-runtime.js +214 -30
  185. package/neural-interface/lib/assistant-task-prompt.js +87 -21
  186. package/neural-interface/lib/assistant-tools.js +51 -0
  187. package/neural-interface/lib/assistant-usage.js +29 -0
  188. package/neural-interface/lib/backup-service.js +626 -4
  189. package/neural-interface/lib/backup-zip-reader.js +10 -5
  190. package/neural-interface/lib/backup-zip-writer.js +257 -0
  191. package/neural-interface/lib/browser-execution.js +10 -2
  192. package/neural-interface/lib/browser-guard-cdp.js +84 -0
  193. package/neural-interface/lib/browser-network-guard.js +476 -0
  194. package/neural-interface/lib/browser-policy-roots.js +64 -0
  195. package/neural-interface/lib/browser-tool-policy.js +198 -38
  196. package/neural-interface/lib/claude-agent-bridge.js +11 -2
  197. package/neural-interface/lib/claude-history-cache.js +210 -0
  198. package/neural-interface/lib/claude-hooks-status.js +103 -0
  199. package/neural-interface/lib/claude-model-catalog.js +5 -1
  200. package/neural-interface/lib/claude-temporary.js +5 -11
  201. package/neural-interface/lib/cli-install-api.js +1 -1
  202. package/neural-interface/lib/cli-install.js +163 -154
  203. package/neural-interface/lib/cli-resolver.js +13 -3
  204. package/neural-interface/lib/cli-update-planner.js +52 -41
  205. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  206. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  207. package/neural-interface/lib/codex-rollout-reader.js +52 -0
  208. package/neural-interface/lib/codex-worker-app-server.js +191 -0
  209. package/neural-interface/lib/confined-fs.js +30 -3
  210. package/neural-interface/lib/crash-notice-api.js +98 -0
  211. package/neural-interface/lib/editor-completion-opencode.js +68 -68
  212. package/neural-interface/lib/editor-git-api.js +3 -20
  213. package/neural-interface/lib/exec-loop-command.js +13 -10
  214. package/neural-interface/lib/file-explorer-api.js +74 -40
  215. package/neural-interface/lib/file-explorer-watch.js +9 -3
  216. package/neural-interface/lib/git-bash/install.js +52 -6
  217. package/neural-interface/lib/git-bash/manager.js +59 -17
  218. package/neural-interface/lib/git-bash/pins.js +12 -0
  219. package/neural-interface/lib/git-read.js +2 -2
  220. package/neural-interface/lib/git-status-runner.js +390 -0
  221. package/neural-interface/lib/git-status-watchdog.js +40 -0
  222. package/neural-interface/lib/greeting/budgets.js +1 -0
  223. package/neural-interface/lib/greeting/engine.js +2 -2
  224. package/neural-interface/lib/greeting/sources.js +10 -12
  225. package/neural-interface/lib/greeting/writer.js +1 -1
  226. package/neural-interface/lib/http-guards.js +8 -2
  227. package/neural-interface/lib/install-details.js +4 -1
  228. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  229. package/neural-interface/lib/mcp-client-config.js +35 -33
  230. package/neural-interface/lib/mcp-external-servers.js +332 -0
  231. package/neural-interface/lib/mcp-installer.js +2 -1
  232. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  233. package/neural-interface/lib/memory-session-capture.js +17 -3
  234. package/neural-interface/lib/morelogin.js +177 -25
  235. package/neural-interface/lib/native-loop-providers.js +965 -66
  236. package/neural-interface/lib/native-loop-runtime.js +290 -42
  237. package/neural-interface/lib/opencode-config.js +557 -0
  238. package/neural-interface/lib/opencode-db-schema.js +17 -34
  239. package/neural-interface/lib/opencode-history.js +48 -218
  240. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  241. package/neural-interface/lib/opencode-native-boundary.js +53 -0
  242. package/neural-interface/lib/opencode-protocol.js +249 -112
  243. package/neural-interface/lib/opencode-runtime-config.js +32 -22
  244. package/neural-interface/lib/opencode-serve-records.js +39 -21
  245. package/neural-interface/lib/opencode-v2-client.js +48 -153
  246. package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
  247. package/neural-interface/lib/opencode-worker-data.js +27 -0
  248. package/neural-interface/lib/opencode2-client.js +73 -37
  249. package/neural-interface/lib/opencode2-proxy.js +23 -63
  250. package/neural-interface/lib/opencode2-translate.js +51 -2
  251. package/neural-interface/lib/owner-authority.js +249 -0
  252. package/neural-interface/lib/page-session.js +275 -0
  253. package/neural-interface/lib/path-confine.js +12 -9
  254. package/neural-interface/lib/peer-identity.js +793 -0
  255. package/neural-interface/lib/pty-host/core.js +28 -1
  256. package/neural-interface/lib/pty-host/lifetime.js +12 -0
  257. package/neural-interface/lib/pty-host/manager.js +12 -1
  258. package/neural-interface/lib/remote-policy.js +1 -1
  259. package/neural-interface/lib/request-gate.js +20 -2
  260. package/neural-interface/lib/rulesets/api.js +7 -6
  261. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  262. package/neural-interface/lib/rulesets/installer.js +180 -36
  263. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  264. package/neural-interface/lib/rulesets/render.js +1 -1
  265. package/neural-interface/lib/session-cache-builder.js +81 -31
  266. package/neural-interface/lib/session-title-generator.js +58 -36
  267. package/neural-interface/lib/skills/api-v2.js +495 -0
  268. package/neural-interface/lib/skills/bundle.js +418 -0
  269. package/neural-interface/lib/skills/catalog.js +298 -0
  270. package/neural-interface/lib/skills/creation-api.js +191 -0
  271. package/neural-interface/lib/skills/creation-brief.js +247 -0
  272. package/neural-interface/lib/skills/creation-sources.js +285 -0
  273. package/neural-interface/lib/skills/creation.js +843 -0
  274. package/neural-interface/lib/skills/deploy.js +569 -0
  275. package/neural-interface/lib/skills/digest.js +119 -0
  276. package/neural-interface/lib/skills/discover.js +111 -0
  277. package/neural-interface/lib/skills/draft-confinement.js +216 -0
  278. package/neural-interface/lib/skills/eval-confinement.js +399 -0
  279. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  280. package/neural-interface/lib/skills/eval-trace.js +135 -0
  281. package/neural-interface/lib/skills/evals-api.js +212 -0
  282. package/neural-interface/lib/skills/evals.js +1573 -0
  283. package/neural-interface/lib/skills/export.js +203 -0
  284. package/neural-interface/lib/skills/frontmatter.js +64 -0
  285. package/neural-interface/lib/skills/health.js +75 -0
  286. package/neural-interface/lib/skills/json-edit.js +165 -0
  287. package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
  288. package/neural-interface/lib/skills/known-bridges.js +96 -0
  289. package/neural-interface/lib/skills/library.js +823 -0
  290. package/neural-interface/lib/skills/local-store.js +21 -0
  291. package/neural-interface/lib/skills/migration.js +433 -0
  292. package/neural-interface/lib/skills/operations.js +45 -0
  293. package/neural-interface/lib/skills/ownership.js +427 -0
  294. package/neural-interface/lib/skills/packages.js +88 -0
  295. package/neural-interface/lib/skills/reviews.js +212 -0
  296. package/neural-interface/lib/skills/revision.js +80 -0
  297. package/neural-interface/lib/skills/roots.js +269 -0
  298. package/neural-interface/lib/skills/runtime-checks.js +358 -0
  299. package/neural-interface/lib/skills/scan-assets.js +252 -0
  300. package/neural-interface/lib/skills/scan-context.js +26 -0
  301. package/neural-interface/lib/skills/scan-shell.js +324 -0
  302. package/neural-interface/lib/skills/scan.js +364 -0
  303. package/neural-interface/lib/skills/scanners.js +54 -0
  304. package/neural-interface/lib/skills/service.js +530 -0
  305. package/neural-interface/lib/skills/telemetry.js +119 -0
  306. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  307. package/neural-interface/lib/synabun-version.js +1 -1
  308. package/neural-interface/lib/system-activity.js +1 -1
  309. package/neural-interface/lib/tool-lists.js +124 -0
  310. package/neural-interface/lib/whatsapp/brain.js +7 -3
  311. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  312. package/neural-interface/lib/whatsapp/cards.js +22 -9
  313. package/neural-interface/lib/whatsapp/config.js +1 -1
  314. package/neural-interface/lib/worker-confinement.js +1268 -0
  315. package/neural-interface/lib/worker-guard-setting.js +56 -0
  316. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  317. package/neural-interface/lib/worker-question.js +74 -0
  318. package/neural-interface/lib/worker-relay-ports.js +227 -0
  319. package/neural-interface/lib/worker-resume.js +238 -0
  320. package/neural-interface/lib/worker-sandbox.js +329 -0
  321. package/neural-interface/package-lock.json +34 -12
  322. package/neural-interface/package.json +3 -2
  323. package/neural-interface/public/index.html +3 -1
  324. package/neural-interface/public/index2d.html +19 -11
  325. package/neural-interface/public/onboarding.html +3 -3
  326. package/neural-interface/public/shared/account-menu.js +8 -5
  327. package/neural-interface/public/shared/agent-runtime-options.js +125 -31
  328. package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
  329. package/neural-interface/public/shared/agy/agy-client.js +266 -0
  330. package/neural-interface/public/shared/agy/agy-commands.js +120 -0
  331. package/neural-interface/public/shared/agy/agy-copy.js +326 -0
  332. package/neural-interface/public/shared/agy/agy-diff.js +161 -0
  333. package/neural-interface/public/shared/agy/agy-events.js +469 -0
  334. package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
  335. package/neural-interface/public/shared/agy/agy-options.js +232 -0
  336. package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
  337. package/neural-interface/public/shared/agy/agy-render.js +392 -0
  338. package/neural-interface/public/shared/agy/agy-setup.js +149 -0
  339. package/neural-interface/public/shared/agy/agy-styles.js +604 -0
  340. package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
  341. package/neural-interface/public/shared/api.js +1527 -1336
  342. package/neural-interface/public/shared/app-frame.js +192 -0
  343. package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
  344. package/neural-interface/public/shared/assistant/asst-api.js +1 -1
  345. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  346. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  347. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  348. package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
  349. package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
  350. package/neural-interface/public/shared/assistant/asst-control.js +205 -26
  351. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  352. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  353. package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
  354. package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
  355. package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
  356. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  357. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  358. package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
  359. package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
  360. package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
  361. package/neural-interface/public/shared/assistant/asst-render.js +445 -82
  362. package/neural-interface/public/shared/assistant/asst-route.js +304 -53
  363. package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
  364. package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
  365. package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
  366. package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
  367. package/neural-interface/public/shared/assistant/asst-state.js +87 -24
  368. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  369. package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
  370. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
  371. package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
  372. package/neural-interface/public/shared/automation-context.js +5 -2
  373. package/neural-interface/public/shared/cc-dropdown.js +89 -19
  374. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  375. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  376. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  377. package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
  378. package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
  379. package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
  380. package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
  381. package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
  382. package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
  383. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  384. package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
  385. package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
  386. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  387. package/neural-interface/public/shared/cli-install-controller.js +218 -0
  388. package/neural-interface/public/shared/cli-install-view.js +11 -12
  389. package/neural-interface/public/shared/cli-status.js +11 -10
  390. package/neural-interface/public/shared/constants.js +5 -4
  391. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  392. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  393. package/neural-interface/public/shared/context-menu-model.js +367 -0
  394. package/neural-interface/public/shared/context-menu.js +372 -0
  395. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  396. package/neural-interface/public/shared/cp/cp-restore.js +162 -0
  397. package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
  398. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  399. package/neural-interface/public/shared/desktop-bridge.js +17 -0
  400. package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
  401. package/neural-interface/public/shared/desktop-titlebar.js +13 -4
  402. package/neural-interface/public/shared/desktop-update-view.js +21 -0
  403. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  404. package/neural-interface/public/shared/explorer/fx-api.js +4 -4
  405. package/neural-interface/public/shared/explorer/fx-links.js +3 -3
  406. package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
  407. package/neural-interface/public/shared/explorer/fx-main.js +48 -16
  408. package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
  409. package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
  410. package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
  411. package/neural-interface/public/shared/html-shell.js +30 -15
  412. package/neural-interface/public/shared/i18n.js +2 -0
  413. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  414. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  415. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  416. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
  417. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  418. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  419. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  420. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  421. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  422. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  423. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  424. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
  425. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  426. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
  427. package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
  428. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
  429. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
  430. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  431. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
  432. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  433. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  434. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  435. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  436. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
  437. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  438. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
  439. package/neural-interface/public/shared/page-session.js +96 -0
  440. package/neural-interface/public/shared/provider-icons.js +4 -2
  441. package/neural-interface/public/shared/registry.js +5 -3
  442. package/neural-interface/public/shared/retired-2d.js +3 -0
  443. package/neural-interface/public/shared/schedules-view.js +195 -61
  444. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  445. package/neural-interface/public/shared/settings/settings-data.js +3 -1
  446. package/neural-interface/public/shared/settings/settings-ia.js +6 -6
  447. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  448. package/neural-interface/public/shared/settings/settings-rules.js +2 -2
  449. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  450. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  451. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  452. package/neural-interface/public/shared/showcase-privacy.js +6 -1
  453. package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
  454. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  455. package/neural-interface/public/shared/skills/ss-creation.js +222 -0
  456. package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
  457. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  458. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  459. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  460. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  461. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  462. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  463. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  464. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  465. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  466. package/neural-interface/public/shared/skills/ss-lint.js +149 -0
  467. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  468. package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
  469. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  470. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  471. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  472. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  473. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  474. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  475. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  476. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
  477. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  478. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  479. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  480. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  481. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  482. package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
  483. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  484. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  485. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  486. package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
  487. package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
  488. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  489. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  490. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  491. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
  492. package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
  493. package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
  494. package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
  495. package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
  496. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  497. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  498. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  499. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  500. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  501. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  502. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  503. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  504. package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
  505. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  506. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  507. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  508. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
  509. package/neural-interface/public/shared/state.js +1 -1
  510. package/neural-interface/public/shared/streaming-markdown.js +58 -0
  511. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  512. package/neural-interface/public/shared/styles.css +1822 -1756
  513. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  514. package/neural-interface/public/shared/text-cache.js +29 -0
  515. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  516. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  517. package/neural-interface/public/shared/tool-list-view.js +112 -0
  518. package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
  519. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  520. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  521. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  522. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  523. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  524. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  525. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  526. package/neural-interface/public/shared/tour/tour.css +144 -0
  527. package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
  528. package/neural-interface/public/shared/ui-assistant.js +2 -0
  529. package/neural-interface/public/shared/ui-automation-studio.js +111 -140
  530. package/neural-interface/public/shared/ui-claude-panel.js +376 -82
  531. package/neural-interface/public/shared/ui-cli-banner.js +23 -167
  532. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  533. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  534. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  535. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  536. package/neural-interface/public/shared/ui-detail.js +15 -3
  537. package/neural-interface/public/shared/ui-file-explorer.js +48 -6
  538. package/neural-interface/public/shared/ui-file-links.js +2 -2
  539. package/neural-interface/public/shared/ui-games.js +2 -2
  540. package/neural-interface/public/shared/ui-image-gallery.js +50 -47
  541. package/neural-interface/public/shared/ui-judgments.js +1 -1
  542. package/neural-interface/public/shared/ui-keybinds.js +33 -2
  543. package/neural-interface/public/shared/ui-link.js +3 -3
  544. package/neural-interface/public/shared/ui-menubar.js +10 -20
  545. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  546. package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
  547. package/neural-interface/public/shared/ui-navbar.js +49 -24
  548. package/neural-interface/public/shared/ui-notifications.js +1 -0
  549. package/neural-interface/public/shared/ui-panels.js +96 -65
  550. package/neural-interface/public/shared/ui-resume.js +9 -7
  551. package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
  552. package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
  553. package/neural-interface/public/shared/ui-sessions.js +27 -15
  554. package/neural-interface/public/shared/ui-settings.js +683 -526
  555. package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
  556. package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
  557. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  558. package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
  559. package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
  560. package/neural-interface/public/shared/ui-skills.js +33 -2830
  561. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  562. package/neural-interface/public/shared/ui-sync.js +15 -5
  563. package/neural-interface/public/shared/ui-terminal.js +270 -190
  564. package/neural-interface/public/shared/ui-tool-updates.js +6 -4
  565. package/neural-interface/public/shared/ui-tooltip.js +81 -51
  566. package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
  567. package/neural-interface/public/shared/ui-trash.js +6 -4
  568. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  569. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  570. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
  571. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  572. package/neural-interface/public/shared/ui-tutorial.js +285 -509
  573. package/neural-interface/public/shared/ui-update.js +38 -2
  574. package/neural-interface/public/shared/ui-whiteboard.js +312 -59
  575. package/neural-interface/public/shared/ui-worker-end.js +5 -1
  576. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  577. package/neural-interface/public/shared/view-variant.js +66 -0
  578. package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
  579. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  580. package/neural-interface/public/shared/worker-end.js +10 -3
  581. package/neural-interface/public/shared/worker-questions.js +34 -0
  582. package/neural-interface/public/shared/worker-restart.js +12 -0
  583. package/neural-interface/public/sidepanel-session.html +2 -2
  584. package/neural-interface/public/variant/2d/background.js +2 -1
  585. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  586. package/neural-interface/public/variant/2d/graph.js +42 -20
  587. package/neural-interface/public/variant/2d/hulls.js +14 -9
  588. package/neural-interface/public/variant/2d/lasso.js +11 -7
  589. package/neural-interface/public/variant/2d/main.js +32 -1
  590. package/neural-interface/public/variant/2d/minimap.js +11 -13
  591. package/neural-interface/public/variant/3d/main.js +69 -6
  592. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  593. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  594. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  595. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  596. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  597. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  598. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  599. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  600. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  601. package/neural-interface/scripts/build-vendor.mjs +32 -0
  602. package/neural-interface/server.js +4553 -2855
  603. package/neural-interface/templates/rulesets/README.md +1 -1
  604. package/neural-interface/templates/rulesets/core.md +1 -1
  605. package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
  606. package/neural-interface/templates/rulesets/manifest.json +8 -8
  607. package/npm-shrinkwrap.json +34 -12
  608. package/package.json +17 -3
  609. package/postinstall.js +9 -4
  610. package/preuninstall.js +1 -1
  611. package/setup.js +97 -322
  612. package/skills/skill-forge/SKILL.md +177 -0
  613. package/skills/skill-forge/evals/evals.json +54 -0
  614. package/skills/skill-forge/references/package.md +105 -0
  615. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  616. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  617. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  618. package/skills/synabun/SKILL.md +10 -7
  619. package/skills/synabun/modules/audit.md +1 -5
  620. package/skills/synabun/modules/changelog.md +1 -5
  621. package/skills/synabun/modules/idea.md +1 -1
  622. package/skills/synabun/modules/memorize.md +6 -9
  623. package/skills/synabun/modules/schedule.md +6 -6
  624. package/mcp-server/dist/services/profiles.d.ts +0 -120
  625. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  626. package/mcp-server/dist/services/profiles.js +0 -387
  627. package/mcp-server/dist/services/profiles.js.map +0 -1
  628. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  629. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  630. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  631. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  632. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  633. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  634. package/mcp-server/dist/tools/leonardo.js +0 -21
  635. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  636. package/mcp-server/dist/tools/profile.d.ts +0 -17
  637. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  638. package/mcp-server/dist/tools/profile.js +0 -114
  639. package/mcp-server/dist/tools/profile.js.map +0 -1
  640. package/mcp-server/src/services/profiles.ts +0 -428
  641. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  642. package/mcp-server/src/tools/leonardo.ts +0 -30
  643. package/mcp-server/src/tools/profile.ts +0 -122
  644. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  645. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  646. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  647. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  648. package/skills/leonardo/SKILL.md +0 -168
  649. package/skills/leonardo/icon.svg +0 -1
  650. package/skills/leonardo/modules/browser-guide.md +0 -378
  651. package/skills/leonardo/modules/image-prompter.md +0 -283
  652. package/skills/leonardo/modules/model-advisor.md +0 -100
  653. package/skills/leonardo/modules/prompt-library.md +0 -110
  654. package/skills/leonardo/modules/style-guide.md +0 -186
  655. package/skills/leonardo/modules/video-prompter.md +0 -317
  656. /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
@@ -0,0 +1,203 @@
1
+ // ── What an install writes for one runtime ──
2
+ // The export of a revision for a target is the revision's folder, byte for byte, unless the target would let the
3
+ // skill be started more freely than its author said (public/shared/skills/ss-profiles.js invocationPlan): then the
4
+ // one setting that keeps it as meant is added to the export, and only to the export (the source revision is never
5
+ // rewritten). Each change is listed (`transforms`) and the export has its own digest: what is installed, and what
6
+ // a plan was approved for, is exactly those bytes.
7
+ // - Claude Code: `disable-model-invocation: true` / `user-invocable: false` in SKILL.md (that key only);
8
+ // - Codex: `policy.allow_implicit_invocation: false` in agents/openai.yaml (made when there is none; otherwise
9
+ // that one value is set and every other value, comment and order is kept);
10
+ // - OpenCode: metadata `opencode/autoinvoke: "false"` in SKILL.md (the metadata key only);
11
+ // - Antigravity: `disable-slash-command: true` in SKILL.md (that key only) for a skill the person may not start by
12
+ // name. Antigravity has no setting that keeps its model from starting a skill: an export of an explicit-only
13
+ // skill for it is refused (L-08-invocation-unrepresentable), never written wider.
14
+ // A Codex export also carries the harness metadata Codex shows in its skill picker (agents/openai.yaml
15
+ // `interface`: display_name, short_description, default_prompt, from the skill's own name and description; the
16
+ // 02-standards-runtimes report, §6.3). A sidecar that is already there keeps every value it has: only the interface
17
+ // keys it lacks are added (`sidecarInterface` transform), and one that cannot be parsed is left as it is, with a
18
+ // warning. Codex 0.164.0 reads those keys back in skills/list (displayName, shortDescription, defaultPrompt).
19
+
20
+ import * as YAML from 'yaml';
21
+ import { frontmatter } from './frontmatter.js';
22
+ import { folderDigest } from './library.js';
23
+ import { fromEditing, toEditing } from '../../public/shared/skills/ss-doc.js';
24
+ import { CODEX_SIDECAR, getProfile, invocationPlan, readInvocationIntent } from '../../public/shared/skills/ss-profiles.js';
25
+
26
+ const isMap = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
27
+
28
+ /** The Codex picker's words for a skill, from its frontmatter: `{ display_name, short_description, default_prompt }`. */
29
+ export function codexInterfaceFor(data) {
30
+ const name = String(data?.name || '').trim();
31
+ const description = String(data?.description || '').replace(/\s+/g, ' ').trim();
32
+ const display = name.split(/[-_\s]+/).filter(Boolean).map((w) => w[0].toUpperCase() + w.slice(1)).join(' ').slice(0, 64).trim();
33
+ const short = clip(description.split(/(?<=[.!?])\s/)[0] || description, 64);
34
+ const first = description.split(/(?<=[.!?])\s/)[0] || '';
35
+ const lead = first ? first[0].toLowerCase() + first.slice(1) : '';
36
+ const prompt = name ? clip(`Use $${name}${lead ? `: ${lead}` : ''}`, 1024) : '';
37
+ const out = {};
38
+ if (display) out.display_name = display;
39
+ if (short) out.short_description = short;
40
+ if (prompt) out.default_prompt = prompt;
41
+ return out;
42
+ }
43
+
44
+ /** A text cut at a word boundary to `max` characters, with an ellipsis when it was cut. */
45
+ function clip(text, max) {
46
+ const s = String(text || '').trim();
47
+ if (s.length <= max) return s;
48
+ const cut = s.slice(0, max - 1);
49
+ const at = cut.lastIndexOf(' ');
50
+ return `${(at > max / 2 ? cut.slice(0, at) : cut).trim()}…`;
51
+ }
52
+
53
+ /**
54
+ * The export's agents/openai.yaml with the interface keys Codex shows, added only where they are missing: the file
55
+ * made when there is none, every present value kept, nothing else of the file touched. Returns `{ files, dirs,
56
+ * transform, diagnostic }` (one of the last two set).
57
+ */
58
+ export function withCodexInterface(files, dirs, data) {
59
+ const wanted = codexInterfaceFor(data);
60
+ if (!Object.keys(wanted).length) return { files, dirs, transform: null, diagnostic: null };
61
+ const sidecar = readSidecar(files);
62
+ const transform = (keys, created) => ({ file: CODEX_SIDECAR, op: 'sidecar-interface', keys, created, reason: `Gives Codex the words it shows for this skill (${keys.join(', ')}), from its name and description.` });
63
+ if (!sidecar.present) {
64
+ const text = YAML.stringify({ interface: wanted });
65
+ return { files: [...files, { path: CODEX_SIDECAR, bytes: Buffer.from(text, 'utf-8'), executable: false }], dirs: [...new Set([...dirs, 'agents'])], transform: transform(Object.keys(wanted), true), diagnostic: null };
66
+ }
67
+ if (sidecar.error) return { files, dirs, transform: null, diagnostic: { ruleId: 'L-09-sidecar-kept', severity: 'warning', message: `${CODEX_SIDECAR} cannot be read (${sidecar.error}): kept as it is; Codex shows the skill without its picker words.`, file: CODEX_SIDECAR, line: null } };
68
+ const kept = (why) => ({ files, dirs, transform: null, diagnostic: { ruleId: 'L-09-sidecar-kept', severity: 'warning', message: `${CODEX_SIDECAR} ${why}: kept as it is; Codex shows the skill without its picker words.`, file: CODEX_SIDECAR, line: null } });
69
+ // Valid YAML that is not a map (a scalar, a list), or an `interface` that is not a map (null, a string, a list):
70
+ // nothing can be added to it without changing what the author wrote.
71
+ if (sidecar.data !== null && sidecar.data !== undefined && !isMap(sidecar.data)) return kept('is not a YAML map');
72
+ if (sidecar.data?.interface !== undefined && !isMap(sidecar.data.interface)) return kept('has an "interface" that is not a map');
73
+ const have = isMap(sidecar.data?.interface) ? sidecar.data.interface : {};
74
+ const missing = Object.keys(wanted).filter((k) => have[k] === undefined || have[k] === null || have[k] === '');
75
+ if (!missing.length) return { files, dirs, transform: null, diagnostic: null };
76
+ let nextText;
77
+ try {
78
+ const doc = YAML.parseDocument(sidecar.text);
79
+ for (const key of missing) doc.setIn(['interface', key], wanted[key]);
80
+ nextText = doc.toString();
81
+ } catch (err) { return kept(`could not take the interface keys (${String(err?.message || err).split('\n')[0]})`); }
82
+ const back = YAML.parse(nextText);
83
+ const expected = JSON.parse(JSON.stringify(sidecar.data ?? {}));
84
+ expected.interface = { ...(isMap(expected.interface) ? expected.interface : {}), ...Object.fromEntries(missing.map((k) => [k, wanted[k]])) };
85
+ if (JSON.stringify(back) !== JSON.stringify(expected)) return { files, dirs, transform: null, diagnostic: { ruleId: 'L-09-sidecar-kept', severity: 'warning', message: `${CODEX_SIDECAR} could not take the interface keys without changing other values: kept as it is.`, file: CODEX_SIDECAR, line: null } };
86
+ const at = files.findIndex((f) => f.path === CODEX_SIDECAR);
87
+ const out = files.map((f, i) => (i === at ? { ...f, bytes: Buffer.from(nextText, 'utf-8') } : f));
88
+ return { files: out, dirs, transform: transform(missing, false), diagnostic: null };
89
+ }
90
+
91
+ /** agents/openai.yaml as Codex would read it: `{ present, data, error, text }`. */
92
+ export function readSidecar(files) {
93
+ const file = (files || []).find((f) => f.path === CODEX_SIDECAR);
94
+ if (!file) return { present: false, data: null, error: null, text: null };
95
+ const text = file.bytes.toString('utf-8');
96
+ try {
97
+ const doc = YAML.parseDocument(text, { uniqueKeys: true, maxAliasCount: 100 });
98
+ if (doc.errors.length) return { present: true, data: null, error: String(doc.errors[0].message).split('\n')[0], text };
99
+ return { present: true, data: doc.toJS({ maxAliasCount: 100 }) ?? null, error: null, text };
100
+ } catch (err) {
101
+ return { present: true, data: null, error: String(err?.message || err).split('\n')[0], text };
102
+ }
103
+ }
104
+
105
+ /** The SKILL.md of a folder as text and parsed frontmatter. */
106
+ export function readHeadOf(files) {
107
+ const head = (files || []).find((f) => f.path === 'SKILL.md');
108
+ const text = head ? head.bytes.toString('utf-8') : '';
109
+ return { head, text, parsed: frontmatter.parse(text) };
110
+ }
111
+
112
+ function patchHead(text, changes) {
113
+ const editing = toEditing(text);
114
+ const result = frontmatter.patch(editing.text, changes);
115
+ if (!result.ok) return null;
116
+ return fromEditing(text, result.text);
117
+ }
118
+
119
+ /**
120
+ * The files an install of these files writes for one profile.
121
+ * @param {{ files: {path, bytes, executable}[], dirs: string[] }} folder
122
+ * @param {string} profileId
123
+ * @returns {{ files, dirs, digest: string, transforms: object[], diagnostics: object[], intent: object }}
124
+ */
125
+ export function buildExport({ files, dirs = [] }, profileId) {
126
+ const profile = getProfile(profileId);
127
+ const { text, parsed } = readHeadOf(files);
128
+ const sidecar = readSidecar(files);
129
+ const intent = readInvocationIntent({ data: parsed.data, sidecar });
130
+ const plan = invocationPlan(profileId, { intent, data: parsed.data || {}, sidecar });
131
+ const out = files.map((f) => ({ ...f }));
132
+ const outDirs = new Set(dirs);
133
+ const applied = [];
134
+ const diagnostics = [...plan.diagnostics];
135
+ let headText = text;
136
+ for (const t of plan.transforms) {
137
+ if (t.op === 'frontmatter' || t.op === 'metadata') {
138
+ let changes;
139
+ if (t.op === 'frontmatter') changes = { [t.key]: t.value };
140
+ else {
141
+ const current = isMap(parsed.data?.metadata) ? parsed.data.metadata : {};
142
+ changes = { metadata: { ...current, [t.key]: t.value } };
143
+ }
144
+ const next = patchHead(headText, changes);
145
+ if (next === null) {
146
+ diagnostics.push({ ruleId: 'L-08-adapt-failed', severity: 'error', message: `The SKILL.md frontmatter could not be changed to keep ${profile?.title || profileId} from ${t.key === 'user-invocable' || t.key === 'disable-slash-command' ? 'showing it to the person' : 'starting it on its own'}: fix the YAML first.`, file: 'SKILL.md', line: null });
147
+ continue;
148
+ }
149
+ headText = next;
150
+ applied.push(t);
151
+ } else if (t.op === 'sidecar') {
152
+ if (!sidecar.present) {
153
+ out.push({ path: CODEX_SIDECAR, bytes: Buffer.from('policy:\n allow_implicit_invocation: false\n', 'utf-8'), executable: false });
154
+ outDirs.add('agents');
155
+ applied.push({ ...t, created: true });
156
+ continue;
157
+ }
158
+ if (sidecar.error) {
159
+ diagnostics.push({ ruleId: 'L-08-adapt-failed', severity: 'error', message: `${CODEX_SIDECAR} cannot be read (${sidecar.error}): Codex could start the skill on its own. Fix the file first.`, file: CODEX_SIDECAR, line: null });
160
+ continue;
161
+ }
162
+ let nextText;
163
+ try {
164
+ const doc = YAML.parseDocument(sidecar.text);
165
+ if (!isMap(sidecar.data)) throw new Error('not a YAML map');
166
+ doc.setIn(t.path, t.value);
167
+ nextText = doc.toString();
168
+ } catch (err) {
169
+ diagnostics.push({ ruleId: 'L-08-adapt-failed', severity: 'error', message: `${CODEX_SIDECAR} could not take policy.allow_implicit_invocation (${String(err?.message || err).split('\n')[0]}): set it yourself.`, file: CODEX_SIDECAR, line: null });
170
+ continue;
171
+ }
172
+ // Read back: the one value changed, nothing else.
173
+ const back = YAML.parse(nextText);
174
+ const expected = JSON.parse(JSON.stringify(sidecar.data ?? {}));
175
+ let node = expected;
176
+ for (const key of t.path.slice(0, -1)) { if (!isMap(node[key])) node[key] = {}; node = node[key]; }
177
+ node[t.path[t.path.length - 1]] = t.value;
178
+ if (JSON.stringify(back) !== JSON.stringify(expected)) {
179
+ diagnostics.push({ ruleId: 'L-08-adapt-failed', severity: 'error', message: `${CODEX_SIDECAR} could not be changed without changing other values: set policy.allow_implicit_invocation yourself.`, file: CODEX_SIDECAR, line: null });
180
+ continue;
181
+ }
182
+ const at = out.findIndex((f) => f.path === CODEX_SIDECAR);
183
+ out[at] = { ...out[at], bytes: Buffer.from(nextText, 'utf-8') };
184
+ applied.push(t);
185
+ }
186
+ }
187
+ if (headText !== text) {
188
+ const at = out.findIndex((f) => f.path === 'SKILL.md');
189
+ out[at] = { ...out[at], bytes: Buffer.from(headText, 'utf-8') };
190
+ }
191
+ for (const t of applied) diagnostics.push({ ruleId: 'L-08-invocation-adapted', severity: 'info', message: `${t.file}: ${t.reason}`, file: t.file, line: null });
192
+ // Codex: the words its picker shows, in agents/openai.yaml (added where missing, never over what is there).
193
+ let withDirs = [...outDirs];
194
+ let withFiles = out;
195
+ if (profile?.runtime === 'codex') {
196
+ const added = withCodexInterface(out, withDirs, parsed.data || {});
197
+ withFiles = added.files; withDirs = added.dirs;
198
+ if (added.transform) { applied.push(added.transform); diagnostics.push({ ruleId: 'L-09-sidecar-interface', severity: 'info', message: `${CODEX_SIDECAR}: ${added.transform.reason}`, file: CODEX_SIDECAR, line: null }); }
199
+ if (added.diagnostic) diagnostics.push(added.diagnostic);
200
+ }
201
+ const result = { files: withFiles.sort((a, b) => (a.path < b.path ? -1 : 1)), dirs: withDirs.sort() };
202
+ return { ...result, digest: folderDigest(result), transforms: applied, diagnostics, intent };
203
+ }
@@ -0,0 +1,64 @@
1
+ // ── The frontmatter of skills, commands and agents, on the server ──
2
+ // One reader for everything the server says about a SKILL.md, a command or an agent: the library, an opened
3
+ // artifact, the validation route, imports. It is the page's own module (public/shared/skills/ss-frontmatter.js)
4
+ // over the `yaml` package, so the server and the Studio's form read a file the same way, and the checks are the
5
+ // page's too (ss-lint.js).
6
+
7
+ import * as YAML from 'yaml';
8
+ import { createFrontmatter } from '../../public/shared/skills/ss-frontmatter.js';
9
+ import { LINT_PROFILE, lintArtifact } from '../../public/shared/skills/ss-lint.js';
10
+ import { fromEditing, toEditing } from '../../public/shared/skills/ss-doc.js';
11
+
12
+ export const frontmatter = createFrontmatter(YAML);
13
+
14
+ /** The metadata of a document as plain data ({} when it has none, or when it cannot be read). */
15
+ export function frontmatterData(text) {
16
+ const parsed = frontmatter.parse(text);
17
+ return { data: parsed.data || Object.create(null), parsed };
18
+ }
19
+
20
+ /** A value shown as text in a list: the text, or '' for anything that is not text. */
21
+ export const asText = (value) => (typeof value === 'string' ? value : '');
22
+
23
+ /**
24
+ * The problems of a document.
25
+ * @param {{ type: 'skill'|'command'|'agent', text: string, folderName?: string, knownNames?: string[], binary?: boolean }} o
26
+ * `binary`: the file is not UTF-8 text (UTF-16, or binary data). Its decoded bytes are not read as metadata:
27
+ * that is the one problem, and the Studio shows the file without editing it.
28
+ */
29
+ export function lintText({ type, text, folderName = '', knownNames = [], binary = false }) {
30
+ if (binary) {
31
+ const parsed = frontmatter.parse('');
32
+ const problem = { ruleId: 'file-not-text', severity: 'error', message: 'This file is not UTF-8 text (UTF-16, or binary data): a runtime may misread it, and it is not edited here. Save it as UTF-8 to edit it.', line: 1 };
33
+ return { parsed, lint: { profile: LINT_PROFILE, errors: [problem], warnings: [], infos: [], all: [problem] } };
34
+ }
35
+ const parsed = frontmatter.parse(text);
36
+ return { parsed, lint: lintArtifact({ type, parsed, folderName, knownNames }) };
37
+ }
38
+
39
+ /** What a library row shows of the problems: counts only. */
40
+ export function problemCounts(lint) {
41
+ return { errors: lint?.errors?.length || 0, warnings: lint?.warnings?.length || 0 };
42
+ }
43
+
44
+ /**
45
+ * A SKILL.md given another `name`: that one key changed, every other byte as it was (its line endings and
46
+ * byte-order mark too). Null when the frontmatter cannot be patched (it does not parse).
47
+ */
48
+ export function renameSkillDocument(text, name) {
49
+ const editing = toEditing(text);
50
+ const result = frontmatter.patch(editing.text, { name });
51
+ if (!result.ok) return null;
52
+ return fromEditing(text, result.text);
53
+ }
54
+
55
+ /**
56
+ * A SKILL.md with another `description` (the evaluation's optimiser proposes one): that one key changed, every other
57
+ * byte as it was. Null when the frontmatter cannot be patched.
58
+ */
59
+ export function withSkillDescription(text, description) {
60
+ const editing = toEditing(text);
61
+ const result = frontmatter.patch(editing.text, { description });
62
+ if (!result.ok) return null;
63
+ return fromEditing(text, result.text);
64
+ }
@@ -0,0 +1,75 @@
1
+ // Deterministic maintenance on the existing scheduler tick. No model, install, repair or retirement runs here.
2
+ import { localRecord } from './local-store.js';
3
+ import { scanEvidenceKey, scanAllows, SCAN_ENGINE_VERSION, SCAN_POLICY } from './scan.js';
4
+
5
+ import { buildExport } from './export.js';
6
+ import { TARGET_PROFILE } from '../../public/shared/skills/ss-profiles.js';
7
+ import { folderDigest } from './library.js';
8
+
9
+ export function createSkillHealth({ dataDir, service, settings, notify = () => false, now = Date.now }) {
10
+ const store = localRecord(dataDir, 'health', { checkedAt: null, rows: [], notifications: [] });
11
+ let running = null;
12
+ const view = () => ({ ...store.read(), enabled: settings().healthEnabled, cadenceHours: settings().cadenceHours, running: !!running, rules: `${SCAN_ENGINE_VERSION}:${SCAN_POLICY}` });
13
+ async function flush() {
14
+ const state = store.read();
15
+ const keep = [];
16
+ for (const item of state.notifications || []) { try { if (!await notify(item)) keep.push(item); } catch { keep.push(item); } }
17
+ if (keep.length !== (state.notifications || []).length) { state.notifications = keep; store.write(state); }
18
+ }
19
+ async function check({ probe = false } = {}) {
20
+ if (running) return running;
21
+ running = (async () => {
22
+ const previous = store.read();
23
+ const rows = [];
24
+ for (const inst of service.deployer.listInstallations({ active: true })) {
25
+ try {
26
+ const checked = await service.deployer.verify(inst.installationId, { probeRuntime: probe });
27
+ let folder = service.library.readRevisionFiles(inst.sourceRevisionId);
28
+ for (const runtime of inst.destination.affectedRuntimes) folder = buildExport(folder, TARGET_PROFILE[runtime]);
29
+ const skill = service.library.getSkill(inst.skillId);
30
+ const scan = service.scanFolder(folder, { name: inst.destination.relativePath, digest: folderDigest(folder), skill });
31
+ const state = checked.state;
32
+ const issues = [];
33
+ if (!state.written) issues.push(state.writtenCheck || 'drift');
34
+ if (!state.discoverable) issues.push('not_discoverable');
35
+ if (state.eligibility === 'disabled') issues.push('disabled');
36
+ if (probe && Object.values(state.discovered || {}).some((v) => v?.discovered === false)) issues.push('not_listed');
37
+ const acknowledged = inst.scanAcknowledgement?.evidenceKey === scanEvidenceKey(scan) ? inst.scanAcknowledgement.digest : null;
38
+ if (!scanAllows(scan, { digest: scan.digest, acknowledgedDigest: acknowledged }).ok) issues.push(`scan_${scan.gate === 'allowed' ? 'blocked' : scan.gate}`);
39
+ const old = previous.rows.find((r) => r.installationId === inst.installationId);
40
+ const rulesChanged = !!old && (old.scan?.engineVersion !== scan.engineVersion || old.scan?.policy !== scan.policy);
41
+ rows.push({ installationId: inst.installationId, skillId: inst.skillId, revisionId: inst.sourceRevisionId,
42
+ name: skill.name, runtime: inst.target.runtime, checkedAt: now(), state, scan, rulesChanged, issues,
43
+ status: issues.length ? 'attention' : state.eligibility === 'unknown' || !probe || !inst.destination.affectedRuntimes.every((r) => state.discovered?.[r]?.discovered === true) ? 'unverified_runtime' : 'checked',
44
+ discoveryFresh: probe,
45
+ // A runtime listing is still not execution or proof of quality.
46
+ executed: null });
47
+ } catch (e) {
48
+ rows.push({ installationId: inst.installationId, skillId: inst.skillId, revisionId: inst.sourceRevisionId,
49
+ runtime: inst.target.runtime, checkedAt: now(), status: 'error', issues: ['check_error'], error: String(e.code || 'check_failed') });
50
+ }
51
+ }
52
+ const notifications = [...(previous.notifications || [])];
53
+ for (const row of rows) {
54
+ const old = previous.rows.find((r) => r.installationId === row.installationId);
55
+ if ((row.issues.length || row.rulesChanged) && JSON.stringify([old?.issues, old?.scan?.policy, old?.scan?.engineVersion, old?.scan?.findings]) !== JSON.stringify([row.issues, row.scan?.policy, row.scan?.engineVersion, row.scan?.findings])) {
56
+ notifications.push({ kind: 'skills_health', text: `Skills Studio health: ${row.installationId} (${row.runtime}): ${row.issues.join(', ') || 'scanner rules changed'}. Review Health in Skills Studio. No installed files changed.`, installationId: row.installationId, revisionId: row.revisionId });
57
+ }
58
+ }
59
+ store.write({ checkedAt: now(), rows, notifications: notifications.slice(-100) });
60
+ service.announce({ type: 'health.changed', attention: rows.filter((r) => r.issues.length).length });
61
+ await flush();
62
+ return view();
63
+ })();
64
+ try { return await running; } finally { running = null; }
65
+ }
66
+ async function tick() {
67
+ service.telemetry?.prune();
68
+ if (!settings().healthEnabled) return;
69
+ await flush();
70
+ const current = view();
71
+ if (!current.checkedAt || now() - current.checkedAt >= settings().cadenceHours * 3600000
72
+ || current.rows.some((r) => r.scan && (r.scan.engineVersion !== SCAN_ENGINE_VERSION || r.scan.policy !== SCAN_POLICY))) await check();
73
+ }
74
+ return { view, check, tick };
75
+ }
@@ -0,0 +1,165 @@
1
+ // ── One value of a JSON file, changed in place ──
2
+ // The owner's "Enable for …" (lib/skills/runtime-checks.js enable) changes one value of a runtime's settings file
3
+ // (opencode.json, Claude Code's settings.json) and nothing else: no reformatting, no reordering, every other byte
4
+ // as it was. A small scanner finds where the value at a path sits in the text (and the members of an object, the
5
+ // elements of an array, with their separators); an edit splices the text there. Comments are not JSON: a .jsonc is
6
+ // refused by the caller before this is asked.
7
+
8
+ /** The nodes of a JSON text with their offsets: `{ type, start, end, value?, members?, elements? }`. */
9
+ export function parseJsonWithOffsets(text) {
10
+ const s = String(text);
11
+ let i = 0;
12
+ const fail = (what) => { throw new SyntaxError(`${what} at ${i}`); };
13
+ const ws = () => { while (i < s.length && /[ \t\r\n]/.test(s[i])) i++; };
14
+ const string = () => {
15
+ const start = i;
16
+ if (s[i] !== '"') fail('string expected');
17
+ i++;
18
+ while (i < s.length && s[i] !== '"') { if (s[i] === '\\') i++; i++; }
19
+ if (s[i] !== '"') fail('unterminated string');
20
+ i++;
21
+ return { type: 'string', start, end: i, value: JSON.parse(s.slice(start, i)) };
22
+ };
23
+ const value = () => {
24
+ ws();
25
+ const c = s[i];
26
+ if (c === '{') {
27
+ const start = i; i++;
28
+ const members = [];
29
+ ws();
30
+ if (s[i] === '}') { i++; return { type: 'object', start, end: i, members }; }
31
+ for (;;) {
32
+ ws();
33
+ const key = string();
34
+ ws();
35
+ if (s[i] !== ':') fail(': expected');
36
+ i++;
37
+ const v = value();
38
+ members.push({ key: key.value, keyStart: key.start, valueStart: v.start, valueEnd: v.end, node: v });
39
+ ws();
40
+ if (s[i] === ',') { i++; continue; }
41
+ if (s[i] === '}') { i++; return { type: 'object', start, end: i, members }; }
42
+ fail(', or } expected');
43
+ }
44
+ }
45
+ if (c === '[') {
46
+ const start = i; i++;
47
+ const elements = [];
48
+ ws();
49
+ if (s[i] === ']') { i++; return { type: 'array', start, end: i, elements }; }
50
+ for (;;) {
51
+ const v = value();
52
+ elements.push(v);
53
+ ws();
54
+ if (s[i] === ',') { i++; continue; }
55
+ if (s[i] === ']') { i++; return { type: 'array', start, end: i, elements }; }
56
+ fail(', or ] expected');
57
+ }
58
+ }
59
+ if (c === '"') return string();
60
+ const start = i;
61
+ const m = /^(?:true|false|null|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)/.exec(s.slice(i));
62
+ if (!m) fail('value expected');
63
+ i += m[0].length;
64
+ return { type: 'scalar', start, end: i, value: JSON.parse(m[0]) };
65
+ };
66
+ const root = value();
67
+ ws();
68
+ if (i !== s.length) fail('trailing text');
69
+ return root;
70
+ }
71
+
72
+ /** The node at a path of keys (and array indexes), or null. */
73
+ export function nodeAt(root, path) {
74
+ let node = root;
75
+ for (const key of path) {
76
+ if (!node) return null;
77
+ if (node.type === 'object') { const m = node.members.find((x) => x.key === key); node = m ? m.node : null; }
78
+ else if (node.type === 'array' && Number.isInteger(key)) node = node.elements[key] || null;
79
+ else return null;
80
+ }
81
+ return node || null;
82
+ }
83
+
84
+ /** The text with the value of one existing member replaced by `json` (the JSON text of the new value). */
85
+ export function replaceValue(text, node, json) {
86
+ return `${text.slice(0, node.start)}${json}${text.slice(node.end)}`;
87
+ }
88
+
89
+ /**
90
+ * The text with a member added as the last of an object (the indentation of its last member, or of the object's
91
+ * closing brace plus two spaces when it is empty); the key must not be there already.
92
+ */
93
+ export function appendMember(text, objectNode, key, json) {
94
+ const s = String(text);
95
+ if (objectNode.type !== 'object') throw new TypeError('not an object');
96
+ if (objectNode.members.some((m) => m.key === key)) throw new Error(`"${key}" is there already`);
97
+ const closing = objectNode.end - 1;
98
+ const last = objectNode.members[objectNode.members.length - 1] || null;
99
+ if (!last) {
100
+ const lineStart = s.lastIndexOf('\n', closing) + 1;
101
+ const inner = lineStart > objectNode.start ? /^[ \t]*/.exec(s.slice(lineStart, closing))[0] : '';
102
+ const multiline = s.slice(objectNode.start + 1, closing).includes('\n');
103
+ const pad = multiline ? `\n${inner} ` : ' ';
104
+ const tail = multiline ? `\n${inner}` : ' ';
105
+ return `${s.slice(0, objectNode.start + 1)}${pad}${JSON.stringify(key)}: ${json}${tail}${s.slice(closing)}`;
106
+ }
107
+ const lineStart = s.lastIndexOf('\n', last.keyStart) + 1;
108
+ const sameLine = lineStart <= objectNode.start;
109
+ const indent = sameLine ? ' ' : `\n${/^[ \t]*/.exec(s.slice(lineStart, last.keyStart))[0]}`;
110
+ return `${s.slice(0, last.valueEnd)},${indent}${JSON.stringify(key)}: ${json}${s.slice(last.valueEnd)}`;
111
+ }
112
+
113
+ /** The text without one member of an object (with the separator and the line it stood on). */
114
+ export function removeMember(text, objectNode, key) {
115
+ const s = String(text);
116
+ const at = objectNode.members.findIndex((m) => m.key === key);
117
+ if (at < 0) return s;
118
+ const m = objectNode.members[at];
119
+ const prev = objectNode.members[at - 1] || null;
120
+ const next = objectNode.members[at + 1] || null;
121
+ let start;
122
+ let end;
123
+ if (prev) { start = prev.valueEnd; end = m.valueEnd; } // ", <key>: <value>" after the one before
124
+ else if (next) { start = m.keyStart; end = next.keyStart; } // "<key>: <value>, " before the one after
125
+ else { start = objectNode.start + 1; end = objectNode.end - 1; } // the only one: the object is left empty
126
+ return `${s.slice(0, start)}${s.slice(end)}`;
127
+ }
128
+
129
+ /** The text without one element of an array (by index). */
130
+ export function removeElement(text, arrayNode, index) {
131
+ const s = String(text);
132
+ const e = arrayNode.elements[index];
133
+ if (!e) return s;
134
+ const prev = arrayNode.elements[index - 1] || null;
135
+ const next = arrayNode.elements[index + 1] || null;
136
+ let start;
137
+ let end;
138
+ if (prev) { start = prev.end; end = e.end; }
139
+ else if (next) { start = e.start; end = next.start; }
140
+ else { start = arrayNode.start + 1; end = arrayNode.end - 1; }
141
+ return `${s.slice(0, start)}${s.slice(end)}`;
142
+ }
143
+
144
+ /**
145
+ * The text with an element added as the last of an array (on a line of its own, at the indentation of the last
146
+ * element, when the array spans lines; else after a space).
147
+ */
148
+ export function appendElement(text, arrayNode, json) {
149
+ const s = String(text);
150
+ if (arrayNode.type !== 'array') throw new TypeError('not an array');
151
+ const closing = arrayNode.end - 1;
152
+ const last = arrayNode.elements[arrayNode.elements.length - 1] || null;
153
+ if (!last) {
154
+ const lineStart = s.lastIndexOf('\n', closing) + 1;
155
+ const inner = lineStart > arrayNode.start ? /^[ \t]*/.exec(s.slice(lineStart, closing))[0] : '';
156
+ const multiline = s.slice(arrayNode.start + 1, closing).includes('\n');
157
+ return multiline
158
+ ? `${s.slice(0, arrayNode.start + 1)}\n${inner} ${json}\n${inner}${s.slice(closing)}`
159
+ : `${s.slice(0, arrayNode.start + 1)}${json}${s.slice(closing)}`;
160
+ }
161
+ const lineStart = s.lastIndexOf('\n', last.start) + 1;
162
+ const sameLine = lineStart <= arrayNode.start;
163
+ const indent = sameLine ? ' ' : `\n${/^[ \t]*/.exec(s.slice(lineStart, last.start))[0]}`;
164
+ return `${s.slice(0, last.end)},${indent}${json}${s.slice(last.end)}`;
165
+ }