novahiz 0.2.3 → 0.3.1

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 (580) hide show
  1. package/NOTICE.md +36 -15
  2. package/README.md +33 -30
  3. package/adapters/README.md +1 -1
  4. package/adapters/opencode/agent/novahiz.md +2 -3
  5. package/adapters/opencode/instructions.md +3 -2
  6. package/adapters/opencode/novahiz.ts +336 -40
  7. package/bin/novahiz.cmd +2 -2
  8. package/catalog/categories.json +1358 -1093
  9. package/catalog/overrides.json +739 -13
  10. package/catalog/providers.json +57 -31
  11. package/catalog/rules.json +55 -29
  12. package/docs/ARCHITECTURE.md +4 -4
  13. package/docs/CATALOG.md +10 -9
  14. package/docs/CLASSIFICATION.md +3 -1
  15. package/docs/CONFIGURATION.md +5 -5
  16. package/docs/CONSTITUTION.md +4 -4
  17. package/docs/CONVERGENCE-2026-09-25.md +5 -0
  18. package/docs/GATE.md +32 -25
  19. package/docs/HARNESSES.md +15 -0
  20. package/docs/INSTALL.md +8 -5
  21. package/docs/PROVIDERS.md +26 -10
  22. package/docs/ROADMAPS.md +33 -3
  23. package/docs/RULES.md +15 -11
  24. package/docs/audit-2026-09-25.md +275 -0
  25. package/install/bootstrap.mjs +32 -37
  26. package/install/install.mjs +70 -53
  27. package/install/lib.mjs +20 -4
  28. package/mcp/novahiz-tools/README.md +5 -0
  29. package/mcp/novahiz-tools/index.mjs +78 -7
  30. package/novahiz.config.example.json +2 -5
  31. package/package.json +2 -3
  32. package/skills/apple-ui-audit/SKILL.md +95 -0
  33. package/skills/apple-ui-audit/references/screen-walkthrough.md +29 -0
  34. package/skills/browser-session/SKILL.md +61 -0
  35. package/skills/browser-session/references/session-run-sheet.md +30 -0
  36. package/skills/browser-session/scripts/browser_session_preflight.mjs +74 -0
  37. package/skills/browser-session/scripts/sample-run.json +5 -0
  38. package/skills/code-standards/SKILL.md +85 -0
  39. package/skills/code-standards/references/pr-review-worksheet.md +35 -0
  40. package/skills/design-token-pipeline/SKILL.md +85 -0
  41. package/skills/design-token-pipeline/references/dtcg-sample.json +37 -0
  42. package/skills/gate/SKILL.md +16 -1
  43. package/skills/llm-threat-review/SKILL.md +99 -0
  44. package/skills/llm-threat-review/references/review-worksheet.md +34 -0
  45. package/skills/llm-threat-review/scripts/llm_risk_lint.mjs +105 -0
  46. package/skills/novahiz-analyse/SKILL.md +2 -2
  47. package/skills/novahiz-audit/SKILL.md +2 -2
  48. package/skills/novahiz-code-review/SKILL.md +1 -1
  49. package/skills/novahiz-converge/SKILL.md +1 -1
  50. package/skills/novahiz-gate/SKILL.md +7 -5
  51. package/skills/novahiz-humanizer/SKILL.md +1 -1
  52. package/skills/novahiz-implement/SKILL.md +2 -2
  53. package/skills/novahiz-init/SKILL.md +1 -1
  54. package/skills/novahiz-plan/SKILL.md +2 -2
  55. package/skills/novahiz-planner/SKILL.md +6 -5
  56. package/skills/novahiz-task/SKILL.md +1 -1
  57. package/skills/openapi-mcp-server/SKILL.md +76 -0
  58. package/skills/openapi-mcp-server/references/mcp-ship-checklist.md +30 -0
  59. package/skills/openapi-mcp-server/references/tool-worksheet.md +30 -0
  60. package/skills/openapi-mcp-server/scripts/openapi_mcp_lint.mjs +133 -0
  61. package/skills/package-risk-audit/SKILL.md +83 -0
  62. package/skills/package-risk-audit/references/intake-worksheet.md +19 -0
  63. package/skills/package-risk-audit/scripts/dep_risk_lint.mjs +131 -0
  64. package/skills/prompt-rewriter/SKILL.md +18 -13
  65. package/skills/secrets-hygiene/SKILL.md +62 -0
  66. package/skills/secrets-hygiene/references/rotation-playbook.md +27 -0
  67. package/skills/secrets-hygiene/scripts/secret_scan.mjs +120 -0
  68. package/skills/skill-authoring/SKILL.md +93 -0
  69. package/skills/skill-authoring/references/skill-template.md +59 -0
  70. package/skills/skill-authoring/scripts/skill_frontmatter_lint.mjs +65 -0
  71. package/skills/skill-eval-loop/SKILL.md +103 -0
  72. package/skills/skill-eval-loop/references/negative-patterns.md +12 -0
  73. package/skills/skill-eval-loop/references/run-sheet.md +40 -0
  74. package/skills/skill-eval-loop/scripts/skill_structure_check.mjs +100 -0
  75. package/skills/ui-craft-rules/SKILL.md +96 -0
  76. package/skills/ui-slop-remover/SKILL.md +110 -0
  77. package/skills/ui-slop-remover/references/tell-catalogue.md +58 -0
  78. package/skills/ui-slop-remover/scripts/slop_lint.mjs +119 -0
  79. package/src/cli.ts +24 -4
  80. package/src/commands/context.ts +43 -4
  81. package/src/commands/doctor.ts +26 -8
  82. package/src/commands/gate.ts +68 -76
  83. package/src/commands/graft.ts +14 -9
  84. package/src/commands/inspect.ts +28 -2
  85. package/src/commands/task.ts +30 -1
  86. package/src/exec.ts +38 -10
  87. package/src/gate-repair.ts +87 -0
  88. package/src/gate.ts +543 -401
  89. package/src/graft.ts +56 -23
  90. package/src/ledger.ts +28 -2
  91. package/src/memory.ts +14 -1
  92. package/src/prompt-rewriter.ts +357 -24
  93. package/src/spec.ts +18 -5
  94. package/bundled-skills/ab-testing/SKILL.md +0 -353
  95. package/bundled-skills/ab-testing/evals/evals.json +0 -105
  96. package/bundled-skills/ab-testing/references/sample-size-guide.md +0 -263
  97. package/bundled-skills/ab-testing/references/test-templates.md +0 -277
  98. package/bundled-skills/ad-creative/SKILL.md +0 -425
  99. package/bundled-skills/ad-creative/assets/creative-review-template.html +0 -400
  100. package/bundled-skills/ad-creative/evals/evals.json +0 -217
  101. package/bundled-skills/ad-creative/references/creative-review-page.md +0 -106
  102. package/bundled-skills/ad-creative/references/creative-roadmap.md +0 -118
  103. package/bundled-skills/ad-creative/references/generative-tools.md +0 -637
  104. package/bundled-skills/ad-creative/references/hook-system.md +0 -115
  105. package/bundled-skills/ad-creative/references/imessage-video-ads.md +0 -201
  106. package/bundled-skills/ad-creative/references/meta-creative-formats.md +0 -114
  107. package/bundled-skills/ad-creative/references/motion-video-ads.md +0 -126
  108. package/bundled-skills/ad-creative/references/platform-specs.md +0 -213
  109. package/bundled-skills/ad-creative/references/short-form-video-specs.md +0 -213
  110. package/bundled-skills/ad-creative/references/static-ad-templates.md +0 -308
  111. package/bundled-skills/ads/SKILL.md +0 -499
  112. package/bundled-skills/ads/evals/evals.json +0 -157
  113. package/bundled-skills/ads/references/abm-playbook.md +0 -93
  114. package/bundled-skills/ads/references/ad-copy-templates.md +0 -207
  115. package/bundled-skills/ads/references/audience-targeting.md +0 -243
  116. package/bundled-skills/ads/references/audit-guardrails.md +0 -83
  117. package/bundled-skills/ads/references/b2b-paid-playbook.md +0 -115
  118. package/bundled-skills/ads/references/conversion-tracking.md +0 -361
  119. package/bundled-skills/ads/references/creative-research-automation.md +0 -103
  120. package/bundled-skills/ads/references/google-ads-audit-checklist.md +0 -84
  121. package/bundled-skills/ads/references/google-search-playbook.md +0 -120
  122. package/bundled-skills/ads/references/linkedin-b2b-playbook.md +0 -107
  123. package/bundled-skills/ads/references/meta-decision-system.md +0 -176
  124. package/bundled-skills/ads/references/payback-period.md +0 -69
  125. package/bundled-skills/ads/references/platform-setup-checklists.md +0 -277
  126. package/bundled-skills/ads/references/rsa-output-spec.md +0 -88
  127. package/bundled-skills/agent-device/SKILL.md +0 -20
  128. package/bundled-skills/ai-seo/SKILL.md +0 -488
  129. package/bundled-skills/ai-seo/evals/evals.json +0 -135
  130. package/bundled-skills/ai-seo/references/agent-readiness.md +0 -57
  131. package/bundled-skills/ai-seo/references/citations-vs-recommendations.md +0 -85
  132. package/bundled-skills/ai-seo/references/content-patterns.md +0 -287
  133. package/bundled-skills/ai-seo/references/content-types.md +0 -71
  134. package/bundled-skills/ai-seo/references/format-volatility.md +0 -98
  135. package/bundled-skills/ai-seo/references/okf.md +0 -104
  136. package/bundled-skills/ai-seo/references/platform-ranking-factors.md +0 -154
  137. package/bundled-skills/ai-seo/references/youtube-ai-citations.md +0 -60
  138. package/bundled-skills/analytics/SKILL.md +0 -310
  139. package/bundled-skills/analytics/evals/evals.json +0 -90
  140. package/bundled-skills/analytics/references/event-library.md +0 -260
  141. package/bundled-skills/analytics/references/ga4-implementation.md +0 -300
  142. package/bundled-skills/analytics/references/gtm-implementation.md +0 -390
  143. package/bundled-skills/android-emulator/SKILL.md +0 -32
  144. package/bundled-skills/android-reverse-engineering/LICENSE +0 -190
  145. package/bundled-skills/android-reverse-engineering/SKILL.md +0 -313
  146. package/bundled-skills/android-reverse-engineering/references/api-extraction-patterns.md +0 -197
  147. package/bundled-skills/android-reverse-engineering/references/call-flow-analysis.md +0 -210
  148. package/bundled-skills/android-reverse-engineering/references/fernflower-usage.md +0 -115
  149. package/bundled-skills/android-reverse-engineering/references/jadx-usage.md +0 -116
  150. package/bundled-skills/android-reverse-engineering/references/kotlin-name-recovery.md +0 -108
  151. package/bundled-skills/android-reverse-engineering/references/setup-guide.md +0 -221
  152. package/bundled-skills/android-reverse-engineering/references/third_party_hosts.txt +0 -122
  153. package/bundled-skills/android-reverse-engineering/scripts/check-deps.ps1 +0 -165
  154. package/bundled-skills/android-reverse-engineering/scripts/check-deps.sh +0 -129
  155. package/bundled-skills/android-reverse-engineering/scripts/decompile.ps1 +0 -400
  156. package/bundled-skills/android-reverse-engineering/scripts/decompile.sh +0 -578
  157. package/bundled-skills/android-reverse-engineering/scripts/find-api-calls.ps1 +0 -121
  158. package/bundled-skills/android-reverse-engineering/scripts/find-api-calls.sh +0 -339
  159. package/bundled-skills/android-reverse-engineering/scripts/fingerprint.sh +0 -241
  160. package/bundled-skills/android-reverse-engineering/scripts/install-dep.ps1 +0 -345
  161. package/bundled-skills/android-reverse-engineering/scripts/install-dep.sh +0 -448
  162. package/bundled-skills/android-reverse-engineering/scripts/lookup-name.sh +0 -85
  163. package/bundled-skills/android-reverse-engineering/scripts/recover-kotlin-names.sh +0 -140
  164. package/bundled-skills/build-graph/SKILL.md +0 -38
  165. package/bundled-skills/claude-history-ingest/SKILL.md +0 -463
  166. package/bundled-skills/claude-history-ingest/references/claude-data-format.md +0 -118
  167. package/bundled-skills/codex-history-ingest/SKILL.md +0 -248
  168. package/bundled-skills/codex-history-ingest/references/codex-data-format.md +0 -82
  169. package/bundled-skills/cold-email/SKILL.md +0 -159
  170. package/bundled-skills/cold-email/evals/evals.json +0 -94
  171. package/bundled-skills/cold-email/references/benchmarks.md +0 -83
  172. package/bundled-skills/cold-email/references/follow-up-sequences.md +0 -81
  173. package/bundled-skills/cold-email/references/frameworks.md +0 -90
  174. package/bundled-skills/cold-email/references/personalization.md +0 -79
  175. package/bundled-skills/cold-email/references/subject-lines.md +0 -53
  176. package/bundled-skills/competitor-profiling/SKILL.md +0 -415
  177. package/bundled-skills/competitor-profiling/evals/evals.json +0 -85
  178. package/bundled-skills/competitor-profiling/references/templates.md +0 -167
  179. package/bundled-skills/competitor-profiling/references/tool-reference.md +0 -179
  180. package/bundled-skills/computer-use/SKILL.md +0 -41
  181. package/bundled-skills/content-strategy/SKILL.md +0 -439
  182. package/bundled-skills/content-strategy/evals/evals.json +0 -116
  183. package/bundled-skills/content-strategy/references/content-distribution.md +0 -83
  184. package/bundled-skills/content-strategy/references/headless-cms.md +0 -194
  185. package/bundled-skills/copilot-history-ingest/SKILL.md +0 -376
  186. package/bundled-skills/copilot-history-ingest/references/copilot-data-format.md +0 -321
  187. package/bundled-skills/copy-editing/SKILL.md +0 -457
  188. package/bundled-skills/copy-editing/evals/evals.json +0 -89
  189. package/bundled-skills/copy-editing/references/checklist.md +0 -66
  190. package/bundled-skills/copy-editing/references/content-refresh.md +0 -38
  191. package/bundled-skills/copy-editing/references/plain-english-alternatives.md +0 -394
  192. package/bundled-skills/copywriting/SKILL.md +0 -256
  193. package/bundled-skills/copywriting/evals/evals.json +0 -126
  194. package/bundled-skills/copywriting/references/copy-frameworks.md +0 -433
  195. package/bundled-skills/copywriting/references/natural-transitions.md +0 -272
  196. package/bundled-skills/cro/SKILL.md +0 -187
  197. package/bundled-skills/cro/evals/evals.json +0 -111
  198. package/bundled-skills/cro/references/experiments.md +0 -248
  199. package/bundled-skills/cro/references/form.md +0 -422
  200. package/bundled-skills/cross-linker/SKILL.md +0 -309
  201. package/bundled-skills/customer-research/SKILL.md +0 -305
  202. package/bundled-skills/customer-research/evals/evals.json +0 -176
  203. package/bundled-skills/customer-research/references/interviews-and-surveys.md +0 -155
  204. package/bundled-skills/customer-research/references/source-guides.md +0 -401
  205. package/bundled-skills/daily-update/SKILL.md +0 -223
  206. package/bundled-skills/dart-add-unit-test/SKILL.md +0 -122
  207. package/bundled-skills/dart-build-cli-app/SKILL.md +0 -185
  208. package/bundled-skills/dart-collect-coverage/SKILL.md +0 -141
  209. package/bundled-skills/dart-fix-runtime-errors/SKILL.md +0 -166
  210. package/bundled-skills/dart-generate-test-mocks/SKILL.md +0 -155
  211. package/bundled-skills/dart-migrate-to-checks-package/SKILL.md +0 -528
  212. package/bundled-skills/dart-resolve-package-conflicts/SKILL.md +0 -116
  213. package/bundled-skills/dart-run-static-analysis/SKILL.md +0 -104
  214. package/bundled-skills/dart-setup-ffi-assets/SKILL.md +0 -419
  215. package/bundled-skills/dart-use-doc-examples/SKILL.md +0 -96
  216. package/bundled-skills/dart-use-ffigen/SKILL.md +0 -218
  217. package/bundled-skills/dart-use-pattern-matching/SKILL.md +0 -146
  218. package/bundled-skills/dart-use-primary-constructors/SKILL.md +0 -262
  219. package/bundled-skills/dart-write-documentation/SKILL.md +0 -136
  220. package/bundled-skills/debug-issue/SKILL.md +0 -28
  221. package/bundled-skills/dogfood/SKILL.md +0 -27
  222. package/bundled-skills/eas-app-stores/SKILL.md +0 -176
  223. package/bundled-skills/eas-app-stores/agents/openai.yaml +0 -4
  224. package/bundled-skills/eas-app-stores/references/app-store-metadata.md +0 -497
  225. package/bundled-skills/eas-app-stores/references/ios-app-store.md +0 -376
  226. package/bundled-skills/eas-app-stores/references/native-ios.md +0 -167
  227. package/bundled-skills/eas-app-stores/references/play-store.md +0 -244
  228. package/bundled-skills/eas-app-stores/references/testflight.md +0 -62
  229. package/bundled-skills/eas-app-stores/references/workflows.md +0 -120
  230. package/bundled-skills/eas-hosting/SKILL.md +0 -431
  231. package/bundled-skills/eas-hosting/agents/openai.yaml +0 -4
  232. package/bundled-skills/eas-observe/SKILL.md +0 -54
  233. package/bundled-skills/eas-observe/agents/openai.yaml +0 -4
  234. package/bundled-skills/eas-observe/references/metrics.md +0 -98
  235. package/bundled-skills/eas-observe/references/queries.md +0 -403
  236. package/bundled-skills/eas-observe/references/setup.md +0 -476
  237. package/bundled-skills/eas-observe/references/third-party.md +0 -136
  238. package/bundled-skills/eas-simulator/SKILL.md +0 -208
  239. package/bundled-skills/eas-simulator/agents/openai.yaml +0 -4
  240. package/bundled-skills/eas-simulator/references/controllers.md +0 -106
  241. package/bundled-skills/eas-simulator/references/run-your-app.md +0 -224
  242. package/bundled-skills/eas-simulator/references/troubleshooting.md +0 -44
  243. package/bundled-skills/eas-update/SKILL.md +0 -146
  244. package/bundled-skills/eas-update/agents/openai.yaml +0 -4
  245. package/bundled-skills/eas-update-insights/SKILL.md +0 -238
  246. package/bundled-skills/eas-update-insights/agents/openai.yaml +0 -4
  247. package/bundled-skills/eas-update-insights/references/channel-insights-schema.md +0 -47
  248. package/bundled-skills/eas-update-insights/references/update-insights-schema.md +0 -69
  249. package/bundled-skills/eas-workflows/SKILL.md +0 -99
  250. package/bundled-skills/eas-workflows/agents/openai.yaml +0 -4
  251. package/bundled-skills/eas-workflows/scripts/fetch.js +0 -109
  252. package/bundled-skills/eas-workflows/scripts/package.json +0 -6
  253. package/bundled-skills/emails/SKILL.md +0 -311
  254. package/bundled-skills/emails/evals/evals.json +0 -93
  255. package/bundled-skills/emails/references/copy-guidelines.md +0 -113
  256. package/bundled-skills/emails/references/email-types.md +0 -515
  257. package/bundled-skills/emails/references/sequence-templates.md +0 -168
  258. package/bundled-skills/explore-codebase/SKILL.md +0 -29
  259. package/bundled-skills/expo-animation/LICENSE +0 -21
  260. package/bundled-skills/expo-animation/RECIPES.md +0 -385
  261. package/bundled-skills/expo-animation/SKILL.md +0 -267
  262. package/bundled-skills/expo-animation/agents/openai.yaml +0 -4
  263. package/bundled-skills/expo-app-clip/SKILL.md +0 -290
  264. package/bundled-skills/expo-app-clip/agents/openai.yaml +0 -4
  265. package/bundled-skills/expo-app-clip/references/native-module.md +0 -96
  266. package/bundled-skills/expo-brownfield/SKILL.md +0 -62
  267. package/bundled-skills/expo-brownfield/agents/openai.yaml +0 -4
  268. package/bundled-skills/expo-brownfield/references/brownfield-integrated.md +0 -526
  269. package/bundled-skills/expo-brownfield/references/brownfield-isolated.md +0 -451
  270. package/bundled-skills/expo-brownfield/references/comparison.md +0 -63
  271. package/bundled-skills/expo-brownfield/references/troubleshooting.md +0 -88
  272. package/bundled-skills/expo-data-fetching/SKILL.md +0 -478
  273. package/bundled-skills/expo-data-fetching/agents/openai.yaml +0 -4
  274. package/bundled-skills/expo-data-fetching/references/expo-router-loaders.md +0 -341
  275. package/bundled-skills/expo-data-fetching/references/offline-and-cancellation.md +0 -68
  276. package/bundled-skills/expo-design-system/SKILL.md +0 -376
  277. package/bundled-skills/expo-design-system/agents/openai.yaml +0 -4
  278. package/bundled-skills/expo-design-system/references/audit.md +0 -190
  279. package/bundled-skills/expo-design-system/references/native-slop.md +0 -74
  280. package/bundled-skills/expo-dev-client/SKILL.md +0 -182
  281. package/bundled-skills/expo-dev-client/agents/openai.yaml +0 -4
  282. package/bundled-skills/expo-dom/SKILL.md +0 -425
  283. package/bundled-skills/expo-dom/agents/openai.yaml +0 -4
  284. package/bundled-skills/expo-examples/SKILL.md +0 -106
  285. package/bundled-skills/expo-examples/agents/openai.yaml +0 -4
  286. package/bundled-skills/expo-examples/references/catalog.md +0 -105
  287. package/bundled-skills/expo-migrate-module/SKILL.md +0 -113
  288. package/bundled-skills/expo-migrate-module/agents/openai.yaml +0 -4
  289. package/bundled-skills/expo-migrate-module/references/compatibility.md +0 -73
  290. package/bundled-skills/expo-migrate-module/references/example.md +0 -212
  291. package/bundled-skills/expo-migrate-module/references/migration-map.md +0 -306
  292. package/bundled-skills/expo-module/SKILL.md +0 -151
  293. package/bundled-skills/expo-module/agents/openai.yaml +0 -4
  294. package/bundled-skills/expo-module/references/config-plugin.md +0 -90
  295. package/bundled-skills/expo-module/references/create-expo-module.md +0 -206
  296. package/bundled-skills/expo-module/references/lifecycle.md +0 -127
  297. package/bundled-skills/expo-module/references/module-config.md +0 -48
  298. package/bundled-skills/expo-module/references/native-module.md +0 -286
  299. package/bundled-skills/expo-module/references/native-view.md +0 -171
  300. package/bundled-skills/expo-native-ui/SKILL.md +0 -201
  301. package/bundled-skills/expo-native-ui/agents/openai.yaml +0 -4
  302. package/bundled-skills/expo-native-ui/references/controls.md +0 -231
  303. package/bundled-skills/expo-native-ui/references/gradients.md +0 -106
  304. package/bundled-skills/expo-native-ui/references/icons.md +0 -232
  305. package/bundled-skills/expo-native-ui/references/media.md +0 -193
  306. package/bundled-skills/expo-native-ui/references/storage.md +0 -121
  307. package/bundled-skills/expo-native-ui/references/visual-effects.md +0 -198
  308. package/bundled-skills/expo-native-ui/references/webgpu-three.md +0 -605
  309. package/bundled-skills/expo-overview/SKILL.md +0 -115
  310. package/bundled-skills/expo-overview/agents/openai.yaml +0 -4
  311. package/bundled-skills/expo-project-structure/SKILL.md +0 -114
  312. package/bundled-skills/expo-project-structure/agents/openai.yaml +0 -4
  313. package/bundled-skills/expo-router/SKILL.md +0 -240
  314. package/bundled-skills/expo-router/agents/openai.yaml +0 -4
  315. package/bundled-skills/expo-router/references/form-sheet.md +0 -253
  316. package/bundled-skills/expo-router/references/route-structure.md +0 -229
  317. package/bundled-skills/expo-router/references/search.md +0 -248
  318. package/bundled-skills/expo-router/references/tabs.md +0 -433
  319. package/bundled-skills/expo-router/references/toolbar-and-headers.md +0 -284
  320. package/bundled-skills/expo-router/references/zoom-transitions.md +0 -158
  321. package/bundled-skills/expo-skill-eval/SKILL.md +0 -314
  322. package/bundled-skills/expo-skill-eval/agents/visual-grader.md +0 -52
  323. package/bundled-skills/expo-skill-eval/references/design-rubric.md +0 -45
  324. package/bundled-skills/expo-skill-eval/references/runtime-matrix.md +0 -34
  325. package/bundled-skills/expo-skill-eval/scripts/check-static.sh +0 -64
  326. package/bundled-skills/expo-skill-eval/scripts/clean-fixture.sh +0 -56
  327. package/bundled-skills/expo-skill-eval/scripts/generate_viewer.py +0 -450
  328. package/bundled-skills/expo-skill-eval/scripts/latest-sdk.sh +0 -46
  329. package/bundled-skills/expo-skill-eval/scripts/make-fixture.sh +0 -95
  330. package/bundled-skills/expo-skill-eval/scripts/make-workspace.sh +0 -31
  331. package/bundled-skills/expo-skill-eval/scripts/snapshot-android.sh +0 -284
  332. package/bundled-skills/expo-skill-eval/scripts/snapshot-ios.sh +0 -132
  333. package/bundled-skills/expo-skill-eval/scripts/snapshot-web.sh +0 -61
  334. package/bundled-skills/expo-skill-feedback/SKILL.md +0 -87
  335. package/bundled-skills/expo-skill-feedback/agents/openai.yaml +0 -4
  336. package/bundled-skills/expo-skill-feedback/scripts/skill-event.cjs +0 -180
  337. package/bundled-skills/expo-skill-feedback/scripts/telemetry.cjs +0 -65
  338. package/bundled-skills/expo-skill-feedback/scripts/telemetry_common.cjs +0 -171
  339. package/bundled-skills/expo-ui/SKILL.md +0 -101
  340. package/bundled-skills/expo-ui/agents/openai.yaml +0 -4
  341. package/bundled-skills/expo-ui/references/drop-in-replacements.md +0 -27
  342. package/bundled-skills/expo-ui/references/jetpack-compose.md +0 -73
  343. package/bundled-skills/expo-ui/references/swift-ui.md +0 -73
  344. package/bundled-skills/expo-ui/references/universal.md +0 -104
  345. package/bundled-skills/expo-ui/scripts/list-components.js +0 -193
  346. package/bundled-skills/expo-upgrade/SKILL.md +0 -150
  347. package/bundled-skills/expo-upgrade/agents/openai.yaml +0 -4
  348. package/bundled-skills/expo-upgrade/references/expo-av-to-audio.md +0 -132
  349. package/bundled-skills/expo-upgrade/references/expo-av-to-video.md +0 -160
  350. package/bundled-skills/expo-upgrade/references/native-tabs.md +0 -124
  351. package/bundled-skills/expo-upgrade/references/new-architecture.md +0 -79
  352. package/bundled-skills/expo-upgrade/references/react-19.md +0 -79
  353. package/bundled-skills/expo-upgrade/references/react-compiler.md +0 -59
  354. package/bundled-skills/expo-upgrade/references/react-navigation-to-expo-router.md +0 -61
  355. package/bundled-skills/expo-web-to-native/SKILL.md +0 -91
  356. package/bundled-skills/expo-web-to-native/agents/openai.yaml +0 -4
  357. package/bundled-skills/expo-web-to-native/references/false-friends.md +0 -119
  358. package/bundled-skills/expo-web-to-native/references/native-patterns.md +0 -39
  359. package/bundled-skills/expo-web-to-native/references/run-as-goal.md +0 -48
  360. package/bundled-skills/expo-web-to-native/references/verify-on-device.md +0 -45
  361. package/bundled-skills/find-skills/SKILL.md +0 -141
  362. package/bundled-skills/flutter-add-integration-test/SKILL.md +0 -163
  363. package/bundled-skills/flutter-add-widget-preview/SKILL.md +0 -145
  364. package/bundled-skills/flutter-add-widget-test/SKILL.md +0 -154
  365. package/bundled-skills/flutter-apply-architecture-best-practices/SKILL.md +0 -162
  366. package/bundled-skills/flutter-build-responsive-layout/SKILL.md +0 -139
  367. package/bundled-skills/flutter-fix-layout-issues/SKILL.md +0 -130
  368. package/bundled-skills/flutter-implement-json-serialization/SKILL.md +0 -153
  369. package/bundled-skills/flutter-setup-declarative-routing/SKILL.md +0 -255
  370. package/bundled-skills/flutter-setup-localization/SKILL.md +0 -210
  371. package/bundled-skills/flutter-use-http-package/SKILL.md +0 -174
  372. package/bundled-skills/graph-colorize/SKILL.md +0 -180
  373. package/bundled-skills/hermes-history-ingest/SKILL.md +0 -239
  374. package/bundled-skills/hermes-history-ingest/references/hermes-data-format.md +0 -131
  375. package/bundled-skills/impl-validator/SKILL.md +0 -118
  376. package/bundled-skills/ios-simulator/SKILL.md +0 -32
  377. package/bundled-skills/json-canvas/SKILL.md +0 -244
  378. package/bundled-skills/json-canvas/references/EXAMPLES.md +0 -329
  379. package/bundled-skills/launch/SKILL.md +0 -381
  380. package/bundled-skills/launch/evals/evals.json +0 -106
  381. package/bundled-skills/llm-wiki/SKILL.md +0 -661
  382. package/bundled-skills/llm-wiki/references/WRITING.md +0 -28
  383. package/bundled-skills/llm-wiki/references/karpathy-pattern.md +0 -45
  384. package/bundled-skills/marketing-plan/SKILL.md +0 -300
  385. package/bundled-skills/marketing-plan/evals/evals.json +0 -112
  386. package/bundled-skills/marketing-plan/references/aarrr-framework.md +0 -180
  387. package/bundled-skills/marketing-plan/references/budget-planning.md +0 -168
  388. package/bundled-skills/marketing-plan/references/client-types.md +0 -373
  389. package/bundled-skills/marketing-plan/references/current-state-rubric.md +0 -255
  390. package/bundled-skills/marketing-plan/references/example-quietude.md +0 -972
  391. package/bundled-skills/marketing-plan/references/funding-stage-unlocks.md +0 -230
  392. package/bundled-skills/marketing-plan/references/growth-patterns.md +0 -190
  393. package/bundled-skills/marketing-plan/references/idea-cross-reference.md +0 -265
  394. package/bundled-skills/marketing-plan/references/measurement-framework.md +0 -213
  395. package/bundled-skills/marketing-plan/references/methodology.md +0 -363
  396. package/bundled-skills/marketing-plan/references/ops-stack-mapping.md +0 -197
  397. package/bundled-skills/marketing-plan/references/plan-template.md +0 -494
  398. package/bundled-skills/marketing-plan/references/team-and-agency-model.md +0 -278
  399. package/bundled-skills/marketing-psychology/SKILL.md +0 -455
  400. package/bundled-skills/marketing-psychology/evals/evals.json +0 -88
  401. package/bundled-skills/memory-bridge/SKILL.md +0 -163
  402. package/bundled-skills/memory-save/SKILL.md +0 -88
  403. package/bundled-skills/obsidian-bases/SKILL.md +0 -499
  404. package/bundled-skills/obsidian-bases/references/FUNCTIONS_REFERENCE.md +0 -173
  405. package/bundled-skills/obsidian-cli/SKILL.md +0 -106
  406. package/bundled-skills/obsidian-layout-adjustment/SKILL.md +0 -226
  407. package/bundled-skills/obsidian-layout-adjustment/evals/evals.json +0 -53
  408. package/bundled-skills/obsidian-layout-adjustment/references/workflow-reference.md +0 -212
  409. package/bundled-skills/obsidian-markdown/SKILL.md +0 -196
  410. package/bundled-skills/obsidian-markdown/references/CALLOUTS.md +0 -58
  411. package/bundled-skills/obsidian-markdown/references/EMBEDS.md +0 -70
  412. package/bundled-skills/obsidian-markdown/references/PROPERTIES.md +0 -61
  413. package/bundled-skills/offers/SKILL.md +0 -155
  414. package/bundled-skills/offers/evals/evals.json +0 -21
  415. package/bundled-skills/offers/references/bonus-stacking.md +0 -150
  416. package/bundled-skills/offers/references/examples.md +0 -215
  417. package/bundled-skills/offers/references/guarantee-design.md +0 -172
  418. package/bundled-skills/offers/references/offer-anatomy.md +0 -203
  419. package/bundled-skills/offers/references/offer-formats.md +0 -240
  420. package/bundled-skills/offers/references/saas-offers.md +0 -116
  421. package/bundled-skills/offers/references/scarcity-urgency.md +0 -175
  422. package/bundled-skills/offers/references/value-equation.md +0 -134
  423. package/bundled-skills/onboarding/SKILL.md +0 -261
  424. package/bundled-skills/onboarding/evals/evals.json +0 -108
  425. package/bundled-skills/onboarding/references/activation-models.md +0 -57
  426. package/bundled-skills/onboarding/references/experiments.md +0 -258
  427. package/bundled-skills/onboarding/references/minimum-path-to-value.md +0 -49
  428. package/bundled-skills/openclaw-history-ingest/SKILL.md +0 -257
  429. package/bundled-skills/openclaw-history-ingest/references/openclaw-data-format.md +0 -154
  430. package/bundled-skills/orchestration/SKILL.md +0 -69
  431. package/bundled-skills/pi-history-ingest/SKILL.md +0 -312
  432. package/bundled-skills/pricing/SKILL.md +0 -295
  433. package/bundled-skills/pricing/evals/evals.json +0 -119
  434. package/bundled-skills/pricing/references/pricing-models.md +0 -66
  435. package/bundled-skills/pricing/references/pricing-page-teardown.md +0 -85
  436. package/bundled-skills/pricing/references/research-methods.md +0 -152
  437. package/bundled-skills/pricing/references/tier-structure.md +0 -232
  438. package/bundled-skills/product-marketing/SKILL.md +0 -255
  439. package/bundled-skills/product-marketing/evals/evals.json +0 -98
  440. package/bundled-skills/prospecting/SKILL.md +0 -262
  441. package/bundled-skills/prospecting/evals/evals.json +0 -122
  442. package/bundled-skills/prospecting/references/b2b-prospecting.md +0 -106
  443. package/bundled-skills/prospecting/references/compliance.md +0 -123
  444. package/bundled-skills/prospecting/references/data-sources.md +0 -287
  445. package/bundled-skills/prospecting/references/demand-signals.md +0 -129
  446. package/bundled-skills/prospecting/references/local-prospecting.md +0 -165
  447. package/bundled-skills/prospecting/references/saas-prospecting.md +0 -123
  448. package/bundled-skills/refactor-safely/SKILL.md +0 -29
  449. package/bundled-skills/review-delta/SKILL.md +0 -46
  450. package/bundled-skills/review-pr/SKILL.md +0 -66
  451. package/bundled-skills/sales-enablement/SKILL.md +0 -359
  452. package/bundled-skills/sales-enablement/evals/evals.json +0 -91
  453. package/bundled-skills/sales-enablement/references/deck-frameworks.md +0 -263
  454. package/bundled-skills/sales-enablement/references/demo-scripts.md +0 -355
  455. package/bundled-skills/sales-enablement/references/objection-library.md +0 -270
  456. package/bundled-skills/sales-enablement/references/one-pager-templates.md +0 -208
  457. package/bundled-skills/seo-audit/SKILL.md +0 -499
  458. package/bundled-skills/seo-audit/evals/evals.json +0 -136
  459. package/bundled-skills/seo-audit/references/ai-writing-detection.md +0 -200
  460. package/bundled-skills/seo-audit/references/international-seo.md +0 -230
  461. package/bundled-skills/session-brain/SKILL.md +0 -101
  462. package/bundled-skills/session-search/SKILL.md +0 -97
  463. package/bundled-skills/social/SKILL.md +0 -413
  464. package/bundled-skills/social/evals/evals.json +0 -107
  465. package/bundled-skills/social/references/carousel-frameworks.md +0 -141
  466. package/bundled-skills/social/references/listening-sources-template.md +0 -123
  467. package/bundled-skills/social/references/listening.md +0 -283
  468. package/bundled-skills/social/references/platform-limits.md +0 -110
  469. package/bundled-skills/social/references/platforms.md +0 -170
  470. package/bundled-skills/social/references/post-templates.md +0 -179
  471. package/bundled-skills/social/references/reverse-engineering.md +0 -195
  472. package/bundled-skills/social/references/short-form-video.md +0 -237
  473. package/bundled-skills/tag-taxonomy/SKILL.md +0 -218
  474. package/bundled-skills/vault-skill-factory/SKILL.md +0 -143
  475. package/bundled-skills/video/SKILL.md +0 -346
  476. package/bundled-skills/video/evals/evals.json +0 -103
  477. package/bundled-skills/video/references/ai-video-prompting.md +0 -175
  478. package/bundled-skills/video/references/edit-anatomy.md +0 -84
  479. package/bundled-skills/wiki-agent/SKILL.md +0 -322
  480. package/bundled-skills/wiki-capture/SKILL.md +0 -337
  481. package/bundled-skills/wiki-capture/references/RAW-FORMAT.md +0 -115
  482. package/bundled-skills/wiki-context-pack/SKILL.md +0 -89
  483. package/bundled-skills/wiki-dashboard/SKILL.md +0 -472
  484. package/bundled-skills/wiki-dedup/SKILL.md +0 -320
  485. package/bundled-skills/wiki-digest/SKILL.md +0 -243
  486. package/bundled-skills/wiki-export/SKILL.md +0 -445
  487. package/bundled-skills/wiki-history-ingest/SKILL.md +0 -61
  488. package/bundled-skills/wiki-import/SKILL.md +0 -276
  489. package/bundled-skills/wiki-ingest/SKILL.md +0 -563
  490. package/bundled-skills/wiki-ingest/references/ingest-prompts.md +0 -54
  491. package/bundled-skills/wiki-ingest/references/pageindex.md +0 -72
  492. package/bundled-skills/wiki-ingest/references/url-sources.md +0 -295
  493. package/bundled-skills/wiki-lint/SKILL.md +0 -643
  494. package/bundled-skills/wiki-narrate/SKILL.md +0 -120
  495. package/bundled-skills/wiki-narrate/references/voices.md +0 -29
  496. package/bundled-skills/wiki-query/SKILL.md +0 -307
  497. package/bundled-skills/wiki-rebuild/SKILL.md +0 -212
  498. package/bundled-skills/wiki-research/SKILL.md +0 -319
  499. package/bundled-skills/wiki-setup/SKILL.md +0 -359
  500. package/bundled-skills/wiki-stage-commit/SKILL.md +0 -164
  501. package/bundled-skills/wiki-status/SKILL.md +0 -556
  502. package/bundled-skills/wiki-switch/SKILL.md +0 -115
  503. package/bundled-skills/wiki-synthesize/SKILL.md +0 -212
  504. package/bundled-skills/wiki-update/SKILL.md +0 -271
  505. package/skills/ai-security/SKILL.md +0 -132
  506. package/skills/ai-security/references/atlas-coverage.md +0 -60
  507. package/skills/ai-security/scripts/ai_threat_scanner.py +0 -373
  508. package/skills/anti-AI-design/SKILL.md +0 -72
  509. package/skills/apple-hig-audit/SKILL.md +0 -64
  510. package/skills/apple-hig-audit/references/accessibility.md +0 -78
  511. package/skills/apple-hig-audit/references/platform-specifics.md +0 -57
  512. package/skills/apple-hig-audit/references/visual-design.md +0 -68
  513. package/skills/apple-hig-audit/scripts/hig_checker.py +0 -115
  514. package/skills/apple-hig-audit/templates/hig-audit-template.md +0 -114
  515. package/skills/dependency-auditor/README.md +0 -98
  516. package/skills/dependency-auditor/SKILL.md +0 -114
  517. package/skills/dependency-auditor/assets/sample_go.mod +0 -53
  518. package/skills/dependency-auditor/assets/sample_package.json +0 -72
  519. package/skills/dependency-auditor/assets/sample_requirements.txt +0 -71
  520. package/skills/dependency-auditor/expected_outputs/sample_license_report.txt +0 -37
  521. package/skills/dependency-auditor/expected_outputs/sample_upgrade_plan.txt +0 -59
  522. package/skills/dependency-auditor/expected_outputs/sample_vulnerability_report.json +0 -71
  523. package/skills/dependency-auditor/references/dependency_management_best_practices.md +0 -46
  524. package/skills/dependency-auditor/references/license_compatibility_matrix.md +0 -57
  525. package/skills/dependency-auditor/references/vulnerability_assessment_guide.md +0 -62
  526. package/skills/dependency-auditor/scripts/dep_scanner.py +0 -595
  527. package/skills/dependency-auditor/scripts/license_checker.py +0 -442
  528. package/skills/dependency-auditor/scripts/upgrade_planner.py +0 -490
  529. package/skills/dependency-auditor/test-inventory.json +0 -421
  530. package/skills/dependency-auditor/test-project/package.json +0 -72
  531. package/skills/design-system-tokens/SKILL.md +0 -90
  532. package/skills/design-system-tokens/assets/design_system_doc_template.md +0 -129
  533. package/skills/design-system-tokens/references/component-architecture.md +0 -88
  534. package/skills/design-system-tokens/references/developer-handoff.md +0 -61
  535. package/skills/design-system-tokens/references/responsive-calculations.md +0 -72
  536. package/skills/design-system-tokens/references/token-generation.md +0 -62
  537. package/skills/design-system-tokens/scripts/design_token_generator.py +0 -315
  538. package/skills/engineering-code-standards/SKILL.md +0 -174
  539. package/skills/env-secrets-manager/SKILL.md +0 -102
  540. package/skills/env-secrets-manager/references/secret-patterns.md +0 -56
  541. package/skills/env-secrets-manager/references/validation-detection-rotation.md +0 -76
  542. package/skills/env-secrets-manager/scripts/env_auditor.py +0 -340
  543. package/skills/frontend-design-taste/SKILL.md +0 -62
  544. package/skills/mcp-server-builder/README.md +0 -42
  545. package/skills/mcp-server-builder/SKILL.md +0 -144
  546. package/skills/mcp-server-builder/references/openapi-extraction-guide.md +0 -34
  547. package/skills/mcp-server-builder/references/production-hardening-guide.md +0 -80
  548. package/skills/mcp-server-builder/references/python-server-template.md +0 -22
  549. package/skills/mcp-server-builder/references/spec-compatibility.md +0 -129
  550. package/skills/mcp-server-builder/references/typescript-server-template.md +0 -19
  551. package/skills/mcp-server-builder/references/validation-checklist.md +0 -30
  552. package/skills/mcp-server-builder/scripts/mcp_validator.py +0 -180
  553. package/skills/mcp-server-builder/scripts/openapi_to_mcp.py +0 -279
  554. package/skills/playwright-agent/SKILL.md +0 -147
  555. package/skills/skill-creator/LICENSE.txt +0 -14
  556. package/skills/skill-creator/SKILL.md +0 -471
  557. package/skills/skill-creator/agents/analyzer.md +0 -274
  558. package/skills/skill-creator/agents/comparator.md +0 -202
  559. package/skills/skill-creator/agents/grader.md +0 -223
  560. package/skills/skill-creator/assets/eval_review.html +0 -143
  561. package/skills/skill-creator/eval-viewer/generate_review.py +0 -471
  562. package/skills/skill-creator/eval-viewer/viewer.html +0 -1321
  563. package/skills/skill-creator/references/schemas.md +0 -430
  564. package/skills/skill-creator/scripts/__init__.py +0 -0
  565. package/skills/skill-creator/scripts/aggregate_benchmark.py +0 -401
  566. package/skills/skill-creator/scripts/generate_report.py +0 -322
  567. package/skills/skill-creator/scripts/improve_description.py +0 -247
  568. package/skills/skill-creator/scripts/package_skill.py +0 -136
  569. package/skills/skill-creator/scripts/quick_validate.py +0 -103
  570. package/skills/skill-creator/scripts/run_eval.py +0 -310
  571. package/skills/skill-creator/scripts/run_loop.py +0 -328
  572. package/skills/skill-creator/scripts/utils.py +0 -47
  573. package/skills/write-a-skill/SKILL.md +0 -111
  574. package/skills/write-a-skill/references/companion_tooling.md +0 -61
  575. package/skills/write-a-skill/references/description_design_patterns.md +0 -136
  576. package/skills/write-a-skill/references/progressive_disclosure_principles.md +0 -87
  577. package/skills/write-a-skill/references/quality_gates_for_skills.md +0 -158
  578. package/skills/write-a-skill/scripts/skill_description_validator.py +0 -241
  579. package/skills/write-a-skill/scripts/skill_review_checklist_runner.py +0 -257
  580. package/skills/write-a-skill/scripts/skill_structure_validator.py +0 -265
