@xhulz/nina 0.37.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/package.json +1 -1
  2. package/releases/0.38.0/core/GAPS.md +125 -0
  3. package/releases/0.38.0/core/answered.json +32 -0
  4. package/releases/0.38.0/core/defaults/tree/.claude/agents/architect.md +1 -0
  5. package/releases/0.38.0/core/defaults/tree/.claude/agents/dba.md +3 -0
  6. package/releases/0.38.0/core/defaults/tree/.claude/agents/devops.md +1 -0
  7. package/releases/0.38.0/core/defaults/tree/.claude/agents/implementer.md +1 -0
  8. package/releases/0.38.0/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
  9. package/releases/0.38.0/core/defaults/tree/.claude/agents/qa.md +2 -0
  10. package/releases/0.38.0/core/defaults/tree/.claude/agents/reviewer.md +3 -0
  11. package/releases/0.38.0/core/defaults/tree/.claude/agents/secops.md +3 -0
  12. package/releases/0.38.0/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
  13. package/releases/0.38.0/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
  14. package/releases/0.38.0/core/tree/.claude/agents/architect.md +127 -0
  15. package/releases/0.38.0/core/tree/.claude/agents/dba.md +110 -0
  16. package/releases/0.38.0/core/tree/.claude/agents/devops.md +114 -0
  17. package/releases/0.38.0/core/tree/.claude/agents/implementer.md +156 -0
  18. package/releases/0.38.0/core/tree/.claude/agents/integration-tester.md +168 -0
  19. package/releases/0.38.0/core/tree/.claude/agents/planner.md +132 -0
  20. package/releases/0.38.0/core/tree/.claude/agents/qa.md +152 -0
  21. package/releases/0.38.0/core/tree/.claude/agents/reviewer.md +183 -0
  22. package/releases/0.38.0/core/tree/.claude/agents/secops.md +121 -0
  23. package/releases/0.38.0/core/tree/.claude/agents/solidity-auditor.md +126 -0
  24. package/releases/0.38.0/core/tree/.claude/agents/solidity-dev.md +123 -0
  25. package/releases/0.38.0/core/tree/.claude/agents-overview.md +64 -0
  26. package/releases/0.38.0/core/tree/.claude/frontend.md +10 -0
  27. package/releases/0.38.0/core/tree/.claude/graph.md +75 -0
  28. package/releases/0.38.0/core/tree/.claude/patterns.md +213 -0
  29. package/releases/0.38.0/core/tree/.claude/pills/README.md +147 -0
  30. package/releases/0.38.0/core/tree/.claude/pipeline.md +101 -0
  31. package/releases/0.38.0/core/tree/.claude/retrieval.md +103 -0
  32. package/releases/0.38.0/core/tree/.claude/router.md +198 -0
  33. package/releases/0.38.0/core/tree/.claude/templates/integration.md +45 -0
  34. package/releases/0.38.0/core/tree/CLAUDE.md +161 -0
  35. package/releases/0.38.0/core/tree/scripts/cost-watch.mjs +18 -0
  36. package/releases/0.38.0/core/tree/scripts/edit-guard.mjs +16 -0
  37. package/releases/0.38.0/core/tree/scripts/harness-check.mjs +71 -0
  38. package/releases/0.38.0/core/tree/scripts/loop-gate.mjs +19 -0
  39. package/releases/0.38.0/core/vocabulary.json +13 -0
  40. package/releases/0.38.0/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
  41. package/releases/0.38.0/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
  42. package/releases/0.38.0/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
  43. package/releases/0.38.0/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
  44. package/releases/0.38.0/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
  45. package/releases/0.38.0/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
  46. package/releases/0.38.0/surfaces/blockchain/tree/.claude/graph.md +11 -0
  47. package/releases/0.38.0/surfaces/blockchain/tree/.claude/router.md +6 -0
  48. package/releases/0.38.0/surfaces/blockchain/tree/CLAUDE.md +12 -0
  49. package/releases/0.38.0/surfaces/db/tree/.claude/agents/architect.md +5 -0
  50. package/releases/0.38.0/surfaces/db/tree/.claude/agents/dba.md +50 -0
  51. package/releases/0.38.0/surfaces/db/tree/.claude/agents/devops.md +5 -0
  52. package/releases/0.38.0/surfaces/db/tree/.claude/agents/implementer.md +2 -0
  53. package/releases/0.38.0/surfaces/db/tree/.claude/agents/integration-tester.md +10 -0
  54. package/releases/0.38.0/surfaces/db/tree/.claude/agents/planner.md +2 -0
  55. package/releases/0.38.0/surfaces/db/tree/.claude/agents/reviewer.md +22 -0
  56. package/releases/0.38.0/surfaces/db/tree/.claude/agents/secops.md +2 -0
  57. package/releases/0.38.0/surfaces/db/tree/.claude/agents-overview.md +5 -0
  58. package/releases/0.38.0/surfaces/db/tree/.claude/graph.md +8 -0
  59. package/releases/0.38.0/surfaces/db/tree/.claude/patterns.md +19 -0
  60. package/releases/0.38.0/surfaces/db/tree/.claude/pipeline.md +13 -0
  61. package/releases/0.38.0/surfaces/db/tree/.claude/retrieval.md +5 -0
  62. package/releases/0.38.0/surfaces/db/tree/.claude/router.md +4 -0
  63. package/releases/0.38.0/surfaces/db/tree/CLAUDE.md +17 -0
  64. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
  65. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
  66. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/agents/devops.md +32 -0
  67. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
  68. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
  69. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
  70. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
  71. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
  72. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
  73. package/releases/0.38.0/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
  74. package/releases/0.38.0/surfaces/edge-cf/tree/CLAUDE.md +27 -0
  75. package/releases/0.38.0/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
  76. package/releases/0.38.0/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
  77. package/releases/0.38.0/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
  78. package/releases/0.38.0/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
  79. package/releases/0.38.0/surfaces/frontend/tree/.claude/agents/reviewer.md +56 -0
  80. package/releases/0.38.0/surfaces/frontend/tree/.claude/patterns.md +8 -0
  81. package/releases/0.38.0/surfaces/frontend/tree/.claude/retrieval.md +2 -0
  82. package/releases/0.38.0/surfaces/frontend/tree/.claude/router.md +14 -0
  83. package/releases/0.38.0/surfaces/frontend/tree/CLAUDE.md +5 -0
  84. package/releases/0.38.0/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
  85. package/releases/0.38.0/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
  86. package/releases/0.38.0/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
  87. package/releases/0.38.0/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
  88. package/releases/0.38.0/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
  89. package/releases/0.38.0/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
  90. package/releases/0.38.0/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
  91. package/releases/0.38.0/surfaces/integrations/tree/.claude/graph.md +10 -0
  92. package/releases/0.38.0/surfaces/integrations/tree/.claude/patterns.md +38 -0
  93. package/releases/0.38.0/surfaces/integrations/tree/.claude/pipeline.md +16 -0
  94. package/releases/0.38.0/surfaces/integrations/tree/.claude/retrieval.md +16 -0
  95. package/releases/0.38.0/surfaces/integrations/tree/.claude/router.md +6 -0
  96. package/releases/0.38.0/surfaces/integrations/tree/CLAUDE.md +17 -0
  97. package/releases/0.38.0/surfaces/money/tree/.claude/agents/architect.md +12 -0
  98. package/releases/0.38.0/surfaces/money/tree/.claude/agents/dba.md +14 -0
  99. package/releases/0.38.0/surfaces/money/tree/.claude/agents/implementer.md +11 -0
  100. package/releases/0.38.0/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
  101. package/releases/0.38.0/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
  102. package/releases/0.38.0/surfaces/money/tree/.claude/agents/secops.md +5 -0
  103. package/releases/0.38.0/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
  104. package/releases/0.38.0/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
  105. package/releases/0.38.0/surfaces/money/tree/.claude/graph.md +2 -0
  106. package/releases/0.38.0/surfaces/money/tree/.claude/patterns.md +49 -0
  107. package/releases/0.38.0/surfaces/money/tree/.claude/pipeline.md +2 -0
  108. package/releases/0.38.0/surfaces/money/tree/.claude/retrieval.md +2 -0
  109. package/releases/0.38.0/surfaces/money/tree/CLAUDE.md +11 -0
  110. package/releases/0.38.0/surfaces/pii/tree/.claude/agents/dba.md +2 -0
  111. package/releases/0.38.0/surfaces/pii/tree/.claude/agents/devops.md +8 -0
  112. package/releases/0.38.0/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
  113. package/releases/0.38.0/surfaces/pii/tree/.claude/agents/secops.md +2 -0
  114. package/releases/0.38.0/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
  115. package/releases/0.38.0/surfaces/pii/tree/CLAUDE.md +5 -0
  116. package/releases/0.38.0/surfaces/prisma/tree/.claude/agents/architect.md +2 -0
  117. package/releases/0.38.0/surfaces/prisma/tree/.claude/agents/dba.md +39 -0
  118. package/releases/0.38.0/surfaces/prisma/tree/.claude/agents/devops.md +11 -0
  119. package/releases/0.38.0/surfaces/prisma/tree/.claude/agents/implementer.md +2 -0
  120. package/releases/0.38.0/surfaces/prisma/tree/.claude/agents/integration-tester.md +2 -0
  121. package/releases/0.38.0/surfaces/prisma/tree/.claude/agents/reviewer.md +2 -0
  122. package/releases/0.38.0/surfaces/prisma/tree/.claude/patterns.md +15 -0
  123. package/releases/0.38.0/surfaces/prisma/tree/CLAUDE.md +5 -0
  124. package/releases/0.39.0/core/GAPS.md +125 -0
  125. package/releases/0.39.0/core/answered.json +32 -0
  126. package/releases/0.39.0/core/defaults/tree/.claude/agents/architect.md +1 -0
  127. package/releases/0.39.0/core/defaults/tree/.claude/agents/dba.md +3 -0
  128. package/releases/0.39.0/core/defaults/tree/.claude/agents/devops.md +1 -0
  129. package/releases/0.39.0/core/defaults/tree/.claude/agents/implementer.md +1 -0
  130. package/releases/0.39.0/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
  131. package/releases/0.39.0/core/defaults/tree/.claude/agents/qa.md +2 -0
  132. package/releases/0.39.0/core/defaults/tree/.claude/agents/reviewer.md +3 -0
  133. package/releases/0.39.0/core/defaults/tree/.claude/agents/secops.md +3 -0
  134. package/releases/0.39.0/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
  135. package/releases/0.39.0/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
  136. package/releases/0.39.0/core/tree/.claude/agents/architect.md +127 -0
  137. package/releases/0.39.0/core/tree/.claude/agents/dba.md +110 -0
  138. package/releases/0.39.0/core/tree/.claude/agents/devops.md +114 -0
  139. package/releases/0.39.0/core/tree/.claude/agents/implementer.md +156 -0
  140. package/releases/0.39.0/core/tree/.claude/agents/integration-tester.md +168 -0
  141. package/releases/0.39.0/core/tree/.claude/agents/planner.md +132 -0
  142. package/releases/0.39.0/core/tree/.claude/agents/qa.md +152 -0
  143. package/releases/0.39.0/core/tree/.claude/agents/reviewer.md +183 -0
  144. package/releases/0.39.0/core/tree/.claude/agents/secops.md +121 -0
  145. package/releases/0.39.0/core/tree/.claude/agents/solidity-auditor.md +126 -0
  146. package/releases/0.39.0/core/tree/.claude/agents/solidity-dev.md +123 -0
  147. package/releases/0.39.0/core/tree/.claude/agents-overview.md +64 -0
  148. package/releases/0.39.0/core/tree/.claude/frontend.md +10 -0
  149. package/releases/0.39.0/core/tree/.claude/graph.md +75 -0
  150. package/releases/0.39.0/core/tree/.claude/patterns.md +213 -0
  151. package/releases/0.39.0/core/tree/.claude/pills/README.md +147 -0
  152. package/releases/0.39.0/core/tree/.claude/pipeline.md +101 -0
  153. package/releases/0.39.0/core/tree/.claude/retrieval.md +103 -0
  154. package/releases/0.39.0/core/tree/.claude/router.md +198 -0
  155. package/releases/0.39.0/core/tree/.claude/templates/integration.md +45 -0
  156. package/releases/0.39.0/core/tree/CLAUDE.md +163 -0
  157. package/releases/0.39.0/core/tree/scripts/cost-watch.mjs +18 -0
  158. package/releases/0.39.0/core/tree/scripts/edit-guard.mjs +24 -0
  159. package/releases/0.39.0/core/tree/scripts/harness-check.mjs +71 -0
  160. package/releases/0.39.0/core/tree/scripts/loop-gate.mjs +19 -0
  161. package/releases/0.39.0/core/vocabulary.json +13 -0
  162. package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
  163. package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
  164. package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
  165. package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
  166. package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
  167. package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
  168. package/releases/0.39.0/surfaces/blockchain/tree/.claude/graph.md +11 -0
  169. package/releases/0.39.0/surfaces/blockchain/tree/.claude/router.md +6 -0
  170. package/releases/0.39.0/surfaces/blockchain/tree/CLAUDE.md +12 -0
  171. package/releases/0.39.0/surfaces/db/tree/.claude/agents/architect.md +5 -0
  172. package/releases/0.39.0/surfaces/db/tree/.claude/agents/dba.md +50 -0
  173. package/releases/0.39.0/surfaces/db/tree/.claude/agents/devops.md +5 -0
  174. package/releases/0.39.0/surfaces/db/tree/.claude/agents/implementer.md +2 -0
  175. package/releases/0.39.0/surfaces/db/tree/.claude/agents/integration-tester.md +10 -0
  176. package/releases/0.39.0/surfaces/db/tree/.claude/agents/planner.md +2 -0
  177. package/releases/0.39.0/surfaces/db/tree/.claude/agents/reviewer.md +22 -0
  178. package/releases/0.39.0/surfaces/db/tree/.claude/agents/secops.md +2 -0
  179. package/releases/0.39.0/surfaces/db/tree/.claude/agents-overview.md +5 -0
  180. package/releases/0.39.0/surfaces/db/tree/.claude/graph.md +8 -0
  181. package/releases/0.39.0/surfaces/db/tree/.claude/patterns.md +19 -0
  182. package/releases/0.39.0/surfaces/db/tree/.claude/pipeline.md +13 -0
  183. package/releases/0.39.0/surfaces/db/tree/.claude/retrieval.md +5 -0
  184. package/releases/0.39.0/surfaces/db/tree/.claude/router.md +4 -0
  185. package/releases/0.39.0/surfaces/db/tree/CLAUDE.md +17 -0
  186. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
  187. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
  188. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/devops.md +32 -0
  189. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
  190. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
  191. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
  192. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
  193. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
  194. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
  195. package/releases/0.39.0/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
  196. package/releases/0.39.0/surfaces/edge-cf/tree/CLAUDE.md +27 -0
  197. package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
  198. package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
  199. package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
  200. package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
  201. package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/reviewer.md +56 -0
  202. package/releases/0.39.0/surfaces/frontend/tree/.claude/patterns.md +8 -0
  203. package/releases/0.39.0/surfaces/frontend/tree/.claude/retrieval.md +2 -0
  204. package/releases/0.39.0/surfaces/frontend/tree/.claude/router.md +14 -0
  205. package/releases/0.39.0/surfaces/frontend/tree/CLAUDE.md +5 -0
  206. package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
  207. package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
  208. package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
  209. package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
  210. package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
  211. package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
  212. package/releases/0.39.0/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
  213. package/releases/0.39.0/surfaces/integrations/tree/.claude/graph.md +10 -0
  214. package/releases/0.39.0/surfaces/integrations/tree/.claude/patterns.md +38 -0
  215. package/releases/0.39.0/surfaces/integrations/tree/.claude/pipeline.md +16 -0
  216. package/releases/0.39.0/surfaces/integrations/tree/.claude/retrieval.md +16 -0
  217. package/releases/0.39.0/surfaces/integrations/tree/.claude/router.md +6 -0
  218. package/releases/0.39.0/surfaces/integrations/tree/CLAUDE.md +17 -0
  219. package/releases/0.39.0/surfaces/money/tree/.claude/agents/architect.md +12 -0
  220. package/releases/0.39.0/surfaces/money/tree/.claude/agents/dba.md +14 -0
  221. package/releases/0.39.0/surfaces/money/tree/.claude/agents/implementer.md +11 -0
  222. package/releases/0.39.0/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
  223. package/releases/0.39.0/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
  224. package/releases/0.39.0/surfaces/money/tree/.claude/agents/secops.md +5 -0
  225. package/releases/0.39.0/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
  226. package/releases/0.39.0/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
  227. package/releases/0.39.0/surfaces/money/tree/.claude/graph.md +2 -0
  228. package/releases/0.39.0/surfaces/money/tree/.claude/patterns.md +49 -0
  229. package/releases/0.39.0/surfaces/money/tree/.claude/pipeline.md +2 -0
  230. package/releases/0.39.0/surfaces/money/tree/.claude/retrieval.md +2 -0
  231. package/releases/0.39.0/surfaces/money/tree/CLAUDE.md +11 -0
  232. package/releases/0.39.0/surfaces/pii/tree/.claude/agents/dba.md +2 -0
  233. package/releases/0.39.0/surfaces/pii/tree/.claude/agents/devops.md +8 -0
  234. package/releases/0.39.0/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
  235. package/releases/0.39.0/surfaces/pii/tree/.claude/agents/secops.md +2 -0
  236. package/releases/0.39.0/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
  237. package/releases/0.39.0/surfaces/pii/tree/CLAUDE.md +5 -0
  238. package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/architect.md +2 -0
  239. package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/dba.md +39 -0
  240. package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/devops.md +11 -0
  241. package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/implementer.md +2 -0
  242. package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/integration-tester.md +2 -0
  243. package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/reviewer.md +2 -0
  244. package/releases/0.39.0/surfaces/prisma/tree/.claude/patterns.md +15 -0
  245. package/releases/0.39.0/surfaces/prisma/tree/CLAUDE.md +5 -0
  246. package/src/commands/compose.mjs +7 -3
  247. package/src/commands/init.mjs +1 -1
  248. package/src/commands/learn.mjs +226 -71
  249. package/src/commands/pills.mjs +32 -9
  250. package/src/commands/stats.mjs +4 -4
  251. package/src/deep.mjs +26 -4
  252. package/src/gate.mjs +59 -1
  253. package/src/guard.mjs +188 -0
  254. package/src/lessons.mjs +55 -0
  255. package/src/wiring.mjs +5 -2
