synabun 2.0.10 → 2.1.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 (517) hide show
  1. package/CHANGELOG.md +86 -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 +2 -2
  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 +17 -8
  11. package/lib/desktop-app.js +7 -1
  12. package/lib/external-tools.js +1 -1
  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 +228 -0
  24. package/lib/virustotal.mjs +192 -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/codex-config-heal.d.ts +6 -2
  37. package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
  38. package/mcp-server/dist/services/codex-config-heal.js +81 -28
  39. package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
  40. package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
  41. package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
  42. package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
  43. package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
  44. package/mcp-server/dist/services/neural-interface.d.ts +16 -10
  45. package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
  46. package/mcp-server/dist/services/neural-interface.js +67 -11
  47. package/mcp-server/dist/services/neural-interface.js.map +1 -1
  48. package/mcp-server/dist/services/server-instructions.d.ts +7 -2
  49. package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
  50. package/mcp-server/dist/services/server-instructions.js +20 -62
  51. package/mcp-server/dist/services/server-instructions.js.map +1 -1
  52. package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
  53. package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
  54. package/mcp-server/dist/services/tool-catalog.js +339 -0
  55. package/mcp-server/dist/services/tool-catalog.js.map +1 -0
  56. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
  57. package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
  58. package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
  59. package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
  60. package/mcp-server/dist/services/tool-list.d.ts +108 -0
  61. package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
  62. package/mcp-server/dist/services/tool-list.js +334 -0
  63. package/mcp-server/dist/services/tool-list.js.map +1 -0
  64. package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
  65. package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
  66. package/mcp-server/dist/services/tool-runtime.js +400 -0
  67. package/mcp-server/dist/services/tool-runtime.js.map +1 -0
  68. package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
  69. package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
  70. package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
  71. package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
  72. package/mcp-server/dist/tools/agents.d.ts +10 -10
  73. package/mcp-server/dist/tools/agents.d.ts.map +1 -1
  74. package/mcp-server/dist/tools/agents.js +22 -13
  75. package/mcp-server/dist/tools/agents.js.map +1 -1
  76. package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
  77. package/mcp-server/dist/tools/image-tools.d.ts +1 -1
  78. package/mcp-server/dist/tools/image-tools.js +1 -1
  79. package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
  80. package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
  81. package/mcp-server/dist/tools/skill-tools.js +639 -0
  82. package/mcp-server/dist/tools/skill-tools.js.map +1 -0
  83. package/mcp-server/dist/tools/skill.d.ts +7 -0
  84. package/mcp-server/dist/tools/skill.d.ts.map +1 -0
  85. package/mcp-server/dist/tools/skill.js +11 -0
  86. package/mcp-server/dist/tools/skill.js.map +1 -0
  87. package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
  88. package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
  89. package/mcp-server/dist/tools/tool-groups.js +147 -0
  90. package/mcp-server/dist/tools/tool-groups.js.map +1 -0
  91. package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
  92. package/mcp-server/dist/tools/whiteboard-format.js +7 -4
  93. package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
  94. package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
  95. package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
  96. package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
  97. package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
  98. package/mcp-server/package-lock.json +2 -2
  99. package/mcp-server/package.json +1 -1
  100. package/mcp-server/src/http.ts +75 -12
  101. package/mcp-server/src/index.ts +147 -154
  102. package/mcp-server/src/preload.ts +12 -12
  103. package/mcp-server/src/services/codex-config-heal.ts +80 -29
  104. package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
  105. package/mcp-server/src/services/neural-interface.ts +79 -20
  106. package/mcp-server/src/services/server-instructions.ts +27 -63
  107. package/mcp-server/src/services/tool-catalog.ts +403 -0
  108. package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
  109. package/mcp-server/src/services/tool-list.ts +410 -0
  110. package/mcp-server/src/services/tool-runtime.ts +457 -0
  111. package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
  112. package/mcp-server/src/tools/agents.ts +22 -14
  113. package/mcp-server/src/tools/image-tools.ts +1 -1
  114. package/mcp-server/src/tools/skill-tools.ts +589 -0
  115. package/mcp-server/src/tools/skill.ts +13 -0
  116. package/mcp-server/src/tools/tool-groups.ts +164 -0
  117. package/mcp-server/src/tools/whiteboard-format.ts +9 -3
  118. package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
  119. package/neural-interface/i18n/en.json +3463 -200
  120. package/neural-interface/i18n/pt-BR.json +3411 -151
  121. package/neural-interface/lib/assistant-api.js +127 -28
  122. package/neural-interface/lib/assistant-brains/claude.js +4 -3
  123. package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
  124. package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
  125. package/neural-interface/lib/assistant-brains/codex.js +9 -5
  126. package/neural-interface/lib/assistant-brains/opencode.js +120 -54
  127. package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
  128. package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
  129. package/neural-interface/lib/assistant-catalog.js +6 -7
  130. package/neural-interface/lib/assistant-dispatch.js +871 -156
  131. package/neural-interface/lib/assistant-envelope.js +3 -1
  132. package/neural-interface/lib/assistant-persona.js +80 -11
  133. package/neural-interface/lib/assistant-plan-permissions.js +10 -9
  134. package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
  135. package/neural-interface/lib/assistant-route-gate.js +6 -4
  136. package/neural-interface/lib/assistant-router.js +13 -8
  137. package/neural-interface/lib/assistant-runtime.js +56 -18
  138. package/neural-interface/lib/assistant-task-prompt.js +78 -14
  139. package/neural-interface/lib/assistant-tools.js +51 -0
  140. package/neural-interface/lib/backup-service.js +620 -3
  141. package/neural-interface/lib/backup-zip-reader.js +10 -5
  142. package/neural-interface/lib/backup-zip-writer.js +257 -0
  143. package/neural-interface/lib/browser-execution.js +10 -2
  144. package/neural-interface/lib/browser-guard-cdp.js +83 -0
  145. package/neural-interface/lib/browser-network-guard.js +284 -0
  146. package/neural-interface/lib/browser-policy-roots.js +64 -0
  147. package/neural-interface/lib/browser-tool-policy.js +186 -31
  148. package/neural-interface/lib/claude-agent-bridge.js +4 -2
  149. package/neural-interface/lib/claude-hooks-status.js +103 -0
  150. package/neural-interface/lib/claude-temporary.js +5 -11
  151. package/neural-interface/lib/cli-install.js +18 -138
  152. package/neural-interface/lib/cli-resolver.js +4 -1
  153. package/neural-interface/lib/cli-update-planner.js +32 -31
  154. package/neural-interface/lib/cloudflared/tunnel.js +42 -2
  155. package/neural-interface/lib/codex-mcp-approvals.js +11 -0
  156. package/neural-interface/lib/codex-worker-app-server.js +172 -0
  157. package/neural-interface/lib/confined-fs.js +30 -3
  158. package/neural-interface/lib/crash-notice-api.js +98 -0
  159. package/neural-interface/lib/editor-completion-opencode.js +68 -68
  160. package/neural-interface/lib/exec-loop-command.js +4 -8
  161. package/neural-interface/lib/http-guards.js +8 -2
  162. package/neural-interface/lib/install-details.js +4 -1
  163. package/neural-interface/lib/mcp-agent-servers.js +67 -0
  164. package/neural-interface/lib/mcp-client-config.js +0 -29
  165. package/neural-interface/lib/mcp-external-servers.js +323 -0
  166. package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
  167. package/neural-interface/lib/morelogin.js +30 -0
  168. package/neural-interface/lib/native-loop-providers.js +547 -47
  169. package/neural-interface/lib/native-loop-runtime.js +268 -41
  170. package/neural-interface/lib/opencode-config.js +557 -0
  171. package/neural-interface/lib/opencode-db-schema.js +17 -34
  172. package/neural-interface/lib/opencode-history.js +48 -218
  173. package/neural-interface/lib/opencode-mcp-ready.js +108 -0
  174. package/neural-interface/lib/opencode-native-boundary.js +44 -0
  175. package/neural-interface/lib/opencode-protocol.js +249 -112
  176. package/neural-interface/lib/opencode-runtime-config.js +32 -22
  177. package/neural-interface/lib/opencode-serve-records.js +39 -21
  178. package/neural-interface/lib/opencode-v2-client.js +48 -153
  179. package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
  180. package/neural-interface/lib/opencode-worker-data.js +27 -0
  181. package/neural-interface/lib/opencode2-client.js +73 -37
  182. package/neural-interface/lib/opencode2-proxy.js +23 -63
  183. package/neural-interface/lib/opencode2-translate.js +51 -2
  184. package/neural-interface/lib/owner-authority.js +249 -0
  185. package/neural-interface/lib/page-session.js +275 -0
  186. package/neural-interface/lib/peer-identity.js +763 -0
  187. package/neural-interface/lib/request-gate.js +17 -2
  188. package/neural-interface/lib/rulesets/api.js +1 -1
  189. package/neural-interface/lib/rulesets/fs-safe.js +1 -1
  190. package/neural-interface/lib/rulesets/installer.js +92 -27
  191. package/neural-interface/lib/rulesets/json-edit.js +1 -1
  192. package/neural-interface/lib/session-cache-builder.js +17 -30
  193. package/neural-interface/lib/session-title-generator.js +58 -36
  194. package/neural-interface/lib/skills/api-v2.js +495 -0
  195. package/neural-interface/lib/skills/bundle.js +418 -0
  196. package/neural-interface/lib/skills/catalog.js +294 -0
  197. package/neural-interface/lib/skills/creation-api.js +191 -0
  198. package/neural-interface/lib/skills/creation-brief.js +247 -0
  199. package/neural-interface/lib/skills/creation-sources.js +267 -0
  200. package/neural-interface/lib/skills/creation.js +843 -0
  201. package/neural-interface/lib/skills/deploy.js +564 -0
  202. package/neural-interface/lib/skills/digest.js +119 -0
  203. package/neural-interface/lib/skills/discover.js +111 -0
  204. package/neural-interface/lib/skills/draft-confinement.js +214 -0
  205. package/neural-interface/lib/skills/eval-confinement.js +397 -0
  206. package/neural-interface/lib/skills/eval-sandbox.js +280 -0
  207. package/neural-interface/lib/skills/eval-trace.js +119 -0
  208. package/neural-interface/lib/skills/evals-api.js +212 -0
  209. package/neural-interface/lib/skills/evals.js +1573 -0
  210. package/neural-interface/lib/skills/export.js +200 -0
  211. package/neural-interface/lib/skills/frontmatter.js +64 -0
  212. package/neural-interface/lib/skills/health.js +75 -0
  213. package/neural-interface/lib/skills/json-edit.js +165 -0
  214. package/neural-interface/lib/skills/known-bridge-digests.json +387 -0
  215. package/neural-interface/lib/skills/known-bridges.js +96 -0
  216. package/neural-interface/lib/skills/library.js +823 -0
  217. package/neural-interface/lib/skills/local-store.js +21 -0
  218. package/neural-interface/lib/skills/migration.js +433 -0
  219. package/neural-interface/lib/skills/operations.js +45 -0
  220. package/neural-interface/lib/skills/ownership.js +427 -0
  221. package/neural-interface/lib/skills/packages.js +88 -0
  222. package/neural-interface/lib/skills/reviews.js +212 -0
  223. package/neural-interface/lib/skills/revision.js +80 -0
  224. package/neural-interface/lib/skills/roots.js +262 -0
  225. package/neural-interface/lib/skills/runtime-checks.js +355 -0
  226. package/neural-interface/lib/skills/scan-assets.js +252 -0
  227. package/neural-interface/lib/skills/scan-context.js +26 -0
  228. package/neural-interface/lib/skills/scan-shell.js +324 -0
  229. package/neural-interface/lib/skills/scan.js +364 -0
  230. package/neural-interface/lib/skills/scanners.js +54 -0
  231. package/neural-interface/lib/skills/service.js +522 -0
  232. package/neural-interface/lib/skills/telemetry.js +113 -0
  233. package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
  234. package/neural-interface/lib/tool-lists.js +124 -0
  235. package/neural-interface/lib/whatsapp/bridge.js +6 -3
  236. package/neural-interface/lib/worker-confinement.js +1192 -0
  237. package/neural-interface/lib/worker-guard-setting.js +56 -0
  238. package/neural-interface/lib/worker-mcp-channel.js +175 -0
  239. package/neural-interface/lib/worker-relay-ports.js +227 -0
  240. package/neural-interface/lib/worker-resume.js +229 -0
  241. package/neural-interface/lib/worker-sandbox.js +299 -0
  242. package/neural-interface/package-lock.json +18 -12
  243. package/neural-interface/package.json +2 -2
  244. package/neural-interface/public/index.html +3 -1
  245. package/neural-interface/public/index2d.html +19 -11
  246. package/neural-interface/public/onboarding.html +2 -2
  247. package/neural-interface/public/shared/account-menu.js +8 -5
  248. package/neural-interface/public/shared/agent-runtime-options.js +35 -19
  249. package/neural-interface/public/shared/api.js +1527 -1336
  250. package/neural-interface/public/shared/app-frame.js +192 -0
  251. package/neural-interface/public/shared/assistant/asst-agents-dock.js +33 -2
  252. package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
  253. package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
  254. package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
  255. package/neural-interface/public/shared/assistant/asst-brain-picker.js +49 -35
  256. package/neural-interface/public/shared/assistant/asst-control.js +157 -26
  257. package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
  258. package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
  259. package/neural-interface/public/shared/assistant/asst-limit-dock.js +40 -0
  260. package/neural-interface/public/shared/assistant/asst-limit-wait.js +294 -0
  261. package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
  262. package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
  263. package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
  264. package/neural-interface/public/shared/assistant/asst-panel.js +106 -11
  265. package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
  266. package/neural-interface/public/shared/assistant/asst-render.js +401 -77
  267. package/neural-interface/public/shared/assistant/asst-route.js +83 -12
  268. package/neural-interface/public/shared/assistant/asst-scenes.js +2 -0
  269. package/neural-interface/public/shared/assistant/asst-sidepanel.js +67 -4
  270. package/neural-interface/public/shared/assistant/asst-slash.js +9 -7
  271. package/neural-interface/public/shared/assistant/asst-state.js +11 -15
  272. package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
  273. package/neural-interface/public/shared/assistant/asst-styles.js +59 -21
  274. package/neural-interface/public/shared/assistant/asst-tool-kinds.js +156 -16
  275. package/neural-interface/public/shared/automation-context.js +5 -2
  276. package/neural-interface/public/shared/cc-dropdown.js +89 -19
  277. package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
  278. package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
  279. package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
  280. package/neural-interface/public/shared/cdx/cdx-output.js +8 -7
  281. package/neural-interface/public/shared/cdx/cdx-panel.js +45 -149
  282. package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
  283. package/neural-interface/public/shared/cdx/cdx-render.js +47 -29
  284. package/neural-interface/public/shared/cdx/cdx-requests.js +3 -3
  285. package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
  286. package/neural-interface/public/shared/cdx/cdx-styles.js +11 -3
  287. package/neural-interface/public/shared/cdx/cdx-tabs.js +52 -39
  288. package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
  289. package/neural-interface/public/shared/cli-install-view.js +4 -8
  290. package/neural-interface/public/shared/cli-status.js +2 -2
  291. package/neural-interface/public/shared/constants.js +2 -2
  292. package/neural-interface/public/shared/context-menu-areas.js +34 -0
  293. package/neural-interface/public/shared/context-menu-logic.js +243 -0
  294. package/neural-interface/public/shared/context-menu-model.js +366 -0
  295. package/neural-interface/public/shared/context-menu.js +372 -0
  296. package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
  297. package/neural-interface/public/shared/crash-notice-view.js +168 -0
  298. package/neural-interface/public/shared/desktop-update-view.js +20 -0
  299. package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
  300. package/neural-interface/public/shared/html-shell.js +9 -11
  301. package/neural-interface/public/shared/i18n.js +2 -0
  302. package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
  303. package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
  304. package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
  305. package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
  306. package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
  307. package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
  308. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
  309. package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
  310. package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
  311. package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
  312. package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
  313. package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +47 -252
  314. package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
  315. package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
  316. package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +6 -21
  317. package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
  318. package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
  319. package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
  320. package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
  321. package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
  322. package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
  323. package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
  324. package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +0 -21
  325. package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
  326. package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +14 -47
  327. package/neural-interface/public/shared/page-session.js +96 -0
  328. package/neural-interface/public/shared/registry.js +5 -3
  329. package/neural-interface/public/shared/retired-2d.js +3 -0
  330. package/neural-interface/public/shared/schedules-view.js +195 -61
  331. package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
  332. package/neural-interface/public/shared/settings/settings-data.js +3 -1
  333. package/neural-interface/public/shared/settings/settings-ia.js +6 -6
  334. package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
  335. package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
  336. package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
  337. package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
  338. package/neural-interface/public/shared/skills/ss-args.js +96 -0
  339. package/neural-interface/public/shared/skills/ss-creation.js +219 -0
  340. package/neural-interface/public/shared/skills/ss-dialog.js +130 -0
  341. package/neural-interface/public/shared/skills/ss-doc.js +173 -0
  342. package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
  343. package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
  344. package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
  345. package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
  346. package/neural-interface/public/shared/skills/ss-evals.js +417 -0
  347. package/neural-interface/public/shared/skills/ss-form.js +159 -0
  348. package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
  349. package/neural-interface/public/shared/skills/ss-ids.js +32 -0
  350. package/neural-interface/public/shared/skills/ss-lint.js +141 -0
  351. package/neural-interface/public/shared/skills/ss-presets.js +117 -0
  352. package/neural-interface/public/shared/skills/ss-profiles.js +475 -0
  353. package/neural-interface/public/shared/skills/ss-resources.js +165 -0
  354. package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
  355. package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
  356. package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
  357. package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
  358. package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
  359. package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
  360. package/neural-interface/public/shared/skills/studio/sx-create-ai.js +236 -0
  361. package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
  362. package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
  363. package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
  364. package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
  365. package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
  366. package/neural-interface/public/shared/skills/studio/sx-dom.js +229 -0
  367. package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
  368. package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
  369. package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
  370. package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
  371. package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
  372. package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
  373. package/neural-interface/public/shared/skills/studio/sx-install-flow.js +279 -0
  374. package/neural-interface/public/shared/skills/studio/sx-install.js +296 -0
  375. package/neural-interface/public/shared/skills/studio/sx-library-view.js +639 -0
  376. package/neural-interface/public/shared/skills/studio/sx-library.js +475 -0
  377. package/neural-interface/public/shared/skills/studio/sx-main.js +681 -0
  378. package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
  379. package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
  380. package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
  381. package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
  382. package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
  383. package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
  384. package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
  385. package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
  386. package/neural-interface/public/shared/skills/studio/sx-subject.js +248 -0
  387. package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
  388. package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
  389. package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
  390. package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +425 -0
  391. package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
  392. package/neural-interface/public/shared/styles.css +1525 -1779
  393. package/neural-interface/public/shared/synabun-mascot.js +1115 -9
  394. package/neural-interface/public/shared/tool-list-picker.js +55 -0
  395. package/neural-interface/public/shared/tool-list-storage.js +24 -0
  396. package/neural-interface/public/shared/tool-list-view.js +112 -0
  397. package/neural-interface/public/shared/tour/tour-actor.js +268 -0
  398. package/neural-interface/public/shared/tour/tour-beats.js +336 -0
  399. package/neural-interface/public/shared/tour/tour-engine.js +884 -0
  400. package/neural-interface/public/shared/tour/tour-ink.js +390 -0
  401. package/neural-interface/public/shared/tour/tour-stage.js +440 -0
  402. package/neural-interface/public/shared/tour/tour-state.js +40 -0
  403. package/neural-interface/public/shared/tour/tour-tips.js +99 -0
  404. package/neural-interface/public/shared/tour/tour.css +144 -0
  405. package/neural-interface/public/shared/ui-automation-studio.js +91 -128
  406. package/neural-interface/public/shared/ui-claude-panel.js +77 -5
  407. package/neural-interface/public/shared/ui-command-runner.js +6 -3
  408. package/neural-interface/public/shared/ui-context-menu.js +295 -0
  409. package/neural-interface/public/shared/ui-cost-widget.js +57 -59
  410. package/neural-interface/public/shared/ui-crash-notice.js +187 -0
  411. package/neural-interface/public/shared/ui-detail.js +15 -3
  412. package/neural-interface/public/shared/ui-image-gallery.js +50 -47
  413. package/neural-interface/public/shared/ui-keybinds.js +26 -1
  414. package/neural-interface/public/shared/ui-menubar.js +8 -18
  415. package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
  416. package/neural-interface/public/shared/ui-native-loop-router.js +7 -1
  417. package/neural-interface/public/shared/ui-navbar.js +4 -24
  418. package/neural-interface/public/shared/ui-panels.js +96 -65
  419. package/neural-interface/public/shared/ui-schedules-studio.js +507 -423
  420. package/neural-interface/public/shared/ui-sessions.js +5 -3
  421. package/neural-interface/public/shared/ui-settings.js +594 -462
  422. package/neural-interface/public/shared/ui-sidepanel-sessions.js +1 -1
  423. package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
  424. package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
  425. package/neural-interface/public/shared/ui-skills.js +33 -2830
  426. package/neural-interface/public/shared/ui-styleguide.js +5 -2
  427. package/neural-interface/public/shared/ui-sync.js +15 -5
  428. package/neural-interface/public/shared/ui-terminal.js +124 -180
  429. package/neural-interface/public/shared/ui-tool-updates.js +3 -1
  430. package/neural-interface/public/shared/ui-tooltip.js +10 -5
  431. package/neural-interface/public/shared/ui-trash.js +6 -4
  432. package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
  433. package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
  434. package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
  435. package/neural-interface/public/shared/ui-tutorial.css +47 -100
  436. package/neural-interface/public/shared/ui-tutorial.js +285 -509
  437. package/neural-interface/public/shared/ui-update.js +38 -2
  438. package/neural-interface/public/shared/ui-whiteboard.js +311 -58
  439. package/neural-interface/public/shared/ui-worker-end.js +4 -0
  440. package/neural-interface/public/shared/ui-workspaces.js +3 -2
  441. package/neural-interface/public/shared/view-variant.js +66 -0
  442. package/neural-interface/public/shared/whatsapp/wa-view.js +1 -1
  443. package/neural-interface/public/shared/whiteboard-list.js +172 -0
  444. package/neural-interface/public/shared/worker-end.js +10 -3
  445. package/neural-interface/public/shared/worker-restart.js +12 -0
  446. package/neural-interface/public/sidepanel-session.html +1 -1
  447. package/neural-interface/public/variant/2d/background.js +2 -1
  448. package/neural-interface/public/variant/2d/context-menu.js +8 -2
  449. package/neural-interface/public/variant/2d/graph.js +42 -20
  450. package/neural-interface/public/variant/2d/hulls.js +14 -9
  451. package/neural-interface/public/variant/2d/lasso.js +11 -7
  452. package/neural-interface/public/variant/2d/main.js +32 -1
  453. package/neural-interface/public/variant/2d/minimap.js +11 -13
  454. package/neural-interface/public/variant/3d/main.js +69 -6
  455. package/neural-interface/public/variant/3d/map-controls.js +24 -9
  456. package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
  457. package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
  458. package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
  459. package/neural-interface/public/vendor/caveat/caveat.css +17 -0
  460. package/neural-interface/public/vendor/caveat/manifest.json +12 -0
  461. package/neural-interface/public/vendor/yaml/LICENSE +13 -0
  462. package/neural-interface/public/vendor/yaml/manifest.json +4 -0
  463. package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
  464. package/neural-interface/scripts/build-vendor.mjs +32 -0
  465. package/neural-interface/server.js +3934 -2454
  466. package/neural-interface/templates/rulesets/core.md +1 -1
  467. package/neural-interface/templates/rulesets/legacy-hashes.json +18 -0
  468. package/neural-interface/templates/rulesets/manifest.json +8 -8
  469. package/npm-shrinkwrap.json +18 -12
  470. package/package.json +16 -3
  471. package/postinstall.js +9 -4
  472. package/preuninstall.js +1 -1
  473. package/setup.js +97 -322
  474. package/skills/skill-forge/SKILL.md +177 -0
  475. package/skills/skill-forge/evals/evals.json +54 -0
  476. package/skills/skill-forge/references/package.md +105 -0
  477. package/skills/skill-forge/references/review-and-recovery.md +63 -0
  478. package/skills/skill-forge/references/runtime-profiles.md +20 -0
  479. package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
  480. package/skills/synabun/SKILL.md +10 -7
  481. package/skills/synabun/modules/audit.md +1 -5
  482. package/skills/synabun/modules/changelog.md +1 -5
  483. package/skills/synabun/modules/idea.md +1 -1
  484. package/skills/synabun/modules/memorize.md +6 -9
  485. package/skills/synabun/modules/schedule.md +4 -4
  486. package/mcp-server/dist/services/profiles.d.ts +0 -120
  487. package/mcp-server/dist/services/profiles.d.ts.map +0 -1
  488. package/mcp-server/dist/services/profiles.js +0 -387
  489. package/mcp-server/dist/services/profiles.js.map +0 -1
  490. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
  491. package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
  492. package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
  493. package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
  494. package/mcp-server/dist/tools/leonardo.d.ts +0 -13
  495. package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
  496. package/mcp-server/dist/tools/leonardo.js +0 -21
  497. package/mcp-server/dist/tools/leonardo.js.map +0 -1
  498. package/mcp-server/dist/tools/profile.d.ts +0 -17
  499. package/mcp-server/dist/tools/profile.d.ts.map +0 -1
  500. package/mcp-server/dist/tools/profile.js +0 -114
  501. package/mcp-server/dist/tools/profile.js.map +0 -1
  502. package/mcp-server/src/services/profiles.ts +0 -428
  503. package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
  504. package/mcp-server/src/tools/leonardo.ts +0 -30
  505. package/mcp-server/src/tools/profile.ts +0 -122
  506. package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
  507. package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
  508. package/neural-interface/lib/mcp-profile-servers.js +0 -120
  509. package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
  510. package/skills/leonardo/SKILL.md +0 -168
  511. package/skills/leonardo/icon.svg +0 -1
  512. package/skills/leonardo/modules/browser-guide.md +0 -378
  513. package/skills/leonardo/modules/image-prompter.md +0 -283
  514. package/skills/leonardo/modules/model-advisor.md +0 -100
  515. package/skills/leonardo/modules/prompt-library.md +0 -110
  516. package/skills/leonardo/modules/style-guide.md +0 -186
  517. package/skills/leonardo/modules/video-prompter.md +0 -317
