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,280 @@
1
+ // ── The OS sandbox of an evaluation's shell (P4, macOS) ──
2
+ // A task case that asks for a shell (`shell: true`) runs untrusted skill text with a real shell. Every command of that
3
+ // shell, and nothing else, runs under a Seatbelt profile of its own (evalShellProfile), through a small wrapper the
4
+ // runtime is told to use for its commands: Claude Code's CLAUDE_CODE_SHELL_PREFIX (its Bash tool and any hook command
5
+ // go through it), OpenCode's SHELL (its bash tool runs `$SHELL -c <command>`). The runtime itself stays outside, with
6
+ // its own sign-in; its shell, inside, has:
7
+ //
8
+ // network none at all: SynaBun's ports, local servers and the internet alike (the deny is `network*`)
9
+ // writes its job folder, its own temp, home and git folders, the terminal devices; inside the job folder, the
10
+ // folders and files a runtime reads its settings, skills or code from (.claude, .opencode, .git,
11
+ // opencode.json, … ss-evals.js EVAL_CONFIG_DIRS / EVAL_CONFIG_FILES, any letter case, a folder at any
12
+ // depth) stay as SynaBun wrote them. No symlink can be created in any writable place (the last file-write
13
+ // rule denies vnode-type SYMLINK): a shell step is the only thing that could plant or repoint a job-folder
14
+ // symlink, and that link is the one way the (unsandboxed) eval read tool could be steered outside the folder
15
+ // between its permission ask and its open — removing it is what makes the ask-time realpath check race-free
16
+ // git a repository of its own beside the job folder, never in it: GIT_DIR is the trial's git folder and
17
+ // GIT_WORK_TREE the job folder, so `git init`, `add`, `commit`, `log`, `diff`, `branch` and `checkout` work on
18
+ // the folder's files while no `.git` (a folder, or a `gitdir:` file) can be made anywhere in it. The runtime
19
+ // outside runs git in the job folder too (Claude Code's status, OpenCode's project and snapshot reads):
20
+ // there is no repository there to read, and that side's git takes no bare repository it was not pointed at
21
+ // and reads no global or system configuration (lib/skills/eval-confinement.js evalGitSafetyEnv), so nothing
22
+ // a command writes is read by it. A commit's identity is the trial home's .gitconfig (a test may set its own)
23
+ // reads nothing under /Users (every home folder), /Volumes, SynaBun's data home, /private/tmp or
24
+ // /private/var/folders (other programs' temp files), except the job folder, its own temp, home and git
25
+ // folders, the folders on PATH and a few language toolchains (runtimes, no settings), and Claude Code's
26
+ // shell snapshot (its shell setup, which every one of its commands sources first)
27
+ // others a signal only to a process of its own sandbox (`kill -0` of any other process is refused); no launchd job
28
+ // (`job-creation` is denied: `launchctl submit` is refused, while `launchctl print` still reads); no Apple
29
+ // event (`appleevent-send` is denied: a real event, to System Events, fails with -4960, while
30
+ // `osascript -e 1` still runs, because it sends none); no lookup of the Mach services that hold the user's
31
+ // data or start programs outside it (EVAL_SHELL_MACH_DENY: a keychain read and pbcopy / pbpaste were seen
32
+ // to fail; LaunchServices, the window server, screen capture and TCC are denied by name)
33
+ // env a short allowlist (locale, terminal, PATH and what the runtime's own command line needs): no token,
34
+ // key or password of the runtime's environment reaches a command; HOME and TMPDIR are the trial's own, and
35
+ // git's variables are the wrapper's (none of the runtime's)
36
+ //
37
+ // The `others` line is what the P4 verification saw. tests/skills-p4-eval-sandbox.test.mjs repeats the signal, keychain
38
+ // and launchd checks (a job its `launchctl submit` did make would be removed at once, and the test would fail); it
39
+ // sends no Apple event and asks no screen or app service again, since one that got through would act on the owner's
40
+ // session (a TCC prompt, an app started).
41
+ // Seatbelt is last-match-wins and matches resolved paths (lib/worker-sandbox.js: canonicalPath), so every path here is
42
+ // canonical and every allow comes after the deny it opens. This module only builds and writes; whether sandbox-exec
43
+ // works is lib/worker-sandbox.js sandboxExecAvailable(). A shell that cannot be set up this way is not given: the run
44
+ // fails closed (lib/skills/evals.js, server.js).
45
+
46
+ import { chmodSync, existsSync, mkdirSync, realpathSync, writeFileSync } from 'node:fs';
47
+ import { basename, dirname, isAbsolute, join, sep } from 'node:path';
48
+ import { SANDBOX_EXEC, canonicalPath, sandboxExecAvailable, sandboxSupported } from '../worker-sandbox.js';
49
+ import { EVAL_CONFIG_DIRS, EVAL_CONFIG_FILES } from '../../public/shared/skills/ss-evals.js';
50
+
51
+ /** Part of an evaluation's confinement version: a change to what an evaluation's shell may do is a new one. */
52
+ export const EVAL_SHELL_VERSION = 'skill-eval-shell/3';
53
+
54
+ /** Mach services an evaluation's shell never reaches (the keychain, the clipboard, apps, the screen). */
55
+ export const EVAL_SHELL_MACH_DENY = Object.freeze([
56
+ ['global-name', 'com.apple.SecurityServer'], ['global-name', 'com.apple.securityd'], ['global-name', 'com.apple.securityd.xpc'],
57
+ ['global-name', 'com.apple.security.agent'], ['global-name', 'com.apple.security.authhost'], ['global-name', 'com.apple.pasteboard.1'],
58
+ ['global-name-prefix', 'com.apple.coreservices.launchservicesd'], ['global-name-prefix', 'com.apple.lsd.'],
59
+ ['global-name', 'com.apple.windowserver.active'], ['global-name-prefix', 'com.apple.screencapture'], ['global-name', 'com.apple.tccd'],
60
+ ]);
61
+
62
+ /** Folders under a home that hold language runtimes only: readable from an evaluation's shell when present. */
63
+ export const EVAL_SHELL_TOOLCHAINS = Object.freeze([
64
+ '.nvm/versions', '.volta/tools/image', '.fnm/node-versions', '.local/share/fnm/node-versions', '.pyenv/versions', '.rbenv/versions',
65
+ '.rustup/toolchains', '.asdf/installs', '.local/share/mise/installs', '.bun/bin', '.deno/bin',
66
+ ]);
67
+
68
+ /** What of the runtime's environment a command keeps (everything else, its tokens and keys among it, is left out). */
69
+ export const EVAL_SHELL_ENV_KEEP = Object.freeze([
70
+ 'PATH', 'LANG', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES', 'LC_COLLATE', 'LC_NUMERIC', 'LC_TIME', 'LC_MONETARY', 'TERM', 'COLORTERM',
71
+ 'NO_COLOR', 'FORCE_COLOR', 'COLUMNS', 'LINES', 'USER', 'LOGNAME', 'TZ', 'SHLVL',
72
+ // Claude Code's command line reads these (it sets BUN_OPTIONS from the first, and refuses to run without it).
73
+ '__CLAUDE_CC_BUN_OPTIONS', 'CLAUDECODE', 'CLAUDE_CODE_ENTRYPOINT',
74
+ ]);
75
+
76
+ /** The identity of a commit a shell step makes, in the trial home's .gitconfig (its lowest place: a test's own wins). */
77
+ export const EVAL_SHELL_GIT_IDENTITY = Object.freeze({ name: 'SynaBun evaluation', email: 'evaluation@synabun.invalid' });
78
+
79
+ const SHELLS = Object.freeze({ zsh: { path: '/bin/zsh', args: ['-f'] }, bash: { path: '/bin/bash', args: ['--noprofile', '--norc'] }, sh: { path: '/bin/sh', args: [] } });
80
+
81
+ /** Whether an evaluation's shell can be held here: macOS with a working sandbox-exec. */
82
+ export function evalShellSupported({ platform = process.platform, probe = sandboxExecAvailable } = {}) {
83
+ return sandboxSupported(platform) && probe({ platform }) === true;
84
+ }
85
+
86
+ /** A Seatbelt string literal. */
87
+ function lit(text) { return `"${String(text).replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; }
88
+ /**
89
+ * Text as a Seatbelt regular expression that matches it and nothing else. A #"…" literal is raw (a backslash is not an
90
+ * escape there), so ASCII punctuation goes in a bracket ([.] is a dot); letters, digits and other characters stay as
91
+ * they are. A path holding a quote, a backslash or a control character cannot be named this way: refused.
92
+ */
93
+ function regexText(text) {
94
+ let out = '';
95
+ for (const c of String(text)) {
96
+ if (c === '"' || c === '\\' || /[\u0000-\u001f\u007f]/.test(c)) throw new Error('The evaluation folder\'s path has a character the sandbox cannot name.');
97
+ if (/[A-Za-z0-9_/ -]/.test(c) || c.charCodeAt(0) > 0x7f) out += c;
98
+ else if (c === ']') out += '[]]';
99
+ else if (c === '^') out += '[*^]';
100
+ else out += `[${c}]`;
101
+ }
102
+ return out;
103
+ }
104
+ /** A Seatbelt regular expression literal (#"…", raw). */
105
+ const rx = (source) => `#"${source}"`;
106
+ /** A name for a regex in any letter case ([cC][lL]…), every other character as itself. */
107
+ function anyCase(name) { return [...String(name)].map((c) => (/[a-z]/i.test(c) ? `[${c.toLowerCase()}${c.toUpperCase()}]` : regexText(c))).join(''); }
108
+ /** The deepest existing ancestor resolved, and absolute: what Seatbelt sees. */
109
+ const canon = (p) => canonicalPath(isAbsolute(String(p)) ? String(p) : join(process.cwd(), String(p)));
110
+ const inside = (p, root) => p === root || p.startsWith(root.endsWith(sep) ? root : `${root}${sep}`);
111
+
112
+ /**
113
+ * The directory nodes on the way to each allowed path that fall in a denied tree: `stat` of those nodes only (a
114
+ * literal, never their contents), so a command can resolve its way into the job folder without listing a home.
115
+ */
116
+ function metadataAncestors(allows, denies) {
117
+ const out = new Set();
118
+ for (const allow of allows) {
119
+ for (let dir = dirname(allow), i = 0; i < 256; i++) {
120
+ if (denies.some((d) => inside(dir, d))) out.add(dir);
121
+ const up = dirname(dir);
122
+ if (up === dir) break;
123
+ dir = up;
124
+ }
125
+ }
126
+ return [...out].sort();
127
+ }
128
+
129
+ /**
130
+ * The profile of one evaluation's shell.
131
+ * @param {object} o
132
+ * @param {string} o.root the job folder (the run's cwd)
133
+ * @param {string} o.temp the trial's own temp folder
134
+ * @param {string} o.home the trial's own home folder (HOME of every command)
135
+ * @param {string} o.git the trial's own git folder (GIT_DIR of every command: the repository of the job folder's files)
136
+ * @param {string[]} [o.denyReadTrees] trees nothing is read from (the home folders, SynaBun's data home, …), on top of
137
+ * /Users, /Volumes, /private/tmp and /private/var/folders
138
+ * @param {string[]} [o.readOnly] paths read back after the denies (PATH folders, toolchains, Claude Code's snapshots)
139
+ * @param {string} [o.note] a comment line
140
+ * @returns {string}
141
+ */
142
+ export function evalShellProfile({ root, temp, home, git, denyReadTrees = [], readOnly = [], note = '' } = {}) {
143
+ if (!root || !temp || !home || !git) throw new Error('An evaluation shell profile needs its job, temp, home and git folders.');
144
+ const job = canon(root);
145
+ const tmp = canon(temp);
146
+ const own = canon(home);
147
+ const repo = canon(git);
148
+ if (inside(repo, job) || inside(job, repo)) throw new Error('An evaluation shell\'s git folder is beside its job folder, never in it or around it.');
149
+ const denies = [...new Set(['/Users', '/Volumes', '/private/tmp', '/private/var/folders', ...denyReadTrees.filter(Boolean).map(canon)])];
150
+ const reads = [...new Set(readOnly.filter(Boolean).map(canon))].filter((p) => p !== '/' && !inside(job, p));
151
+ const lines = ['(version 1)', `; synabun ${EVAL_SHELL_VERSION}${note ? `: ${String(note).replace(/[\r\n]+/g, ' ').slice(0, 200)}` : ''}`, '(allow default)'];
152
+ lines.push('; no network at all (SynaBun, local servers, the internet)');
153
+ lines.push('(deny network*)');
154
+ lines.push('; a signal only to a process of this sandbox; no launchd job (launchctl submit refused); no Apple event sent');
155
+ lines.push('(deny signal)', '(allow signal (target same-sandbox))', '(deny job-creation)', '(deny appleevent-send)');
156
+ lines.push('; the keychain, the clipboard, LaunchServices, the window server, screen capture and TCC, by service name');
157
+ lines.push(`(deny mach-lookup ${EVAL_SHELL_MACH_DENY.map(([kind, name]) => `(${kind} ${lit(name)})`).join(' ')})`);
158
+ lines.push('; writes: the job folder, the trial\'s temp, home and git folders, the terminal devices');
159
+ lines.push('(deny file-write*)');
160
+ lines.push(`(allow file-write* (subpath ${lit(job)}) (subpath ${lit(tmp)}) (subpath ${lit(own)}) (subpath ${lit(repo)}) (literal "/dev/null") (literal "/dev/zero") (literal "/dev/random") (literal "/dev/urandom") (literal "/dev/dtracehelper") (literal "/dev/tty") (literal "/dev/stdout") (literal "/dev/stderr") (regex #"^/dev/ttys[0-9]+$") (regex #"^/dev/fd/[0-9]+$"))`);
161
+ lines.push('; the folders (at any depth: .git among them, so no repository is ever made here) and top files a runtime reads its settings or code from stay as SynaBun wrote them (any letter case)');
162
+ const base = regexText(job);
163
+ const dirRules = Object.keys(EVAL_CONFIG_DIRS).map((name) => `(regex ${rx(`^${base}/(.+/)?${anyCase(name)}(/|$)`)})`);
164
+ const fileRules = Object.keys(EVAL_CONFIG_FILES).map((name) => `(regex ${rx(`^${base}/${anyCase(name)}$`)})`);
165
+ lines.push(`(deny file-write* ${[...dirRules, ...fileRules].join(' ')})`);
166
+ lines.push('; reads: no home folder, other volume, other temp files or SynaBun data');
167
+ lines.push(`(deny file-read* ${denies.map((d) => `(subpath ${lit(d)})`).join(' ')})`);
168
+ lines.push('; read back: the job folder, the trial\'s temp, home and git folders, the tools on PATH and the runtime\'s shell setup');
169
+ lines.push(`(allow file-read* (subpath ${lit(job)}) (subpath ${lit(tmp)}) (subpath ${lit(own)}) (subpath ${lit(repo)})${reads.map((p) => ` (subpath ${lit(p)})`).join('')})`);
170
+ // Apple's command-line tool shims (git, python3 from the Command Line Tools) keep an SDK lookup cache in the user's
171
+ // temp folder whatever TMPDIR says: that one file name only.
172
+ lines.push('(allow file-read* file-write* (regex #"^/private/var/folders/[^/]+/[^/]+/T/xcrun_db"))');
173
+ // No symlink may be created in any writable place (last of the file-write rules, so it wins over every allow above,
174
+ // xcrun_db included). A symlink is the one way a shell step of a trial could repoint a path inside the job folder at
175
+ // a file OUTSIDE it between the read tool's permission ask (evalOpenCodeDecision, which resolves the real path and
176
+ // refuses one leaving the folder) and the tool's open — a TOCTOU the ask alone cannot close, because the eval read
177
+ // tool runs in the runtime's own process, not under this sandbox, so SynaBun cannot bind the path it finally opens.
178
+ // The job folder is created fresh with no symlink, SynaBun's skill copy follows none, and Write/Edit make plain files
179
+ // only, so the shell is the sole writer that could introduce one; deny it here and no symlink can ever exist in the
180
+ // folder, which is what makes the ask-time realpath check race-free. Regular writes, mkdir, rename (mv) and hardlinks
181
+ // to in-folder files are untouched; a hardlink to an outside file already fails (its lookup needs a read the denies
182
+ // above refuse). Verified on macOS 26 (scratch probes, 2026-10-25): ln -s / ln -sf are refused, mv and mkdir work.
183
+ lines.push('(deny file-write* (vnode-type SYMLINK))');
184
+ const ancestors = metadataAncestors([job, tmp, own, repo, ...reads], denies);
185
+ if (ancestors.length) lines.push(`(allow file-read-metadata ${ancestors.map((d) => `(literal ${lit(d)})`).join(' ')})`);
186
+ return `${lines.join('\n')}\n`;
187
+ }
188
+
189
+ /**
190
+ * The folders of a trial an evaluation's shell uses: the job folder, and beside it its temp, home, git (the repository
191
+ * of the job folder's files, GIT_DIR) and sandbox folders.
192
+ */
193
+ export function evalShellPaths(cwd) {
194
+ const root = realpathSync(String(cwd || ''));
195
+ const trialDir = dirname(root);
196
+ return { root, trialDir, temp: join(trialDir, 'tmp'), home: join(trialDir, 'home'), git: join(trialDir, 'git'), dir: join(trialDir, 'sandbox') };
197
+ }
198
+
199
+ /** The real shell a command runs in (the runtime's shell's family: Claude Code's snapshot is written for it). */
200
+ export function evalInnerShell(shell = process.env.SHELL) {
201
+ const name = basename(String(shell || '')).toLowerCase();
202
+ return name === 'bash' ? 'bash' : name === 'sh' ? 'sh' : 'zsh';
203
+ }
204
+
205
+ /**
206
+ * The wrapper one command goes through. Claude Code calls it as `wrapper '<command>'` (its shell prefix), OpenCode as
207
+ * `wrapper -c '<command>'` (its shell); `-l`/`-i` before `-c` are let go. Anything else is refused (exit 126). Its git
208
+ * works on the job folder's files from the trial's git folder (GIT_DIR, GIT_WORK_TREE), never looks above the trial's
209
+ * folder for another repository and reads no system configuration; the global one is the trial home's.
210
+ */
211
+ export function evalShellWrapper({ profilePath, shell = 'zsh', home, temp, root, git }) {
212
+ if (!root || !git) throw new Error('An evaluation shell\'s wrapper needs its job and git folders.');
213
+ const sh = (s) => `'${String(s).replace(/'/g, `'\\''`)}'`;
214
+ const inner = SHELLS[shell] || SHELLS.zsh;
215
+ const keep = EVAL_SHELL_ENV_KEEP.map((name) => `\${${name}+"${name}=$${name}"}`).join(' ');
216
+ const gitEnv = `GIT_DIR=${sh(git)} GIT_WORK_TREE=${sh(root)} GIT_CEILING_DIRECTORIES=${sh(dirname(root))} GIT_CONFIG_NOSYSTEM=1`;
217
+ return [
218
+ '#!/bin/sh',
219
+ `# SynaBun (${EVAL_SHELL_VERSION}): one command of a skill evaluation, under the evaluation's sandbox. Written per trial.`,
220
+ 'cmd=',
221
+ 'if [ $# -eq 1 ]; then cmd=$1',
222
+ 'else',
223
+ ' while [ $# -gt 0 ]; do',
224
+ ' case "$1" in',
225
+ ' -c|-lc|-cl|-ic|-ci|-ilc|-lic) shift; cmd=${1-}; break ;;',
226
+ ' -l|-i|--login|--interactive|--noprofile|--norc) shift ;;',
227
+ ' *) break ;;',
228
+ ' esac',
229
+ ' done',
230
+ 'fi',
231
+ 'if [ -z "$cmd" ]; then echo "synabun: an evaluation shell runs one command (-c)." >&2; exit 126; fi',
232
+ `exec /usr/bin/env -i ${keep} HOME=${sh(home)} TMPDIR=${sh(`${temp}/`)} CLAUDE_CODE_TMPDIR=${sh(temp)} SHELL=${sh(inner.path)} ${gitEnv} ${sh(SANDBOX_EXEC)} -f ${sh(profilePath)} ${sh(inner.path)}${inner.args.map((a) => ` ${a}`).join('')} -c "$cmd"`,
233
+ '',
234
+ ].join('\n');
235
+ }
236
+
237
+ /** The folders on PATH that sit in a denied tree, and the toolchains under each home: read back for the shell. */
238
+ export function evalShellReadPaths({ path = process.env.PATH, homes = [], claudeConfigDir = null } = {}) {
239
+ const out = new Set();
240
+ for (const dir of String(path || '').split(':')) if (dir && isAbsolute(dir) && existsSync(dir)) out.add(canon(dir));
241
+ for (const h of homes.filter(Boolean)) for (const rel of EVAL_SHELL_TOOLCHAINS) { const p = join(h, rel); if (existsSync(p)) out.add(canon(p)); }
242
+ if (claudeConfigDir) out.add(canon(join(claudeConfigDir, 'shell-snapshots')));
243
+ return [...out];
244
+ }
245
+
246
+ /** The trial home's .gitconfig: a commit's identity (EVAL_SHELL_GIT_IDENTITY) and git's default-branch hint off. */
247
+ export function evalShellGitConfig() {
248
+ return [
249
+ `# SynaBun (${EVAL_SHELL_VERSION}): git's settings for a skill evaluation's shell. Written per trial.`,
250
+ '[user]', `\tname = ${EVAL_SHELL_GIT_IDENTITY.name}`, `\temail = ${EVAL_SHELL_GIT_IDENTITY.email}`,
251
+ '[advice]', '\tdefaultBranchName = false', '',
252
+ ].join('\n');
253
+ }
254
+
255
+ /**
256
+ * Set up one trial's shell: its temp, home and git folders (the home with its .gitconfig), its profile and its wrapper
257
+ * (in the trial's own sandbox folder, outside the job folder, so nothing the shell does can change them).
258
+ * → { wrapperPath, profilePath, shell, env, paths }
259
+ * `env` is what the runtime gets (TMPDIR and CLAUDE_CODE_TMPDIR: its own temp files go into the trial's).
260
+ * @param {object} o
261
+ * @param {string} o.cwd the job folder
262
+ * @param {string[]} [o.denyReadTrees] SynaBun's data home, the home folders
263
+ * @param {string[]} [o.readOnly] evalShellReadPaths()
264
+ * @param {string} [o.shell] the runtime's shell (its family is the inner shell)
265
+ * @param {string} [o.wrapperName] the wrapper's file name (OpenCode accepts a shell by its name: zsh, bash or sh)
266
+ */
267
+ export function prepareEvalShell({ cwd, denyReadTrees = [], readOnly = [], shell = process.env.SHELL, wrapperName = null, note = '' } = {}) {
268
+ const paths = evalShellPaths(cwd);
269
+ for (const dir of [paths.temp, paths.home, paths.git, paths.dir]) mkdirSync(dir, { recursive: true, mode: 0o700 });
270
+ writeFileSync(join(paths.home, '.gitconfig'), evalShellGitConfig(), { mode: 0o600 });
271
+ const inner = evalInnerShell(shell);
272
+ const profile = evalShellProfile({ root: paths.root, temp: paths.temp, home: paths.home, git: paths.git, denyReadTrees, readOnly, note });
273
+ const profilePath = join(paths.dir, 'shell.sb');
274
+ writeFileSync(profilePath, profile, { mode: 0o600 });
275
+ const name = wrapperName && /^(?:zsh|bash|sh)$/.test(wrapperName) ? wrapperName : inner;
276
+ const wrapperPath = join(paths.dir, name);
277
+ writeFileSync(wrapperPath, evalShellWrapper({ profilePath, shell: inner, home: canon(paths.home), temp: canon(paths.temp), root: paths.root, git: canon(paths.git) }), { mode: 0o700 });
278
+ chmodSync(wrapperPath, 0o700);
279
+ return { wrapperPath, profilePath, shell: inner, paths, env: { TMPDIR: `${canon(paths.temp)}/`, CLAUDE_CODE_TMPDIR: canon(paths.temp) } };
280
+ }
@@ -0,0 +1,135 @@
1
+ // ── What an evaluation run did: its tool calls, and whether the runtime picked the skill (P4, SK-085) ──
2
+ // The dispatcher keeps the tool calls of an evaluation run (assistant-dispatch.js, transcript format `tools`), read
3
+ // here from each provider's own events; a trigger trial is read from them:
4
+ //
5
+ // Claude Code a `Skill` call naming the skill: method `native_skill_tool` (seen). A Read of its SKILL.md without
6
+ // one: `successful_skill_file_read` (an inference).
7
+ // OpenCode a `skill` tool call naming it (`{ id }`): `native_skill_tool`;
8
+ // a read of its SKILL.md: the inference.
9
+ // Codex Codex has no skill tool: it lists its skills and the model reads the file with its shell. A command
10
+ // that ran (exit 0) and names the skill's SKILL.md: `successful_skill_file_read` (an inference).
11
+ //
12
+ // A skill named that is not the one under test is evidence too (the runtime picked another), never a "yes". The
13
+ // runtime's own listing at start (Claude's init `skills`) is kept as the catalog the run saw: a baseline that lists
14
+ // the skill under test was not a baseline. Startup discovery is never counted as a selection. A call's input is kept with
15
+ // its secrets redacted, the way an answer and a written file are (lib/log-redact.js). Pure.
16
+
17
+ import { redactSecrets } from '../../../lib/log-redact.js';
18
+
19
+ const clipJson = (value, max = 600) => {
20
+ let text;
21
+ try { text = typeof value === 'string' ? value : JSON.stringify(value ?? null); } catch { text = String(value); }
22
+ return text.length > max ? `${text.slice(0, max - 1)}…` : text;
23
+ };
24
+ const isObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
25
+
26
+ /**
27
+ * The tool calls one provider event carries: [{ id, tool, input, phase?, ok? }]. Claude: the tool_use blocks of a
28
+ * whole assistant message; Codex: a command (started, then done with its exit code), an MCP call, a file change;
29
+ * OpenCode: a tool part (each update of a call has its id: the caller keeps one entry per id).
30
+ */
31
+ export function toolCallsOf(payload = {}) {
32
+ const event = payload?.event || {};
33
+ const eventType = String(payload?.eventType || event.type || '');
34
+ const out = [];
35
+ if (payload.provider === 'claude-code') {
36
+ if (event.type === 'assistant' && Array.isArray(event.message?.content)) {
37
+ for (const block of event.message.content) {
38
+ if (block?.type === 'tool_use') out.push({ id: String(block.id || ''), tool: String(block.name || ''), input: isObject(block.input) ? block.input : {}, sub: !!event.parent_tool_use_id });
39
+ }
40
+ }
41
+ return out;
42
+ }
43
+ if (payload.provider === 'codex') {
44
+ if (event.type === 'item.started' || event.type === 'item.completed') {
45
+ const item = event.item || {};
46
+ const done = event.type === 'item.completed';
47
+ if (item.type === 'command_execution') {
48
+ const command = typeof item.command === 'string' ? item.command : Array.isArray(item.command) ? item.command.join(' ') : '';
49
+ out.push({ id: String(item.id || ''), tool: 'shell', input: { command }, phase: done ? 'done' : 'started', ok: done ? Number(item.exit_code) === 0 : null });
50
+ } else if (item.type === 'mcp_tool_call') out.push({ id: String(item.id || ''), tool: `${item.server || ''}.${item.tool || ''}`, input: {}, phase: done ? 'done' : 'started' });
51
+ else if (item.type === 'file_change') out.push({ id: String(item.id || ''), tool: 'file_change', input: { paths: (item.changes || []).map((c) => c?.path).filter(Boolean) }, phase: done ? 'done' : 'started' });
52
+ else if (item.type === 'web_search') out.push({ id: String(item.id || ''), tool: 'web_search', input: { query: item.query || '' }, phase: done ? 'done' : 'started' });
53
+ }
54
+ return out;
55
+ }
56
+ if (payload.provider === 'opencode') {
57
+ if (/^message[.:]part[.:]updated$/i.test(eventType)) {
58
+ const part = event.part || {};
59
+ if (part.type === 'tool') out.push({ id: String(part.callID || part.id || ''), tool: String(part.tool || part.name || ''), input: isObject(part.state?.input) ? part.state.input : {}, phase: String(part.state?.status || ''), ok: part.state?.status === 'completed' ? true : part.state?.status === 'error' ? false : null });
60
+ }
61
+ return out;
62
+ }
63
+ if (payload.provider === 'antigravity') {
64
+ // An ACP tool call (session/update tool_call, then tool_call_update with its status). Antigravity names its
65
+ // tool (read_file, run_command, call_mcp_tool …) and its arguments in its own words: the path a read names
66
+ // and a command's line are kept under `path` / `command`; an MCP call is <server>.<tool>.
67
+ if ((eventType === 'tool_call' || eventType === 'tool_call_update') && event.toolCallId) {
68
+ const raw = isObject(event.rawInput) ? event.rawInput : {};
69
+ const mcp = String(event.name || '') === 'call_mcp_tool' && raw.ServerName && raw.ToolName ? `${raw.ServerName}.${raw.ToolName}` : '';
70
+ const location = Array.isArray(event.locations) ? event.locations.find((l) => typeof l?.path === 'string' && l.path)?.path : '';
71
+ const path = [raw.AbsolutePath, raw.Path, raw.TargetFile, raw.path, raw.file_path, location].find((v) => typeof v === 'string' && v) || '';
72
+ const command = typeof raw.CommandLine === 'string' ? raw.CommandLine : typeof raw.command === 'string' ? raw.command : '';
73
+ const input = { ...(path ? { path } : {}), ...(command ? { command } : {}) };
74
+ const status = String(event.status || '');
75
+ out.push({ id: String(event.toolCallId), tool: mcp || String(event.name || event.kind || ''), input, phase: status, ok: status === 'completed' ? true : status === 'failed' ? false : null });
76
+ }
77
+ return out;
78
+ }
79
+ return out;
80
+ }
81
+
82
+ /** Claude's init event, as the catalog the run saw: { model, skills, tools, cwd } (null for any other event). */
83
+ export function initOf(payload = {}) {
84
+ const event = payload?.event || {};
85
+ if (payload.provider !== 'claude-code' || event.type !== 'system' || event.subtype !== 'init') return null;
86
+ const names = (list) => (Array.isArray(list) ? list.map((x) => (typeof x === 'string' ? x : x?.name)).filter((x) => typeof x === 'string').slice(0, 200) : null);
87
+ return { model: typeof event.model === 'string' ? event.model : null, skills: names(event.skills), tools: names(event.tools), cwd: typeof event.cwd === 'string' ? event.cwd : null };
88
+ }
89
+
90
+ /** A value with a secret in any of its texts redacted (each string as it is, before it is written as JSON). Bounded. */
91
+ function redactValue(value, depth = 0) {
92
+ if (typeof value === 'string') return redactSecrets(value.length > 20_000 ? value.slice(0, 20_000) : value);
93
+ if (depth > 8 || value === null || typeof value !== 'object') return value;
94
+ if (Array.isArray(value)) return value.slice(0, 200).map((v) => redactValue(v, depth + 1));
95
+ return Object.fromEntries(Object.entries(value).slice(0, 200).map(([k, v]) => [k, redactValue(v, depth + 1)]));
96
+ }
97
+
98
+ /** A tool call kept for the record: its tool, its input as bounded JSON text, every secret in it redacted first. */
99
+ export const callRecord = (c) => ({ tool: c.tool, input: clipJson(redactValue(c.input), 400), ...(c.phase ? { phase: c.phase } : {}), ...(c.ok === true || c.ok === false ? { ok: c.ok } : {}) });
100
+
101
+ const skillFilePattern = (name) => new RegExp(`(?:^|[\\\\/\\s'"])skills[\\\\/]${name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\\\/]SKILL\\.md\\b`, 'i');
102
+ const SKILL_MD = /(?:^|[\\/\s'"])skills[\\/]([a-z0-9][a-z0-9._-]{0,63})[\\/]SKILL\.md\b/gi;
103
+
104
+ /**
105
+ * Whether the run picked the skill: { observed: true|false, method, evidence: [{ tool, input }], others: [names] }.
106
+ * `observed` is false when nothing named it (the caller decides whether the run got far enough to say so).
107
+ */
108
+ export function detectSelection({ provider, calls = [], skillName }) {
109
+ const name = String(skillName || '');
110
+ const evidence = [];
111
+ const others = new Set();
112
+ let native = false;
113
+ let read = false;
114
+ const file = name ? skillFilePattern(name) : null;
115
+ for (const c of calls) {
116
+ const tool = String(c.tool || '');
117
+ const input = isObject(c.input) ? c.input : {};
118
+ if ((provider === 'claude-code' && tool === 'Skill') || (provider === 'opencode' && tool === 'skill')) {
119
+ // Claude Code's Skill sends { skill }, OpenCode's skill tool { id } (seen in a live run).
120
+ const asked = String(input.skill ?? input.id ?? input.command ?? '').replace(/^\//, '');
121
+ const bare = asked.includes(':') ? asked.split(':').pop() : asked;
122
+ if (name && (asked === name || bare === name)) { native = true; evidence.push(callRecord(c)); } else if (asked) others.add(asked.slice(0, 64));
123
+ continue;
124
+ }
125
+ const text = provider === 'codex' ? String(input.command || '') : String(input.file_path ?? input.filePath ?? input.path ?? '');
126
+ if (!text) continue;
127
+ if (provider === 'codex' && c.phase === 'started') continue; // a command that ran (its done item, exit 0) is a read
128
+ if (provider === 'codex' && c.ok === false) continue;
129
+ const readTool = provider === 'codex' ? tool === 'shell' : /^(?:read|Read)$/.test(tool);
130
+ if (!readTool) continue;
131
+ if (file && file.test(text)) { read = true; evidence.push(callRecord(c)); continue; }
132
+ for (const m of text.matchAll(SKILL_MD)) if (m[1] !== name) others.add(m[1]);
133
+ }
134
+ return { observed: native || read, method: native ? 'native_skill_tool' : read ? 'successful_skill_file_read' : null, evidence: evidence.slice(0, 5), others: [...others].slice(0, 10) };
135
+ }