package/src/gate.mjs CHANGED
@@ -54,12 +54,14 @@
54
54
  * gate that could block work on its own crash would be worse than the loops it exists to stop.
55
55
  */
56
56
 
57
+ import { spawnSync } from 'node:child_process';
57
58
  import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
58
59
  import { dirname, join } from 'node:path';
59
60
  import { fileURLToPath } from 'node:url';
60
61
  import { TERMINALS, declaredTokens, parseGraph } from './graph.mjs';
61
62
  import { gateDir, slugFor } from './paths.mjs';
62
63
  import { declaredIssues, isLoopBack, saidToAgent } from './transcripts.mjs';
64
+ import { lessonIndex } from './lessons.mjs';
63
65
 
64
66
  /** The package this runs from: its releases say whether a pinned version ships the gate at all. */
65
67
  const PACKAGE = dirname(dirname(fileURLToPath(import.meta.url)));
@@ -431,7 +433,18 @@ export function replay(entries, loops, forward = new Map()) {
431
433
  }
432
434
  }
433
435
  });
434
- return { effect: (to) => effect(to, entries.length), rounds: made };
436
+ // What is open when the replay ends: each loop with its rounds, the rounds the owner's replies gave it and the
437
+ // issues it counted by, and each loop-back no fix has acted on yet — what a compaction takes from the orchestrator.
438
+ const open = [...streak.entries()]
439
+ .filter(([key]) => key.split('|').length === 2)
440
+ .map(([key, s]) => {
441
+ const [source, token] = key.split('|');
442
+ const cap = Math.max(0, ...(loops.get(source)?.get(token)?.values() ?? []));
443
+ const issues = [...streak.keys()].filter((k) => k.startsWith(`${key}|`)).map((k) => k.slice(key.length + 1));
444
+ return { source, token, rounds: s.n, cap, given: grace.get(key) ?? 0, issues };
445
+ });
446
+ const waiting = [...pending.entries()].flatMap(([source, batch]) => batch.filter((v) => isLoopBack(v.verdict)).map((v) => ({ source, verdict: v.verdict, issues: v.issues ?? [] })));
447
+ return { effect: (to) => effect(to, entries.length), rounds: made, open, waiting };
435
448
  }
