exonous 0.0.0-stage → 2.10.4

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 (385) hide show
  1. package/README.md +100 -2
  2. package/assets/THIRD-PARTY-NOTICES.md +29 -0
  3. package/assets/adapters/opencode/exonous.js +54 -0
  4. package/assets/agents/exo-backend.md +22 -0
  5. package/assets/agents/exo-cto.md +22 -0
  6. package/assets/agents/exo-data-ai.md +22 -0
  7. package/assets/agents/exo-designer.md +22 -0
  8. package/assets/agents/exo-devops.md +22 -0
  9. package/assets/agents/exo-frontend.md +22 -0
  10. package/assets/agents/exo-infra.md +22 -0
  11. package/assets/agents/exo-mobile.md +22 -0
  12. package/assets/agents/exo-pm.md +22 -0
  13. package/assets/agents/exo-qa.md +22 -0
  14. package/assets/agents/exo-researcher.md +22 -0
  15. package/assets/agents/exo-security.md +22 -0
  16. package/assets/agents/roster.json +209 -0
  17. package/assets/agents/taxis.js +189 -0
  18. package/assets/editors/cursor/frontend-skills.mdc +27 -0
  19. package/assets/editors/hooks/cursor/hooks.json +11 -0
  20. package/assets/machine/PR-TEMPLATE.md +21 -0
  21. package/assets/machine/hooks/anamnesis.cjs +61 -0
  22. package/assets/machine/hooks/ethos.cjs +48 -0
  23. package/assets/machine/hooks/kairos.cjs +46 -0
  24. package/assets/machine/hooks/lib/cli-options.cjs +133 -0
  25. package/assets/machine/hooks/lib/memory.cjs +488 -0
  26. package/assets/machine/hooks/lib/metron.cjs +52 -0
  27. package/assets/machine/hooks/lib/paths.cjs +99 -0
  28. package/assets/machine/hooks/lib/payload.cjs +81 -0
  29. package/assets/machine/hooks/lib/pr-template-validate.cjs +103 -0
  30. package/assets/machine/hooks/lib/release.cjs +58 -0
  31. package/assets/machine/hooks/lib/repo.cjs +138 -0
  32. package/assets/machine/hooks/lib/sanitize.cjs +37 -0
  33. package/assets/machine/hooks/lib/selfupdate.cjs +354 -0
  34. package/assets/machine/hooks/lib/shell.cjs +722 -0
  35. package/assets/machine/hooks/lib/template.cjs +70 -0
  36. package/assets/machine/hooks/lib/token.cjs +110 -0
  37. package/assets/machine/hooks/lib/validate-pr-body.cjs +21 -0
  38. package/assets/machine/hooks/pyle.cjs +302 -0
  39. package/assets/rules/nomos.md +59 -0
  40. package/assets/rules/praxis.md +38 -0
  41. package/assets/skills/code-review/SKILL.md +124 -0
  42. package/assets/skills/commit-changes/SKILL.md +49 -0
  43. package/assets/skills/deliver/SKILL.md +114 -0
  44. package/assets/skills/deliver/references/parallel.md +37 -0
  45. package/assets/skills/doc/SKILL.md +140 -0
  46. package/assets/skills/doc/doc.mjs +277 -0
  47. package/assets/skills/issue-board/SKILL.md +84 -0
  48. package/assets/skills/issue-board/board.mjs +389 -0
  49. package/assets/skills/issue-board/config.example.json +9 -0
  50. package/assets/skills/issue-board/render.py +189 -0
  51. package/assets/skills/make-pr/SKILL.md +24 -0
  52. package/assets/skills/native-ui/SKILL.md +67 -0
  53. package/assets/skills/native-ui/reference/apple.md +180 -0
  54. package/assets/skills/native-ui/reference/mobile-feel.md +221 -0
  55. package/assets/skills/native-ui/reference/swift.md +289 -0
  56. package/assets/skills/project-memory/SKILL.md +59 -0
  57. package/assets/skills/project-memory/config.example.json +4 -0
  58. package/assets/skills/project-memory/project-memory.mjs +478 -0
  59. package/assets/skills/security-review/SKILL.md +102 -0
  60. package/assets/skills/session-handoff/SKILL.md +23 -0
  61. package/assets/skills/session-handoff/config.example.json +3 -0
  62. package/assets/skills/ui-design/SKILL.md +75 -0
  63. package/assets/skills/ui-design/reference/adapt.md +151 -0
  64. package/assets/skills/ui-design/reference/adapt.native.md +35 -0
  65. package/assets/skills/ui-design/reference/android.md +50 -0
  66. package/assets/skills/ui-design/reference/animate.md +87 -0
  67. package/assets/skills/ui-design/reference/audit.md +76 -0
  68. package/assets/skills/ui-design/reference/audit.native.md +126 -0
  69. package/assets/skills/ui-design/reference/bolder.md +33 -0
  70. package/assets/skills/ui-design/reference/clarify.md +84 -0
  71. package/assets/skills/ui-design/reference/colorize.md +86 -0
  72. package/assets/skills/ui-design/reference/craft-floor.md +25 -0
  73. package/assets/skills/ui-design/reference/critique.md +345 -0
  74. package/assets/skills/ui-design/reference/degraded/asset-producer.md +35 -0
  75. package/assets/skills/ui-design/reference/degraded/documenter.md +23 -0
  76. package/assets/skills/ui-design/reference/degraded/finish-reviewer.md +43 -0
  77. package/assets/skills/ui-design/reference/degraded/manual-edit-applier.md +56 -0
  78. package/assets/skills/ui-design/reference/delight.md +63 -0
  79. package/assets/skills/ui-design/reference/distill.md +98 -0
  80. package/assets/skills/ui-design/reference/doctor.md +49 -0
  81. package/assets/skills/ui-design/reference/document.md +273 -0
  82. package/assets/skills/ui-design/reference/extract.md +52 -0
  83. package/assets/skills/ui-design/reference/harden.md +122 -0
  84. package/assets/skills/ui-design/reference/hooks.md +114 -0
  85. package/assets/skills/ui-design/reference/init.md +47 -0
  86. package/assets/skills/ui-design/reference/ios.md +55 -0
  87. package/assets/skills/ui-design/reference/layout.md +81 -0
  88. package/assets/skills/ui-design/reference/live-setup.md +75 -0
  89. package/assets/skills/ui-design/reference/live.md +326 -0
  90. package/assets/skills/ui-design/reference/new-work.md +350 -0
  91. package/assets/skills/ui-design/reference/onboard.md +85 -0
  92. package/assets/skills/ui-design/reference/operate.md +29 -0
  93. package/assets/skills/ui-design/reference/optimize.md +101 -0
  94. package/assets/skills/ui-design/reference/overdrive.md +83 -0
  95. package/assets/skills/ui-design/reference/polish.md +77 -0
  96. package/assets/skills/ui-design/reference/quieter.md +95 -0
  97. package/assets/skills/ui-design/reference/routing.md +37 -0
  98. package/assets/skills/ui-design/reference/shape.md +43 -0
  99. package/assets/skills/ui-design/reference/styles/brutalist.md +45 -0
  100. package/assets/skills/ui-design/reference/styles/design-md.md +70 -0
  101. package/assets/skills/ui-design/reference/styles/direction.md +95 -0
  102. package/assets/skills/ui-design/reference/styles/full-output.md +42 -0
  103. package/assets/skills/ui-design/reference/styles/minimalist.md +64 -0
  104. package/assets/skills/ui-design/reference/styles/premium.md +65 -0
  105. package/assets/skills/ui-design/reference/styles/redesign.md +59 -0
  106. package/assets/skills/ui-design/reference/typeset.md +73 -0
  107. package/assets/skills/ui-design/reference/visualize.md +156 -0
  108. package/assets/skills/ui-design/scripts/ENGINE-LICENSE +191 -0
  109. package/assets/skills/ui-design/scripts/VERSION +1 -0
  110. package/assets/skills/ui-design/scripts/bin/darwin-arm64/impeccable +0 -0
  111. package/assets/skills/ui-design/scripts/command-metadata.json +94 -0
  112. package/assets/skills/ui-design/scripts/data/font-index-failures.json +121 -0
  113. package/assets/skills/ui-design/scripts/data/font-index.json +1 -0
  114. package/assets/skills/ui-design/scripts/impeccable +206 -0
  115. package/assets/skills/ui-design/scripts/impeccable.cmd +214 -0
  116. package/assets/skills/ui-design/scripts/live-browser-dom.js +167 -0
  117. package/assets/skills/ui-design/scripts/live-browser-ignores.js +242 -0
  118. package/assets/skills/ui-design/scripts/live-browser-session.js +144 -0
  119. package/assets/skills/ui-design/scripts/live-browser.js +12990 -0
  120. package/assets/skills/ui-design/scripts/modern-screenshot.umd.js +14 -0
  121. package/assets/skills/ui-design/scripts/ui-design +6 -0
  122. package/assets/skills/ui-design/scripts/ui-design.cmd +3 -0
  123. package/assets/skills/ui-design/scripts/ui-design.mjs +124 -0
  124. package/assets/skills/ui-mockup/SKILL.md +68 -0
  125. package/assets/skills/ui-mockup/reference/brandkit.md +101 -0
  126. package/assets/skills/ui-mockup/reference/image-to-code.md +83 -0
  127. package/assets/skills/ui-mockup/reference/mobile-comps.md +94 -0
  128. package/assets/skills/ui-mockup/reference/web-comps.md +83 -0
  129. package/assets/skills/ui-motion/SKILL.md +112 -0
  130. package/assets/skills/ui-motion/reference/expo.md +224 -0
  131. package/assets/skills/ui-motion/reference/opportunities.md +81 -0
  132. package/assets/skills/ui-motion/reference/prototype.md +238 -0
  133. package/assets/skills/ui-motion/reference/review.md +163 -0
  134. package/assets/skills/ui-motion/reference/toasts.md +144 -0
  135. package/assets/skills/ui-motion/reference/ui-libraries.md +71 -0
  136. package/assets/skills/ui-motion/reference/vocabulary.md +130 -0
  137. package/assets/skills/ui-motion/reference/web.md +294 -0
  138. package/assets/skills/ui-patterns/SKILL.md +105 -0
  139. package/assets/skills/ui-patterns/references/stacks/html-tailwind.md +40 -0
  140. package/assets/skills/ui-patterns/references/stacks/nextjs.md +52 -0
  141. package/assets/skills/ui-patterns/references/stacks/nuxt.md +100 -0
  142. package/assets/skills/ui-patterns/references/stacks/react-native.md +48 -0
  143. package/assets/skills/ui-patterns/references/stacks/react.md +49 -0
  144. package/assets/skills/ui-patterns/references/stacks/shadcn.md +57 -0
  145. package/assets/skills/ui-patterns/references/stacks/vue.md +37 -0
  146. package/assets/techne/.claude-plugin/marketplace.json +31 -0
  147. package/assets/techne/.claude-plugin/plugin.json +24 -0
  148. package/assets/techne/.mcp.json +8 -0
  149. package/assets/techne/commands/build-fix.md +48 -0
  150. package/assets/techne/commands/refactor-clean.md +46 -0
  151. package/assets/techne/commands/test-coverage.md +42 -0
  152. package/assets/techne/hooks/hooks.json +49 -0
  153. package/assets/techne/rules/angular/coding-style.md +49 -0
  154. package/assets/techne/rules/angular/hooks.md +23 -0
  155. package/assets/techne/rules/angular/patterns.md +48 -0
  156. package/assets/techne/rules/angular/security.md +26 -0
  157. package/assets/techne/rules/angular/testing.md +46 -0
  158. package/assets/techne/rules/arkts/coding-style.md +63 -0
  159. package/assets/techne/rules/arkts/hooks.md +38 -0
  160. package/assets/techne/rules/arkts/patterns.md +42 -0
  161. package/assets/techne/rules/arkts/security.md +35 -0
  162. package/assets/techne/rules/arkts/testing.md +39 -0
  163. package/assets/techne/rules/common/agents.md +6 -0
  164. package/assets/techne/rules/common/code-review.md +15 -0
  165. package/assets/techne/rules/common/coding-style.md +13 -0
  166. package/assets/techne/rules/common/development-workflow.md +5 -0
  167. package/assets/techne/rules/common/git-workflow.md +30 -0
  168. package/assets/techne/rules/common/hooks.md +7 -0
  169. package/assets/techne/rules/common/patterns.md +3 -0
  170. package/assets/techne/rules/common/performance.md +3 -0
  171. package/assets/techne/rules/common/security.md +5 -0
  172. package/assets/techne/rules/common/testing.md +3 -0
  173. package/assets/techne/rules/cpp/coding-style.md +31 -0
  174. package/assets/techne/rules/cpp/hooks.md +26 -0
  175. package/assets/techne/rules/cpp/patterns.md +31 -0
  176. package/assets/techne/rules/cpp/security.md +37 -0
  177. package/assets/techne/rules/cpp/testing.md +31 -0
  178. package/assets/techne/rules/csharp/coding-style.md +30 -0
  179. package/assets/techne/rules/csharp/hooks.md +24 -0
  180. package/assets/techne/rules/csharp/patterns.md +28 -0
  181. package/assets/techne/rules/csharp/security.md +32 -0
  182. package/assets/techne/rules/csharp/testing.md +27 -0
  183. package/assets/techne/rules/dart/coding-style.md +47 -0
  184. package/assets/techne/rules/dart/hooks.md +26 -0
  185. package/assets/techne/rules/dart/patterns.md +38 -0
  186. package/assets/techne/rules/dart/security.md +44 -0
  187. package/assets/techne/rules/dart/testing.md +39 -0
  188. package/assets/techne/rules/fsharp/coding-style.md +34 -0
  189. package/assets/techne/rules/fsharp/hooks.md +25 -0
  190. package/assets/techne/rules/fsharp/patterns.md +43 -0
  191. package/assets/techne/rules/fsharp/security.md +32 -0
  192. package/assets/techne/rules/fsharp/testing.md +27 -0
  193. package/assets/techne/rules/golang/coding-style.md +30 -0
  194. package/assets/techne/rules/golang/hooks.md +17 -0
  195. package/assets/techne/rules/golang/patterns.md +43 -0
  196. package/assets/techne/rules/golang/security.md +33 -0
  197. package/assets/techne/rules/golang/testing.md +20 -0
  198. package/assets/techne/rules/java/coding-style.md +51 -0
  199. package/assets/techne/rules/java/hooks.md +18 -0
  200. package/assets/techne/rules/java/patterns.md +55 -0
  201. package/assets/techne/rules/java/security.md +33 -0
  202. package/assets/techne/rules/java/testing.md +33 -0
  203. package/assets/techne/rules/kotlin/coding-style.md +50 -0
  204. package/assets/techne/rules/kotlin/hooks.md +17 -0
  205. package/assets/techne/rules/kotlin/patterns.md +44 -0
  206. package/assets/techne/rules/kotlin/security.md +34 -0
  207. package/assets/techne/rules/kotlin/testing.md +38 -0
  208. package/assets/techne/rules/nuxt/coding-style.md +20 -0
  209. package/assets/techne/rules/nuxt/hooks.md +16 -0
  210. package/assets/techne/rules/nuxt/patterns.md +46 -0
  211. package/assets/techne/rules/nuxt/security.md +19 -0
  212. package/assets/techne/rules/nuxt/testing.md +15 -0
  213. package/assets/techne/rules/perl/coding-style.md +33 -0
  214. package/assets/techne/rules/perl/hooks.md +22 -0
  215. package/assets/techne/rules/perl/patterns.md +43 -0
  216. package/assets/techne/rules/perl/security.md +39 -0
  217. package/assets/techne/rules/perl/testing.md +42 -0
  218. package/assets/techne/rules/php/coding-style.md +30 -0
  219. package/assets/techne/rules/php/hooks.md +24 -0
  220. package/assets/techne/rules/php/patterns.md +26 -0
  221. package/assets/techne/rules/php/security.md +27 -0
  222. package/assets/techne/rules/php/testing.md +28 -0
  223. package/assets/techne/rules/python/coding-style.md +38 -0
  224. package/assets/techne/rules/python/fastapi.md +57 -0
  225. package/assets/techne/rules/python/hooks.md +19 -0
  226. package/assets/techne/rules/python/patterns.md +37 -0
  227. package/assets/techne/rules/python/security.md +26 -0
  228. package/assets/techne/rules/python/testing.md +32 -0
  229. package/assets/techne/rules/react/coding-style.md +24 -0
  230. package/assets/techne/rules/react/hooks.md +62 -0
  231. package/assets/techne/rules/react/patterns.md +48 -0
  232. package/assets/techne/rules/react/security.md +45 -0
  233. package/assets/techne/rules/react/testing.md +42 -0
  234. package/assets/techne/rules/react-native/accessibility.md +14 -0
  235. package/assets/techne/rules/react-native/coding-style.md +16 -0
  236. package/assets/techne/rules/react-native/hooks.md +16 -0
  237. package/assets/techne/rules/react-native/patterns.md +18 -0
  238. package/assets/techne/rules/react-native/performance.md +14 -0
  239. package/assets/techne/rules/react-native/production-readiness.md +16 -0
  240. package/assets/techne/rules/react-native/security.md +16 -0
  241. package/assets/techne/rules/react-native/testing.md +14 -0
  242. package/assets/techne/rules/ruby/coding-style.md +40 -0
  243. package/assets/techne/rules/ruby/hooks.md +33 -0
  244. package/assets/techne/rules/ruby/patterns.md +33 -0
  245. package/assets/techne/rules/ruby/security.md +39 -0
  246. package/assets/techne/rules/ruby/testing.md +35 -0
  247. package/assets/techne/rules/rust/coding-style.md +41 -0
  248. package/assets/techne/rules/rust/hooks.md +16 -0
  249. package/assets/techne/rules/rust/patterns.md +42 -0
  250. package/assets/techne/rules/rust/security.md +33 -0
  251. package/assets/techne/rules/rust/testing.md +30 -0
  252. package/assets/techne/rules/swift/coding-style.md +30 -0
  253. package/assets/techne/rules/swift/hooks.md +20 -0
  254. package/assets/techne/rules/swift/patterns.md +30 -0
  255. package/assets/techne/rules/swift/security.md +22 -0
  256. package/assets/techne/rules/swift/testing.md +28 -0
  257. package/assets/techne/rules/typescript/coding-style.md +38 -0
  258. package/assets/techne/rules/typescript/hooks.md +14 -0
  259. package/assets/techne/rules/typescript/patterns.md +12 -0
  260. package/assets/techne/rules/typescript/security.md +14 -0
  261. package/assets/techne/rules/typescript/testing.md +12 -0
  262. package/assets/techne/rules/vue/coding-style.md +19 -0
  263. package/assets/techne/rules/vue/hooks.md +13 -0
  264. package/assets/techne/rules/vue/patterns.md +29 -0
  265. package/assets/techne/rules/vue/security.md +11 -0
  266. package/assets/techne/rules/vue/testing.md +11 -0
  267. package/assets/techne/rules/web/coding-style.md +25 -0
  268. package/assets/techne/rules/web/design-quality.md +21 -0
  269. package/assets/techne/rules/web/hooks.md +39 -0
  270. package/assets/techne/rules/web/patterns.md +23 -0
  271. package/assets/techne/rules/web/performance.md +25 -0
  272. package/assets/techne/rules/web/security.md +23 -0
  273. package/assets/techne/rules/web/testing.md +21 -0
  274. package/assets/techne/scripts/hooks/config-guard.js +50 -0
  275. package/assets/techne/scripts/hooks/edit-tracker.js +26 -0
  276. package/assets/techne/scripts/hooks/lib/shell.js +204 -0
  277. package/assets/techne/scripts/hooks/no-verify-guard.js +205 -0
  278. package/assets/techne/scripts/hooks/run.js +92 -0
  279. package/assets/techne/scripts/hooks/stop-checks.js +136 -0
  280. package/assets/techne/skills/angular/SKILL.md +34 -0
  281. package/assets/techne/skills/angular/reference/components-and-templates.md +63 -0
  282. package/assets/techne/skills/angular/reference/dependency-injection.md +44 -0
  283. package/assets/techne/skills/angular/reference/forms.md +97 -0
  284. package/assets/techne/skills/angular/reference/routing.md +50 -0
  285. package/assets/techne/skills/angular/reference/signals-and-state.md +59 -0
  286. package/assets/techne/skills/angular/reference/styling-motion-a11y.md +54 -0
  287. package/assets/techne/skills/angular/reference/testing.md +52 -0
  288. package/assets/techne/skills/angular/reference/tooling.md +31 -0
  289. package/assets/techne/skills/cpp/SKILL.md +27 -0
  290. package/assets/techne/skills/cpp/reference/coding-standards.md +160 -0
  291. package/assets/techne/skills/databases/SKILL.md +35 -0
  292. package/assets/techne/skills/databases/reference/clickhouse.md +102 -0
  293. package/assets/techne/skills/databases/reference/migrations.md +94 -0
  294. package/assets/techne/skills/databases/reference/mysql.md +101 -0
  295. package/assets/techne/skills/databases/reference/postgres.md +72 -0
  296. package/assets/techne/skills/databases/reference/prisma.md +105 -0
  297. package/assets/techne/skills/databases/reference/redis.md +108 -0
  298. package/assets/techne/skills/delivery/SKILL.md +35 -0
  299. package/assets/techne/skills/delivery/reference/deployment-patterns.md +58 -0
  300. package/assets/techne/skills/delivery/reference/docker-patterns.md +77 -0
  301. package/assets/techne/skills/delivery/reference/git-workflow.md +64 -0
  302. package/assets/techne/skills/delivery/reference/github-ops.md +67 -0
  303. package/assets/techne/skills/delivery/reference/jira-integration.md +53 -0
  304. package/assets/techne/skills/delivery/reference/kubernetes-patterns.md +67 -0
  305. package/assets/techne/skills/dotnet/SKILL.md +27 -0
  306. package/assets/techne/skills/dotnet/reference/dotnet-core.md +131 -0
  307. package/assets/techne/skills/flutter/SKILL.md +29 -0
  308. package/assets/techne/skills/flutter/reference/code-review.md +76 -0
  309. package/assets/techne/skills/flutter/reference/patterns.md +201 -0
  310. package/assets/techne/skills/go/SKILL.md +28 -0
  311. package/assets/techne/skills/go/reference/patterns.md +87 -0
  312. package/assets/techne/skills/go/reference/testing.md +142 -0
  313. package/assets/techne/skills/java/SKILL.md +29 -0
  314. package/assets/techne/skills/java/reference/java-standards.md +117 -0
  315. package/assets/techne/skills/java/reference/springboot.md +108 -0
  316. package/assets/techne/skills/kotlin/SKILL.md +35 -0
  317. package/assets/techne/skills/kotlin/reference/android-clean-architecture.md +115 -0
  318. package/assets/techne/skills/kotlin/reference/compose-multiplatform-patterns.md +113 -0
  319. package/assets/techne/skills/kotlin/reference/kotlin-coroutines-flows.md +93 -0
  320. package/assets/techne/skills/kotlin/reference/kotlin-patterns.md +74 -0
  321. package/assets/techne/skills/kotlin/reference/kotlin-testing.md +115 -0
  322. package/assets/techne/skills/ml/SKILL.md +34 -0
  323. package/assets/techne/skills/ml/reference/ai-regression-testing.md +99 -0
  324. package/assets/techne/skills/ml/reference/cost-aware-llm-pipeline.md +133 -0
  325. package/assets/techne/skills/ml/reference/eval-harness.md +94 -0
  326. package/assets/techne/skills/ml/reference/mle-workflow.md +177 -0
  327. package/assets/techne/skills/ml/reference/prompt-optimizer.md +107 -0
  328. package/assets/techne/skills/ml/reference/pytorch-patterns.md +164 -0
  329. package/assets/techne/skills/php/SKILL.md +27 -0
  330. package/assets/techne/skills/php/reference/laravel.md +142 -0
  331. package/assets/techne/skills/python/SKILL.md +33 -0
  332. package/assets/techne/skills/python/reference/django.md +104 -0
  333. package/assets/techne/skills/python/reference/fastapi.md +118 -0
  334. package/assets/techne/skills/python/reference/python-core.md +88 -0
  335. package/assets/techne/skills/python/reference/python-testing.md +105 -0
  336. package/assets/techne/skills/quality/SKILL.md +34 -0
  337. package/assets/techne/skills/quality/reference/benchmark.md +55 -0
  338. package/assets/techne/skills/quality/reference/browser-qa.md +60 -0
  339. package/assets/techne/skills/quality/reference/coding-standards.md +88 -0
  340. package/assets/techne/skills/quality/reference/e2e-testing.md +99 -0
  341. package/assets/techne/skills/quality/reference/tdd-workflow.md +89 -0
  342. package/assets/techne/skills/quality/reference/verification-loop.md +80 -0
  343. package/assets/techne/skills/react/SKILL.md +30 -0
  344. package/assets/techne/skills/react/reference/nextjs-turbopack.md +42 -0
  345. package/assets/techne/skills/react/reference/react-patterns.md +139 -0
  346. package/assets/techne/skills/react/reference/react-performance.md +101 -0
  347. package/assets/techne/skills/react/reference/react-testing.md +139 -0
  348. package/assets/techne/skills/react-native/SKILL.md +28 -0
  349. package/assets/techne/skills/react-native/reference/expo-patterns.md +196 -0
  350. package/assets/techne/skills/research/SKILL.md +35 -0
  351. package/assets/techne/skills/research/reference/architecture-decision-records.md +65 -0
  352. package/assets/techne/skills/research/reference/codebase-onboarding.md +44 -0
  353. package/assets/techne/skills/research/reference/deep-research.md +50 -0
  354. package/assets/techne/skills/research/reference/iterative-retrieval.md +62 -0
  355. package/assets/techne/skills/research/reference/product-lens.md +38 -0
  356. package/assets/techne/skills/research/reference/search-first.md +50 -0
  357. package/assets/techne/skills/rust/SKILL.md +28 -0
  358. package/assets/techne/skills/rust/reference/patterns.md +108 -0
  359. package/assets/techne/skills/rust/reference/testing.md +142 -0
  360. package/assets/techne/skills/services/SKILL.md +32 -0
  361. package/assets/techne/skills/services/reference/api-contracts.md +139 -0
  362. package/assets/techne/skills/services/reference/backend-layers.md +95 -0
  363. package/assets/techne/skills/services/reference/errors-and-resilience.md +146 -0
  364. package/assets/techne/skills/services/reference/hexagonal-boundaries.md +93 -0
  365. package/assets/techne/skills/services/reference/mcp-servers.md +50 -0
  366. package/assets/techne/skills/services/reference/nestjs.md +96 -0
  367. package/assets/techne/skills/swift/SKILL.md +29 -0
  368. package/assets/techne/skills/swift/reference/concurrency.md +83 -0
  369. package/assets/techne/skills/swift/reference/swiftui.md +139 -0
  370. package/assets/techne/skills/vue/SKILL.md +29 -0
  371. package/assets/techne/skills/vue/reference/nuxt4-patterns.md +90 -0
  372. package/assets/techne/skills/vue/reference/ui-to-vue.md +90 -0
  373. package/assets/techne/skills/vue/reference/vue-patterns.md +151 -0
  374. package/assets/techne/skills/web/SKILL.md +30 -0
  375. package/assets/techne/skills/web/reference/bun-runtime.md +55 -0
  376. package/assets/techne/skills/web/reference/frontend-patterns.md +54 -0
  377. package/assets/techne/skills/web/reference/seo.md +77 -0
  378. package/assets/techne/skills/web/reference/vite-patterns.md +96 -0
  379. package/bin/native.cjs +30 -0
  380. package/native/aarch64-apple-darwin/exonous +0 -0
  381. package/native/aarch64-unknown-linux-gnu/exonous +0 -0
  382. package/native/x86_64-apple-darwin/exonous +0 -0
  383. package/native/x86_64-pc-windows-msvc/exonous.exe +0 -0
  384. package/native/x86_64-unknown-linux-gnu/exonous +0 -0
  385. package/package.json +1 -6
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ // PR template resolution: repo template (any case) → ~/.claude/exonous/PR-TEMPLATE.md → copy shipped beside the hooks.
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const { exoDir, stateDir, repoRoot, repoKey } = require('./paths.cjs');
7
+
8
+ const TEMPLATE_NAME = 'pull_request_template.md';
9
+ const REPO_DIRS = ['.github', 'docs', ''];
10
+ const BUNDLED = path.join(__dirname, '..', '..', 'PR-TEMPLATE.md');
11
+ const MAX_BYTES = 64 * 1024;
12
+
13
+ function sectionsOf(text) {
14
+ const visible = String(text)
15
+ .replace(/<!--[\s\S]*?-->/g, '')
16
+ .replace(/^(```|~~~)[\s\S]*?^\1[^\n]*$/gm, '');
17
+ return [...visible.matchAll(/^##(?!#)[ \t]+(.+?)[ \t#]*$/gm)].map((m) => m[1].trim());
18
+ }
19
+
20
+ function findInDir(dir) {
21
+ let names;
22
+ try {
23
+ names = fs.readdirSync(dir);
24
+ } catch {
25
+ return null;
26
+ }
27
+ const matches = names.filter((n) => n.toLowerCase() === TEMPLATE_NAME).map((n) => path.join(dir, n));
28
+ return matches.find(usable) || null;
29
+ }
30
+
31
+ // Symlinks could point outside the repo; huge files are not templates.
32
+ function usable(file) {
33
+ try {
34
+ const stat = fs.lstatSync(file);
35
+ return stat.isFile() && stat.size <= MAX_BYTES;
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ function candidates(cwd) {
42
+ let root = null;
43
+ try {
44
+ root = repoRoot(cwd);
45
+ } catch {
46
+ // outside a repo only the machine templates apply
47
+ }
48
+ const repo = root ? REPO_DIRS.map((d) => () => findInDir(path.join(root, d))) : [];
49
+ return [...repo, () => path.join(exoDir(), 'PR-TEMPLATE.md'), () => BUNDLED];
50
+ }
51
+
52
+ /** @returns {{ path: string | null, sections: string[] }} */
53
+ function resolveTemplate(cwd = process.cwd()) {
54
+ for (const candidate of candidates(cwd)) {
55
+ const file = candidate();
56
+ if (!file || !usable(file)) continue;
57
+ try {
58
+ return { path: file, sections: sectionsOf(fs.readFileSync(file, 'utf8')) };
59
+ } catch {
60
+ // unreadable: try the next one
61
+ }
62
+ }
63
+ return { path: null, sections: [] };
64
+ }
65
+
66
+ function draftPath(cwd = process.cwd()) {
67
+ return path.join(stateDir(), 'pr', `${repoKey(cwd)}.md`);
68
+ }
69
+
70
+ module.exports = { resolveTemplate, sectionsOf, draftPath };
@@ -0,0 +1,110 @@
1
+ 'use strict';
2
+
3
+ // One-shot gate tokens: commit binds the staged tree, push binds the pushed commit; both expire in 15 minutes.
4
+ const crypto = require('crypto');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { exoDir, stateDir, repoKey, gitOut, foreignOwner } = require('./paths.cjs');
8
+
9
+ const TTL_MS = 15 * 60 * 1000;
10
+ const BINDINGS = {
11
+ commit: ['write-tree'],
12
+ push: ['rev-parse', '--verify', 'HEAD^{commit}'],
13
+ };
14
+
15
+ function bindingArgs(kind) {
16
+ const args = BINDINGS[kind];
17
+ if (!args) throw new Error(`unknown token kind: ${kind}`);
18
+ return args;
19
+ }
20
+
21
+ function currentSha(kind, cwd) {
22
+ const out = gitOut(cwd, bindingArgs(kind));
23
+ return out ? out.trim() : null;
24
+ }
25
+
26
+ function tokenFile(kind, cwd) {
27
+ return path.join(stateDir(), kind, `${repoKey(cwd)}.json`);
28
+ }
29
+
30
+ const unique = () => `${process.pid}.${crypto.randomBytes(6).toString('hex')}`;
31
+
32
+ /** @param {{ now?: number }} [options] */
33
+ function mint(kind, cwd, { now = Date.now() } = {}) {
34
+ bindingArgs(kind);
35
+ for (const dir of [exoDir(), stateDir()]) {
36
+ const owner = foreignOwner(dir);
37
+ if (owner !== null) throw new Error(`${dir} is owned by uid ${owner}, not you — run exonous as that user, or fix it with sudo chown -R "$(id -un)" ~/.claude/exonous`);
38
+ }
39
+ const file = tokenFile(kind, cwd);
40
+ const sha = currentSha(kind, cwd);
41
+ if (!sha) throw new Error(`git could not read the ${kind === 'commit' ? 'staged tree' : 'HEAD commit'} in ${cwd}`);
42
+ fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
43
+ const tmp = `${file}.${unique()}.tmp`;
44
+ fs.writeFileSync(tmp, JSON.stringify({ sha, exp: now + TTL_MS }), { mode: 0o600, flag: 'wx' });
45
+ fs.renameSync(tmp, file);
46
+ return { file, sha, exp: now + TTL_MS };
47
+ }
48
+
49
+ function judge(raw, expected) {
50
+ let data;
51
+ try {
52
+ data = JSON.parse(raw);
53
+ } catch {
54
+ return { ok: false, reason: 'invalid' };
55
+ }
56
+ if (!data || typeof data.sha !== 'string' || typeof data.exp !== 'number') return { ok: false, reason: 'invalid' };
57
+ if (Date.now() > data.exp) return { ok: false, reason: 'expired' };
58
+ return expected.length && expected.every((sha) => sha === data.sha) ? { ok: true } : { ok: false, reason: 'mismatch' };
59
+ }
60
+
61
+ function expectedShas(kind, cwd, expected) {
62
+ if (expected) return expected;
63
+ const sha = currentSha(kind, cwd);
64
+ return sha ? [sha] : [];
65
+ }
66
+
67
+ /**
68
+ * @param {string[]} [expected] shas the token must match; default: the current binding.
69
+ * @returns {{ ok: true } | { ok: false, reason: 'none'|'expired'|'mismatch'|'invalid' }}
70
+ */
71
+ function verify(kind, cwd, expected) {
72
+ bindingArgs(kind);
73
+ let file;
74
+ let raw;
75
+ try {
76
+ file = tokenFile(kind, cwd);
77
+ raw = fs.readFileSync(file, 'utf8');
78
+ } catch {
79
+ return { ok: false, reason: 'none' };
80
+ }
81
+ const result = judge(raw, expectedShas(kind, cwd, expected));
82
+ if (result.reason === 'expired') fs.rmSync(file, { force: true });
83
+ return result;
84
+ }
85
+
86
+ // The rename is the lock: only one consumer can move the file away, the rest see 'none'.
87
+ function consume(kind, cwd, expected) {
88
+ bindingArgs(kind);
89
+ let file;
90
+ try {
91
+ file = tokenFile(kind, cwd);
92
+ } catch {
93
+ return { ok: false, reason: 'none' };
94
+ }
95
+ const claim = `${file}.${unique()}.claim`;
96
+ try {
97
+ fs.renameSync(file, claim);
98
+ } catch {
99
+ return { ok: false, reason: 'none' };
100
+ }
101
+ let raw;
102
+ try {
103
+ raw = fs.readFileSync(claim, 'utf8');
104
+ } finally {
105
+ fs.rmSync(claim, { force: true });
106
+ }
107
+ return judge(raw, expectedShas(kind, cwd, expected));
108
+ }
109
+
110
+ module.exports = { mint, verify, consume, TTL_MS, KINDS: Object.keys(BINDINGS) };
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { validateBodyFile } = require('./pr-template-validate.cjs');
5
+ const { resolveTemplate } = require('./template.cjs');
6
+
7
+ const file = process.argv[2];
8
+ if (!file) {
9
+ process.stderr.write('Usage: node validate-pr-body.cjs <path-to-body-file>\n');
10
+ process.exit(2);
11
+ }
12
+
13
+ const template = resolveTemplate(process.cwd());
14
+ const result = validateBodyFile(file, process.cwd(), template);
15
+ if (!result.ok) {
16
+ process.stderr.write(`${result.reason}\n`);
17
+ process.exit(1);
18
+ }
19
+
20
+ process.stdout.write(`PR body OK — all ${template.sections.length} template titles present (${template.path}).\n`);
21
+ process.exit(0);
@@ -0,0 +1,302 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Pre-exec shell gate: pyle.cjs <auto|commit|pr|push> [--adapter <id>]. Node builtins + ./lib only.
5
+ const { spawnSync } = require('child_process');
6
+
7
+ // A half-updated or broken runtime must still block git/gh: Windsurf, for one, only blocks on exit 2.
8
+ let payload, token, repoRoot, gitEnv, gitOut, analyze, isolationProblem, redirectionProblem;
9
+ let parseOptions, has, COMMIT, PUSH, GH_PR_CREATE, validatePrCreate, prFields;
10
+ let loadError = null;
11
+ try {
12
+ payload = require('./lib/payload.cjs');
13
+ token = require('./lib/token.cjs');
14
+ ({ repoRoot, gitEnv, gitOut } = require('./lib/paths.cjs'));
15
+ ({ analyze, isolationProblem, redirectionProblem } = require('./lib/shell.cjs'));
16
+ ({ parseOptions, has, COMMIT, PUSH, GH_PR_CREATE } = require('./lib/cli-options.cjs'));
17
+ ({ validatePrCreate, prFields } = require('./lib/pr-template-validate.cjs'));
18
+ } catch (err) {
19
+ loadError = err;
20
+ }
21
+
22
+ const MODES = ['commit', 'pr', 'push'];
23
+ const PROTECTED = /^(main|master)$/;
24
+ const GATED_WORD = /commit|push|\bpr\b[\s\S]*\b(create|new)\b/i;
25
+ const GIT_WORD = /\bgit\b|\bgh\b/;
26
+ const DISPLAY = { commit: 'git commit', push: 'git push', pr: 'gh pr create' };
27
+ const STAGING = ['all', 'patch', 'interactive', 'include', 'only', 'pathspec-from-file'];
28
+ // Tool hooks time out (Copilot defaults to 30 s): probe + scan stay well under that, and a timeout denies.
29
+ const GITLEAKS_TIMEOUT_MS = 20000;
30
+ const GITLEAKS_PROBE_MS = 5000;
31
+
32
+ const TOKEN_REASONS = {
33
+ commit: {
34
+ none: 'no commit token for this repo',
35
+ expired: 'the commit token expired (15 min)',
36
+ mismatch: 'the staged changes differ from what was reviewed',
37
+ invalid: 'the commit token is unreadable',
38
+ },
39
+ push: {
40
+ none: 'no push token for this repo',
41
+ expired: 'the push token expired (15 min)',
42
+ mismatch: 'the commit being pushed is not the one the push token was minted for',
43
+ invalid: 'the push token is unreadable',
44
+ },
45
+ };
46
+
47
+ function denyText(mode, why) {
48
+ if (mode === 'commit') return `exonous: git commit blocked — ${why}. Run \`exonous workflow commit\`, follow it (review), then \`exonous token commit\` and retry.`;
49
+ if (mode === 'push') return `exonous: git push blocked — ${why}. Run \`exonous workflow commit\`, review, then \`exonous token push\` and retry.`;
50
+ return `exonous: gh pr create blocked — ${why}. Run \`exonous workflow pr\`, review, then retry.`;
51
+ }
52
+
53
+ // ── Commit ───────────────────────────────────────────────────────────────────
54
+
55
+ // Case-insensitive: macOS and Windows resolve .GITLEAKS.toml as the config gitleaks reads.
56
+ const GITLEAKS_SPEC = ':(glob,icase)**/.gitleaks*';
57
+ const isGitleaksFile = (rel) => !rel.endsWith('/') && /^\.gitleaks/i.test(rel.split('/').pop());
58
+
59
+ // Tracked changes from status; untracked and ignored files one by one from ls-files, which (unlike status --ignored)
60
+ // never collapses an ignored directory into a single entry.
61
+ function gitleaksConfigChanged(root) {
62
+ const tracked = gitOut(root, ['status', '--porcelain=v1', '-z', '--untracked-files=no', '--', GITLEAKS_SPEC]);
63
+ const others = gitOut(root, ['ls-files', '-z', '--others', '--', GITLEAKS_SPEC]);
64
+ if (tracked === null || others === null) return 'git could not report the gitleaks config state';
65
+ // -z entries are "XY path"; a rename or copy is followed by its original path as a bare entry.
66
+ const changed = [];
67
+ const tokens = tracked.split('\0');
68
+ for (let i = 0; i < tokens.length; i++) {
69
+ if (!tokens[i]) continue;
70
+ changed.push(tokens[i].slice(3));
71
+ if (/^[RC]/.test(tokens[i])) changed.push(tokens[++i] || '');
72
+ }
73
+ const files = [...new Set([...changed, ...others.split('\0')])].filter((rel) => rel && isGitleaksFile(rel));
74
+ return files.length ? `the gitleaks config differs from HEAD (${files.join(', ')}); a human must commit it` : null;
75
+ }
76
+
77
+ function allowCommentStaged(root) {
78
+ const diff = gitOut(root, ['diff', '--cached', '-U0', '--no-color', '--no-ext-diff', '--no-textconv']);
79
+ if (diff === null) return 'git could not read the staged diff';
80
+ const added = diff.split('\n').filter((l) => l.startsWith('+') && !l.startsWith('+++ '));
81
+ return added.some((l) => l.includes('gitleaks:allow')) ? 'a staged line adds a `gitleaks:allow` comment; a human must commit it' : null;
82
+ }
83
+
84
+ function scanStaged(cwd, warnings) {
85
+ const root = repoRoot(cwd);
86
+ const tampered = gitleaksConfigChanged(root) || allowCommentStaged(root);
87
+ if (tampered) return tampered;
88
+ const run = (args, timeout = GITLEAKS_TIMEOUT_MS) => spawnSync('gitleaks', args, { cwd: root, env: gitEnv(), encoding: 'utf8', timeout });
89
+ // Older gitleaks lacks the flag; the staged-diff check above covers it then.
90
+ const help = run(['git', '--help'], GITLEAKS_PROBE_MS);
91
+ const args = ['git', '--staged', '--redact', '--no-banner'];
92
+ if (!help.error && `${help.stdout}${help.stderr}`.includes('--ignore-gitleaks-allow')) args.push('--ignore-gitleaks-allow');
93
+ const res = help.error && help.error.code === 'ENOENT' ? help : run(args);
94
+ if (res.error && res.error.code === 'ENOENT') {
95
+ warnings.push('exonous: gitleaks not installed — staged content was NOT scanned for secrets (https://github.com/gitleaks/gitleaks#installing).');
96
+ return null;
97
+ }
98
+ if (res.status === 0 && !res.error && !res.signal) return null;
99
+ const detail = `${res.stdout || ''}${res.stderr || ''}`.split('\n').filter((l) => l.trim()).slice(0, 15).join('\n');
100
+ const how = res.error ? res.error.message : res.signal ? `killed by ${res.signal}` : `exit ${res.status}`;
101
+ return `gitleaks did not pass the staged changes (${how}); remove any secret and re-stage, or allowlist a false positive in a separately reviewed commit${detail ? `:\n${detail}\n` : ''}`;
102
+ }
103
+
104
+ function checkCommit(call, { warnings }) {
105
+ const parsed = parseOptions(call.args, COMMIT);
106
+ if (parsed.error) return `cannot verify its options: ${parsed.error}`;
107
+ if (has(parsed, 'help', 'dry-run')) return null;
108
+ if (has(parsed, ...STAGING) || parsed.positional.length) {
109
+ return 'commits that stage at commit time (-a, -i, -o, -p, pathspecs) are not covered by the token; stage with `git add`, mint the token, then run a plain `git commit`';
110
+ }
111
+ const state = token.verify('commit', call.cwd);
112
+ if (!state.ok) return TOKEN_REASONS.commit[state.reason];
113
+ const leak = scanStaged(call.cwd, warnings);
114
+ if (leak) return leak;
115
+ const claimed = token.consume('commit', call.cwd);
116
+ return claimed.ok ? null : TOKEN_REASONS.commit[claimed.reason];
117
+ }
118
+
119
+ // ── Push ─────────────────────────────────────────────────────────────────────
120
+
121
+ function currentBranch(cwd) {
122
+ return (gitOut(cwd, ['branch', '--show-current']) || '').trim();
123
+ }
124
+
125
+ /** dst null = destination unresolved, treated as protected. @returns {{ force: boolean, all: boolean, pushes: { src: string | null, dst: string | null }[] }} */
126
+ function pushPlan(parsed, cwd) {
127
+ const force = has(parsed, 'force', 'force-with-lease', 'force-if-includes', 'mirror');
128
+ let all = has(parsed, 'all', 'branches', 'mirror', 'prune');
129
+ const deleting = has(parsed, 'delete');
130
+ const refspecs = parsed.opts.some((o) => o.name === 'repo') ? parsed.positional : parsed.positional.slice(1);
131
+ const branch = currentBranch(cwd);
132
+ const upstream = () => {
133
+ const out = gitOut(cwd, ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{push}']);
134
+ return out && out.trim() ? out.trim().replace(/^[^/]+\//, '') : null;
135
+ };
136
+ const short = (ref) => {
137
+ const name = ref.replace(/^refs\/heads\//, '');
138
+ return name === 'HEAD' ? branch : name;
139
+ };
140
+ if (!refspecs.length) return { force, all, pushes: all ? [] : [{ src: 'HEAD', dst: upstream() }] };
141
+ const pushes = refspecs.map((raw) => {
142
+ const spec = raw.replace(/^\+/, '');
143
+ if (spec.includes('*') || spec === ':') all = true;
144
+ if (deleting) return { src: null, dst: short(spec) };
145
+ const colon = spec.indexOf(':');
146
+ if (colon === -1) return { src: spec, dst: short(spec) };
147
+ const src = spec.slice(0, colon);
148
+ return { src: src || null, dst: short(spec.slice(colon + 1) || src) };
149
+ });
150
+ return { force: force || refspecs.some((r) => r.startsWith('+')), all, pushes };
151
+ }
152
+
153
+ function checkPush(call) {
154
+ const override = call.configs.find((k) => /^(push|remote|branch)\./i.test(k));
155
+ if (override) return `inline \`-c ${override}\` changes where the push goes`;
156
+ const parsed = parseOptions(call.args, PUSH);
157
+ if (parsed.error) return `cannot verify its options: ${parsed.error}`;
158
+ if (has(parsed, 'help', 'dry-run')) return null;
159
+ const plan = pushPlan(parsed, call.cwd);
160
+ const guarded = plan.pushes.find((p) => p.dst === null || PROTECTED.test(p.dst));
161
+ const target = plan.all ? 'every branch' : guarded && (guarded.dst || 'an upstream that cannot be resolved');
162
+ if (!plan.force && !target) return null;
163
+ const what = plan.force ? 'force-push' : `push to ${target}`;
164
+ if (plan.all) return `${plan.force ? 'force-push' : 'push'} touches every branch; push one branch at a time`;
165
+ const deleted = plan.pushes.find((p) => p.src === null);
166
+ if (deleted) return `deleting ${deleted.dst} needs a human`;
167
+ const shas = plan.pushes.map((p) => (gitOut(call.cwd, ['rev-parse', '--verify', '--end-of-options', `${p.src}^{commit}`]) || '').trim());
168
+ const missing = plan.pushes.find((p, i) => !shas[i]);
169
+ if (missing) {
170
+ const branch = missing.src && !/[~^:@]|^HEAD$/.test(missing.src) ? missing.src.replace(/^refs\/heads\//, '') : null;
171
+ return branch
172
+ ? `there is no local branch "${branch}" to push (${what}); push the branch you mean, e.g. \`git push origin HEAD:${missing.dst}\`, after review`
173
+ : `cannot resolve what ${what} would send`;
174
+ }
175
+ const state = token.verify('push', call.cwd, shas);
176
+ if (!state.ok) return `${what} needs review; ${TOKEN_REASONS.push[state.reason]}`;
177
+ const claimed = token.consume('push', call.cwd, shas);
178
+ return claimed.ok ? null : `${what} needs review; ${TOKEN_REASONS.push[claimed.reason]}`;
179
+ }
180
+
181
+ // ── PR ───────────────────────────────────────────────────────────────────────
182
+
183
+ function checkPr(call) {
184
+ const parsed = parseOptions(call.args, GH_PR_CREATE);
185
+ if (parsed.error) return `cannot verify its options: ${parsed.error}`;
186
+ if (has(parsed, 'help')) return null;
187
+ if (parsed.positional.length) return `unexpected argument "${parsed.positional[0]}"`;
188
+ const result = validatePrCreate(prFields(parsed), call.cwd);
189
+ return result.ok ? null : result.reason.replace(/\.$/, '');
190
+ }
191
+
192
+ // ── Gate ─────────────────────────────────────────────────────────────────────
193
+
194
+ /** @returns {{ allow: boolean, reason?: string, warnings: string[] }} */
195
+ function gate(mode, { command, cwd }) {
196
+ const warnings = [];
197
+ const result = analyze(command, cwd);
198
+ const deny = (why) => ({ allow: false, reason: denyText(mode, why), warnings });
199
+ if (result.forced.length) return deny(result.forced[0]);
200
+ const gatedWord = GATED_WORD.test(command) || result.words.some((w) => GATED_WORD.test(w));
201
+ const gitWord = GIT_WORD.test(command);
202
+ // Computed names are fine for ordinary tools; near git/gh or with computed arguments they could be anything.
203
+ if (result.dynamicHeads.some((h) => !h.argsStatic) || (result.dynamicHeads.length && (gitWord || gatedWord))) return deny('a command name is computed at run time');
204
+ if (result.dynamicScripts.length && (gitWord || gatedWord)) return deny(result.dynamicScripts[0]);
205
+ const call = result.calls.find((c) => c.kind === mode);
206
+ if (!call) return gatedWord && result.notes.length ? deny(`${result.notes[0]} on a line that mentions a gated command`) : { allow: true, warnings };
207
+ const alone = isolationProblem(result, call);
208
+ if (alone) return deny(`run \`${DISPLAY[mode]}\` alone (optionally after one \`cd <dir> &&\`): ${alone}`);
209
+ if (result.notes.length) return deny(result.notes[0]);
210
+ const redirected = redirectionProblem(call);
211
+ if (redirected) return deny(redirected);
212
+ let reason;
213
+ try {
214
+ if (mode === 'commit') reason = checkCommit(call, { warnings });
215
+ else if (mode === 'push') reason = checkPush(call);
216
+ else reason = checkPr(call);
217
+ } catch (err) {
218
+ reason = `the gate could not verify this command (${err.message})`;
219
+ }
220
+ return reason ? deny(reason) : { allow: true, warnings };
221
+ }
222
+
223
+ /** First deny across modes wins; one hook entry can gate commit, push and pr. */
224
+ function gateAll(modes, input) {
225
+ const warnings = [];
226
+ for (const mode of modes) {
227
+ const result = gate(mode, input);
228
+ warnings.push(...result.warnings);
229
+ if (!result.allow) return { ...result, warnings };
230
+ }
231
+ return { allow: true, warnings };
232
+ }
233
+
234
+ // ── Entry ────────────────────────────────────────────────────────────────────
235
+
236
+ const mentionsGit = (raw) => raw.includes('git') || raw.includes('gh');
237
+
238
+ function option(argv, name) {
239
+ const i = argv.indexOf(name);
240
+ return i === -1 ? null : argv[i + 1] || null;
241
+ }
242
+
243
+ function finish({ code, stdout, stderr }) {
244
+ if (stdout) process.stdout.write(stdout);
245
+ if (stderr) process.stderr.write(stderr);
246
+ process.exitCode = code;
247
+ }
248
+
249
+ function failClosed(adapter, raw, why) {
250
+ if (!mentionsGit(raw)) return finish(payload.allow(adapter, [`exonous: ${why} — command not checked.`]));
251
+ return finish(payload.deny(adapter, `exonous: blocked — ${why}, and the input mentions git or gh. Run the command again on its own line.`));
252
+ }
253
+
254
+ function main(argv) {
255
+ const mode = argv[0];
256
+ const adapter = option(argv, '--adapter') || 'claude';
257
+ let raw = '';
258
+ process.stdin.setEncoding('utf8');
259
+ process.stdin.on('error', () => failClosed(adapter, raw, 'hook input was unreadable'));
260
+ process.stdin.on('data', (chunk) => { raw += chunk; });
261
+ process.stdin.on('end', () => {
262
+ try {
263
+ if (mode !== 'auto' && !MODES.includes(mode)) return failClosed(adapter, raw, `unknown gate mode "${mode}"`);
264
+ const input = payload.parse(adapter, raw);
265
+ if (!input) return failClosed(adapter, raw, 'hook input had no shell command');
266
+ const result = gateAll(mode === 'auto' ? MODES : [mode], input);
267
+ const warn = result.warnings.map((w) => `${w}\n`).join('');
268
+ if (result.allow) return finish(payload.allow(adapter, result.warnings));
269
+ const out = payload.deny(adapter, result.reason);
270
+ return finish({ ...out, stderr: `${warn}${out.stderr}` });
271
+ } catch (err) {
272
+ return failClosed(adapter, raw, `gate error (${err.message})`);
273
+ }
274
+ });
275
+ }
276
+
277
+ /** No libs available: deny anything that mentions git or gh with exit 2 (the one block signal every tool honors). */
278
+ function loadFailure(err) {
279
+ let raw = '';
280
+ const done = () => {
281
+ if (!GIT_WORD.test(raw)) return;
282
+ process.stderr.write(`exonous: blocked — the gate could not load (${err.message}); run \`exonous install\` or \`exonous doctor\`.\n`);
283
+ process.exitCode = 2;
284
+ };
285
+ process.stdin.setEncoding('utf8');
286
+ process.stdin.on('data', (chunk) => { raw += chunk; });
287
+ process.stdin.on('end', done);
288
+ process.stdin.on('error', done);
289
+ }
290
+
291
+ if (require.main === module) {
292
+ if (loadError) loadFailure(loadError);
293
+ else {
294
+ try {
295
+ main(process.argv.slice(2));
296
+ } catch (err) {
297
+ loadFailure(err);
298
+ }
299
+ }
300
+ }
301
+
302
+ module.exports = { gate, gateAll, pushPlan };
@@ -0,0 +1,59 @@
1
+ # Nomos — always on
2
+
3
+ Enforced by `exonous`. Pillars, never trade a higher one for a lower one: security → architecture → model governance → quality → token economy → speed. Repo `AGENTS.md`/`CLAUDE.md` win over this file; scoped `.claude/rules/exonous/` win on coding standards.
4
+
5
+ Always-on set: this file and `praxis.md` (craft discipline per change — make it work, make it right, keep the practice). Both bind every agent; neither is invoked, both are already in force.
6
+
7
+ ## Communication — terse
8
+ - Cut filler, pleasantries, hedges, restated questions. Fragments ok. Shape: `[subject] [what happens] [why]. [next step].`
9
+ - Quote code, commands, paths, errors and identifiers exactly. Answer in the user's language.
10
+ - Levels: `terse lite|full|ultra`; off with `stop terse` / `normal mode`.
11
+ - Full prose for security warnings, irreversible actions, or a confused user — then back to terse.
12
+ - Normal prose for commits, PR bodies and team docs.
13
+
14
+ ## Engineering
15
+ - Clarify before building: name shaky assumptions, show competing readings, push back on a simpler path.
16
+ - No speculative wrappers, options or conversions; no abstraction before a second real caller.
17
+ - Change only what the task needs; finish affected callers, tests, fixtures, config and exports. Match local style; clean only what you orphaned. Mention unrelated dead code.
18
+ - Done = proven: turn the task into a runnable check (bug → failing test that passes; refactor → tests green before and after).
19
+ - Comments: default none. Only a business rule earns one, one terse line. Any comment over 2 lines in a file you edit → cut to one line.
20
+
21
+ ## Context economy — locate first, read second
22
+ - Code: `atlas` (`search_graph`, `trace_path`, `get_code_snippet`, `get_architecture`) before raw reads. No graph → read raw and say so.
23
+ - Read whole files only to edit them; otherwise read the line range you need. Never re-read a file you just edited.
24
+ - Project memory: `project-memory search "<q>"` in the vault, then `show` only the hits that matter.
25
+ - Subagents get a packet (goal, paths/symbols, constraints, done-criteria), never a transcript.
26
+
27
+ ## Verify before done
28
+ - Run the relevant tests, type-check and lint yourself; report real output, failures included.
29
+ - Never weaken, skip or delete a test to pass it.
30
+ - Same file edited 3× without a passing check → stop, restate expected vs actual, re-read, new hypothesis.
31
+ - Keep error output until understood.
32
+
33
+ ## Git and PRs
34
+ - `git commit` only via `/commit-changes`; push and `gh pr create` only via `/make-pr`. Never without an explicit request.
35
+ - Destructive ops (`rm -rf`, `reset --hard`, force-push, clean) need explicit confirmation after inspecting what is lost.
36
+ - PR ≤ 30 changed files; body follows `.claude/PR-TEMPLATE.md`. Conventional commits.
37
+
38
+ ## Agents
39
+ Only these 12 subagents exist (plus built-ins); others are remapped or blocked by a hook. Tier is fixed per agent: sonnet plans/reviews/researches, opus writes code.
40
+
41
+ | Agent | Use for |
42
+ |---|---|
43
+ | `exo-pm` | requirements, plans, phases, backlog |
44
+ | `exo-cto` | architecture, ADRs, tech choices |
45
+ | `exo-researcher` | codebase mapping, docs lookup, docs writing |
46
+ | `exo-designer` | UX/UI direction, a11y, design review |
47
+ | `exo-frontend` · `exo-backend` · `exo-mobile` · `exo-data-ai` · `exo-devops` · `exo-infra` | implementers by domain (backend = default) |
48
+ | `exo-qa` | review, tests, debugging, verification gate |
49
+ | `exo-security` | AppSec, auth, secrets, dependencies |
50
+
51
+ - Inline first: one domain, few files, no independent review → main thread. Delegate for parallel, cross-domain, fresh-context review or context-flooding work.
52
+ - Multi-step delivery runs through `/deliver` (classify → plan → execute → verify → close).
53
+ - Independent agents go out in one message. Revision rounds continue the same agent (`SendMessage`), never a respawn.
54
+ - Every subagent report starts with `{"status":"done|partial|blocked","cause":"…","risks":[…]}`.
55
+
56
+ ## Design
57
+ - Any visible UI change: `ui-design` first, then `ui-motion` / `native-ui` / `ui-mockup` as needed; `ui-patterns` only after direction is set. Announce `Using ui-design for [purpose]`.
58
+ - Three people open every screen: the user experience (UX), developer experience (DX), and agent experience (AX) that edits it next. Serve all three, or you're robbing one to pay another.
59
+ - Kill any label that only exists to explain the layout. If the screen needs a caption, the screen is broken.
@@ -0,0 +1,38 @@
1
+ # Praxis — always on
2
+
3
+ Enforced by `exonous`. Craft discipline for every code change, in this order: make it work → make it right → keep the practice. Never reach for the second before the first is proven. Interpreted from Robert C. Martin's published principles; the gate tools named below are his.
4
+
5
+ ## Make it work
6
+
7
+ - One decision belongs in a single place. Edit the smallest surface that settles the stated problem.
8
+ - Before code: necessity → existing repo code → standard library/platform → installed dependency → minimum clear code.
9
+ - Equal size: edge correctness. Preserve validation, errors, required behavior, security and accessibility. A known shortcut states its limit and reason.
10
+ - Fix the data shape before the logic. Work that unblocks every later step goes first.
11
+ - Tests lead: a failing test, failing for the predicted reason, then the least code that turns it green. No honest test is possible → say so, never write a hollow one.
12
+ - A new requirement is not bolted onto the old shape. Ask what the design would have been had it always been there, then ship that in slices.
13
+ - Two fixes that fail the same gate share a false premise. Write the premise in one sentence, name who holds it, drop it. No third attempt before that.
14
+ - Subtract complexity before adding any. Aim at an end state you can check; a planned, reversible break mid-way is allowed.
15
+ - Work that is not obvious at a glance earns a tool: do one case by hand, then teach the tool that case.
16
+
17
+ ## Architecture
18
+
19
+ - Shape the domain so illegal states cannot be written, and keep a glossary of its terms. Code already clear and local stays as it is.
20
+ - Validate at the entry point, then trust the value inside. Business rules live in pure functions.
21
+ - Parse foreign data once, where it arrives. Never quiet the compiler to move on.
22
+ - An operation ends in the same state run twice, or resumed after a crash halfway through.
23
+ - Actors that need no shared mutable state each get their own. If they truly share, exactly one writes, and the structure enforces it.
24
+
25
+ ## Make it right
26
+
27
+ - Reproduce, then fix the cause. A guard that only hides the symptom is not a fix.
28
+ - Finish one verifiable unit and check it before opening the next.
29
+ - A test drives the code the way a caller does and asserts what that caller sees. A test that still passes when the body returns nothing gets deleted.
30
+ - Restructure under pinned behavior: capture what it does, change the shape, prove the behavior held.
31
+ - Quality gates, where the stack has them wired: complexity-over-coverage score under 10 (`crapper`), structural duplication under 0.8 (`dryer`), surviving mutants killed and dead code deleted (`mutator`), dependency direction read off the map (`uml-viewer`). All four live at https://github.com/unclebob.
32
+
33
+ ## Practice
34
+
35
+ - Log each action and the reason for it; hand that log over when the work is done.
36
+ - Keep the main thread lean: bulk work goes to a subagent, only its summary returns.
37
+ - Reclaim a worktree once nothing in use needs it. Uncommitted work waits for a decision, never for a cleanup.
38
+ - Commit small and ordered; each message says why, what moved, and how it was proven. Push at the end of the line of work.