@@ -0,0 +1,200 @@
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
+ // A Codex export also carries the harness metadata Codex shows in its skill picker (agents/openai.yaml
12
+ // `interface`: display_name, short_description, default_prompt, from the skill's own name and description; the
13
+ // 02-standards-runtimes report, §6.3). A sidecar that is already there keeps every value it has: only the interface
14
+ // keys it lacks are added (`sidecarInterface` transform), and one that cannot be parsed is left as it is, with a
15
+ // warning. Codex 0.164.0 reads those keys back in skills/list (displayName, shortDescription, defaultPrompt).
16
+
17
+ import * as YAML from 'yaml';
18
+ import { frontmatter } from './frontmatter.js';
19
+ import { folderDigest } from './library.js';
20
+ import { fromEditing, toEditing } from '../../public/shared/skills/ss-doc.js';
21
+ import { CODEX_SIDECAR, getProfile, invocationPlan, readInvocationIntent } from '../../public/shared/skills/ss-profiles.js';
22
+
23
+ const isMap = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
24
+
25
+ /** The Codex picker's words for a skill, from its frontmatter: `{ display_name, short_description, default_prompt }`. */
26
+ export function codexInterfaceFor(data) {
27
+ const name = String(data?.name || '').trim();
28
+ const description = String(data?.description || '').replace(/\s+/g, ' ').trim();
29
+ const display = name.split(/[-_\s]+/).filter(Boolean).map((w) => w[0].toUpperCase() + w.slice(1)).join(' ').slice(0, 64).trim();
30
+ const short = clip(description.split(/(?<=[.!?])\s/)[0] || description, 64);
31
+ const first = description.split(/(?<=[.!?])\s/)[0] || '';
32
+ const lead = first ? first[0].toLowerCase() + first.slice(1) : '';
33
+ const prompt = name ? clip(`Use $${name}${lead ? `: ${lead}` : ''}`, 1024) : '';
34
+ const out = {};
35
+ if (display) out.display_name = display;
36
+ if (short) out.short_description = short;
37
+ if (prompt) out.default_prompt = prompt;
38
+ return out;
39
+ }
40
+
41
+ /** A text cut at a word boundary to `max` characters, with an ellipsis when it was cut. */
42
+ function clip(text, max) {
43
+ const s = String(text || '').trim();
44
+ if (s.length <= max) return s;
45
+ const cut = s.slice(0, max - 1);
46
+ const at = cut.lastIndexOf(' ');
47
+ return `${(at > max / 2 ? cut.slice(0, at) : cut).trim()}…`;
48
+ }
49
+
50
+ /**
51
+ * The export's agents/openai.yaml with the interface keys Codex shows, added only where they are missing: the file
52
+ * made when there is none, every present value kept, nothing else of the file touched. Returns `{ files, dirs,
53
+ * transform, diagnostic }` (one of the last two set).
54
+ */
55
+ export function withCodexInterface(files, dirs, data) {
56
+ const wanted = codexInterfaceFor(data);
57
+ if (!Object.keys(wanted).length) return { files, dirs, transform: null, diagnostic: null };
58
+ const sidecar = readSidecar(files);
59
+ 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.` });
60
+ if (!sidecar.present) {
61
+ const text = YAML.stringify({ interface: wanted });
62
+ 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 };
63
+ }
64
+ 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 } };
65
+ 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 } });
66
+ // Valid YAML that is not a map (a scalar, a list), or an `interface` that is not a map (null, a string, a list):
67
+ // nothing can be added to it without changing what the author wrote.
68
+ if (sidecar.data !== null && sidecar.data !== undefined && !isMap(sidecar.data)) return kept('is not a YAML map');
69
+ if (sidecar.data?.interface !== undefined && !isMap(sidecar.data.interface)) return kept('has an "interface" that is not a map');
70
+ const have = isMap(sidecar.data?.interface) ? sidecar.data.interface : {};
71
+ const missing = Object.keys(wanted).filter((k) => have[k] === undefined || have[k] === null || have[k] === '');
72
+ if (!missing.length) return { files, dirs, transform: null, diagnostic: null };
73
+ let nextText;
74
+ try {
75
+ const doc = YAML.parseDocument(sidecar.text);
76
+ for (const key of missing) doc.setIn(['interface', key], wanted[key]);
77
+ nextText = doc.toString();
78
+ } catch (err) { return kept(`could not take the interface keys (${String(err?.message || err).split('\n')[0]})`); }
79
+ const back = YAML.parse(nextText);
80
+ const expected = JSON.parse(JSON.stringify(sidecar.data ?? {}));
81
+ expected.interface = { ...(isMap(expected.interface) ? expected.interface : {}), ...Object.fromEntries(missing.map((k) => [k, wanted[k]])) };
82
+ 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 } };
83
+ const at = files.findIndex((f) => f.path === CODEX_SIDECAR);
84
+ const out = files.map((f, i) => (i === at ? { ...f, bytes: Buffer.from(nextText, 'utf-8') } : f));
85
+ return { files: out, dirs, transform: transform(missing, false), diagnostic: null };
86
+ }
87
+
88
+ /** agents/openai.yaml as Codex would read it: `{ present, data, error, text }`. */
89
+ export function readSidecar(files) {
90
+ const file = (files || []).find((f) => f.path === CODEX_SIDECAR);
91
+ if (!file) return { present: false, data: null, error: null, text: null };
92
+ const text = file.bytes.toString('utf-8');
93
+ try {
94
+ const doc = YAML.parseDocument(text, { uniqueKeys: true, maxAliasCount: 100 });
95
+ if (doc.errors.length) return { present: true, data: null, error: String(doc.errors[0].message).split('\n')[0], text };
96
+ return { present: true, data: doc.toJS({ maxAliasCount: 100 }) ?? null, error: null, text };
97
+ } catch (err) {
98
+ return { present: true, data: null, error: String(err?.message || err).split('\n')[0], text };
99
+ }
100
+ }
101
+
102
+ /** The SKILL.md of a folder as text and parsed frontmatter. */
103
+ export function readHeadOf(files) {
104
+ const head = (files || []).find((f) => f.path === 'SKILL.md');
105
+ const text = head ? head.bytes.toString('utf-8') : '';
106
+ return { head, text, parsed: frontmatter.parse(text) };
107
+ }
108
+
109
+ function patchHead(text, changes) {
110
+ const editing = toEditing(text);
111
+ const result = frontmatter.patch(editing.text, changes);
112
+ if (!result.ok) return null;
113
+ return fromEditing(text, result.text);
114
+ }
115
+
116
+ /**
117
+ * The files an install of these files writes for one profile.
118
+ * @param {{ files: {path, bytes, executable}[], dirs: string[] }} folder
119
+ * @param {string} profileId
120
+ * @returns {{ files, dirs, digest: string, transforms: object[], diagnostics: object[], intent: object }}
121
+ */
122
+ export function buildExport({ files, dirs = [] }, profileId) {
123
+ const profile = getProfile(profileId);
124
+ const { text, parsed } = readHeadOf(files);
125
+ const sidecar = readSidecar(files);
126
+ const intent = readInvocationIntent({ data: parsed.data, sidecar });
127
+ const plan = invocationPlan(profileId, { intent, data: parsed.data || {}, sidecar });
128
+ const out = files.map((f) => ({ ...f }));
129
+ const outDirs = new Set(dirs);
130
+ const applied = [];
131
+ const diagnostics = [...plan.diagnostics];
132
+ let headText = text;
133
+ for (const t of plan.transforms) {
134
+ if (t.op === 'frontmatter' || t.op === 'metadata') {
135
+ let changes;
136
+ if (t.op === 'frontmatter') changes = { [t.key]: t.value };
137
+ else {
138
+ const current = isMap(parsed.data?.metadata) ? parsed.data.metadata : {};
139
+ changes = { metadata: { ...current, [t.key]: t.value } };
140
+ }
141
+ const next = patchHead(headText, changes);
142
+ if (next === null) {
143
+ 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' ? 'showing it to the person' : 'starting it on its own'}: fix the YAML first.`, file: 'SKILL.md', line: null });
144
+ continue;
145
+ }
146
+ headText = next;
147
+ applied.push(t);
148
+ } else if (t.op === 'sidecar') {
149
+ if (!sidecar.present) {
150
+ out.push({ path: CODEX_SIDECAR, bytes: Buffer.from('policy:\n allow_implicit_invocation: false\n', 'utf-8'), executable: false });
151
+ outDirs.add('agents');
152
+ applied.push({ ...t, created: true });
153
+ continue;
154
+ }
155
+ if (sidecar.error) {
156
+ 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 });
157
+ continue;
158
+ }
159
+ let nextText;
160
+ try {
161
+ const doc = YAML.parseDocument(sidecar.text);
162
+ if (!isMap(sidecar.data)) throw new Error('not a YAML map');
163
+ doc.setIn(t.path, t.value);
164
+ nextText = doc.toString();
165
+ } catch (err) {
166
+ 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 });
167
+ continue;
168
+ }
169
+ // Read back: the one value changed, nothing else.
170
+ const back = YAML.parse(nextText);
171
+ const expected = JSON.parse(JSON.stringify(sidecar.data ?? {}));
172
+ let node = expected;
173
+ for (const key of t.path.slice(0, -1)) { if (!isMap(node[key])) node[key] = {}; node = node[key]; }
174
+ node[t.path[t.path.length - 1]] = t.value;
175
+ if (JSON.stringify(back) !== JSON.stringify(expected)) {
176
+ 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 });
177
+ continue;
178
+ }
179
+ const at = out.findIndex((f) => f.path === CODEX_SIDECAR);
180
+ out[at] = { ...out[at], bytes: Buffer.from(nextText, 'utf-8') };
181
+ applied.push(t);
182
+ }
183
+ }
184
+ if (headText !== text) {
185
+ const at = out.findIndex((f) => f.path === 'SKILL.md');
186
+ out[at] = { ...out[at], bytes: Buffer.from(headText, 'utf-8') };
187
+ }
188
+ for (const t of applied) diagnostics.push({ ruleId: 'L-08-invocation-adapted', severity: 'info', message: `${t.file}: ${t.reason}`, file: t.file, line: null });
189
+ // Codex: the words its picker shows, in agents/openai.yaml (added where missing, never over what is there).
190
+ let withDirs = [...outDirs];
191
+ let withFiles = out;
192
+ if (profile?.runtime === 'codex') {
193
+ const added = withCodexInterface(out, withDirs, parsed.data || {});
194
+ withFiles = added.files; withDirs = added.dirs;
195
+ 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 }); }
196
+ if (added.diagnostic) diagnostics.push(added.diagnostic);
197
+ }
198
+ const result = { files: withFiles.sort((a, b) => (a.path < b.path ? -1 : 1)), dirs: withDirs.sort() };
199
+ return { ...result, digest: folderDigest(result), transforms: applied, diagnostics, intent };
200
+ }
@@ -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
+ }