436
449
 
437
450
  /**
@@ -659,6 +672,40 @@ function onPre(input, project, path, at) {
659
672
  return confirmation(worst);
660
673
  }
661
674
 
675
+ /**
676
+ * What the gate hands the orchestrator after its conversation was compacted: the loops still open and the
677
+ * loop-backs waiting on a fix, the latest dispatches, where the checkout stands, and the two documents to read
678
+ * again. The graph and the router are read once, at a session's start, and a compaction drops them with every
679
+ * report; the router told the orchestrator to write "round 2 of max 2" in a dispatch so "you after a
680
+ * compaction" could see it, and after a compaction it sees only a summary.
681
+ *
682
+ * @param {object} project - `loadProject`'s.
683
+ * @param {string} path - The session's ledger.
684
+ * @param {string} root - The project.
685
+ * @returns {object}
686
+ */
687
+ function afterCompaction(project, path, root) {
688
+ const entries = readLedger(path);
689
+ const { open, waiting } = replay(entries, project.loops, project.forward);
690
+ const lines = ['The conversation was compacted. What the NINA loop gate kept of this session:'];
691
+ for (const l of open) {
692
+ lines.push(
693
+ `- open loop: ${l.source} ${l.token} — ${l.rounds} round(s), capped at ${l.cap}${l.given ? ` and ${l.given} more from the owner's replies` : ''}` +
694
+ (l.issues.length ? `, issues ${l.issues.join(', ')}` : ''),
695
+ );
696
+ }
697
+ for (const w of waiting) lines.push(`- waiting on a fix: ${w.source} ${w.verdict}${w.issues.length ? `, issues ${w.issues.join(', ')}` : ''}`);
698
+ if (open.length === 0 && waiting.length === 0) lines.push('- no loop is open');
699
+ const dispatched = entries.filter((e) => e.k === 'dispatch' && e.role).slice(-4);
700
+ if (dispatched.length) lines.push(`- the latest dispatches: ${dispatched.map((e) => e.role).join(', ')}, the newest at ${String(dispatched.at(-1).at ?? '').slice(11, 16)} UTC`);
701
+ const git = (...args) => spawnSync('git', ['-C', root, ...args], { encoding: 'utf8', timeout: 2000 }).stdout?.trim() ?? '';
702
+ const branch = git('rev-parse', '--abbrev-ref', 'HEAD');
703
+ const last = git('log', '-1', '--format=%h %s');
704
+ if (branch) lines.push(`- the checkout: branch ${branch}${last ? `, last commit ${last.slice(0, 100)}` : ''}`);
705
+ lines.push('Before the next dispatch, read .claude/graph.md and .claude/router.md again: they were read at the start of the session, and are no longer in your context.');
706
+ return { hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: lines.join('\n') } };
707
+ }
708
+
662
709
  /** Drops a project's ledgers nobody has written to in a month, and error lines older than a week. */