@@ -8,9 +8,119 @@ import { join, relative, resolve } from "node:path";
8
8
  // ~/.config/opencode/plugins/ and cannot resolve ../../src/*.
9
9
  type RewriteResult = { original: string; rewritten: string; sourceLanguage: string; wasRewritten: boolean };
10
10
 
11
+ function fold(value: string): string {
12
+ return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
13
+ }
14
+
15
+ function rx(words: string, flags: string): RegExp {
16
+ return new RegExp(`(?<![\\p{L}\\p{N}])(?:${words})(?![\\p{L}\\p{N}])`, flags);
17
+ }
18
+
19
+ function marker(words: string): RegExp {
20
+ return rx(words, "iu");
21
+ }
22
+
23
+ function word(words: string): RegExp {
24
+ return rx(words, "giu");
25
+ }
26
+
27
+ const DETECT_MIN_SCORE = 3;
28
+ const LANG_ORDER = ["fr", "es", "de", "pt"];
29
+
30
+ const LANG_PATTERNS: Record<string, Array<[RegExp, number]>> = {
31
+ fr: [
32
+ [marker("corriger|corrige"), 3], [marker("ajouter|ajoute|ajoutez"), 3],
33
+ [marker("supprimer|supprime|supprimez"), 3], [marker("creer|creez|creation"), 3],
34
+ [marker("developper|developpe"), 3], [marker("implementer|implemente"), 3],
35
+ [marker("refactoriser|refactorise"), 3], [marker("configurer"), 3],
36
+ [marker("installer"), 3], [marker("ameliorer|amelioration"), 3],
37
+ [marker("optimiser"), 3], [marker("verifier|verifie"), 3],
38
+ [marker("expliquer|explique"), 3], [marker("pourquoi"), 3],
39
+ [marker("comment faire"), 3],
40
+ [marker("dans"), 2], [marker("avec"), 2], [marker("pour"), 2], [marker("vous"), 2],
41
+ [marker("nous"), 2], [marker("votre|notre"), 2], [marker("fonction|fonctions"), 2],
42
+ [marker("classe|classes"), 2], [marker("fichier|fichiers"), 2],
43
+ [marker("probleme|problemes"), 2], [marker("erreur|erreurs"), 2],
44
+ [marker("serveur"), 2], [marker("donnees"), 2], [marker("utilisateur|utilisateurs"), 2],
45
+ [marker("ecran"), 2], [marker("bouton"), 2], [marker("formulaire"), 2],
46
+ [marker("securite"), 2], [marker("reseau"), 2], [marker("requete"), 2],
47
+ [marker("besoin"), 2], [marker("faites|fait"), 2],
48
+ [marker("le"), 1], [marker("la"), 1], [marker("les"), 1], [marker("des"), 1],
49
+ [marker("du"), 1], [marker("de"), 1], [marker("un"), 1], [marker("une"), 1],
50
+ [marker("est"), 1], [marker("ne"), 1], [marker("pas"), 1],
51
+ ],
52
+ es: [
53
+ [marker("hacer"), 3], [marker("crear|cree"), 3], [marker("anadir"), 3],
54
+ [marker("borrar"), 3], [marker("arreglar"), 3], [marker("corregir"), 3],
55
+ [marker("explicar"), 3], [marker("necesito"), 3], [marker("quiero"), 3],
56
+ [marker("tengo"), 3], [marker("base de datos"), 3], [marker("inicio de sesion"), 3],
57
+ [marker("para"), 2], [marker("con"), 2], [marker("pero"), 2], [marker("muy"), 2],
58
+ [marker("tambien"), 2], [marker("pagina|paginas"), 2], [marker("servidor"), 2],
59
+ [marker("usuario|usuarios"), 2], [marker("archivo|archivos"), 2], [marker("codigo"), 2],
60
+ [marker("pantalla"), 2], [marker("mensaje"), 2], [marker("conexion"), 2],
61
+ [marker("datos"), 2], [marker("diseno"), 2], [marker("aplicacion"), 2],
62
+ [marker("de"), 1], [marker("la"), 1], [marker("el"), 1], [marker("los"), 1],
63
+ [marker("las"), 1], [marker("un"), 1], [marker("una"), 1], [marker("es"), 1],
64
+ [marker("en"), 1], [marker("por"), 1], [marker("que"), 1], [marker("se"), 1],
65
+ [marker("al"), 1], [marker("lo"), 1],
66
+ ],
67
+ de: [
68
+ [marker("bitte"), 3], [marker("machen"), 3], [marker("erstellen|erstelle"), 3],
69
+ [marker("hinzufugen"), 3], [marker("loschen"), 3], [marker("beheben|behebt"), 3],
70
+ [marker("debuggen"), 3], [marker("testen"), 3], [marker("erklaren|erklare"), 3],
71
+ [marker("warum"), 3], [marker("nicht"), 3], [marker("muss"), 3], [marker("soll"), 3],
72
+ [marker("funktion|funktionen"), 2], [marker("klasse"), 2], [marker("datei|dateien"), 2],
73
+ [marker("fehler"), 2], [marker("seite|seiten"), 2], [marker("datenbank"), 2],
74
+ [marker("anwendung|anwendungen"), 2], [marker("benutzer"), 2], [marker("anmelden"), 2],
75
+ [marker("einloggen"), 2], [marker("variablen"), 2], [marker("speichern"), 2],
76
+ [marker("anzeigen"), 2], [marker("verbessern"), 2], [marker("optimieren"), 2],
77
+ [marker("implementieren"), 2], [marker("schreiben"), 2], [marker("suchen"), 2],
78
+ [marker("starten"), 2],
79
+ [marker("der"), 1], [marker("die"), 1], [marker("das"), 1], [marker("den"), 1],
80
+ [marker("dem"), 1], [marker("ein"), 1], [marker("eine"), 1], [marker("ist"), 1],
81
+ [marker("mit"), 1], [marker("fur"), 1], [marker("und"), 1], [marker("auf"), 1],
82
+ [marker("zu"), 1],
83
+ ],
84
+ pt: [
85
+ [marker("criar|crie"), 3], [marker("fazer"), 3], [marker("adicionar"), 3],
86
+ [marker("corrigir"), 3], [marker("preciso"), 3], [marker("quero"), 3],
87
+ [marker("banco de dados"), 3],
88
+ [marker("pagina|paginas"), 2], [marker("usuario|usuarios"), 2],
89
+ [marker("arquivo|arquivos"), 2], [marker("codigo"), 2], [marker("mensagem"), 2],
90
+ [marker("tela"), 2], [marker("configurar"), 2], [marker("instalar"), 2],
91
+ [marker("melhorar"), 2], [marker("conectar"), 2], [marker("senha"), 2],
92
+ [marker("rede"), 2], [marker("funcao"), 2], [marker("nao"), 2], [marker("tambem"), 2],
93
+ [marker("uma"), 1], [marker("um"), 1], [marker("para"), 1], [marker("com"), 1],
94
+ [marker("que"), 1], [marker("na"), 1], [marker("os"), 1], [marker("as"), 1],
95
+ [marker("ao"), 1], [marker("mais"), 1],
96
+ ],
97
+ };
98
+
11
99
  function detectLanguage(prompt: string): string {
12
100
  if (/[\u0600-\u06FF]/.test(prompt)) return "ar";
13
- return "en";
101
+ const folded = fold(prompt);
102
+ let bestLang = "en";
103
+ let bestScore = 0;
104
+ let bestStrong = false;
105
+ for (const lang of LANG_ORDER) {
106
+ let score = 0;
107
+ let strong = false;
108
+ for (const [pattern, weight] of LANG_PATTERNS[lang]) {
109
+ if (pattern.test(folded)) {
110
+ score += weight;
111
+ if (weight >= 3) strong = true;
112
+ }
113
+ }
114
+ if (score < DETECT_MIN_SCORE) continue;
115
+ const wins =
116
+ bestScore === 0 ? true : strong !== bestStrong ? strong : score > bestScore;
117
+ if (wins) {
118
+ bestLang = lang;
119
+ bestScore = score;
120
+ bestStrong = strong;
121
+ }
122
+ }
123
+ return bestLang;
14
124
  }
