@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,198 @@
1
+ # Jev problem-solving patterns
2
+
3
+ Load Setup + the matching example only. Evidence → focused judgment → next action.
4
+ Reassess changed inputs; reuse unchanged evidence/questions/criteria across stages.
5
+ Synthetic scenarios; replace observations with actual evidence in real work.
6
+
7
+ Sources: TypeSafe [semantic search](https://docs.typesafe.ai/cookbooks/semantic_find.md)
8
+ (separate ranking/existence), [citation checking](https://docs.typesafe.ai/cookbooks/citation_check.md)
9
+ (exact quote check before context judgment), [batching](https://docs.typesafe.ai/patterns/fan-out.md)
10
+ (independent questions, shared state). Evaluation only: [record](../evals/README.md).
11
+
12
+ ## Setup and failure handling
13
+
14
+ Run setup + selected example in one Bash shell. Requires `curl`, `jq`, environment
15
+ `TYPESAFE_API_KEY`; never read `.env`.
16
+
17
+ ```bash
18
+ # Codex (for Claude Code use the second line instead):
19
+ JEV="${TOOLU_CONFIG_DIR:-${CODEX_HOME:-$HOME/.codex}}/jev/jev.sh"
20
+ # JEV="${TOOLU_CONFIG_DIR:-${CLAUDE_CONFIG_DIR:-$HOME/.claude}}/jev/jev.sh"
21
+ # Repository development, from the repository root, if not installed:
22
+ if [ ! -x "$JEV" ]; then JEV="$PWD/plugins/jev/skills/jev/scripts/jev.sh"; fi
23
+ JEV_EXAMPLES=$(mktemp -d)
24
+
25
+ judge() {
26
+ local name="$1"
27
+ if "$JEV" ask "$JEV_EXAMPLES/$name.questions.json" \
28
+ -s "@$JEV_EXAMPLES/$name.state.json" --raw >"$JEV_EXAMPLES/$name.result.json"; then
29
+ jq '.answers' "$JEV_EXAMPLES/$name.result.json"
30
+ else
31
+ rm -f "$JEV_EXAMPLES/$name.result.json"
32
+ printf '%s\n' "Jev unavailable for $name; inspect the named evidence and apply the rubric manually." >&2
33
+ return 1
34
+ fi
35
+ }
36
+ ```
37
+
38
+ Failure → apply the example's rubric manually. Missing output is not a negative
39
+ judgment. Uncertain/conflicting distributions → inspect source, gather evidence,
40
+ or narrow question. No universal thresholds. Confidence is concentration, not
41
+ correctness. Retain raw model/usage for evaluation; never credentials.
42
+
43
+ ## Search: rank excerpts and detect no answer
44
+
45
+ Named retrieved excerpts: access/restoration and billing. Neither states retention.
46
+
47
+ ```bash
48
+ cat > "$JEV_EXAMPLES/search.state.json" <<'JSON'
49
+ {
50
+ "query": "How long are deleted project backups retained?",
51
+ "excerpts": {
52
+ "access": {"source": "docs/access.md", "text": "Administrators may restore a deleted project from a backup."},
53
+ "billing": {"source": "docs/billing.md", "text": "Invoices are emailed to the billing contact every month."}
54
+ }
55
+ }
56
+ JSON
57
+ cat > "$JEV_EXAMPLES/search.questions.json" <<'JSON'
58
+ {
59
+ "exists": {
60
+ "type": "noul",
61
+ "instructions": "Do the supplied `excerpts` contain an answer to `query`, including its requested retention duration?",
62
+ "criteria": {"true": "The duration is stated or unambiguously implied in the excerpts.", "false": "The excerpts omit the duration, even if they discuss backups or restoration."}
63
+ },
64
+ "access_relevance": {
65
+ "type": "score",
66
+ "instructions": "How well does `excerpts.access.text` answer `query`? Use only this excerpt.",
67
+ "criteria": ["Unrelated to deleted project backups.", "Discusses backups or restoration but omits the requested duration.", "Supplies the requested backup retention duration."]
68
+ },
69
+ "billing_relevance": {
70
+ "type": "score",
71
+ "instructions": "How well does `excerpts.billing.text` answer `query`? Use only this excerpt.",
72
+ "criteria": ["Unrelated to deleted project backups.", "Discusses backups or restoration but omits the requested duration.", "Supplies the requested backup retention duration."]
73
+ }
74
+ }
75
+ JSON
76
+ judge search
77
+ ```
78
+
79
+ Interpret: sort comparable Scores in code; inspect legend/distribution. A top
80
+ rank can still be incomplete. Choice probabilities are relative, not graded
81
+ relevance. Here, access ranks first but existence should be negative.
82
+ Next: retrieve retention policy; never infer retention from billing frequency.
83
+ Uncertain → inspect surrounding source/refine retrieval. API failure → manually
84
+ confirm missing duration, then retrieve policy.
85
+
86
+ ## Debugging: prioritize an experiment, then reassess
87
+
88
+ Supplied observations + hypotheses + experiments. Judgments prioritize tests;
89
+ they do not prove causes.
90
+
91
+ ```bash
92
+ cat > "$JEV_EXAMPLES/debug.state.json" <<'JSON'
93
+ {
94
+ "observations": {"cold": "A fresh profile renders the current label.", "warm": "An existing profile still renders the old label after refresh."},
95
+ "hypotheses": {"cache": "A browser cache is serving stale assets.", "server": "The server serves an old build to every profile."},
96
+ "experiments": {"cache": "Disable the browser cache in the affected profile and reload.", "server": "Compare the deployed asset hash against the build artifact."}
97
+ }
98
+ JSON
99
+ cat > "$JEV_EXAMPLES/debug.questions.json" <<'JSON'
100
+ {
101
+ "next": {
102
+ "type": "choice",
103
+ "instructions": "Which supplied hypothesis best fits all `observations` and should have its `experiments` entry tried next? This is experiment prioritization, not proof of a cause.",
104
+ "criteria": {"cache": "The profile-dependent behavior favors stale browser assets.", "server": "The observations favor the same old deployment affecting all profiles.", "insufficient": "Neither hypothesis explains the observations, or evidence cannot distinguish them."}
105
+ }
106
+ }
107
+ JSON
108
+ judge debug
109
+
110
+ # Synthetic result of running the cache experiment; in real work supply actual output.
111
+ jq '.observations += {"cache_disabled": "Old label persists with browser cache disabled.", "network": "Both profiles receive identical current assets.", "storage": "Only the affected profile has a saved label override in local storage."}' \
112
+ "$JEV_EXAMPLES/debug.state.json" > "$JEV_EXAMPLES/debug-next.state.json"
113
+ cp "$JEV_EXAMPLES/debug.questions.json" "$JEV_EXAMPLES/debug-next.questions.json"
114
+ judge debug-next
115
+ ```
116
+
117
+ Interpret: first judgment prioritizes the cache experiment. New observations
118
+ invalidate reuse; second should select `insufficient`. Next: test a local-storage
119
+ hypothesis by removing/restoring only the saved override in a disposable profile.
120
+ Confirm through reproduction before fixing. Cache still selected → inspect
121
+ contradictory evidence, revise candidates. Uncertainty/API failure → choose the
122
+ discriminating experiment from explicit evidence, without claiming certainty.
123
+
124
+ ## Planning: compare approaches against separate preferences
125
+
126
+ Named alternatives + separate preferences → independent questions, one batch.
127
+
128
+ ```bash
129
+ cat > "$JEV_EXAMPLES/plan.state.json" <<'JSON'
130
+ {
131
+ "preferences": {"delivery": "Ship a working export this week.", "operations": "Avoid operating a new service."},
132
+ "approaches": {"worker": "Use the existing job worker and database; estimated two days of implementation.", "service": "Build and deploy a dedicated export service; estimated two weeks plus new monitoring."}
133
+ }
134
+ JSON
135
+ cat > "$JEV_EXAMPLES/plan.questions.json" <<'JSON'
136
+ {
137
+ "delivery": {
138
+ "type": "choice",
139
+ "instructions": "Which approach in `approaches` best fits `preferences.delivery`, taking the supplied estimates as assumptions rather than verified facts?",
140
+ "criteria": {"worker": "The existing worker approach better meets the delivery preference.", "service": "The dedicated service approach better meets the delivery preference.", "neither": "Neither approach meets it, or the supplied information cannot distinguish them."}
141
+ },
142
+ "operations": {
143
+ "type": "choice",
144
+ "instructions": "Which approach in `approaches` best fits `preferences.operations`?",
145
+ "criteria": {"worker": "The existing worker approach better meets the operations preference.", "service": "The dedicated service approach better meets the operations preference.", "neither": "Neither approach meets it, or the supplied information cannot distinguish them."}
146
+ }
147
+ }
148
+ JSON
149
+ judge plan
150
+ ```
151
+
152
+ Interpret: worker fits both supplied preferences. Next: verify worker capacity,
153
+ retry semantics, and export requirements; Jev cannot validate estimates or
154
+ feasibility. Conflicting preferences/`neither`/uncertainty → inspect tradeoffs or
155
+ missing requirements. Reuse unchanged results at review; changed capacity →
156
+ reassess affected questions. API failure → manually compare each preference and
157
+ retain the technical checks.
158
+
159
+ ## Review: support, contradiction, or unsupported claim
160
+
161
+ Named policy source + quote + claim. Check quote presence with code, then context.
162
+
163
+ ```bash
164
+ cat > "$JEV_EXAMPLES/review.state.json" <<'JSON'
165
+ {
166
+ "source": {"path": "docs/export-policy.md", "text": "Admins may request exports. Members cannot request exports; ask an admin to submit the request."},
167
+ "quote": "Members cannot request exports",
168
+ "claim": "Members may request exports directly."
169
+ }
170
+ JSON
171
+ cat > "$JEV_EXAMPLES/review.questions.json" <<'JSON'
172
+ {
173
+ "relation": {
174
+ "type": "choice",
175
+ "instructions": "How does `source.text`, read in full context, relate to `claim`? Use only the supplied source, not outside knowledge.",
176
+ "criteria": {"supports": "The source establishes the claim as stated, including its scope and qualifications.", "contradicts": "The source states something incompatible with the claim.", "unsupported": "The source neither establishes nor contradicts the claim, or lacks the context needed to decide."}
177
+ }
178
+ }
179
+ JSON
180
+ if jq -e '.quote as $quote | .source.text | contains($quote)' \
181
+ "$JEV_EXAMPLES/review.state.json" >/dev/null; then
182
+ judge review
183
+ else
184
+ printf '%s\n' 'Quote absent: fetch the source and repair the citation before semantic review.' >&2
185
+ fi
186
+ ```
187
+
188
+ Interpret: `contradicts` → correct claim and cite full passage. `unsupported` →
189
+ retrieve evidence, qualify, or drop claim; unsupported does not mean false.
190
+ `supports` concerns this excerpt, not source truth/currency. Next: verify provenance
191
+ and product behavior with tools. Uncertain/API failure → read full passage and
192
+ record explicit reasoning; never fabricate a Jev verdict.
193
+
194
+ Clean up after retaining evaluation notes:
195
+
196
+ ```bash
197
+ rm -rf "$JEV_EXAMPLES"
198
+ ```
@@ -0,0 +1,405 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # jev — typed judgments from TypeSafe's System One API.
5
+ # Usage: ./jev.sh <command> [options]
6
+ #
7
+ # Reads TYPESAFE_API_KEY from the environment (never from .env).
8
+
9
+ command -v jq >/dev/null 2>&1 || { echo "jev: jq required" >&2; exit 1; }
10
+ command -v curl >/dev/null 2>&1 || { echo "jev: curl required" >&2; exit 1; }
11
+
12
+ JEV_URL="https://api.typesafe.ai/v1/systemone"
13
+ DEFAULT_MODEL="jev-latest"
14
+
15
+ # One check covers both unset and empty; the inline default keeps `set -u`
16
+ # from aborting before the message can print.
17
+ if [[ -z "${TYPESAFE_API_KEY:-}" ]]; then
18
+ echo "jev: TYPESAFE_API_KEY unset" >&2
19
+ exit 1
20
+ fi
21
+ if [[ "$TYPESAFE_API_KEY" == *$'\r'* || "$TYPESAFE_API_KEY" == *$'\n'* ]]; then
22
+ echo "jev: TYPESAFE_API_KEY must not contain line breaks" >&2
23
+ exit 1
24
+ fi
25
+
26
+ die() { echo "jev: $1" >&2; exit 1; }
27
+
28
+ usage() {
29
+ cat >&2 <<'EOF'
30
+ jev.sh <command> [options]
31
+
32
+ Commands:
33
+ noul <instructions> Yes/no judgment -> probability of yes
34
+ choice <instructions> Pick one option -> choice + probabilities + confidence
35
+ score <instructions> Rate on ordered levels -> score + legend + confidence
36
+ ask <questions-json> Many typed questions in ONE call (file path, or - for stdin)
37
+
38
+ Shared options:
39
+ -s, --state VALUE State to judge: literal text, @FILE, or - for stdin [required]
40
+ -m, --model NAME Model (default: jev-latest)
41
+ --id NAME Question id in the answer map (default: q)
42
+ --raw Print the whole response body instead of just .answers
43
+
44
+ noul: --true DESC / --false DESC what a yes / a no means
45
+ choice: -o, --option KEY=DESC repeatable, 2..255 (bare -o KEY sends no description)
46
+ score: -l, --level DESC repeatable, 2..10, lowest level first
47
+ EOF
48
+ exit 1
49
+ }
50
+
51
+ # Shared option state.
52
+ STATE_RAW=""
53
+ STATE_SET=false
54
+ STATE_FROM_STDIN=false
55
+ MODEL="$DEFAULT_MODEL"
56
+ QID="q"
57
+ RAW=false
58
+ INSTRUCTIONS=""
59
+
60
+ # state_json -> the JSON value for the request's `state` field.
61
+ # A literal string stays a string. @FILE and - are sent as structured JSON only
62
+ # when they parse as an object or an array; anything else (including a bare
63
+ # JSON scalar such as 123) is sent as a string.
64
+ state_json() {
65
+ local text file
66
+ case "$STATE_RAW" in
67
+ -)
68
+ text="$(cat)"
69
+ ;;
70
+ @*)
71
+ file="${STATE_RAW#@}"
72
+ [[ -r "$file" ]] || die "cannot read $file"
73
+ text="$(cat "$file")"
74
+ ;;
75
+ *)
76
+ printf '%s' "$STATE_RAW" | jq -Rs '.'
77
+ return
78
+ ;;
79
+ esac
80
+ if printf '%s' "$text" | jq -se 'length == 1 and (.[0] | type == "object" or type == "array")' >/dev/null 2>&1; then
81
+ printf '%s' "$text" | jq -c '.'
82
+ else
83
+ printf '%s' "$text" | jq -Rs '.'
84
+ fi
85
+ }
86
+
87
+ # claim_stdin — only one option may read stdin per invocation.
88
+ claim_stdin() {
89
+ [[ "$STATE_FROM_STDIN" == true ]] && die "only one option can read stdin"
90
+ STATE_FROM_STDIN=true
91
+ }
92
+
93
+ # parse_shared OPTION ARG... -> RETURNS the consumed-arg count (0 = unrecognized).
94
+ # Callers must invoke it as `consumed=0; parse_shared "$@" || consumed=$?` so the
95
+ # non-zero count is read as data instead of tripping `set -e`.
96
+ parse_shared() {
97
+ case "$1" in
98
+ -s|--state)
99
+ [[ $# -ge 2 ]] || die "--state needs a value"
100
+ STATE_RAW="$2"; STATE_SET=true
101
+ [[ "$2" == "-" ]] && claim_stdin
102
+ return 2;;
103
+ -m|--model)
104
+ [[ $# -ge 2 ]] || die "--model needs a value"
105
+ MODEL="$2"; return 2;;
106
+ --id)
107
+ [[ $# -ge 2 ]] || die "--id needs a value"
108
+ QID="$2"; return 2;;
109
+ --raw)
110
+ RAW=true; return 1;;
111
+ esac
112
+ return 0
113
+ }
114
+
115
+ require_state() { [[ "$STATE_SET" == true ]] || die "--state is required"; }
116
+ require_instructions() { [[ -n "$INSTRUCTIONS" ]] || usage; }
117
+
118
+ jev_post() (
119
+ local request="$1" tmp code status attempt delay retry_after
120
+ umask 077
121
+ tmp=$(mktemp -d "${TMPDIR:-/tmp}/jev.XXXXXXXX") || return 1
122
+ trap 'rm -rf "$tmp"' EXIT
123
+ # Keep the key out of process arguments; the private directory is removed on exit.
124
+ printf 'Authorization: Bearer %s\n' "$TYPESAFE_API_KEY" > "$tmp/auth-header"
125
+ for attempt in 1 2 3; do
126
+ status=0
127
+ code=$(printf '%s' "$request" | curl -sS \
128
+ --max-time "${JEV_TIMEOUT:-60}" \
129
+ --output "$tmp/body" --dump-header "$tmp/headers" --write-out '%{http_code}' \
130
+ -X POST "$JEV_URL" \
131
+ -H "@$tmp/auth-header" \
132
+ -H "Content-Type: application/json" -H "Accept: application/json" \
133
+ --data-binary @- 2>"$tmp/error") || status=$?
134
+ if [[ "$status" -eq 0 && "$code" == 2* ]]; then
135
+ cat "$tmp/body"
136
+ return 0
137
+ fi
138
+ # Same retry set as TypeSafe's SDK default policy: HTTP 408, 429, every
139
+ # 5xx (which covers the documented 529 overload), timeouts, and connection
140
+ # errors. curl's own --retry omits 529, so the loop lives here. Separate
141
+ # attempt bodies so transient errors never become answer JSON.
142
+ delay=$((1 << (attempt - 1)))
143
+ # Retry-After (seconds) wins over retry-after-ms (milliseconds, rounded up);
144
+ # both are documented SDK-honored headers. Waits over 60s surface the error.
145
+ retry_after=$(awk 'tolower($1) == "retry-after:" {gsub("\r", "", $2); print $2}' "$tmp/headers")
146
+ if [[ ! "$retry_after" =~ ^[0-9]+$ ]]; then
147
+ retry_after=$(awk 'tolower($1) == "retry-after-ms:" {gsub("\r", "", $2); print $2}' "$tmp/headers")
148
+ if [[ "$retry_after" =~ ^[0-9]+$ ]]; then
149
+ # More than 8 digits is already past the 60s ceiling; skip the arithmetic
150
+ # so an absurd header cannot overflow into a negative delay.
151
+ if [[ ${#retry_after} -gt 8 ]]; then
152
+ retry_after=61
153
+ else
154
+ retry_after=$(( (10#$retry_after + 999) / 1000 ))
155
+ fi
156
+ else
157
+ retry_after=""
158
+ fi
159
+ fi
160
+ if [[ "$retry_after" =~ ^[0-9]+$ ]]; then
161
+ if [[ ${#retry_after} -gt 2 ]] || ((10#$retry_after > 60)); then
162
+ break
163
+ fi
164
+ ((10#$retry_after <= delay)) || delay=$((10#$retry_after))
165
+ fi
166
+ [[ "$attempt" -lt 3 ]] || break
167
+ # $code is curl's %{http_code}: three digits, or 000 when no status line
168
+ # arrived (retried as a connection error whatever the exit status).
169
+ # Connection-level failures carry curl's own exit status instead:
170
+ # 7 (connect), 28 (timeout), 35 (TLS handshake), 52 (empty reply),
171
+ # 55 (send), 56 (receive) — the SDK retries these as connection errors.
172
+ case "$status:$code" in
173
+ 0:408|0:429|0:5[0-9][0-9]|0:000|7:*|28:*|35:*|52:*|55:*|56:*) sleep "$delay";;
174
+ *) break;;
175
+ esac
176
+ done
177
+ [[ ! -s "$tmp/error" ]] || cat "$tmp/error" >&2
178
+ [[ ! -s "$tmp/body" ]] || cat "$tmp/body" >&2
179
+ [[ "$status" -ne 0 ]] || status=22
180
+ return "$status"
181
+ )
182
+
183
+ # evaluate QUESTIONS_JSON — send the request and print the answers.
184
+ # An HTTP failure propagates: the API's error body goes to stderr and the exit
185
+ # status is curl's own (22 for an error response, 28 for a timeout).
186
+ evaluate() {
187
+ local questions="$1" state body out status
188
+ # Resolved in its own statement: a failure inside state_json exits the command
189
+ # substitution's subshell, and only an explicit check propagates that here.
190
+ state="$(state_json)" || exit $?
191
+ body=$(printf '%s\n%s\n' "$state" "$questions" | jq -sc --arg model "$MODEL" \
192
+ '{state: .[0], model: $model, questions: .[1]}')
193
+
194
+ set +e
195
+ out="$(jev_post "$body")"
196
+ status=$?
197
+ set -e
198
+ if [[ "$status" -ne 0 ]]; then
199
+ [[ -n "$out" ]] && printf '%s\n' "$out" >&2
200
+ exit "$status"
201
+ fi
202
+
203
+ # Never let a malformed success response be consumed as a false/no judgment.
204
+ printf '%s\n%s\n' "$questions" "$out" | jq -se '
205
+ def probability: type == "number" and . >= 0 and . <= 1;
206
+ def tokens: type == "number" and . >= 0 and . == floor;
207
+ def distribution($keys):
208
+ type == "object" and keys == ($keys | sort) and
209
+ all(.[]; probability) and (([.[]] | add) - 1 | fabs) < 0.000001;
210
+ length == 2 and
211
+ (.[0] as $questions | .[1] as $response | $response.answers as $answers |
212
+ ($response.model | type == "string" and length > 0) and
213
+ ($response.usage.input_tokens | tokens) and ($response.usage.output_tokens | tokens) and
214
+ ($answers | type == "object") and
215
+ (($questions | keys) == ($answers | keys)) and
216
+ all($questions | to_entries[];
217
+ . as $q | $answers[$q.key] as $a |
218
+ $a.type == $q.value.type and
219
+ if $a.type == "noul" then ($a.noul | probability)
220
+ elif $a.type == "choice" then
221
+ ($a.confidence | probability) and
222
+ ($a.probabilities | distribution($q.value.criteria | keys)) and
223
+ ($q.value.criteria | has($a.choice))
224
+ elif $a.type == "score" then
225
+ [range($q.value.criteria | length) | tostring] as $levels |
226
+ ($a.confidence | probability) and ($a.score | type == "number") and
227
+ $a.score >= 0 and $a.score <= ($q.value.criteria | length) - 1 and
228
+ ($a.legend | type == "object" and keys == ($levels | sort)) and
229
+ ($a.probabilities | distribution($levels))
230
+ else false end))
231
+ ' >/dev/null 2>&1 || die "invalid response: expected a typed answer for every question"
232
+
233
+ if [[ "$RAW" == true ]]; then
234
+ printf '%s\n' "$out" | jq '.'
235
+ else
236
+ printf '%s\n' "$out" | jq -c '.answers'
237
+ fi
238
+ }
239
+
240
+ # ── noul ────────────────────────────────────────────────────
241
+ cmd_noul() {
242
+ local true_desc="" false_desc="" consumed
243
+
244
+ while [[ $# -gt 0 ]]; do
245
+ consumed=0
246
+ parse_shared "$@" || consumed=$?
247
+ if [[ "$consumed" -gt 0 ]]; then shift "$consumed"; continue; fi
248
+ case "$1" in
249
+ --true) [[ $# -ge 2 ]] || die "--true needs a value"
250
+ true_desc="$2"; shift 2;;
251
+ --false) [[ $# -ge 2 ]] || die "--false needs a value"
252
+ false_desc="$2"; shift 2;;
253
+ -*) die "unknown option: $1";;
254
+ *) [[ -z "$INSTRUCTIONS" ]] || die "unexpected argument: $1"
255
+ INSTRUCTIONS="$1"; shift;;
256
+ esac
257
+ done
258
+
259
+ require_instructions
260
+ require_state
261
+
262
+ # criteria carries only the side(s) actually described, and is omitted
263
+ # entirely when neither was.
264
+ local question
265
+ question=$(jq -nc \
266
+ --arg id "$QID" \
267
+ --arg instructions "$INSTRUCTIONS" \
268
+ --arg t "$true_desc" \
269
+ --arg f "$false_desc" \
270
+ '((if $t == "" then {} else {"true": $t} end)
271
+ + (if $f == "" then {} else {"false": $f} end)) as $criteria
272
+ | {($id): ({type: "noul", instructions: $instructions}
273
+ + (if ($criteria | length) > 0 then {criteria: $criteria} else {} end))}')
274
+ evaluate "$question"
275
+ }
276
+
277
+ # ── choice ──────────────────────────────────────────────────
278
+ cmd_choice() {
279
+ local criteria='{}' consumed key desc
280
+
281
+ while [[ $# -gt 0 ]]; do
282
+ consumed=0
283
+ parse_shared "$@" || consumed=$?
284
+ if [[ "$consumed" -gt 0 ]]; then shift "$consumed"; continue; fi
285
+ case "$1" in
286
+ -o|--option)
287
+ [[ $# -ge 2 ]] || die "--option needs a value"
288
+ key="${2%%=*}"
289
+ [[ -n "$key" ]] || die "--option needs a KEY (KEY=DESCRIPTION)"
290
+ # A bare KEY sends null — the API's documented "no extra detail" form.
291
+ # A repeated KEY keeps its original position and takes the last value.
292
+ if [[ "$2" == *=* ]]; then
293
+ desc="${2#*=}"
294
+ criteria=$(jq -c --arg k "$key" --arg d "$desc" '. + {($k): $d}' <<<"$criteria")
295
+ else
296
+ criteria=$(jq -c --arg k "$key" '. + {($k): null}' <<<"$criteria")
297
+ fi
298
+ shift 2;;
299
+ -*) die "unknown option: $1";;
300
+ *) [[ -z "$INSTRUCTIONS" ]] || die "unexpected argument: $1"
301
+ INSTRUCTIONS="$1"; shift;;
302
+ esac
303
+ done
304
+
305
+ require_instructions
306
+ require_state
307
+ [[ "$(jq 'length' <<<"$criteria")" -ge 2 ]] || die "choice needs at least 2 options"
308
+ # The API accepts up to 255 options per Choice.
309
+ [[ "$(jq 'length' <<<"$criteria")" -le 255 ]] || die "choice accepts at most 255 options"
310
+
311
+ local question
312
+ question=$(jq -nc \
313
+ --arg id "$QID" \
314
+ --arg instructions "$INSTRUCTIONS" \
315
+ --argjson criteria "$criteria" \
316
+ '{($id): {type: "choice", instructions: $instructions, criteria: $criteria}}')
317
+ evaluate "$question"
318
+ }
319
+
320
+ # ── score ───────────────────────────────────────────────────
321
+ cmd_score() {
322
+ local levels='[]' consumed
323
+
324
+ while [[ $# -gt 0 ]]; do
325
+ consumed=0
326
+ parse_shared "$@" || consumed=$?
327
+ if [[ "$consumed" -gt 0 ]]; then shift "$consumed"; continue; fi
328
+ case "$1" in
329
+ -l|--level)
330
+ [[ $# -ge 2 ]] || die "--level needs a value"
331
+ # Order is the rubric: levels stay in the order they were given.
332
+ levels=$(jq -c --arg l "$2" '. + [$l]' <<<"$levels")
333
+ shift 2;;
334
+ -*) die "unknown option: $1";;
335
+ *) [[ -z "$INSTRUCTIONS" ]] || die "unexpected argument: $1"
336
+ INSTRUCTIONS="$1"; shift;;
337
+ esac
338
+ done
339
+
340
+ require_instructions
341
+ require_state
342
+ [[ "$(jq 'length' <<<"$levels")" -ge 2 ]] || die "score needs at least 2 levels"
343
+ # The API accepts up to 10 levels per Score.
344
+ [[ "$(jq 'length' <<<"$levels")" -le 10 ]] || die "score accepts at most 10 levels"
345
+
346
+ local question
347
+ question=$(jq -nc \
348
+ --arg id "$QID" \
349
+ --arg instructions "$INSTRUCTIONS" \
350
+ --argjson levels "$levels" \
351
+ '{($id): {type: "score", instructions: $instructions, criteria: $levels}}')
352
+ evaluate "$question"
353
+ }
354
+
355
+ # ── ask ─────────────────────────────────────────────────────
356
+ # Many typed questions against one state, in a single request. Jev ingests the
357
+ # state once and answers every question in parallel, so this is the cheap way
358
+ # to ask several things — including speculative ones the caller may discard.
359
+ cmd_ask() {
360
+ local src="" consumed text questions
361
+
362
+ while [[ $# -gt 0 ]]; do
363
+ # ask answers under the ids in the payload, so --id would name nothing.
364
+ [[ "$1" == "--id" ]] && die "ask takes its question ids from the payload; --id does not apply"
365
+ consumed=0
366
+ parse_shared "$@" || consumed=$?
367
+ if [[ "$consumed" -gt 0 ]]; then shift "$consumed"; continue; fi
368
+ case "$1" in
369
+ # A lone dash is the stdin source, not an option.
370
+ -) [[ -z "$src" ]] || die "unexpected argument: -"
371
+ src="-"; claim_stdin; shift;;
372
+ -*) die "unknown option: $1";;
373
+ *) [[ -z "$src" ]] || die "unexpected argument: $1"
374
+ src="$1"; shift;;
375
+ esac
376
+ done
377
+
378
+ [[ -n "$src" ]] || usage
379
+ require_state
380
+
381
+ if [[ "$src" == "-" ]]; then
382
+ text="$(cat)"
383
+ else
384
+ [[ -r "$src" ]] || die "cannot read $src"
385
+ text="$(cat "$src")"
386
+ fi
387
+
388
+ questions="$(printf '%s' "$text" | jq -sc 'if length == 1 then .[0] else error("expected one questions object") end' 2>/dev/null)" || die "invalid JSON in $src"
389
+ [[ "$(jq -r 'type' <<<"$questions")" == "object" ]] || die "questions must be a JSON object"
390
+ [[ "$(jq 'length' <<<"$questions")" -ge 1 ]] || die "questions must not be empty"
391
+
392
+ evaluate "$questions"
393
+ }
394
+
395
+ # ── dispatch ────────────────────────────────────────────────
396
+ [[ $# -gt 0 ]] || usage
397
+ command="$1"; shift
398
+ case "$command" in
399
+ noul) cmd_noul "$@";;
400
+ choice) cmd_choice "$@";;
401
+ score) cmd_score "$@";;
402
+ ask) cmd_ask "$@";;
403
+ -h|--help|help) usage;;
404
+ *) echo "jev: unknown command: $command" >&2; usage;;
405
+ esac
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "jira",
3
+ "version": "6.8.0",
4
+ "description": "Jira issue search and workflow from the session via a REST wrapper (skill + bash). Cloud + Server/DC, read and safe writes. Standalone, no dependencies.",
5
+ "author": {
6
+ "name": "Falconiere Barbosa",
7
+ "email": "hello@falconiere.io"
8
+ },
9
+ "homepage": "https://github.com/falconiere/toolu",
10
+ "repository": "https://github.com/falconiere/toolu.git",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "claude-code",
14
+ "jira",
15
+ "atlassian",
16
+ "skills"
17
+ ]
18
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "jira",
3
+ "version": "6.8.0",
4
+ "description": "Jira issue search and workflow from the session via a REST wrapper (skill + bash). Cloud + Server/DC, read and safe writes. Standalone, no dependencies.",
5
+ "skills": "./skills/",
6
+ "hooks": "./hooks/hooks.json"
7
+ }
@@ -0,0 +1,42 @@
1
+ # jira
2
+
3
+ Jira issue search and workflow from the session via a REST wrapper — a skill plus bash. Cloud + Server/DC, read and safe writes.
4
+
5
+ ## Install
6
+
7
+ ```
8
+ /plugin install jira@toolu
9
+ ```
10
+
11
+ Standalone, no dependencies.
12
+
13
+ ## What it provides
14
+
15
+ - **`jira` skill** — work a ticket without leaving the session: JQL search, read/create/comment/transition/assign issues, plus boards, sprints, worklogs, projects, users, and attachments, with a `raw` verb for any endpoint. Triggers on Jira mentions, JQL, issue keys like `ABC-123`, a pasted `*.atlassian.net/browse/...` link, "create a task at Jira", "my tickets", and create/comment/transition/assign requests. **Prefer this skill over the Atlassian MCP** — it reuses your existing Jira auth and stays in-session. If you also run the toolu plugin, its `UserPromptSubmit` hook nudges the same way when a prompt mentions Jira.
16
+ - **`plan` family** — decomposes non-trivial ticket work into small, individually verifiable steps and tracks them in a ledger.
17
+
18
+ ## Plans
19
+
20
+ Read-only lookups run directly. Anything that **mutates** a ticket, or needs two or more calls, is planned first:
21
+
22
+ ```
23
+ jira.sh plan init ABC-123 # scaffold the host-native Jira plan path
24
+ jira.sh plan run <DOC> [--step <id>] # run each step's check, update the ledger
25
+ jira.sh plan status ABC-123 # summary
26
+ ```
27
+
28
+ Each step carries a `check` — a shell command that exits 0 **only when Jira itself reflects the change** (`"$JIRA" issue get ABC-123 --lean | jq -e '.status=="Done"'`). A step is green because Jira agrees, not because the agent said so. `plan run` probes Jira once before running anything, so an auth or network failure aborts instead of marking every step red.
29
+
30
+ The ledger is written to `<repo>/.claude/tmp/plan-ledger/jira-<KEY>.json` on
31
+ Claude or `<repo>/.codex/tmp/plan-ledger/jira-<KEY>.json` on Codex. It is
32
+ deliberately **not** the branch ledger: toolu's push gate only reads
33
+ `<branch-slug>.json`, so a pending Jira step can never block `git push`.
34
+
35
+ ## The Jira API
36
+
37
+ The skill drives `scripts/jira.sh`, a bash wrapper over the Jira REST API (Cloud and Server/Data Center).
38
+
39
+ - **Easiest** — if the [`jira` CLI](https://github.com/ankitpokhrel/jira-cli) is configured (`jira init`), the plugin reuses its login automatically (server + login from `~/.config/.jira/.config.yml`, token from the OS keyring). No extra setup.
40
+ - **Or set environment variables** (these always take precedence; never a `.env` file): `JIRA_BASE_URL` (required), then either `JIRA_PAT` (Bearer) or `JIRA_EMAIL` + `JIRA_API_TOKEN` (basic). Set `JIRA_API_VERSION=2` for Server/Data Center.
41
+
42
+ When nothing is configured the plugin prints a short, friendly setup prompt and exits.