@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,7 @@
1
+ import { expect, test } from "bun:test";
2
+ import { lifecycleSupport } from "../table.ts";
3
+
4
+ test("session/start and permission/evaluate supported after #204", () => {
5
+ expect(lifecycleSupport("session/start")).toBe("supported");
6
+ expect(lifecycleSupport("permission/evaluate")).toBe("supported");
7
+ });
@@ -0,0 +1,2 @@
1
+ export { lifecycleSupport, lifecycleSupportTable } from "./table.ts";
2
+ export type { LifecycleEvent, LifecycleSupport } from "./table.ts";
@@ -0,0 +1,42 @@
1
+ /**
2
+ * OpenCode lifecycle handler map.
3
+ * permission/evaluate hard-deny path is wired in #204; remaining session/tool
4
+ * hooks stay deferred until fuller host coverage / #212 evidence.
5
+ */
6
+
7
+ export type LifecycleSupport = "supported" | "deferred" | "unsupported";
8
+
9
+ export type LifecycleEvent =
10
+ | "session/start"
11
+ | "session/resume"
12
+ | "session/clear"
13
+ | "session/unload"
14
+ | "session/load"
15
+ | "prompt"
16
+ | "pre_compact"
17
+ | "permission/evaluate"
18
+ | "tool/pre"
19
+ | "tool/post"
20
+ | "shell/pre";
21
+
22
+ const TABLE: Record<LifecycleEvent, LifecycleSupport> = {
23
+ "session/start": "supported",
24
+ "session/resume": "deferred",
25
+ "session/clear": "deferred",
26
+ "session/unload": "deferred",
27
+ "session/load": "deferred",
28
+ prompt: "unsupported",
29
+ pre_compact: "unsupported",
30
+ "permission/evaluate": "supported",
31
+ "tool/pre": "deferred",
32
+ "tool/post": "deferred",
33
+ "shell/pre": "deferred",
34
+ };
35
+
36
+ export function lifecycleSupport(event: LifecycleEvent): LifecycleSupport {
37
+ return TABLE[event];
38
+ }
39
+
40
+ export function lifecycleSupportTable(): Record<LifecycleEvent, LifecycleSupport> {
41
+ return { ...TABLE };
42
+ }
@@ -0,0 +1,6 @@
1
+ import { expect, test } from "bun:test";
2
+ import { classifyStub } from "../plugin-stub.ts";
3
+
4
+ test("classifyStub uses core policy", () => {
5
+ expect(classifyStub("port-native")).toBe("port-native");
6
+ });
@@ -0,0 +1,7 @@
1
+ /** Thin compatibility surface — proves workspace import of @toolu/core. */
2
+ import { parseClassification } from "@toolu/core/policy";
3
+
4
+ /** Echo a classification through core to prove the workspace link. */
5
+ export function classifyStub(token: string): string {
6
+ return parseClassification(token);
7
+ }
@@ -0,0 +1,142 @@
1
+ /** OpenCode plugin entry — bootstrap + permission.evaluate bridge (#204). */
2
+ import { Plugin } from "@opencode/plugin";
3
+ import { existsSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { bootstrapRuntime } from "../bootstrap/runtime.ts";
6
+ import { runPreflight } from "../preflight/check.ts";
7
+ import {
8
+ createDenyAllPermissionHandler,
9
+ createPermissionEvaluateHandler,
10
+ } from "../adapter/evaluate.ts";
11
+ import { selectPluginsWithDependencies } from "../select/resolve.ts";
12
+ import { opencodeDataRoot } from "../host/roots.ts";
13
+
14
+ function readNonEmptyString(value: unknown): string | undefined {
15
+ return typeof value === "string" && value.length > 0 ? value : undefined;
16
+ }
17
+
18
+ /**
19
+ * The published package carries the bash plugins/ tree beside its sources, so an
20
+ * npm install needs no environment variable. Absent that copy — a contributor
21
+ * running from a clone — this returns undefined and the explicit sources win.
22
+ */
23
+ function bundledRepoRoot(): string | undefined {
24
+ const packageRoot = join(import.meta.dir, "../..");
25
+ return existsSync(join(packageRoot, "plugins")) ? packageRoot : undefined;
26
+ }
27
+
28
+ function repoRootFromOptions(
29
+ options: Readonly<Record<string, unknown>>,
30
+ env: Record<string, string>,
31
+ ): string | undefined {
32
+ return (
33
+ readNonEmptyString(options.repoRoot) ??
34
+ readNonEmptyString(env.TOOLU_REPO_ROOT) ??
35
+ readNonEmptyString(env.TOOLU_ROOT) ??
36
+ bundledRepoRoot()
37
+ );
38
+ }
39
+
40
+ export type SetupTooluPermissionOptions = {
41
+ repoRoot: string;
42
+ projectRoot: string;
43
+ env?: Record<string, string>;
44
+ };
45
+
46
+ /** Wire permission.evaluate after preflight + bootstrap; deny-all when NotReady. */
47
+ export async function setupTooluPermissionHook(
48
+ ctx: Pick<Plugin.Context, "permission" | "location">,
49
+ setupOpts: SetupTooluPermissionOptions,
50
+ ): Promise<void> {
51
+ const env = setupOpts.env ?? {};
52
+ const preflight = runPreflight({ env });
53
+ if (!preflight.bootstrapAllowed) {
54
+ const reason = preflight.reasons.join("; ") || "preflight failed";
55
+ await ctx.permission.hook(
56
+ "evaluate",
57
+ createDenyAllPermissionHandler(`toolu preflight: ${reason}`),
58
+ );
59
+ return;
60
+ }
61
+
62
+ const pluginsRoot = join(setupOpts.repoRoot, "plugins");
63
+ const selected = selectPluginsWithDependencies(pluginsRoot, setupOpts.projectRoot);
64
+ if (!selected.ok) {
65
+ await ctx.permission.hook(
66
+ "evaluate",
67
+ createDenyAllPermissionHandler(`toolu plugin selection: ${selected.reason}`),
68
+ );
69
+ return;
70
+ }
71
+
72
+ const dataRoot = opencodeDataRoot({
73
+ projectRoot: setupOpts.projectRoot,
74
+ env,
75
+ });
76
+
77
+ const bootstrap = await bootstrapRuntime({
78
+ repoRoot: setupOpts.repoRoot,
79
+ projectRoot: setupOpts.projectRoot,
80
+ dataRoot,
81
+ plugins: selected.plugins,
82
+ env,
83
+ });
84
+
85
+ if (bootstrap.status !== "ready") {
86
+ await ctx.permission.hook(
87
+ "evaluate",
88
+ createDenyAllPermissionHandler(`toolu bootstrap: ${bootstrap.reason}`),
89
+ );
90
+ return;
91
+ }
92
+
93
+ const bridgeContext = {
94
+ cwd: ctx.location.directory,
95
+ projectRoot: setupOpts.projectRoot,
96
+ worktree: ctx.location.directory,
97
+ host: "opencode",
98
+ };
99
+
100
+ const handler = createPermissionEvaluateHandler({
101
+ repoRoot: setupOpts.repoRoot,
102
+ bridgeContext,
103
+ env: {
104
+ ...env,
105
+ TOOLU_SETTINGS_DIR: join(setupOpts.repoRoot, "plugins/toolu/settings"),
106
+ TOOLU_HOST_OVERRIDE: "opencode",
107
+ },
108
+ });
109
+
110
+ await ctx.permission.hook("evaluate", handler);
111
+ }
112
+
113
+ export default Plugin.define({
114
+ id: "toolu",
115
+ async setup(ctx) {
116
+ const env: Record<string, string> = {};
117
+ for (const [key, value] of Object.entries(process.env)) {
118
+ if (value !== undefined) {
119
+ env[key] = value;
120
+ }
121
+ }
122
+
123
+ const optionsRecord: Record<string, unknown> = { ...ctx.options };
124
+ const repoRoot = repoRootFromOptions(optionsRecord, env);
125
+ if (!repoRoot) {
126
+ await ctx.permission.hook(
127
+ "evaluate",
128
+ createDenyAllPermissionHandler(
129
+ "toolu: no bundled plugins/ tree; set plugin option repoRoot or TOOLU_REPO_ROOT",
130
+ ),
131
+ );
132
+ return;
133
+ }
134
+
135
+ const projectRoot = ctx.location.project.directory;
136
+ await setupTooluPermissionHook(ctx, {
137
+ repoRoot,
138
+ projectRoot,
139
+ env,
140
+ });
141
+ },
142
+ });
@@ -0,0 +1,20 @@
1
+ import { expect, test } from "bun:test";
2
+ import { mkdtempSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { runPreflight } from "../check.ts";
5
+
6
+ const tmpBase = process.env.TMPDIR ?? "/tmp";
7
+
8
+ test("preflight reports bash and jq when PATH is normal", () => {
9
+ const report = runPreflight();
10
+ expect(report.entries.find((e) => e.tool === "bash")?.present).toBe(true);
11
+ expect(report.entries.find((e) => e.tool === "jq")?.present).toBe(true);
12
+ expect(report.bootstrapAllowed).toBe(true);
13
+ });
14
+
15
+ test("preflight fail closed when jq is not on PATH", () => {
16
+ const emptyPath = mkdtempSync(join(tmpBase, "toolu-pf-path-"));
17
+ const report = runPreflight({ env: { PATH: emptyPath } });
18
+ expect(report.bootstrapAllowed).toBe(false);
19
+ expect(report.reasons.some((r) => r.includes("jq"))).toBe(true);
20
+ });
@@ -0,0 +1,75 @@
1
+ /** Prerequisite probe for OpenCode bootstrap (#211). */
2
+ import { statSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ export type PreflightTool = "bash" | "jq" | "git" | "bun" | "opencode";
6
+
7
+ export type PreflightEntry = {
8
+ tool: PreflightTool;
9
+ present: boolean;
10
+ detail?: string;
11
+ };
12
+
13
+ export type PreflightReport = {
14
+ entries: PreflightEntry[];
15
+ bootstrapAllowed: boolean;
16
+ reasons: string[];
17
+ };
18
+
19
+ const REQUIRED_FOR_BOOTSTRAP: PreflightTool[] = ["bash", "jq"];
20
+
21
+ const ALLOWED_BINARY = /^[A-Za-z0-9._+-]+$/;
22
+
23
+ /** PATH lookup without shell — binary must be a simple tool name. */
24
+ function commandPresent(binary: string, env: Record<string, string>): boolean {
25
+ if (!ALLOWED_BINARY.test(binary)) {
26
+ return false;
27
+ }
28
+ const pathEnv = env.PATH ?? process.env.PATH ?? "";
29
+ for (const dir of pathEnv.split(":")) {
30
+ if (dir.length === 0) {
31
+ continue;
32
+ }
33
+ const candidate = join(dir, binary);
34
+ try {
35
+ if (statSync(candidate).isFile()) {
36
+ return true;
37
+ }
38
+ } catch {
39
+ continue;
40
+ }
41
+ }
42
+ return false;
43
+ }
44
+
45
+ /** Structured prerequisite report; missing bash/jq fail closed for bootstrap. */
46
+ function stringEnv(source: NodeJS.ProcessEnv): Record<string, string> {
47
+ const out: Record<string, string> = {};
48
+ for (const [key, value] of Object.entries(source)) {
49
+ if (value !== undefined) {
50
+ out[key] = value;
51
+ }
52
+ }
53
+ return out;
54
+ }
55
+
56
+ export function runPreflight(options?: { env?: Record<string, string> }): PreflightReport {
57
+ const env = { ...stringEnv(process.env), ...options?.env };
58
+ const tools: PreflightTool[] = ["bash", "jq", "git", "bun", "opencode"];
59
+ const entries: PreflightEntry[] = tools.map((tool) => ({
60
+ tool,
61
+ present: commandPresent(tool, env),
62
+ }));
63
+ const reasons: string[] = [];
64
+ for (const required of REQUIRED_FOR_BOOTSTRAP) {
65
+ const entry = entries.find((e) => e.tool === required);
66
+ if (entry && !entry.present) {
67
+ reasons.push(`missing required tool: ${required}`);
68
+ }
69
+ }
70
+ return {
71
+ entries,
72
+ bootstrapAllowed: reasons.length === 0,
73
+ reasons,
74
+ };
75
+ }
@@ -0,0 +1,2 @@
1
+ export { runPreflight } from "./check.ts";
2
+ export type { PreflightEntry, PreflightReport, PreflightTool } from "./check.ts";
@@ -0,0 +1,52 @@
1
+ import { expect, test } from "bun:test";
2
+ import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { selectPluginsWithDependencies } from "../resolve.ts";
5
+ import { opencodePluginSelectionPath } from "../../host/roots.ts";
6
+
7
+ const tmpBase = process.env.TMPDIR ?? "/tmp";
8
+
9
+ function writeManifest(
10
+ pluginsRoot: string,
11
+ name: string,
12
+ dependencies: Array<{ name: string; marketplace: string }> = [],
13
+ ): void {
14
+ const dir = join(pluginsRoot, name, ".claude-plugin");
15
+ mkdirSync(dir, { recursive: true });
16
+ writeFileSync(join(dir, "plugin.json"), JSON.stringify({ name, version: "1.0.0", dependencies }));
17
+ }
18
+
19
+ test("select fails closed on missing dependency", () => {
20
+ const project = mkdtempSync(join(tmpBase, "toolu-sel-proj-"));
21
+ const pluginsRoot = mkdtempSync(join(tmpBase, "toolu-sel-pl-"));
22
+ writeManifest(pluginsRoot, "ts-quality", [{ name: "toolu", marketplace: "toolu" }]);
23
+ mkdirSync(join(project, ".opencode", "toolu"), { recursive: true });
24
+ writeFileSync(
25
+ opencodePluginSelectionPath(project),
26
+ JSON.stringify({ version: 1, enabled: ["ts-quality"] }),
27
+ );
28
+ const result = selectPluginsWithDependencies(pluginsRoot, project);
29
+ expect(result.ok).toBe(false);
30
+ if (result.ok) {
31
+ return;
32
+ }
33
+ expect(result.missingDependency).toBe("toolu");
34
+ });
35
+
36
+ test("select includes dependency closure", () => {
37
+ const project = mkdtempSync(join(tmpBase, "toolu-sel-cl-"));
38
+ const pluginsRoot = mkdtempSync(join(tmpBase, "toolu-sel-cl-pl-"));
39
+ writeManifest(pluginsRoot, "toolu");
40
+ writeManifest(pluginsRoot, "ts-quality", [{ name: "toolu", marketplace: "toolu" }]);
41
+ mkdirSync(join(project, ".opencode", "toolu"), { recursive: true });
42
+ writeFileSync(
43
+ opencodePluginSelectionPath(project),
44
+ JSON.stringify({ version: 1, enabled: ["ts-quality"] }),
45
+ );
46
+ const result = selectPluginsWithDependencies(pluginsRoot, project);
47
+ expect(result.ok).toBe(true);
48
+ if (!result.ok) {
49
+ return;
50
+ }
51
+ expect(result.plugins.map((p) => p.name).toSorted()).toEqual(["toolu", "ts-quality"]);
52
+ });
@@ -0,0 +1,2 @@
1
+ export { selectPluginsByEnabledNames, selectPluginsWithDependencies } from "./resolve.ts";
2
+ export type { SelectResult } from "./resolve.ts";
@@ -0,0 +1,87 @@
1
+ /** Enabled plugin set + dependency closure (#211). */
2
+ import { pluginSpec } from "../inventory/manifest.ts";
3
+ import { listPluginManifests } from "../inventory/scan.ts";
4
+ import { resolveEnabledPluginNames } from "../inventory/selection.ts";
5
+ import type { PluginManifest } from "../inventory/types.ts";
6
+
7
+ export type SelectResult =
8
+ | { ok: true; plugins: PluginManifest[] }
9
+ | { ok: false; reason: string; missingDependency?: string };
10
+
11
+ function manifestByName(manifests: PluginManifest[]): Map<string, PluginManifest> {
12
+ const map = new Map<string, PluginManifest>();
13
+ for (const m of manifests) {
14
+ map.set(m.name, m);
15
+ }
16
+ return map;
17
+ }
18
+
19
+ function closePluginDependencies(
20
+ pluginsRoot: string,
21
+ byName: Map<string, PluginManifest>,
22
+ seedNames: Iterable<string>,
23
+ ): SelectResult {
24
+ const queue = [...seedNames];
25
+ const selected = new Set<string>();
26
+ const ordered: PluginManifest[] = [];
27
+
28
+ while (queue.length > 0) {
29
+ const name = queue.shift();
30
+ if (!name || selected.has(name)) {
31
+ continue;
32
+ }
33
+ const manifest = byName.get(name);
34
+ if (!manifest) {
35
+ return {
36
+ ok: false,
37
+ reason: `enabled plugin "${name}" is not installed under ${pluginsRoot}`,
38
+ missingDependency: name,
39
+ };
40
+ }
41
+ selected.add(name);
42
+ ordered.push(manifest);
43
+ for (const dep of manifest.dependencies) {
44
+ if (!byName.has(dep.name)) {
45
+ return {
46
+ ok: false,
47
+ reason: `plugin "${manifest.spec}" requires missing dependency ${pluginSpec(dep.name, dep.marketplace)}`,
48
+ missingDependency: dep.name,
49
+ };
50
+ }
51
+ if (!selected.has(dep.name)) {
52
+ queue.push(dep.name);
53
+ }
54
+ }
55
+ }
56
+
57
+ return { ok: true, plugins: ordered };
58
+ }
59
+
60
+ /** Resolve enabled plugins and transitive manifest dependencies. */
61
+ export function selectPluginsWithDependencies(
62
+ pluginsRoot: string,
63
+ projectRoot: string,
64
+ ): SelectResult {
65
+ const enabledResult = resolveEnabledPluginNames(pluginsRoot, projectRoot);
66
+ if (!enabledResult.ok) {
67
+ return { ok: false, reason: enabledResult.reason };
68
+ }
69
+
70
+ const allManifests = listPluginManifests(pluginsRoot);
71
+ if (allManifests === null) {
72
+ return { ok: false, reason: `cannot read plugins root: ${pluginsRoot}` };
73
+ }
74
+ return closePluginDependencies(pluginsRoot, manifestByName(allManifests), enabledResult.enabled);
75
+ }
76
+
77
+ /** Resolve an explicit enabled list plus manifest dependency closure (#211). */
78
+ export function selectPluginsByEnabledNames(
79
+ pluginsRoot: string,
80
+ enabledNames: readonly string[],
81
+ ): SelectResult {
82
+ const allManifests = listPluginManifests(pluginsRoot);
83
+ if (allManifests === null) {
84
+ return { ok: false, reason: `cannot read plugins root: ${pluginsRoot}` };
85
+ }
86
+ return closePluginDependencies(pluginsRoot, manifestByName(allManifests), enabledNames);
87
+ }