663
710
  function prune(root, now) {
664
711
  const dir = projectGateDir(root);
@@ -718,6 +765,17 @@ export function handle(input, { root, now = new Date(), pkg = PACKAGE }) {
718
765
  return null;
719
766
  case 'SubagentStop':
720
767
  return onStop(input, project, path, at);
768
+ case 'SessionStart':
769
+ return input.source === 'compact' ? afterCompaction(project, path, root) : null;
770
+ case 'SubagentStart': {
771
+ // Not the loop's business, but the one hook every stage passes through as it begins: its lessons. Claude
772
+ // Code reads `additionalContext` from this event's `hookSpecificOutput` into the subagent's context as it
773
+ // starts — its hook schema and handler say so in 2.1.283, and the handler in 2.1.158 — though the help text
774
+ // it prints for a malformed hook output does not list the event.
775
+ const role = input.agent_type;
776
+ const text = role && project.graph.stages.has(role) ? lessonIndex(root, role) : null;
777
+ return text ? { hookSpecificOutput: { hookEventName: 'SubagentStart', additionalContext: text } } : null;
778
+ }
721
779
  case 'PostToolUse':
722
780
  return onPost(input, project, path, at);
723
781
  case 'PreToolUse':
package/src/guard.mjs CHANGED
@@ -32,6 +32,190 @@ const PACKAGE = dirname(dirname(fileURLToPath(import.meta.url)));
32
32
  /** The tools that change a file, and where each names it. */
33
33
  const EDITS = { Edit: 'file_path', Write: 'file_path', MultiEdit: 'file_path', NotebookEdit: 'notebook_path' };
34
34
 
35
+ /** The git subcommands that move the checkout or write its history — Hard Rule #18's. */
36
+ const MOVES = new Set(['stash', 'checkout', 'switch', 'reset', 'restore', 'clean', 'commit', 'merge', 'rebase', 'cherry-pick', 'revert', 'am', 'apply', 'pull', 'push']);
37
+
38
+ /** Words before the command word that leave it the command: `env X=1 git …`, `command git …`, `{ git …; }`. */
39
+ const RUNNERS = new Set(['env', 'command', 'exec', 'time', 'nohup', 'nice', '{', '}', '!']);
40
+
41
+ /** A `-C` or a `cd` to one of these is still the tree the stage was dispatched into. */
42
+ const HERE = new Set(['.', './']);
43
+
44
+ /** Where a heredoc's delimiter word ends. */
45
+ const DELIMITER_ENDS = new Set([' ', '\t', '\r', '\n', ';', '&', '|', '(', ')', '`', '<', '>']);
46
+
47
+ /** The characters that can end a run of plain word characters. */
48
+ const SPECIAL = new Set(["'", '"', '\\', '#', '\n', '<', '&', ';', '|', '(', ')', '`', ' ', '\t', '\r']);
49
+
50
+ /**
51
+ * A shell command as the shell reads it: its simple commands, in order, each as its words with the quotes removed.
52
+ * `&&`, `||`, `;`, `|`, `&`, a newline, a parenthesis and a backquote end one; a quoted string is part of a word — `"git" stash`
53
+ * is git — and never a separator or a command of its own, across lines too; a comment and a heredoc's body are not
54
+ * read. One pass, no pattern: the command is a model's, and a pattern that backtracks on it is one a stage could
55
+ * stall the guard with.
56
+ *
57
+ * @param {string} command
58
+ * @returns {string[][]}
59
+ */
60
+ export function simpleCommands(command) {
61
+ const text = String(command);
62
+ const commands = [[]];
63
+ const heredocs = [];
64
+ let word = null;
65
+ const end = () => {
66
+ if (word !== null) commands.at(-1).push(word);
67
+ word = null;
68
+ };
69
+ const next = () => {
70
+ end();
71
+ if (commands.at(-1).length) commands.push([]);
72
+ };
73
+ let i = 0;
74
+ while (i < text.length) {
75
+ const c = text[i];
76
+ if (c === "'") {
77
+ const close = text.indexOf("'", i + 1);
78
+ const stop = close === -1 ? text.length : close;
79
+ word = (word ?? '') + text.slice(i + 1, stop);
80
+ i = stop + 1;
81
+ } else if (c === '"') {
82
+ const parts = [];
83
+ i += 1;
84
+ let from = i;
85
+ while (i < text.length && text[i] !== '"') {
86
+ if (text[i] === '\\' && i + 1 < text.length) {
87
+ parts.push(text.slice(from, i));
88
+ from = i + 1;
89
+ i += 2;
90
+ } else i += 1;
91
+ }
92
+ parts.push(text.slice(from, i));
93
+ word = (word ?? '') + parts.join('');
94
+ i += 1;
95
+ } else if (c === '\\') {
96
+ if (text[i + 1] !== '\n') word = (word ?? '') + (text[i + 1] ?? '');
97
+ i += 2;
98
+ } else if (c === '#' && word === null) {
99
+ const line = text.indexOf('\n', i);
100
+ i = line === -1 ? text.length : line;
101
+ } else if (c === '\n') {
102
+ next();
103
+ i += 1;
104
+ for (const delimiter of heredocs.splice(0)) {
105
+ while (i < text.length) {
106
+ const line = text.indexOf('\n', i);
107
+ const stop = line === -1 ? text.length : line;
108
+ const body = text.slice(i, stop);
109
+ i = stop + 1;
110
+ if (body.trim() === delimiter) break;
111
+ }
112
+ }
113
+ } else if (c === '<' && text.startsWith('<<<', i)) {
114
+ word = (word ?? '') + '<<<';
115
+ i += 3;
116
+ } else if (c === '<' && text[i + 1] === '<') {
117
+ end();
118
+ i += text[i + 2] === '-' ? 3 : 2;
119
+ while (text[i] === ' ' || text[i] === '\t') i += 1;
120
+ const from = i;
121
+ while (i < text.length && !DELIMITER_ENDS.has(text[i])) i += 1;
122
+ const delimiter = text.slice(from, i).replaceAll("'", '').replaceAll('"', '').replaceAll('\\', '');
123
+ if (delimiter) heredocs.push(delimiter);
124
+ } else if (c === '&' && (text[i + 1] === '>' || word?.endsWith('>') || word?.endsWith('<'))) {
125
+ word = (word ?? '') + c;
126
+ i += 1;
127
+ } else if (c === ';' || c === '&' || c === '|' || c === '(' || c === ')' || c === '`') {
128
+ next();
129
+ i += (c === '&' || c === '|') && text[i + 1] === c ? 2 : 1;
130
+ } else if (c === ' ' || c === '\t' || c === '\r') {
131
+ end();
132
+ i += 1;
133
+ } else {
134
+ const from = i;
135
+ i += 1;
136
+ while (i < text.length && !SPECIAL.has(text[i])) i += 1;
137
+ word = (word ?? '') + text.slice(from, i);
138
+ }
139
+ }
140
+ end();
141
+ return commands.filter((words) => words.length);
142
+ }
143
+
144
+ /**
145
+ * The git subcommand in a shell command that would move the checkout the command runs in, or null. Read command
146
+ * by command, in order, as the shell runs it: a `cd` exempts only what comes after it — `git stash && cd /tmp`
147
+ * stashed the tree all the same, and a test of the whole string for a `cd` let it through — and `-C .` is not
148
+ * another directory. A git command is one whose command word is `git`, not a phrase in a quoted string or a
149
+ * heredoc's body; its subcommand is the word after its global options, so `merge-base` is not `merge`; and a
150
+ * stash's `list` or `show`, and an `apply` that only checks, read.
151
+ *
152
+ * @param {string} command - A Bash tool call's command.
153
+ * @returns {string|null}
154
+ */
155
+ export function checkoutMove(command) {
156
+ let moved = false;
157
+ for (const words of simpleCommands(command)) {
158
+ while (words.length && (/^[A-Za-z_][A-Za-z0-9_]*=/.test(words[0]) || RUNNERS.has(words[0]))) words.shift();
159
+ if (words[0] === 'cd' || words[0] === 'pushd') {
160
+ moved ||= !HERE.has(words[1] ?? '');
161
+ continue;
162
+ }
163
+ if (words[0] !== 'git') continue;
164
+ let i = 1;
165
+ let elsewhere = false;
166
+ while (words[i]?.startsWith('-')) {
167
+ if (words[i] === '-C') {
168
+ elsewhere ||= !HERE.has(words[i + 1] ?? '.');
169
+ i += 2;
170
+ } else if (words[i] === '-c') {
171
+ i += 2;
172
+ } else {
173
+ if (/^--(git-dir|work-tree)\b/.test(words[i])) elsewhere = true;
174
+ i += 1;
175
+ }
176
+ }
177
+ const sub = words[i];
178
+ if (!MOVES.has(sub) || moved || elsewhere) continue;
179
+ const rest = words.slice(i + 1);
180
+ if (sub === 'stash' && ['list', 'show'].includes(rest[0])) continue;
181
+ if (sub === 'apply' && rest.some((w) => ['--check', '--stat', '--numstat', '--summary'].includes(w)) && !rest.includes('--apply')) continue;
182
+ return sub;
183
+ }
184
+ return null;
185
+ }
186
+
187
+ /**
188
+ * A stage's shell command that would move the checkout it was dispatched into, refused. Only the orchestrator
189
+ * commits, and the work in flight lives in that tree, uncommitted: one reviewer, told not to edit, stashed it to
190
+ * compare with the baseline, and its pop failed on a conflict.
191
+ *
192
+ * @param {object} input - The hook's stdin, parsed.
193
+ * @param {{layers: string}} pinned - The pinned layers, whose hard rules say whether this one is the project's.
194
+ * @returns {object|null}
195
+ */
196
+ function handleShell(input, pinned) {
197
+ if (!input.agent_id) return null;
198
+ const moves = checkoutMove(input.tool_input?.command ?? '');
199
+ if (!moves) return null;
200
+ let rules = '';
201
+ try {
202
+ rules = readFileSync(join(pinned.layers, 'core', 'tree', 'CLAUDE.md'), 'utf8');
203
+ } catch {
204
+ return null;
205
+ }
206
+ if (!rules.includes('Only the orchestrator commits')) return null;
207
+ return {
208
+ hookSpecificOutput: {
209
+ hookEventName: 'PreToolUse',
210
+ permissionDecision: 'deny',
211
+ permissionDecisionReason:
212
+ `NINA: \`git ${moves}\` would move the checkout the pipeline's work in flight lives in — Hard Rule #18: only the orchestrator ` +
213
+ 'commits, and no stage moves the checkout. Read history with git diff, log, show, status or blame, and build or test another ' +
214
+ 'revision in a `git worktree` you remove afterwards.',
215
+ },
216
+ };
217
+ }
218
+
35
219
  /** How much of a file is read to find it: the head, not the whole of a large file on every edit. */
36
220
  const HEAD_BYTES = 16 * 1024;
37
221
 
@@ -83,6 +267,10 @@ function head(path) {
83
267
  export async function handleEdit(input, { root, pkg = PACKAGE }) {
84
268
  try {
85
269
  if (input?.hook_event_name !== 'PreToolUse') return null;
270
+ if (input.tool_name === 'Bash') {
271
+ const pinnedShell = input.agent_id ? pinnedLayers(root, pkg) : null;
272
+ return pinnedShell ? handleShell(input, pinnedShell) : null;
273
+ }
86
274
  const key = EDITS[input.tool_name];
87
275
  const path = key ? input.tool_input?.[key] : null;
88
276
  const pinned = typeof path === 'string' ? pinnedLayers(root, pkg) : null;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The lessons a stage is handed as it starts: the list of its active pills, each with the trigger that says
3
+ * when it applies, given to the subagent by the `SubagentStart` hook.
4
+ *
5
+ * Every spec told its stage to read its pills, and a stage found them by opening files: every pill in its own
6
+ * directory, and every shared one to see whether its `applies_to` named it. So a reviewer read one in only
7
+ * seven of fifteen runs while twelve applied to it, and a stage no pill named opened them in two runs of three.
8
+ * Handed the list, a stage opens the ones whose trigger matches its task, and nothing else.
9
+ */
10
+
11
+ import { readFileSync, readdirSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import { frontmatter, list } from './commands/pills.mjs';
14
+
15
+ /** How much of a trigger goes in the list: enough to say when, not the lesson. */
16
+ const TRIGGER_CHARS = 160;
17
+
18
+ /**
19
+ * A stage's lessons as the text handed to it, or null when it has none.
20
+ *
21
+ * @param {string} root - The project directory.
22
+ * @param {string} role - The stage.
23
+ * @returns {string|null}
24
+ */
25
+ export function lessonIndex(root, role) {
26
+ const found = [];
27
+ for (const sub of [role, 'shared']) {
28
+ let files = [];
29
+ try {
30
+ files = readdirSync(join(root, '.claude', 'pills', sub)).filter((f) => f.endsWith('.md')).sort();
31
+ } catch {
32
+ continue;
33
+ }
34
+ for (const file of files) {
35
+ let fields = null;
36
+ try {
37
+ fields = frontmatter(readFileSync(join(root, '.claude', 'pills', sub, file), 'utf8'));
38
+ } catch {
39
+ continue;
40
+ }
41
+ if (!fields || fields.status === 'retired') continue;
42
+ const applies = list(fields.applies_to);
43
+ // A shared pill is this stage's when it names it; one in the stage's own directory, unless it names others.
44
+ if (sub === 'shared' ? !applies.includes(role) : applies.length > 0 && !applies.includes(role)) continue;
45
+ const trigger = String(fields.trigger ?? '').replace(/\s+/g, ' ').trim();
46
+ const when = trigger ? `when ${trigger.length > TRIGGER_CHARS ? `${trigger.slice(0, TRIGGER_CHARS - 1)}…` : trigger}` : 'on every task';
47
+ found.push(`- \`.claude/pills/${sub}/${file}\` — ${when}`);
48
+ }
49
+ }
50
+ if (found.length === 0) return null;
51
+ return [
52
+ `Your lessons in this project, ${found.length}: before acting, open each one whose trigger matches this task, and only those.`,
53
+ ...found,
54
+ ].join('\n');
55
+ }
package/src/wiring.mjs CHANGED
@@ -109,7 +109,7 @@ const previousCommands = (h) => [command(h.script, h.mode), ...EARLIER_CANNOT_ST
109
109
  * The harness check has two: `Stop` tells the person what a turn left behind, `UserPromptSubmit` puts
110
110
  * the same findings in the model's context before it answers — the only one of the two it reads. The
111
111
  * loop gate has four, one per fact it keeps: a verdict, a dispatch, the owner speaking, and the
112
- * decision itself.
112
+ * decision itself; and a fifth, as each stage starts, that hands the stage its lessons (`src/lessons.mjs`).
113
113
  */
114
114
  export const HOOKS = [
115
115
  {
@@ -132,8 +132,11 @@ export const HOOKS = [
132
132
  },
133
133
  { event: 'PostToolUse', matcher: 'Agent|Task|SendMessage|AskUserQuestion|SubagentHandback', script: GATE, timeout: 10, why: 'the gate never learns which rounds went out, or that the owner answered' },
134
134
  { event: 'SubagentStop', script: GATE, timeout: 10, why: 'the gate misses the verdict of a stage that wrote its report as its last message' },
135
+ { event: 'SubagentStart', script: GATE, timeout: 10, why: 'a stage is not handed its lessons, and opens every shared pill to find them, or none' },
136
+ { event: 'SessionStart', matcher: 'compact', script: GATE, timeout: 10, why: 'after a compaction the orchestrator has lost the graph, the router and its open loops, and nothing gives them back' },
135
137
  {
136
- event: 'PreToolUse', matcher: 'Edit|Write|MultiEdit|NotebookEdit', script: GUARD, timeout: 10, why: 'a hand edit to a composed file is found only after the turn, as drift, and the next compose overwrites it',
138
+ event: 'PreToolUse', matcher: 'Edit|Write|MultiEdit|NotebookEdit|Bash', script: GUARD, timeout: 10,
139
+ why: "a hand edit to a composed file is found only after the turn, as drift, and a stage's git stash or checkout takes the work in flight",
137
140
  crash: (cannot) => ({ systemMessage: `NINA: the edit guard could not start, so composed files can be edited in place — ${cannot}` }),
138
141
  },
139
142
  // Every tool, since what it watches is a subagent's every turn; a call outside a subagent returns at once.