@toolu/opencode 6.8.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 (331) hide show
  1. package/generated/GENERATED-NOTES.md +16 -0
  2. package/generated/agents/toolu--architect.md +52 -0
  3. package/generated/agents/toolu--deep-explore.md +65 -0
  4. package/generated/agents/toolu--implementer.md +50 -0
  5. package/generated/agents/toolu--quick-task.md +54 -0
  6. package/generated/agents/toolu--research-agent.md +101 -0
  7. package/generated/commands/toolu--commit.md +8 -0
  8. package/generated/commands/toolu--review-and-commit.md +8 -0
  9. package/generated/opencode.toolu.json +116 -0
  10. package/generated/skills/toolu--brainstorm/SKILL.md +57 -0
  11. package/generated/skills/toolu--brainstorm/references/design-questions.md +36 -0
  12. package/generated/skills/toolu--commit--skill/SKILL.md +11 -0
  13. package/generated/skills/toolu--debug/SKILL.md +54 -0
  14. package/generated/skills/toolu--deep-research/SKILL.md +51 -0
  15. package/generated/skills/toolu--execution/SKILL.md +77 -0
  16. package/generated/skills/toolu--orchestrator/SKILL.md +145 -0
  17. package/generated/skills/toolu--orchestrator/references/delegation-cost.md +104 -0
  18. package/generated/skills/toolu--orchestrator/references/model-routing.md +112 -0
  19. package/generated/skills/toolu--plan/SKILL.md +56 -0
  20. package/generated/skills/toolu--plan/references/ledger.md +18 -0
  21. package/generated/skills/toolu--plan-review/SKILL.md +48 -0
  22. package/generated/skills/toolu--review-and-commit--skill/SKILL.md +10 -0
  23. package/generated/skills/toolu--setup/SKILL.md +24 -0
  24. package/generated/skills/toolu--setup/scripts/setup.sh +206 -0
  25. package/generated/skills/toolu--spec/SKILL.md +67 -0
  26. package/generated/skills/toolu--spec-review/SKILL.md +50 -0
  27. package/generated/skills/toolu--test/SKILL.md +49 -0
  28. package/package.json +51 -0
  29. package/plugins/agent-browser/.claude-plugin/plugin.json +18 -0
  30. package/plugins/agent-browser/.codex-plugin/plugin.json +7 -0
  31. package/plugins/agent-browser/README.md +18 -0
  32. package/plugins/agent-browser/hooks/hooks.json +15 -0
  33. package/plugins/agent-browser/hooks/session-start.sh +42 -0
  34. package/plugins/agent-browser/skills/agent-browser/SKILL.md +77 -0
  35. package/plugins/agent-browser/skills/agent-browser/scripts/agent-browser.sh +80 -0
  36. package/plugins/ast-grep/.claude-plugin/plugin.json +18 -0
  37. package/plugins/ast-grep/.codex-plugin/plugin.json +7 -0
  38. package/plugins/ast-grep/README.md +21 -0
  39. package/plugins/ast-grep/hooks/hooks.json +15 -0
  40. package/plugins/ast-grep/hooks/post-tools.d/byte-savings.sh +67 -0
  41. package/plugins/ast-grep/hooks/pre-tools.d/search-nudge.sh +170 -0
  42. package/plugins/ast-grep/hooks/register.sh +68 -0
  43. package/plugins/ast-grep/scripts/byte-savings-report.sh +28 -0
  44. package/plugins/ast-grep/skills/ast-grep/SKILL.md +127 -0
  45. package/plugins/ast-grep/skills/ast-grep/references/ast-grep-advanced.md +44 -0
  46. package/plugins/ast-grep/skills/ast-grep/scripts/ast-grep.sh +103 -0
  47. package/plugins/context7/.claude-plugin/plugin.json +18 -0
  48. package/plugins/context7/.codex-plugin/plugin.json +7 -0
  49. package/plugins/context7/README.md +19 -0
  50. package/plugins/context7/hooks/hooks.json +15 -0
  51. package/plugins/context7/hooks/session-start.sh +42 -0
  52. package/plugins/context7/skills/context7/SKILL.md +64 -0
  53. package/plugins/context7/skills/context7/scripts/search.sh +151 -0
  54. package/plugins/exa-search/.claude-plugin/plugin.json +18 -0
  55. package/plugins/exa-search/.codex-plugin/plugin.json +7 -0
  56. package/plugins/exa-search/README.md +19 -0
  57. package/plugins/exa-search/hooks/hooks.json +15 -0
  58. package/plugins/exa-search/hooks/session-start.sh +34 -0
  59. package/plugins/exa-search/skills/exa-search/SKILL.md +91 -0
  60. package/plugins/exa-search/skills/exa-search/scripts/search.sh +221 -0
  61. package/plugins/jev/.claude-plugin/plugin.json +19 -0
  62. package/plugins/jev/.codex-plugin/plugin.json +7 -0
  63. package/plugins/jev/README.md +61 -0
  64. package/plugins/jev/hooks/hooks.json +25 -0
  65. package/plugins/jev/hooks/lib/common.sh +49 -0
  66. package/plugins/jev/hooks/session-start.sh +45 -0
  67. package/plugins/jev/hooks/user-prompt-submit.sh +41 -0
  68. package/plugins/jev/skills/jev/SKILL.md +81 -0
  69. package/plugins/jev/skills/jev/evals/README.md +98 -0
  70. package/plugins/jev/skills/jev/references/problem-solving.md +198 -0
  71. package/plugins/jev/skills/jev/scripts/jev.sh +405 -0
  72. package/plugins/jira/.claude-plugin/plugin.json +18 -0
  73. package/plugins/jira/.codex-plugin/plugin.json +7 -0
  74. package/plugins/jira/README.md +42 -0
  75. package/plugins/jira/hooks/hooks.json +15 -0
  76. package/plugins/jira/hooks/session-start.sh +34 -0
  77. package/plugins/jira/skills/jira/SKILL.md +123 -0
  78. package/plugins/jira/skills/jira/scripts/jira.sh +70 -0
  79. package/plugins/jira/skills/jira/scripts/lib/adf.sh +17 -0
  80. package/plugins/jira/skills/jira/scripts/lib/attachment.sh +94 -0
  81. package/plugins/jira/skills/jira/scripts/lib/board.sh +58 -0
  82. package/plugins/jira/skills/jira/scripts/lib/http.sh +184 -0
  83. package/plugins/jira/skills/jira/scripts/lib/issue.sh +159 -0
  84. package/plugins/jira/skills/jira/scripts/lib/paginate.sh +45 -0
  85. package/plugins/jira/skills/jira/scripts/lib/plan-parse.sh +70 -0
  86. package/plugins/jira/skills/jira/scripts/lib/plan-run.sh +115 -0
  87. package/plugins/jira/skills/jira/scripts/lib/plan-store.sh +168 -0
  88. package/plugins/jira/skills/jira/scripts/lib/plan.sh +108 -0
  89. package/plugins/jira/skills/jira/scripts/lib/project.sh +42 -0
  90. package/plugins/jira/skills/jira/scripts/lib/raw.sh +15 -0
  91. package/plugins/jira/skills/jira/scripts/lib/search.sh +41 -0
  92. package/plugins/jira/skills/jira/scripts/lib/sprint.sh +88 -0
  93. package/plugins/jira/skills/jira/scripts/lib/user.sh +45 -0
  94. package/plugins/jira/skills/jira/scripts/lib/worklog.sh +56 -0
  95. package/plugins/pr-babysit/.claude-plugin/plugin.json +25 -0
  96. package/plugins/pr-babysit/.codex-plugin/plugin.json +7 -0
  97. package/plugins/pr-babysit/README.md +38 -0
  98. package/plugins/pr-babysit/commands/babysit.md +13 -0
  99. package/plugins/pr-babysit/hooks/check-toolu.sh +20 -0
  100. package/plugins/pr-babysit/hooks/hooks.json +15 -0
  101. package/plugins/pr-babysit/scripts/babysit-tick.sh +133 -0
  102. package/plugins/pr-babysit/scripts/collect-pr.sh +224 -0
  103. package/plugins/pr-babysit/scripts/lib/common.sh +146 -0
  104. package/plugins/pr-babysit/scripts/lib/gh.sh +150 -0
  105. package/plugins/pr-babysit/scripts/lib/lock.sh +84 -0
  106. package/plugins/pr-babysit/scripts/lib/normalize.sh +98 -0
  107. package/plugins/pr-babysit/scripts/lib/state.sh +37 -0
  108. package/plugins/pr-babysit/scripts/parse-verdict.sh +171 -0
  109. package/plugins/pr-babysit/scripts/record.sh +69 -0
  110. package/plugins/pr-babysit/scripts/reduce-state.sh +245 -0
  111. package/plugins/pr-babysit/scripts/reply-thread.sh +90 -0
  112. package/plugins/pr-babysit/scripts/resolve-thread.sh +71 -0
  113. package/plugins/pr-babysit/skills/babysit/SKILL.md +31 -0
  114. package/plugins/pr-babysit/skills/babysit/references/helper.md +209 -0
  115. package/plugins/pr-babysit/workflows/babysit.md +722 -0
  116. package/plugins/python-quality/.claude-plugin/plugin.json +24 -0
  117. package/plugins/python-quality/.codex-plugin/plugin.json +6 -0
  118. package/plugins/python-quality/README.md +23 -0
  119. package/plugins/python-quality/hooks/check-toolu.sh +20 -0
  120. package/plugins/python-quality/hooks/concerns/00-preamble.sh +85 -0
  121. package/plugins/python-quality/hooks/concerns/10-size-file.sh +6 -0
  122. package/plugins/python-quality/hooks/concerns/20-tests.sh +37 -0
  123. package/plugins/python-quality/hooks/concerns/30-suppression.sh +33 -0
  124. package/plugins/python-quality/hooks/concerns/50-size-fn.sh +49 -0
  125. package/plugins/python-quality/hooks/concerns/70-no-mocks.sh +76 -0
  126. package/plugins/python-quality/hooks/concerns/90-docs.sh +52 -0
  127. package/plugins/python-quality/hooks/concerns/99-finalize.sh +36 -0
  128. package/plugins/python-quality/hooks/hooks.json +19 -0
  129. package/plugins/python-quality/hooks/register.sh +65 -0
  130. package/plugins/rust-quality/.claude-plugin/plugin.json +24 -0
  131. package/plugins/rust-quality/.codex-plugin/plugin.json +6 -0
  132. package/plugins/rust-quality/README.md +24 -0
  133. package/plugins/rust-quality/hooks/check-toolu.sh +20 -0
  134. package/plugins/rust-quality/hooks/concerns/00-preamble.sh +93 -0
  135. package/plugins/rust-quality/hooks/concerns/10-size-file.sh +10 -0
  136. package/plugins/rust-quality/hooks/concerns/20-tests.sh +84 -0
  137. package/plugins/rust-quality/hooks/concerns/30-suppression.sh +26 -0
  138. package/plugins/rust-quality/hooks/concerns/40-unsafe.sh +39 -0
  139. package/plugins/rust-quality/hooks/concerns/50-size-fn.sh +38 -0
  140. package/plugins/rust-quality/hooks/concerns/55-size-impl.sh +28 -0
  141. package/plugins/rust-quality/hooks/concerns/60-error-handling.sh +149 -0
  142. package/plugins/rust-quality/hooks/concerns/70-no-mocks.sh +139 -0
  143. package/plugins/rust-quality/hooks/concerns/90-docs.sh +32 -0
  144. package/plugins/rust-quality/hooks/concerns/99-finalize.sh +36 -0
  145. package/plugins/rust-quality/hooks/hooks.json +19 -0
  146. package/plugins/rust-quality/hooks/register.sh +65 -0
  147. package/plugins/statusline/.claude-plugin/plugin.json +19 -0
  148. package/plugins/statusline/.codex-plugin/plugin.json +7 -0
  149. package/plugins/statusline/README.md +108 -0
  150. package/plugins/statusline/commands/setup.md +30 -0
  151. package/plugins/statusline/hooks/hooks.json +15 -0
  152. package/plugins/statusline/hooks/session-start.sh +45 -0
  153. package/plugins/statusline/scripts/collect-status.sh +147 -0
  154. package/plugins/statusline/scripts/setup.sh +93 -0
  155. package/plugins/statusline/scripts/status.sh +55 -0
  156. package/plugins/statusline/skills/status/SKILL.md +13 -0
  157. package/plugins/statusline/statusline.sh +177 -0
  158. package/plugins/toolu/.claude-plugin/plugin.json +19 -0
  159. package/plugins/toolu/.codex-plugin/plugin.json +7 -0
  160. package/plugins/toolu/README.md +35 -0
  161. package/plugins/toolu/agents/.gitkeep +0 -0
  162. package/plugins/toolu/agents/architect.md +52 -0
  163. package/plugins/toolu/agents/deep-explore.md +65 -0
  164. package/plugins/toolu/agents/implementer.md +50 -0
  165. package/plugins/toolu/agents/quick-task.md +54 -0
  166. package/plugins/toolu/agents/research-agent.md +107 -0
  167. package/plugins/toolu/assets/agents/architect.toml +9 -0
  168. package/plugins/toolu/assets/agents/deep-explore.toml +9 -0
  169. package/plugins/toolu/assets/agents/implementer.toml +9 -0
  170. package/plugins/toolu/assets/agents/quick-task.toml +9 -0
  171. package/plugins/toolu/assets/agents/research-agent.toml +9 -0
  172. package/plugins/toolu/commands/.gitkeep +0 -0
  173. package/plugins/toolu/commands/commit.md +5 -0
  174. package/plugins/toolu/commands/review-and-commit.md +5 -0
  175. package/plugins/toolu/hooks/docs/gates.md +157 -0
  176. package/plugins/toolu/hooks/docs/model-routing.md +14 -0
  177. package/plugins/toolu/hooks/docs/post-compaction.md +3 -0
  178. package/plugins/toolu/hooks/docs/push-review.md +123 -0
  179. package/plugins/toolu/hooks/docs/session-start-python.md +3 -0
  180. package/plugins/toolu/hooks/docs/session-start-rust.md +4 -0
  181. package/plugins/toolu/hooks/docs/session-start-ts.md +3 -0
  182. package/plugins/toolu/hooks/docs/session-start.md +16 -0
  183. package/plugins/toolu/hooks/hooks.json +76 -0
  184. package/plugins/toolu/hooks/lib/config.sh +355 -0
  185. package/plugins/toolu/hooks/lib/detect.sh +929 -0
  186. package/plugins/toolu/hooks/lib/diff-sha.sh +32 -0
  187. package/plugins/toolu/hooks/lib/dispatch.sh +365 -0
  188. package/plugins/toolu/hooks/lib/docs-sync-config.sh +81 -0
  189. package/plugins/toolu/hooks/lib/edit-records.sh +157 -0
  190. package/plugins/toolu/hooks/lib/gate-file.sh +201 -0
  191. package/plugins/toolu/hooks/lib/gate-mode.sh +244 -0
  192. package/plugins/toolu/hooks/lib/host.sh +205 -0
  193. package/plugins/toolu/hooks/lib/permissions.sh +125 -0
  194. package/plugins/toolu/hooks/lib/plan-ledger-parse.sh +219 -0
  195. package/plugins/toolu/hooks/lib/plan-ledger-preflight.sh +137 -0
  196. package/plugins/toolu/hooks/lib/plan-ledger.sh +749 -0
  197. package/plugins/toolu/hooks/lib/push-waiver.sh +116 -0
  198. package/plugins/toolu/hooks/lib/quality-config.sh +184 -0
  199. package/plugins/toolu/hooks/lib/registry.sh +72 -0
  200. package/plugins/toolu/hooks/lib/state-sweeper.sh +194 -0
  201. package/plugins/toolu/hooks/lib/telemetry.sh +94 -0
  202. package/plugins/toolu/hooks/lib/verdict.sh +477 -0
  203. package/plugins/toolu/hooks/post-tools/mod.sh +42 -0
  204. package/plugins/toolu/hooks/post-tools/modules/gate-status.sh +140 -0
  205. package/plugins/toolu/hooks/post-tools/modules/push-waiver.sh +97 -0
  206. package/plugins/toolu/hooks/pre-compact.sh +18 -0
  207. package/plugins/toolu/hooks/pre-tools/agent-tier.sh +111 -0
  208. package/plugins/toolu/hooks/pre-tools/mod.sh +37 -0
  209. package/plugins/toolu/hooks/pre-tools/modules/bash-commands.sh +187 -0
  210. package/plugins/toolu/hooks/pre-tools/modules/code-edit-rules.sh +78 -0
  211. package/plugins/toolu/hooks/pre-tools/modules/commit-gate.sh +70 -0
  212. package/plugins/toolu/hooks/pre-tools/modules/docs-sync.sh +137 -0
  213. package/plugins/toolu/hooks/pre-tools/modules/mcp-blocker.sh +151 -0
  214. package/plugins/toolu/hooks/pre-tools/modules/plan-ledger.sh +201 -0
  215. package/plugins/toolu/hooks/pre-tools/modules/protected-files.sh +177 -0
  216. package/plugins/toolu/hooks/pre-tools/modules/push-review.sh +273 -0
  217. package/plugins/toolu/hooks/pre-tools/modules/quality-gate.sh +87 -0
  218. package/plugins/toolu/hooks/session-start.sh +379 -0
  219. package/plugins/toolu/hooks/user-prompt-submit.sh +197 -0
  220. package/plugins/toolu/scripts/context-budget.sh +111 -0
  221. package/plugins/toolu/scripts/debug-log.sh +98 -0
  222. package/plugins/toolu/scripts/debug-stack.sh +108 -0
  223. package/plugins/toolu/scripts/debug-testfail.sh +97 -0
  224. package/plugins/toolu/settings/.gitkeep +0 -0
  225. package/plugins/toolu/settings/README.md +127 -0
  226. package/plugins/toolu/settings/bash-allowlist.txt +12 -0
  227. package/plugins/toolu/settings/bash-denylist.txt +25 -0
  228. package/plugins/toolu/settings/code-edit-rules.json +67 -0
  229. package/plugins/toolu/settings/commit-prefixes.txt +12 -0
  230. package/plugins/toolu/settings/mcp-blocklist.txt +8 -0
  231. package/plugins/toolu/settings/permissions.fragment.json +36 -0
  232. package/plugins/toolu/settings/protected-files.txt +30 -0
  233. package/plugins/toolu/settings/rust-unsafe-exemptions.txt +5 -0
  234. package/plugins/toolu/settings/toolu.config.example.json +130 -0
  235. package/plugins/toolu/skills/.gitkeep +0 -0
  236. package/plugins/toolu/skills/brainstorm/SKILL.md +57 -0
  237. package/plugins/toolu/skills/brainstorm/references/design-questions.md +36 -0
  238. package/plugins/toolu/skills/commit/SKILL.md +11 -0
  239. package/plugins/toolu/skills/debug/SKILL.md +54 -0
  240. package/plugins/toolu/skills/debug/evals/README.md +17 -0
  241. package/plugins/toolu/skills/debug/evals/cases.json +24 -0
  242. package/plugins/toolu/skills/debug/evals/results.json +34 -0
  243. package/plugins/toolu/skills/deep-research/SKILL.md +51 -0
  244. package/plugins/toolu/skills/execution/SKILL.md +77 -0
  245. package/plugins/toolu/skills/orchestrator/SKILL.md +145 -0
  246. package/plugins/toolu/skills/orchestrator/references/delegation-cost.md +104 -0
  247. package/plugins/toolu/skills/orchestrator/references/model-routing.md +112 -0
  248. package/plugins/toolu/skills/plan/SKILL.md +56 -0
  249. package/plugins/toolu/skills/plan/references/ledger.md +18 -0
  250. package/plugins/toolu/skills/plan-review/SKILL.md +48 -0
  251. package/plugins/toolu/skills/review-and-commit/SKILL.md +10 -0
  252. package/plugins/toolu/skills/setup/SKILL.md +24 -0
  253. package/plugins/toolu/skills/setup/scripts/setup.sh +206 -0
  254. package/plugins/toolu/skills/spec/SKILL.md +67 -0
  255. package/plugins/toolu/skills/spec-review/SKILL.md +50 -0
  256. package/plugins/toolu/skills/test/SKILL.md +49 -0
  257. package/plugins/toolu/workflows/commit.md +21 -0
  258. package/plugins/toolu/workflows/host-mapping.md +22 -0
  259. package/plugins/toolu/workflows/review-and-commit.md +54 -0
  260. package/plugins/toolu/workflows/semantic-judgments.md +35 -0
  261. package/plugins/toolu-review/.claude-plugin/plugin.json +18 -0
  262. package/plugins/toolu-review/.codex-plugin/plugin.json +7 -0
  263. package/plugins/toolu-review/README.md +17 -0
  264. package/plugins/toolu-review/hooks/hooks.json +15 -0
  265. package/plugins/toolu-review/hooks/session-start.sh +34 -0
  266. package/plugins/toolu-review/skills/review/SKILL.md +90 -0
  267. package/plugins/toolu-review/skills/review/scripts/write-state.sh +189 -0
  268. package/plugins/ts-quality/.claude-plugin/plugin.json +24 -0
  269. package/plugins/ts-quality/.codex-plugin/plugin.json +6 -0
  270. package/plugins/ts-quality/README.md +24 -0
  271. package/plugins/ts-quality/hooks/check-toolu.sh +20 -0
  272. package/plugins/ts-quality/hooks/concerns/00-preamble.sh +123 -0
  273. package/plugins/ts-quality/hooks/concerns/10-imports.sh +33 -0
  274. package/plugins/ts-quality/hooks/concerns/15-type-as.sh +9 -0
  275. package/plugins/ts-quality/hooks/concerns/20-tests.sh +26 -0
  276. package/plugins/ts-quality/hooks/concerns/25-size-file.sh +40 -0
  277. package/plugins/ts-quality/hooks/concerns/30-size-fn.sh +53 -0
  278. package/plugins/ts-quality/hooks/concerns/35-react-hooks.sh +7 -0
  279. package/plugins/ts-quality/hooks/concerns/40-factory.sh +5 -0
  280. package/plugins/ts-quality/hooks/concerns/45-typeguard.sh +6 -0
  281. package/plugins/ts-quality/hooks/concerns/50-type-dup.sh +16 -0
  282. package/plugins/ts-quality/hooks/concerns/55-naming.sh +11 -0
  283. package/plugins/ts-quality/hooks/concerns/60-console.sh +6 -0
  284. package/plugins/ts-quality/hooks/concerns/65-suppression.sh +12 -0
  285. package/plugins/ts-quality/hooks/concerns/70-ui-confirm.sh +8 -0
  286. package/plugins/ts-quality/hooks/concerns/72-ui-radix.sh +12 -0
  287. package/plugins/ts-quality/hooks/concerns/74-react-props.sh +6 -0
  288. package/plugins/ts-quality/hooks/concerns/76-toast.sh +10 -0
  289. package/plugins/ts-quality/hooks/concerns/78-error-ast.sh +242 -0
  290. package/plugins/ts-quality/hooks/concerns/80-throw-literal.sh +23 -0
  291. package/plugins/ts-quality/hooks/concerns/85-no-mocks.sh +109 -0
  292. package/plugins/ts-quality/hooks/concerns/90-duplication.sh +30 -0
  293. package/plugins/ts-quality/hooks/concerns/92-docs.sh +36 -0
  294. package/plugins/ts-quality/hooks/concerns/94-handler.sh +15 -0
  295. package/plugins/ts-quality/hooks/concerns/99-finalize.sh +46 -0
  296. package/plugins/ts-quality/hooks/hooks.json +19 -0
  297. package/plugins/ts-quality/hooks/register.sh +65 -0
  298. package/src/adapter/__tests__/evaluate.test.ts +82 -0
  299. package/src/adapter/__tests__/permission-map.test.ts +91 -0
  300. package/src/adapter/evaluate.ts +54 -0
  301. package/src/adapter/permission-map.ts +177 -0
  302. package/src/bootstrap/__tests__/bootstrap.test.ts +148 -0
  303. package/src/bootstrap/entrypoint.ts +18 -0
  304. package/src/bootstrap/index.ts +5 -0
  305. package/src/bootstrap/readiness.ts +59 -0
  306. package/src/bootstrap/result.ts +21 -0
  307. package/src/bootstrap/runtime.ts +99 -0
  308. package/src/bootstrap/test-helpers.ts +25 -0
  309. package/src/host/__tests__/host.test.ts +37 -0
  310. package/src/host/detect.ts +46 -0
  311. package/src/host/index.ts +10 -0
  312. package/src/host/roots.ts +59 -0
  313. package/src/host/types.ts +14 -0
  314. package/src/inventory/__tests__/inventory.test.ts +69 -0
  315. package/src/inventory/index.ts +9 -0
  316. package/src/inventory/manifest.ts +46 -0
  317. package/src/inventory/scan.ts +66 -0
  318. package/src/inventory/selection.ts +92 -0
  319. package/src/inventory/types.ts +22 -0
  320. package/src/lifecycle/__tests__/lifecycle.test.ts +7 -0
  321. package/src/lifecycle/index.ts +2 -0
  322. package/src/lifecycle/table.ts +42 -0
  323. package/src/plugin/__tests__/plugin-stub.test.ts +6 -0
  324. package/src/plugin/plugin-stub.ts +7 -0
  325. package/src/plugin/toolu.ts +142 -0
  326. package/src/preflight/__tests__/preflight.test.ts +20 -0
  327. package/src/preflight/check.ts +75 -0
  328. package/src/preflight/index.ts +2 -0
  329. package/src/select/__tests__/select.test.ts +52 -0
  330. package/src/select/index.ts +2 -0
  331. package/src/select/resolve.ts +87 -0
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env bash
2
+ # context-budget.sh — enforce context-window budgets on harness-injected text.
3
+ #
4
+ # Every session, Claude Code loads the Session Protocol + per-language docs and
5
+ # all skill `description` fields into the model's context. This guard caps that
6
+ # recurring footprint so it cannot silently regrow, and asserts that trimming
7
+ # never drops a skill's discriminating trigger phrases (which would stop it
8
+ # auto-firing).
9
+ #
10
+ # Fails CLOSED: a missing/renamed target file, or a description that can't be
11
+ # parsed, is RED — never a silent pass.
12
+ #
13
+ # Usage: context-budget.sh [docs|skills] (no arg = all)
14
+ set -u
15
+
16
+ ROOT="${CONTEXT_BUDGET_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null)}"
17
+
18
+ fail=0
19
+ err() { printf 'RED %s\n' "$1" >&2; fail=1; }
20
+ ok() { printf 'ok %s\n' "$1"; }
21
+
22
+ # count_words FILE -> prints word count; returns 1 if file missing.
23
+ count_words() {
24
+ [ -f "$1" ] || return 1
25
+ wc -w < "$1" | tr -d ' '
26
+ }
27
+
28
+ # extract_description FILE -> prints the YAML frontmatter `description` value.
29
+ # Handles single-line (`description: text`) and folded/block scalars
30
+ # (`description: >` followed by indented lines). Returns 1 if the file is absent.
31
+ extract_description() {
32
+ [ -f "$1" ] || return 1
33
+ awk '
34
+ /^description:/ && !started {
35
+ started=1
36
+ v=$0; sub(/^description:[ \t]*/,"",v)
37
+ if (v=="" || v==">" || v==">-" || v=="|" || v=="|-") { folded=1; next }
38
+ print v; exit
39
+ }
40
+ folded {
41
+ if ($0=="---") exit
42
+ if ($0 ~ /^[A-Za-z0-9_-]+:/) exit
43
+ sub(/^[ \t]+/,"")
44
+ buf=(buf=="")?$0:buf" "$0
45
+ }
46
+ END { if (folded) print buf }
47
+ ' "$1"
48
+ }
49
+
50
+ # check_doc NAME PATH BUDGET
51
+ check_doc() {
52
+ local name="$1" path="$2" budget="$3" n
53
+ n=$(count_words "$ROOT/$path") || { err "$name: MISSING $path"; return; }
54
+ if [ "$n" -le "$budget" ]; then ok "$name ${n}w (<= ${budget})"
55
+ else err "$name ${n}w EXCEEDS ${budget} ($path)"; fi
56
+ }
57
+
58
+ # check_skill NAME PATH BUDGET PHRASES(;-separated, may be empty)
59
+ check_skill() {
60
+ local name="$1" path="$2" budget="$3" phrases="$4" desc n p
61
+ desc=$(extract_description "$ROOT/$path") || { err "$name: MISSING $path"; return; }
62
+ [ -n "$desc" ] || { err "$name: empty/unparseable description ($path)"; return; }
63
+ n=$(printf '%s' "$desc" | wc -w | tr -d ' ')
64
+ if [ "$n" -le "$budget" ]; then ok "$name desc ${n}w (<= ${budget})"
65
+ else err "$name desc ${n}w EXCEEDS ${budget} ($path)"; fi
66
+ local IFS=';'
67
+ for p in $phrases; do
68
+ [ -z "$p" ] && continue
69
+ case "$desc" in
70
+ *"$p"*) : ;;
71
+ *) err "$name: missing trigger phrase \"$p\" ($path)" ;;
72
+ esac
73
+ done
74
+ }
75
+
76
+ run_docs() {
77
+ check_doc session-start plugins/toolu/hooks/docs/session-start.md 110
78
+ check_doc model-routing plugins/toolu/hooks/docs/model-routing.md 90
79
+ check_doc post-compaction plugins/toolu/hooks/docs/post-compaction.md 28
80
+ check_doc session-start-ts plugins/toolu/hooks/docs/session-start-ts.md 30
81
+ check_doc session-start-rust plugins/toolu/hooks/docs/session-start-rust.md 36
82
+ check_doc session-start-python plugins/toolu/hooks/docs/session-start-python.md 36
83
+ }
84
+
85
+ run_skills() {
86
+ # Trimmed skills: word ceiling + trigger phrases that MUST survive the trim.
87
+ check_skill brainstorm plugins/toolu/skills/brainstorm/SKILL.md 90 "where do I even start;help me scope it;think through the approach and tradeoffs"
88
+ check_skill spec plugins/toolu/skills/spec/SKILL.md 70 "write the spec;document the design"
89
+ check_skill spec-review plugins/toolu/skills/spec-review/SKILL.md 60 "review the spec;poke holes in this spec"
90
+ check_skill deep-research plugins/toolu/skills/deep-research/SKILL.md 90 "deep research;cited report"
91
+ check_skill plan-review plugins/toolu/skills/plan-review/SKILL.md 55 "review the plan;poke holes in the plan"
92
+ check_skill toolu-review plugins/toolu-review/skills/review/SKILL.md 65 "review before push"
93
+ # Already-lean skills: word ceiling only, lock against regrowth.
94
+ check_skill plan plugins/toolu/skills/plan/SKILL.md 60 ""
95
+ check_skill execution plugins/toolu/skills/execution/SKILL.md 60 ""
96
+ check_skill test plugins/toolu/skills/test/SKILL.md 60 ""
97
+ check_skill ast-grep plugins/ast-grep/skills/ast-grep/SKILL.md 40 ""
98
+ check_skill jev plugins/jev/skills/jev/SKILL.md 60 ""
99
+ }
100
+
101
+ main() {
102
+ case "${1:-all}" in
103
+ docs) run_docs ;;
104
+ skills) run_skills ;;
105
+ all) run_docs; run_skills ;;
106
+ *) echo "usage: context-budget.sh [docs|skills]" >&2; exit 2 ;;
107
+ esac
108
+ [ "$fail" -eq 0 ] || exit 1
109
+ }
110
+
111
+ if [ "${BASH_SOURCE[0]:-}" = "${0:-}" ]; then main "$@"; fi
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env bash
2
+ # debug-log.sh — language-agnostic log summarizer for the debug skill's Observe step.
3
+ # Reads a log (stdin or --file) and emits a compact, capped summary: deduped error/warning
4
+ # lines plus a tail of recent lines, always reporting TOTAL lines so the caller knows what was
5
+ # elided. Its primary job is cap enforcement — a huge log in, a small summary out, never a flood.
6
+ # Output stays at/under DEBUG_MAX_LINES lines AND under DEBUG_MAX_BYTES bytes.
7
+ set -euo pipefail
8
+
9
+ usage() {
10
+ cat <<'EOF'
11
+ Usage: debug-log.sh [--file <path>] [--json]
12
+ Reads a log from stdin or --file and prints a compact, capped summary:
13
+ deduped ERROR/WARN-ish lines and a tail of the most recent lines.
14
+ --json Emit a JSON object {errors,tail,total_lines,truncated} instead of text.
15
+ Env caps (override): DEBUG_MAX_LINES=100 (max output lines) DEBUG_MAX_BYTES=65536 (hard output byte ceiling)
16
+ EOF
17
+ }
18
+
19
+ file=""
20
+ json=0
21
+ while [ $# -gt 0 ]; do
22
+ case "$1" in
23
+ --file) file="${2:-}"; shift 2 || { echo "debug-log.sh: --file needs a path" >&2; exit 2; } ;;
24
+ --json) json=1; shift ;;
25
+ -h|--help) usage; exit 0 ;;
26
+ *) echo "debug-log.sh: unknown arg: $1" >&2; usage >&2; exit 2 ;;
27
+ esac
28
+ done
29
+
30
+ if [ -n "$file" ]; then
31
+ [ -r "$file" ] || { echo "debug-log.sh: cannot read file: $file" >&2; exit 2; }
32
+ exec < "$file"
33
+ elif [ -t 0 ]; then
34
+ echo "debug-log.sh: no input (pipe a log or pass --file)" >&2
35
+ exit 2
36
+ fi
37
+
38
+ LC_ALL=C awk -v json="$json" \
39
+ -v maxl="${DEBUG_MAX_LINES:-100}" \
40
+ -v maxb="${DEBUG_MAX_BYTES:-65536}" '
41
+ function jesc(s){ gsub(/\\/,"\\\\",s); gsub(/"/,"\\\"",s); gsub(/\t/," ",s); gsub(/\r/,"",s); return s }
42
+ # Normalize a leading timestamp to a placeholder so timestamped repeats collapse on dedup.
43
+ function norm(s, k){ k=s
44
+ sub(/^[0-9]{4}-[0-9]{2}-[0-9]{2}[T ][0-9:.]+([Zz]|[+-][0-9:]+)?/,"<TS>",k) # ISO 8601
45
+ sub(/^\[[0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?\]/,"<TS>",k) # [12:00:00]
46
+ return k
47
+ }
48
+ {
49
+ total=NR
50
+ line=$0; sub(/\r$/,"",line)
51
+ tail[NR]=line # ring of recent lines (indexed by NR)
52
+ if (NR>maxl) delete tail[NR-maxl] # keep at most maxl tail candidates
53
+ if (line ~ /[Ee][Rr][Rr][Oo][Rr]|[Ww][Aa][Rr][Nn]|[Pp][Aa][Nn][Ii][Cc]|[Ff][Aa][Ii][Ll]|[Ee][Xx][Cc][Ee][Pp][Tt][Ii][Oo][Nn]|[Ff][Aa][Tt][Aa][Ll]|[Tt][Rr][Aa][Cc][Ee][Bb][Aa][Cc][Kk]/) {
54
+ key=norm(line)
55
+ if (!(key in eseen)) { eseen[key]=1; errs[++ne]=line }
56
+ else eskip++
57
+ }
58
+ }
59
+ END {
60
+ # Budget: errors get up to ~60% of the line cap, tail gets the rest (header lines count too).
61
+ emax = int(maxl*0.6); if (emax<1) emax=1
62
+ eshow = (ne<emax?ne:emax); eover = ne-eshow
63
+ # Reserve lines already spent by error section + its 2 headers; remainder for tail + its header.
64
+ used = eshow + (ne>0?1:0) + (eover>0?1:0) + 1 # errors + ERRORS hdr + overflow + TOTAL line
65
+ tmax = maxl - used - 1 # -1 for the TAIL header
66
+ if (tmax<0) tmax=0
67
+ # Tail = the last tshow of the kept tail lines.
68
+ tn=0; for(i=(total>maxl?total-maxl+1:1); i<=total; i++) if(i in tail) tline[++tn]=tail[i]
69
+ tshow = (tn<tmax?tn:tmax)
70
+ tstart = tn - tshow + 1; if (tstart<1) tstart=1
71
+
72
+ if (json) {
73
+ printf "{"
74
+ printf "\"errors\":["; for(i=1;i<=eshow;i++){printf "%s\"%s\"",(i>1?",":""),jesc(errs[i])} printf "],"
75
+ printf "\"tail\":["; for(i=tstart;i<=tn;i++){printf "%s\"%s\"",(i>tstart?",":""),jesc(tline[i])} printf "],"
76
+ printf "\"total_lines\":%d,", total
77
+ printf "\"truncated\":%s", ((eover>0 || tshow<tn || total>maxl)?"true":"false")
78
+ printf "}\n"
79
+ exit 0
80
+ }
81
+
82
+ # Text mode — assemble into a buffer, then enforce the byte ceiling by dropping from the end.
83
+ o=0
84
+ out[++o]="ERRORS/WARNINGS (" eshow (eover>0?"+":"") "):"
85
+ for(i=1;i<=eshow;i++) out[++o]=" " errs[i]
86
+ if (eover>0) out[++o]=" ... (+" eover " more)"
87
+ out[++o]="TAIL (last " tshow " of " total " lines):"
88
+ for(i=tstart;i<=tn;i++) out[++o]=" " tline[i]
89
+ out[++o]="TOTAL lines: " total
90
+
91
+ # Hard byte ceiling: count bytes (incl. newline) and drop trailing lines if we would exceed maxb.
92
+ bytes=0; keep=o
93
+ for(i=1;i<=o;i++){ bytes += length(out[i])+1; if (bytes>maxb) { keep=i-1; break } }
94
+ bytetrunc = (keep<o)
95
+ for(i=1;i<=keep;i++) print out[i]
96
+ if (bytetrunc) print "... (output truncated to stay under " maxb " bytes)"
97
+ }
98
+ '
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env bash
2
+ # debug-stack.sh — language-agnostic stack/backtrace summarizer for the debug skill's Observe step.
3
+ # Reads a stack trace / panic backtrace (stdin or --file) and surfaces APP frames first, collapsing
4
+ # framework/runtime/stdlib frames into a count. Never a per-language grammar — it keys on line SHAPE
5
+ # (a symbol and/or a file:line[:col]) and flags noise by path/symbol markers (/rustc/, node:internal,
6
+ # core::, std::, __rustc, <anonymous>, …). JS (symbol+loc on one line) and Rust (symbol then `at <path>`
7
+ # on the next line) both work. Unrecognized input → capped raw passthrough.
8
+ set -euo pipefail
9
+
10
+ usage() {
11
+ cat <<'EOF'
12
+ Usage: debug-stack.sh [--file <path>] [--json]
13
+ Reads a stack trace / backtrace from stdin or --file and prints APP frames first, runtime noise collapsed.
14
+ --json Emit {"app_frames":[...],"noise_frames":N,"recognized":bool} instead of text.
15
+ Env caps (override): DEBUG_MAX_FRAMES=20 DEBUG_MAX_LINES=100
16
+ EOF
17
+ }
18
+
19
+ file=""
20
+ json=0
21
+ while [ $# -gt 0 ]; do
22
+ case "$1" in
23
+ --file) file="${2:-}"; shift 2 || { echo "debug-stack.sh: --file needs a path" >&2; exit 2; } ;;
24
+ --json) json=1; shift ;;
25
+ -h|--help) usage; exit 0 ;;
26
+ *) echo "debug-stack.sh: unknown arg: $1" >&2; usage >&2; exit 2 ;;
27
+ esac
28
+ done
29
+
30
+ if [ -n "$file" ]; then
31
+ [ -r "$file" ] || { echo "debug-stack.sh: cannot read file: $file" >&2; exit 2; }
32
+ exec < "$file"
33
+ elif [ -t 0 ]; then
34
+ echo "debug-stack.sh: no input (pipe a trace or pass --file)" >&2
35
+ exit 2
36
+ fi
37
+
38
+ awk -v json="$json" \
39
+ -v maxfr="${DEBUG_MAX_FRAMES:-20}" \
40
+ -v maxraw="${DEBUG_MAX_LINES:-100}" '
41
+ function trim(s){ sub(/^[ \t]+/,"",s); sub(/[ \t]+$/,"",s); return s }
42
+ function jesc(s){ gsub(/\\/,"\\\\",s); gsub(/"/,"\\\"",s); gsub(/\t/," ",s); return s }
43
+ # A frame is NOISE when its symbol or location points into a runtime/stdlib (language-agnostic markers).
44
+ function isnoise(text){ return (text ~ /\/rustc\/|node:internal|node:|core::|std::|__rustc|rust_begin_unwind|panic_fmt|panic_bounds_check|FnOnce::call_once|<anonymous>/) }
45
+ function emit(sym,loc, txt){
46
+ # sym/loc are the parts; txt is what we classify on. "func @ file:line" is the rendered frame.
47
+ txt=sym " " loc
48
+ if (isnoise(txt)) { noise++; return }
49
+ if (sym!="" && loc!="") f=sym " @ " loc
50
+ else if (loc!="") f=loc
51
+ else f=sym
52
+ napp++; app[napp]=f
53
+ }
54
+ {
55
+ raw[NR]=$0
56
+ line=$0
57
+
58
+ # --- Rust continuation FIRST: ` at <location>` pairs with the pending `N: symbol` ---
59
+ if (pend && match(line, /^[ \t]*at[ \t]+/)) {
60
+ emit(pend_sym, trim(substr(line, RSTART+RLENGTH))); pend=0; pend_sym=""; next
61
+ }
62
+ # A pending Rust symbol with no following `at` line: still a frame, no location.
63
+ if (pend) { emit(pend_sym, ""); pend=0; pend_sym="" }
64
+
65
+ # --- JS shape: a stack frame line begins with `at <symbol> (<location>)` or `at <location>` ---
66
+ if (match(line, /^[ \t]*at[ \t]+/)) {
67
+ rest=substr(line, RSTART+RLENGTH)
68
+ sym=""; loc=""
69
+ if (match(rest, /\(.*\)[ \t]*$/)) { # at func (loc)
70
+ sym=trim(substr(rest, 1, RSTART-1))
71
+ loc=substr(rest, RSTART+1, RLENGTH-2) # strip the surrounding ()
72
+ sub(/[ \t]+$/,"",loc)
73
+ } else { # at loc (no symbol)
74
+ loc=trim(rest)
75
+ }
76
+ if (sym!="" || loc!="") { emit(sym, loc); next }
77
+ }
78
+
79
+ # --- Rust shape: ` N: <symbol>` then the NEXT line ` at <location>` ---
80
+ if (match(line, /^[ \t]*[0-9]+:[ \t]+/)) {
81
+ pend_sym=trim(substr(line, RSTART+RLENGTH)); pend=1; next
82
+ }
83
+ }
84
+ END {
85
+ if (pend) emit(pend_sym, "") # flush a trailing pending Rust frame
86
+ recognized = (napp + noise) > 0
87
+ if (json) {
88
+ printf "{"
89
+ printf "\"app_frames\":["; for(i=1;i<=napp;i++){printf "%s\"%s\"", (i>1?",":""), jesc(app[i])} printf "],"
90
+ printf "\"noise_frames\":%d,", noise
91
+ printf "\"recognized\":%s", (recognized?"true":"false")
92
+ printf "}\n"
93
+ exit 0
94
+ }
95
+ if (!recognized) {
96
+ print "debug-stack: no recognizable stack frames — raw input (capped):"
97
+ cap = (NR<maxraw?NR:maxraw)
98
+ for(i=1;i<=cap;i++) print raw[i]
99
+ if (NR>maxraw) printf "... (+%d more lines)\n", NR-maxraw
100
+ exit 0
101
+ }
102
+ shown = (napp<maxfr?napp:maxfr)
103
+ print "APP FRAMES (" napp (napp>maxfr?"+":"") "):"
104
+ for(i=1;i<=shown;i++) print " - " app[i]
105
+ if (napp>maxfr) printf " ... (+%d more)\n", napp-maxfr
106
+ if (noise>0) printf "(+%d framework/runtime frames collapsed)\n", noise
107
+ }
108
+ '
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env bash
2
+ # debug-testfail.sh — language-agnostic test-failure summarizer for the debug skill's Observe step.
3
+ # Reads a failing test transcript (stdin or --file), emits a compact, capped summary:
4
+ # failed test names, error/assertion lines, and code file:line locations. Never a per-language grammar —
5
+ # it keys on line shape only (works on bun/jest, cargo, and similar). Unrecognized input → capped raw passthrough.
6
+ set -euo pipefail
7
+
8
+ usage() {
9
+ cat <<'EOF'
10
+ Usage: debug-testfail.sh [--file <path>] [--json]
11
+ Reads a test-failure transcript from stdin or --file and prints a compact summary.
12
+ --json Emit a JSON object {failures,errors,locations} instead of text.
13
+ Env caps (override): DEBUG_MAX_FAILURES=25 DEBUG_MAX_ERRORS=25 DEBUG_MAX_LOCATIONS=25 DEBUG_MAX_LINES=100
14
+ EOF
15
+ }
16
+
17
+ file=""
18
+ json=0
19
+ while [ $# -gt 0 ]; do
20
+ case "$1" in
21
+ --file) file="${2:-}"; shift 2 || { echo "debug-testfail.sh: --file needs a path" >&2; exit 2; } ;;
22
+ --json) json=1; shift ;;
23
+ -h|--help) usage; exit 0 ;;
24
+ *) echo "debug-testfail.sh: unknown arg: $1" >&2; usage >&2; exit 2 ;;
25
+ esac
26
+ done
27
+
28
+ if [ -n "$file" ]; then
29
+ [ -r "$file" ] || { echo "debug-testfail.sh: cannot read file: $file" >&2; exit 2; }
30
+ exec < "$file"
31
+ elif [ -t 0 ]; then
32
+ echo "debug-testfail.sh: no input (pipe a transcript or pass --file)" >&2
33
+ exit 2
34
+ fi
35
+
36
+ awk -v json="$json" \
37
+ -v maxf="${DEBUG_MAX_FAILURES:-25}" \
38
+ -v maxe="${DEBUG_MAX_ERRORS:-25}" \
39
+ -v maxl="${DEBUG_MAX_LOCATIONS:-25}" \
40
+ -v maxraw="${DEBUG_MAX_LINES:-100}" '
41
+ function trim(s){ sub(/^[ \t]+/,"",s); sub(/[ \t]+$/,"",s); return s }
42
+ function jesc(s){ gsub(/\\/,"\\\\",s); gsub(/"/,"\\\"",s); gsub(/\t/," ",s); return s }
43
+ function add(arr,seen,n,max,val, key){ val=trim(val); if(val=="")return n; key=val; if(key in seen)return n; if(n>=max){over[max==maxf?"f":(max==maxe?"e":"l")]++;return n} seen[key]=1; arr[++n]=val; return n }
44
+ {
45
+ raw[NR]=$0
46
+ line=$0
47
+
48
+ # --- failed test NAMES (line-shape, not language) ---
49
+ if (match(line, /\(fail\)[ \t]+/)) { # bun/jest: (fail) NAME [1ms]
50
+ name=substr(line, RSTART+RLENGTH); sub(/[ \t]*\[[^]]*\][ \t]*$/,"",name)
51
+ nf=add(fails,fseen,nf,maxf,name)
52
+ } else if (match(line, /(^|[ \t])test[ \t]+[^ \t]+[ \t]+\.\.\.[ \t]+FAILED/)) { # cargo: test NAME ... FAILED
53
+ n=line; sub(/^[ \t]*test[ \t]+/,"",n); sub(/[ \t]+\.\.\..*/,"",n)
54
+ nf=add(fails,fseen,nf,maxf,n)
55
+ } else if (match(line, /^[ \t]*(FAIL|✕|✗|×)[ \t]+/)) { # generic fail markers
56
+ name=substr(line, RSTART+RLENGTH)
57
+ nf=add(fails,fseen,nf,maxf,name)
58
+ }
59
+
60
+ # --- ERROR / assertion lines ---
61
+ if (line ~ /([Ee]rror:|panicked at|[Aa]ssertion|AssertionError|Expected:|Received:|^[ \t]*left:|^[ \t]*right:|thread .* panicked)/) {
62
+ ne=add(errs,eseen,ne,maxe,line)
63
+ }
64
+
65
+ # --- code file:line[:col] locations (path with extension + :digits) ---
66
+ s=line
67
+ while (match(s, /[A-Za-z0-9_.\/\\-]+\.[A-Za-z]+:[0-9]+(:[0-9]+)?/)) {
68
+ loc=substr(s, RSTART, RLENGTH)
69
+ nl=add(locs,lseen,nl,maxl,loc)
70
+ s=substr(s, RSTART+RLENGTH)
71
+ }
72
+ }
73
+ END {
74
+ recognized = (nf+ne+nl) > 0
75
+ if (json) {
76
+ printf "{"
77
+ printf "\"failures\":["; for(i=1;i<=nf;i++){printf "%s\"%s\"", (i>1?",":""), jesc(fails[i])} printf "],"
78
+ printf "\"errors\":["; for(i=1;i<=ne;i++){printf "%s\"%s\"", (i>1?",":""), jesc(errs[i])} printf "],"
79
+ printf "\"locations\":[";for(i=1;i<=nl;i++){printf "%s\"%s\"", (i>1?",":""), jesc(locs[i])} printf "],"
80
+ printf "\"recognized\":%s", (recognized?"true":"false")
81
+ printf "}\n"
82
+ exit 0
83
+ }
84
+ if (!recognized) {
85
+ print "debug-testfail: no recognizable test failures — raw input (capped):"
86
+ cap = (NR<maxraw?NR:maxraw)
87
+ for(i=1;i<=cap;i++) print raw[i]
88
+ if (NR>maxraw) printf "... (+%d more lines)\n", NR-maxraw
89
+ exit 0
90
+ }
91
+ print "FAILED TESTS (" nf (over["f"]?"+":"") "):"
92
+ for(i=1;i<=nf;i++) print " - " fails[i]
93
+ if (over["f"]) print " ... (+" over["f"] " more)"
94
+ if (ne>0) { print "\nERRORS (" ne (over["e"]?"+":"") "):"; for(i=1;i<=ne;i++) print " " errs[i]; if(over["e"]) print " ... (+" over["e"] " more)" }
95
+ if (nl>0) { print "\nLOCATIONS (" nl (over["l"]?"+":"") "):"; for(i=1;i<=nl;i++) print " " locs[i]; if(over["l"]) print " ... (+" over["l"] " more)" }
96
+ }
97
+ '
File without changes
@@ -0,0 +1,127 @@
1
+ # settings/
2
+
3
+ Reusable Claude Code settings fragments plus data files consumed by hooks.
4
+
5
+ ## Fragments
6
+
7
+ - `permissions.fragment.json` — sanitized union of permission allowlists/denylists from the source repos. Its `deny` block is deliberately short: `permissions.deny` **overrides** a PreToolUse hook's `ask`, so a rule here silently outranks whatever `gates.<name>.mode` says. Only catastrophic, never-ask-me commands belong in it (`rm -rf /`, `mkfs`, `dd`, `sudo rm`, `chmod 777`); `git push --force` and `node -e` moved to `bash-denylist.txt`, where the gate mode decides whether they deny, ask, or pass. Most repos do not need to merge this at all — toolu writes `Bash(*)`, `Edit`, `Write` into `.claude/settings.local.json` on first run (see `permissions.autoAllow` in `docs/config.md`). This is a **dev-mode merge for the repo checkout**; the `ast-grep` wrapper allow-rules pin the full `plugins/ast-grep/` paths (repo-root and `.claude/worktrees/*` variants) so an untrusted temp/checkout directory with a same-named tail cannot satisfy the allowlist. Installed plugins are governed by Claude Code's own plugin permissions, not this fragment.
8
+
9
+ Hook wiring ships in the plugin manifest (`plugins/toolu/hooks/hooks.json`);
10
+ installing the plugin registers all hooks — no manual settings merge needed.
11
+
12
+ ### Merge into your settings
13
+
14
+ For the permissions fragment, run from the repo root:
15
+
16
+ ```bash
17
+ jq -s '.[0] * .[1]' ~/.claude/settings.json plugins/toolu/settings/permissions.fragment.json \
18
+ > ~/.claude/settings.json.new && mv ~/.claude/settings.json.new ~/.claude/settings.json
19
+ ```
20
+
21
+ > Never add a path that contains secrets (e.g. `.env`) to `additionalDirectories`.
22
+
23
+ ## Security note
24
+
25
+ The settings.json deny matcher is substring-based and unreliable for argv
26
+ shapes like `node -e`, `git push --force`, or `git push origin main`. The
27
+ `hooks/pre-tools/modules/bash-commands.sh` hook performs argv-aware
28
+ enforcement using `bash-denylist.txt`. Both layers must be installed for
29
+ the security model to hold:
30
+
31
+ - Settings denies catch obvious cases at the matcher layer.
32
+ - `bash-commands.sh` parses argv and reliably rejects the listed tokens
33
+ even when they are embedded mid-command-line.
34
+
35
+ ## Data files (read by hooks)
36
+
37
+ Consumer paths below are relative to the plugin root (`plugins/toolu/`);
38
+ the merge commands above are written for the repo root because cwd matters
39
+ when you run them.
40
+
41
+ | File | Consumer | Purpose |
42
+ |-------------------------------|---------------------------------------------------|--------------------------------------------------------------------|
43
+ | `bash-allowlist.txt` | `hooks/pre-tools/modules/bash-commands.sh` | Explicit overrides on top of the denylist (deny + allow → allowed). |
44
+ | `bash-denylist.txt` | `hooks/pre-tools/modules/bash-commands.sh` | Tokens the bash guard rejects via argv-aware parsing. |
45
+ | `code-edit-rules.json` | `hooks/pre-tools/modules/code-edit-rules.sh` | Pattern rules for Write/Edit gating on source files. |
46
+ | `commit-prefixes.txt` | `hooks/pre-tools/modules/commit-gate.sh` | Allowed Conventional Commits prefixes for `git commit` messages. |
47
+ | `mcp-blocklist.txt` | `hooks/pre-tools/modules/mcp-blocker.sh` | MCP server prefixes blocked unconditionally (plain text). |
48
+ | `toolu.config.example.json` | (reference — copy to `~/.claude/toolu.config.json`) | Example runtime opt-out config (skills/hooks/mcp). See `docs/config.md`. |
49
+ | `protected-files.txt` | `hooks/pre-tools/modules/protected-files.sh` | Paths the edit guard refuses to modify (lockfiles, secrets, etc.). |
50
+ | `rust-unsafe-exemptions.txt` | `hooks/post-tools/modules/rust-quality.sh` | Files/paths exempt from the `unsafe` Rust check. |
51
+
52
+ Each plain-text file is one entry per line, `#` for comments. JSON files
53
+ follow whatever schema the consuming script documents.
54
+
55
+ ### `mcp-blocklist.txt` redirect hints
56
+
57
+ A blocklist line may carry an optional `-> <text>` suffix after the server
58
+ prefix. When that server is denied, the text is appended to the deny reason so
59
+ the user is pointed at the replacement. The prefix alone drives the match; the
60
+ hint is ignored for matching.
61
+
62
+ ```text
63
+ # <server-prefix> -> <redirect text shown in the deny reason>
64
+ # Example (commented = inert; uncomment to actually block the Atlassian MCP and
65
+ # steer Jira work to the bundled jira skill):
66
+ # claude_ai_Atlassian -> use the `jira` skill instead
67
+ ```
68
+
69
+ The example is shown **commented**, so nothing is blocked out of the box — the
70
+ `jira`/toolu prompt nudge handles discoverability without denying the MCP.
71
+ Uncomment the line (in your own settings dir) only if you want a hard block too.
72
+
73
+ Allow/deny semantics for the bash guard: the denylist is checked first; a
74
+ command that matches a deny rule is still allowed if it also matches an
75
+ allowlist rule (the allowlist is an explicit override, not a default gate).
76
+ Commands that match no deny rule are allowed by default.
77
+
78
+ > Allowlist caveat: single-token allowlist entries match anywhere in the
79
+ > command string as **substrings** (only multi-token entries are argv-aware —
80
+ > see `bash-commands.sh`). A broad single-token entry such as `node` therefore
81
+ > overrides far more than intended and quietly broadens the attack surface
82
+ > (e.g. it would exempt `node -e '…'`). Prefer specific multi-token entries for
83
+ > exemptions so the override stays argv-scoped to exactly the command you mean.
84
+
85
+ Lookup order (see `toolu_settings_dir` in `hooks/lib/detect.sh`, sibling of
86
+ this directory inside the plugin):
87
+ `$TOOLU_SETTINGS_DIR` (if set) → `~/.claude/settings` (if it exists) →
88
+ the plugin's own `settings/` directory, resolved relative to the hooks. There is
89
+ no per-project `.claude/settings/` lookup — to override per project, point
90
+ `TOOLU_SETTINGS_DIR` at a project-local directory.
91
+
92
+ ## Env vars
93
+
94
+ | Variable | Effect |
95
+ |---------------------------|-----------------------------------------|
96
+ | `TOOLU_SETTINGS_DIR` | Directory the hooks read data files from |
97
+ | `MY_CLAUDE_QUALITY` | `off` to disable `quality-gate.sh` |
98
+ | `MY_CLAUDE_COMEMORY_REPO` | Overrides the comemory `--repo` scope used by the comemory wrapper (the comemory plugin's `skills/agent-memory/scripts/comemory.sh`). Defaults to the git project name. Not read by any hook. |
99
+
100
+ ## Statusline
101
+
102
+ The statusline moved to its own optional plugin, **`statusline`** — it shows
103
+ `model | effort | ctx | <gate> | folder | branch`, with a loud red
104
+ `✗ gate:failing` marker driven by the same `.claude/tmp/quality-gate-status.json`
105
+ the rust-quality / ts-quality / python-quality hooks write. Install it and wire `settings.json` per
106
+ `plugins/statusline/README.md`:
107
+
108
+ ```
109
+ /plugin install statusline@toolu
110
+ ```
111
+
112
+ ```json
113
+ { "statusLine": { "type": "command",
114
+ "command": "bash ~/.claude/statusline/statusline.sh" } }
115
+ ```
116
+
117
+ Toolu no longer ships or symlinks the statusline; on upgrade it sweeps the
118
+ old `~/.claude/toolu/statusline.sh` symlink it used to own. If you previously
119
+ wired that path, re-point it to `~/.claude/statusline/statusline.sh`.
120
+
121
+ ## Runtime config
122
+
123
+ For per-skill, per-hook, or per-MCP opt-out without touching the data
124
+ files above, see `docs/config.md`. The config file lives at
125
+ `~/.claude/toolu.config.json` (or the project-local override) and is
126
+ deep-merged at runtime. The `mcp-blocklist.txt` blocklist still works in
127
+ parallel; either source can block a server.
@@ -0,0 +1,12 @@
1
+ # bash-commands.sh allowlist (one pattern per line; '#' starts a comment).
2
+ #
3
+ # IMPORTANT: deny is checked FIRST, allow second. Allow is intended for
4
+ # per-project override of deny rules, not for substring evasion of
5
+ # security-hardened blocks like `node -e`.
6
+ #
7
+ # Multi-token rules (e.g. `bun run check`) are argv-aware: the first
8
+ # token must equal tokens[0] AND every other rule-token must appear as
9
+ # a distinct later argv token. Single-token rules substring-match the
10
+ # full command.
11
+ #
12
+ # Currently empty — add per-project exemptions here.
@@ -0,0 +1,25 @@
1
+ # bash-commands.sh denylist (one token per line; '#' starts a comment).
2
+ #
3
+ # Each line is matched argv-aware against the parsed command:
4
+ # "<bin> <flag>" — bin must be the first argv token and flag must be a later
5
+ # argv token (covers JSON-matcher gaps).
6
+ # single token — substring-matched against the whole command for tokens like
7
+ # "biome" or "cargo test".
8
+ #
9
+ # Delivery is a MODE, not a constant: `gates.bashCommands.mode` decides whether
10
+ # a match here denies, asks, advises (the shipped default), or is ignored. A
11
+ # rule in this file means "worth telling the agent about", not "impossible".
12
+ # `ask` is opt-in via `gates.bashCommands.mode`.
13
+ #
14
+ # git and gh are deliberately absent. Every git operation — force pushes and
15
+ # pushes to the base branch included — is not this file's call to make.
16
+ #
17
+ # Security-hardened: argv-aware blocks the JSON matcher cannot reliably reject.
18
+ node -e
19
+ node -p
20
+ node --eval
21
+ node --print
22
+ bun -e
23
+ bun --eval
24
+ # General policy: never run cargo test (use nextest instead).
25
+ cargo test
@@ -0,0 +1,67 @@
1
+ {
2
+ "//": "code-edit-rules.sh data file. Each entry maps a file-glob pattern to a list of one-line rule reminders. The hook joins the strings and surfaces them before edits. Schema: {rules: [{ match: string (glob), docs: [string] (one-line rule texts), when_path_matches?: [string] (extra_docs added when the file path also matches one of these), extra_docs?: [string]}]}",
3
+ "rules": [
4
+ {
5
+ "match": "*.rs",
6
+ "docs": [
7
+ "Rust: zero compiler/clippy warnings",
8
+ "no unwrap()/expect()/panic! outside tests",
9
+ "keep it simple — no speculative abstractions"
10
+ ]
11
+ },
12
+ {
13
+ "match": "*.ts",
14
+ "docs": [
15
+ "TS: zero typecheck/lint errors and warnings",
16
+ "no `any`, @ts-ignore, or non-null assertions",
17
+ "keep it simple — no speculative abstractions"
18
+ ],
19
+ "when_path_matches": [
20
+ "*/features/*",
21
+ "*/components/*",
22
+ "*/routes/*"
23
+ ],
24
+ "extra_docs": [
25
+ "frontend: colocate by feature (components/hooks/routes per feature dir)"
26
+ ]
27
+ },
28
+ {
29
+ "match": "*.tsx",
30
+ "docs": [
31
+ "TS: zero typecheck/lint errors and warnings",
32
+ "no `any`, @ts-ignore, or non-null assertions",
33
+ "keep it simple — no speculative abstractions"
34
+ ],
35
+ "when_path_matches": [
36
+ "*/features/*",
37
+ "*/components/*",
38
+ "*/routes/*"
39
+ ],
40
+ "extra_docs": [
41
+ "frontend: colocate by feature (components/hooks/routes per feature dir)"
42
+ ]
43
+ },
44
+ {
45
+ "match": "*.js",
46
+ "docs": [
47
+ "JS: keep lint/tests green",
48
+ "keep it simple — no speculative abstractions"
49
+ ]
50
+ },
51
+ {
52
+ "match": "*.jsx",
53
+ "docs": [
54
+ "JS: keep lint/tests green",
55
+ "keep it simple — no speculative abstractions"
56
+ ]
57
+ },
58
+ {
59
+ "match": "*.py",
60
+ "docs": [
61
+ "Python: colocated test_<module>.py, real-data tests (no mocks)",
62
+ "no bare except:/blanket # noqa/bare # type: ignore — fix the cause",
63
+ "size limits via lang.python.* (default 400/file, 50/function)"
64
+ ]
65
+ }
66
+ ]
67
+ }
@@ -0,0 +1,12 @@
1
+ # Conventional Commits prefixes (one per line; '#' starts a comment).
2
+ feat
3
+ fix
4
+ chore
5
+ docs
6
+ refactor
7
+ test
8
+ perf
9
+ build
10
+ ci
11
+ style
12
+ revert