15
125
 
16
126
  const AR_EN: Array<[RegExp, string]> = [
@@ -33,22 +143,75 @@ const AR_EN: Array<[RegExp, string]> = [
33
143
  [/تسجيل الدخول/g, "login"], [/خطأ/g, "bug"], [/اداء/g, "performance"], [/امان/g, "security"],
34
144
  ];
35
145
 
36
- function rewritePrompt(prompt: string): RewriteResult {
37
- const sourceLanguage = detectLanguage(prompt);
38
- if (sourceLanguage === "en") {
39
- let r = prompt.trim().replace(/^I\s+want\s+to\s+/i, "").replace(/^I\s+need\s+to\s+/i, "")
40
- .replace(/^Can\s+you\s+/i, "").replace(/^Could\s+you\s+/i, "").replace(/^Please\s+/i, "")
41
- .replace(/^I\s+would\s+like\s+to\s+/i, "").replace(/^It\s+would\s+be\s+great\s+if\s+you\s+could\s+/i, "")
42
- .replace(/[.!?]+$/, "").trim();
43
- return { original: prompt, rewritten: r, sourceLanguage, wasRewritten: r !== prompt };
44
- }
146
+ const FR_EN: Array<[RegExp, string]> = [
147
+ [word("base de donnees|base de données"), "database"],
148
+ [word("page d'accueil|page daccueil|page d accueil"), "homepage"],
149
+ [word("mot de passe"), "password"],
150
+ [word("site web"), "website"],
151
+ [word("mise a jour|mise à jour"), "update"],
152
+ [word("tableau de bord"), "dashboard"],
153
+ [word("code source"), "source code"],
154
+ [word("en temps reel|en temps réel"), "realtime"],
155
+ [word("formulaire de contact"), "contact form"],
156
+ [word("point d'entree|point d entree|point d'entrée"), "entry point"],
157
+ [word("se deconnecter|se déconnecter"), "logout"],
158
+ [word("se connecter"), "login"],
159
+ [word("corriger|corrige"), "fix"], [word("ajouter|ajoute|ajoutez"), "add"],
160
+ [word("supprimer|supprime|supprimez|effacer|enlever"), "remove"],
161
+ [word("creer|créer|creez|créez"), "create"], [word("developper|développer"), "develop"],
162
+ [word("implementer|implémenter"), "implement"], [word("refactoriser|refactorer"), "refactor"],
163
+ [word("configurer"), "configure"], [word("installer"), "install"], [word("migrer"), "migrate"],
164
+ [word("ameliorer|améliorer"), "improve"], [word("amelioration|amélioration"), "improvement"],
165
+ [word("optimiser"), "optimize"], [word("verifier|vérifier|verifie"), "verify"],
166
+ [word("expliquer|explique"), "explain"], [word("afficher|affiche|montrer|montre"), "display"],
167
+ [word("masquer|cacher"), "hide"], [word("activer"), "enable"],
168
+ [word("desactiver|désactiver"), "disable"], [word("ecrire|écrire"), "write"],
169
+ [word("sauvegarder|enregistrer"), "save"], [word("utiliser|utilise"), "use"],
170
+ [word("remplacer"), "replace"], [word("simplifier"), "simplify"],
171
+ [word("nettoyer"), "clean up"], [word("tester|teste|testez"), "test"],
172
+ [word("deboguer|déboguer"), "debug"], [word("compiler"), "compile"],
173
+ [word("deployer|déployer"), "deploy"], [word("rechercher|chercher"), "search"],
174
+ [word("telecharger|télécharger"), "download"], [word("envoyer"), "send"],
175
+ [word("ouvrir"), "open"], [word("fermer"), "close"],
176
+ [word("fonction|fonctions"), "function"], [word("classe|classes"), "class"],
177
+ [word("methode|méthode"), "method"], [word("fichier|fichiers"), "file"],
178
+ [word("probleme|problème|problemes"), "issue"], [word("erreur|erreurs"), "error"],
179
+ [word("serveur|serveurs"), "server"], [word("donnees|données"), "data"],
180
+ [word("ecran|écran"), "screen"], [word("bouton|boutons"), "button"],
181
+ [word("formulaire|formulaires"), "form"], [word("champ|champs"), "field"],
182
+ [word("lien|liens"), "link"], [word("modele|modèle"), "model"],
183
+ [word("schema|schéma"), "schema"], [word("reseau|réseau"), "network"],
184
+ [word("securite|sécurité"), "security"], [word("utilisateur|utilisateurs"), "user"],
185
+ [word("requete|requête"), "request"], [word("reponse|réponse"), "response"],
186
+ [word("performances"), "performance"], [word("tableau"), "table"],
187
+ [word("liste"), "list"], [word("boucle"), "loop"], [word("authentification"), "auth"],
188
+ [word("inscription"), "register"], [word("connexion"), "login"],
189
+ [word("dans"), "in"], [word("avec"), "with"], [word("pour"), "for"], [word("sur"), "on"],
190
+ [word("sans"), "without"], [word("aussi"), "also"], [word("mais"), "but"],
191
+ [word("pas"), "not"], [word("plus"), "more"], [word("tres|très"), "very"],
192
+ [word("comment"), "how to"], [word("pourquoi"), "why"], [word("besoin"), "need"],
193
+ ];
194
+
195
+ function translateTerms(prompt: string, lang: string): string {
196
+ const map = lang === "ar" ? AR_EN : lang === "fr" ? FR_EN : null;
197
+ if (!map) return prompt;
45
198
  let result = prompt;
46
- for (const [pattern, replacement] of AR_EN) result = result.replace(pattern, replacement);
47
- let r = result.trim().replace(/^I\s+want\s+to\s+/i, "").replace(/^I\s+need\s+to\s+/i, "")
199
+ for (const [pattern, replacement] of map) result = result.replace(pattern, replacement);
200
+ return result;
201
+ }
202
+
203
+ function optimizeEnglish(prompt: string): string {
204
+ return prompt.trim()
205
+ .replace(/^I\s+want\s+to\s+/i, "").replace(/^I\s+need\s+to\s+/i, "")
48
206
  .replace(/^Can\s+you\s+/i, "").replace(/^Could\s+you\s+/i, "").replace(/^Please\s+/i, "")
49
207
  .replace(/^I\s+would\s+like\s+to\s+/i, "").replace(/^It\s+would\s+be\s+great\s+if\s+you\s+could\s+/i, "")
50
208
  .replace(/[.!?]+$/, "").trim();
51
- return { original: prompt, rewritten: r, sourceLanguage, wasRewritten: true };
209
+ }
210
+
211
+ function rewritePrompt(prompt: string): RewriteResult {
212
+ const sourceLanguage = detectLanguage(prompt);
213
+ const rewritten = optimizeEnglish(translateTerms(prompt, sourceLanguage));
214
+ return { original: prompt, rewritten, sourceLanguage, wasRewritten: rewritten !== prompt };
52
215
  }
53
216
 
54
217
  // Inlined from src/autodocs.ts — same reason as prompt-rewriter: relative
@@ -229,12 +392,18 @@ const GATE = CONFIG.gate ?? {};
229
392
  // redirect the kill-switch to an unrelated variable (e.g. CI=false).
230
393
  // Single escape hatch name after brand rename.
231
394
  const ESCAPE = (process.env.NOVAHIZ_GATE ?? "").toLowerCase();
232
- // gate.enabled=false disables the plugin the same way the CLI gate does (see src/commands/gate.ts).
233
- // gate.mode (block/warn/audit) stays owned by the CLI: the plugin only forwards the gate exit code.
234
- const DISABLED =
235
- ["off", "0", "false", "no", "disabled"].includes(ESCAPE) || GATE.enabled === false;
395
+ // P0-B: gate.enabled=false is no longer honored — a writable config must not
396
+ // silently disable enforcement (same rule as the CLI and the MCP tool).
397
+ // Only the env escape turns the gate off; gate.mode stays owned by the CLI.
398
+ const DISABLED = ["off", "0", "false", "no", "disabled"].includes(ESCAPE);
236
399
  const GATE_TOOLS = new Set(
237
- (Array.isArray(GATE.tools) && GATE.tools.length > 0 ? GATE.tools : ["edit", "write", "patch", "apply_patch", "bash", "shell"]).map((tool) => tool.toLowerCase())
400
+ (Array.isArray(GATE.tools) && GATE.tools.length > 0
401
+ ? GATE.tools
402
+ // MINEUR#8: cron tools that carry/execute shell commands are gated too —
403
+ // cron_add_command_task was a bash-gate bypass. Keep in sync with
404
+ // DEFAULT_CONFIG.gate.tools (src/spec.ts) and novahiz.config.json.
405
+ : ["edit", "write", "patch", "apply_patch", "bash", "shell", "cron_add_command_task", "cron_update_command_task", "cron_update_task", "cron_run_task_now"]
406
+ ).map((tool) => tool.toLowerCase())
238
407
  );
239
408
 
240
409
  type RunResult = { status: number; stdout: string; stderr: string; spawnError?: string };
@@ -282,11 +451,78 @@ function isValidSessionId(id: unknown): id is string {
282
451
  return typeof id === "string" && id.trim().length > 0;
283
452
  }
284
453
 
454
+ // Inlined from src/gate-repair.ts — the installed plugin lives in
455
+ // ~/.config/opencode/plugins/ and cannot resolve ../../src/*.
456
+ type GateFailure = {
457
+ tool: string;
458
+ missingSkills: string[];
459
+ reasons: string[];
460
+ error: string | null;
461
+ };
462
+
463
+ function parseGateFailure(stdout: string): GateFailure | null {
464
+ let parsed: unknown;
465
+ try {
466
+ parsed = JSON.parse(stdout);
467
+ } catch {
468
+ return null;
469
+ }
470
+ if (!parsed || typeof parsed !== "object") return null;
471
+ const record = parsed as Record<string, unknown>;
472
+ const asStringArray = (value: unknown): string[] =>
473
+ Array.isArray(value)
474
+ ? value.filter((entry): entry is string => typeof entry === "string")
475
+ : [];
476
+ const tool = typeof record.tool === "string" && record.tool.length > 0 ? record.tool : "tool";
477
+ return {
478
+ tool,
479
+ missingSkills: asStringArray(record.missingSkills),
480
+ reasons: asStringArray(record.reasons),
481
+ error: typeof record.error === "string" ? record.error : null
482
+ };
483
+ }
484
+
485
+ function buildRepairDirective(failure: GateFailure, attempt: number): string {
486
+ const head = `Novahiz gate blocked ${failure.tool}.`;
487
+ const missing = failure.missingSkills;
488
+
489
+ if (missing.length === 0) {
490
+ const detail = failure.error ?? failure.reasons.join("; ") ?? "no reason reported";
491
+ return `${head}\nBlocked by rule, not by a missing skill: ${detail}\nResolve the listed rule, then retry once. Never bypass the gate.`;
492
+ }
493
+
494
+ if (attempt <= 1) {
495
+ const steps = missing.map((skill, index) => ` ${index + 1}. skill({name:"${skill}"})`).join("\n");
496
+ return [
497
+ `${head} Missing skills: ${missing.join(", ")}.`,
498
+ "AUTO-REPAIR — execute now, do not ask the user, do not stop:",
499
+ steps,
500
+ ` ${missing.length + 1}. Retry this exact ${failure.tool} call once, then continue the user's task where it left off.`,
501
+ "Never bypass the gate: no NOVAHIZ_GATE, no alternate tool, no shell write, no editing around the block."
502
+ ].join("\n");
503
+ }
504
+
505
+ return [
506
+ `${head} AUTO-REPAIR FAILED on attempt ${attempt}: still missing ${missing.join(", ")} after skill() loads.`,
507
+ "The loads did not register — diagnose instead of retrying:",
508
+ " 1. Confirm the skill is installed and the index matches (`novahiz doctor`).",
509
+ " 2. Realign the index (`novahiz sync`), then load the named skills again.",
510
+ "If the skill genuinely does not exist, report that honestly to the user and stop. Never bypass the gate."
511
+ ].join("\n");
512
+ }
513
+
285
514
  export const NovahizPlugin: Plugin = async ({ client }) => {
286
515
  const loadedBySession = new Map<string, Set<string>>();
287
516
  const categoriesBySession = new Map<string, string[]>();
288
517
  const enforcementBySession = new Map<string, string>();
289
518
  const lastSeenBySession = new Map<string, number>();
519
+ // P0-B: reason of the last failed classify per session — gate tool calls are
520
+ // refused while set, instead of running with empty categories (fail-open).
521
+ const classifyFailedBySession = new Map<string, string>();
522
+ // Auto-repair: denial count per `session|tool|missing set`. A first denial
523
+ // carries the repair protocol; an identical repeat escalates to diagnosis
524
+ // instead of looping. Cleared on a successful call of the same tool.
525
+ const repairAttemptsBySession = new Map<string, number>();
290
526
  const SESSION_TTL_MS = 4 * 60 * 60 * 1000;
291
527
 
292
528
  const log = async (level: "info" | "warn", message: string): Promise<void> => {
@@ -302,6 +538,11 @@ export const NovahizPlugin: Plugin = async ({ client }) => {
302
538
  categoriesBySession.delete(sessionID);
303
539
  enforcementBySession.delete(sessionID);
304
540
  lastSeenBySession.delete(sessionID);
541
+ classifyFailedBySession.delete(sessionID);
542
+ // Auto-repair keys are prefixed with the session ID — drop them too.
543
+ for (const key of repairAttemptsBySession.keys()) {
544
+ if (key.startsWith(`${sessionID}|`)) repairAttemptsBySession.delete(key);
545
+ }
305
546
  };
306
547
 
307
548
  // Sessions only vanish from memory on session.deleted, which may never arrive.
@@ -314,8 +555,9 @@ export const NovahizPlugin: Plugin = async ({ client }) => {
314
555
  }
315
556
  };
316
557
 
317
- if (DISABLED)
318
- await log("info", GATE.enabled === false ? "Gate disabled via config (gate.enabled=false)" : "Gate disabled via environment escape");
558
+ if (GATE.enabled === false)
559
+ await log("warn", "gate.enabled=false in config is ignored; enforcement stays active. Use NOVAHIZ_GATE=off to disable the gate.");
560
+ if (DISABLED) await log("info", "Gate disabled via environment escape");
319
561
 
320
562
  return {
321
563
  config: async (input) => {
@@ -397,9 +639,13 @@ export const NovahizPlugin: Plugin = async ({ client }) => {
397
639
  await log("info", `Prompt rewritten: ${rewrite.sourceLanguage} → English ("${classifyText.slice(0, 80)}")`);
398
640
  }
399
641
 
400
- const result = run(["classify", classifyText]);
642
+ // P0-B: the prompt travels on stdin. On argv it allowed option
643
+ // injection (--home), broke past the Windows 32k limit, and was
644
+ // readable in the process list.
645
+ const result = run(["classify", "--stdin"], classifyText);
401
646
  if (result.status !== 0) {
402
- await log("warn", `Classify failed (exit ${result.status}), no enforcement injected: ${result.stderr.trim().slice(0, 200)}`);
647
+ classifyFailedBySession.set(input.sessionID, `classify exit ${result.status}`);
648
+ await log("warn", `Classify failed (exit ${result.status}), gate tool calls refused for this session: ${result.stderr.trim().slice(0, 200)}`);
403
649
  return;
404
650
  }
405
651
  let parsed: {
@@ -413,15 +659,18 @@ export const NovahizPlugin: Plugin = async ({ client }) => {
413
659
  try {
414
660
  parsed = JSON.parse(result.stdout) as typeof parsed;
415
661
  } catch {
416
- await log("warn", "Classify returned invalid JSON, no enforcement injected");
662
+ classifyFailedBySession.set(input.sessionID, "classify returned invalid JSON");
663
+ await log("warn", "Classify returned invalid JSON, gate tool calls refused for this session");
417
664
  return;
418
665
  }
419
666
  // M5: the `as` cast is compile-time only — validate the shape at runtime
420
667
  // so a malformed classify response cannot silently disable enforcement.
421
668
  if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.categories)) {
422
- await log("warn", "Classify returned unexpected structure, no enforcement injected");
669
+ classifyFailedBySession.set(input.sessionID, "classify returned an unexpected structure");
670
+ await log("warn", "Classify returned unexpected structure, gate tool calls refused for this session");
423
671
  return;
424
672
  }
673
+ classifyFailedBySession.delete(input.sessionID);
425
674
  const categories = (parsed.categories ?? []).map((entry) => entry.id);
426
675
  categoriesBySession.set(input.sessionID, categories);
427
676
  const primary = parsed.primary ?? categories[0] ?? null;
@@ -434,7 +683,7 @@ export const NovahizPlugin: Plugin = async ({ client }) => {
434
683
  "[Novahiz enforcement]",
435
684
  `Categories detected: ${categories.join(", ") || "none"}${primary ? ` (primary: ${primary})` : ""}`
436
685
  ];
437
- if (rewrite.wasRewritten) {
686
+ if (rewrite.sourceLanguage !== "en") {
438
687
  lines.push(`User language: ${rewrite.sourceLanguage} — respond in this language, not English.`);
439
688
  }
440
689
  if (roadmap) {
@@ -457,12 +706,13 @@ export const NovahizPlugin: Plugin = async ({ client }) => {
457
706
  }
458
707
  }
459
708
  lines.push("The gate blocks edit/write/patch/apply_patch/bash/shell until the required skills are loaded via skill({name:\"...\"}).");
460
- lines.push("The gate is content-aware: novahiz-humanizer for prose; design files take no style gate rule.");
709
+ lines.push("The gate is content-aware: novahiz-humanizer, ui-slop-remover and ui-craft-rules are required only on frontend design tasks (R13), and impeccable on the same design selectors (R14).");
461
710
  lines.push("Config edited = opencode restart required (config read at import).");
462
711
  lines.push("Memory lives in project-memory/ under the project root (cwd): index.json + fixed-size slots (8000 chars / 200 lines) with compact → archive → new-slot rotation. Use the MCP memory_* tools to read and append.");
463
712
  enforcementBySession.set(input.sessionID, lines.join("\n"));
464
713
  } catch (error) {
465
- await log("warn", `chat.message hook failed, no enforcement injected: ${String(error).slice(0, 200)}`);
714
+ classifyFailedBySession.set(input.sessionID, "chat.message hook error");
715
+ await log("warn", `chat.message hook failed, gate tool calls refused for this session: ${String(error).slice(0, 200)}`);
466
716
  return;
467
717
  }
468
718
  },
@@ -481,29 +731,57 @@ export const NovahizPlugin: Plugin = async ({ client }) => {
481
731
 
482
732
  "tool.execute.before": async (input, output) => {
483
733
  try {
484
- // H-Plugin: validate session ID before using it — prevents undefined/null
485
- // from being passed to spawnSync env (throws on Windows).
486
- if (!isValidSessionId(input.sessionID)) return;
734
+ const tool = input.tool.toLowerCase();
735
+ const gated = !DISABLED && GATE_TOOLS.has(tool);
736
+ // P0-B: an invalid session ID must not bypass the gate. Gate tools and
737
+ // skill loads are refused; tools that need no enforcement still pass.
738
+ if (!isValidSessionId(input.sessionID)) {
739
+ if (gated || (!DISABLED && tool === "skill")) {
740
+ throw new Error(
741
+ `Novahiz gate blocked ${input.tool}: invalid session ID — loaded skills cannot be tracked. Fix the session or set NOVAHIZ_GATE=off to disable.`
742
+ );
743
+ }
744
+ return;
745
+ }
487
746
  touch(input.sessionID);
488
747
  if (!loadedBySession.has(input.sessionID)) loadedBySession.set(input.sessionID, new Set());
489
748
  const loaded = loadedBySession.get(input.sessionID)!;
490
749
 
491
- if (input.tool.toLowerCase() === "skill") {
492
- const args = output.args as { name?: string; skill?: string } | undefined;
493
- const name = args?.name ?? args?.skill;
494
- if (name) {
495
- loaded.add(String(name));
496
- // H3: surface session-load failures — otherwise the gate blocks later
497
- // with no trace of why the skill was never recorded.
498
- const loadResult = run(["session-load", "--session", input.sessionID, "--skill", String(name)]);
750
+ if (tool === "skill") {
751
+ const args = output.args as { name?: unknown; skill?: unknown } | undefined;
752
+ const raw = args?.name ?? args?.skill;
753
+ if (raw !== undefined && raw !== null && typeof raw !== "string") {
754
+ throw new Error("Novahiz gate blocked the skill load: the skill name must be a string.");
755
+ }
756
+ const name = typeof raw === "string" ? raw.trim() : "";
757
+ // P0-B: no commas or spaces — the gate re-splits --loaded on commas,
758
+ // so a loose name could inject extra "loaded" skills.
759
+ if (name.length > 0 && !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(name)) {
760
+ throw new Error(`Novahiz gate blocked the skill load: invalid skill name "${name.slice(0, 64)}".`);
761
+ }
762
+ if (name.length > 0) {
763
+ // P0-B: record only after session-load validated the name against
764
+ // the installed index — an unverified name never counts as loaded.
765
+ // H3 stays: failures are surfaced in the log instead of vanishing.
766
+ const loadResult = run(["session-load", "--session", input.sessionID, "--skill", name]);
499
767
  if (loadResult.status !== 0) {
500
- await log("warn", `session-load failed for skill ${name}: ${(loadResult.stderr || "").trim().slice(0, 200)}`);
768
+ await log("warn", `session-load failed for skill ${name}, not recorded: ${(loadResult.stderr || loadResult.stdout || "").trim().slice(0, 200)}`);
769
+ } else {
770
+ loaded.add(name);
501
771
  }
502
772
  }
503
773
  return;
504
774
  }
505
775
 
506
- if (DISABLED || !GATE_TOOLS.has(input.tool.toLowerCase())) return;
776
+ if (!gated) return;
777
+ // P0-B: a failed classify would empty the session categories and
778
+ // neutralize the prompt-scoped rules — refuse instead of failing open.
779
+ const classifyFailure = classifyFailedBySession.get(input.sessionID);
780
+ if (classifyFailure) {
781
+ throw new Error(
782
+ `Novahiz gate blocked ${input.tool}: prompt classification failed (${classifyFailure}). Fix the install (run "novahiz sync", check catalog/) and send a new message, or set NOVAHIZ_GATE=off to disable.`
783
+ );
784
+ }
507
785
 
508
786
  const categories = categoriesBySession.get(input.sessionID) ?? [];
509
787
  const result = run(
@@ -537,6 +815,18 @@ export const NovahizPlugin: Plugin = async ({ client }) => {
537
815
  );
538
816
  }
539
817
  if (result.status === 2) {
818
+ // Auto-repair: a structured denial becomes an executable directive
819
+ // (load the named skills, retry the same call, resume the task).
820
+ // Counting identical denials turns a failed repair into a diagnosis
821
+ // instead of an infinite retry loop. The denial itself still stands
822
+ // until the gate CLI sees the skills — nothing is granted here.
823
+ const failure = parseGateFailure(result.stdout);
824
+ if (failure) {
825
+ const key = `${input.sessionID}|${failure.tool}|${[...failure.missingSkills].sort().join(",")}`;
826
+ const attempt = (repairAttemptsBySession.get(key) ?? 0) + 1;
827
+ repairAttemptsBySession.set(key, attempt);
828
+ throw new Error(buildRepairDirective(failure, attempt));
829
+ }
540
830
  throw new Error(`Novahiz gate blocked ${input.tool}.\n${result.stdout}`);
541
831
  }
542
832
  if (result.status !== 0) {
@@ -544,6 +834,12 @@ export const NovahizPlugin: Plugin = async ({ client }) => {
544
834
  `Novahiz gate unavailable (exit ${result.status}). Fix the install (run sync, check catalog/) or set the escape variable to disable.\n${result.stderr}`
545
835
  );
546
836
  }
837
+ // The call is allowed: the repair converged — drop this session's
838
+ // denial counters so the next task starts a fresh cycle.
839
+ const allowedPrefix = `${input.sessionID}|${input.tool.toLowerCase()}|`;
840
+ for (const key of repairAttemptsBySession.keys()) {
841
+ if (key.startsWith(allowedPrefix)) repairAttemptsBySession.delete(key);
842
+ }
547
843
  } catch (error) {
548
844
  if (error instanceof Error && error.message.startsWith("Novahiz gate")) throw error;
549
845
  // H2: fail-closed — unknown gate errors deny, they never bypass.
package/bin/novahiz.cmd CHANGED
@@ -1,2 +1,2 @@
1
- @echo off
2
- node "%~dp0..\src\cli.ts" %*
1
+ @echo off
2
+ node "%~dp0..\src\cli.ts" %*