@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.
- package/generated/GENERATED-NOTES.md +16 -0
- package/generated/agents/toolu--architect.md +52 -0
- package/generated/agents/toolu--deep-explore.md +65 -0
- package/generated/agents/toolu--implementer.md +50 -0
- package/generated/agents/toolu--quick-task.md +54 -0
- package/generated/agents/toolu--research-agent.md +101 -0
- package/generated/commands/toolu--commit.md +8 -0
- package/generated/commands/toolu--review-and-commit.md +8 -0
- package/generated/opencode.toolu.json +116 -0
- package/generated/skills/toolu--brainstorm/SKILL.md +57 -0
- package/generated/skills/toolu--brainstorm/references/design-questions.md +36 -0
- package/generated/skills/toolu--commit--skill/SKILL.md +11 -0
- package/generated/skills/toolu--debug/SKILL.md +54 -0
- package/generated/skills/toolu--deep-research/SKILL.md +51 -0
- package/generated/skills/toolu--execution/SKILL.md +77 -0
- package/generated/skills/toolu--orchestrator/SKILL.md +145 -0
- package/generated/skills/toolu--orchestrator/references/delegation-cost.md +104 -0
- package/generated/skills/toolu--orchestrator/references/model-routing.md +112 -0
- package/generated/skills/toolu--plan/SKILL.md +56 -0
- package/generated/skills/toolu--plan/references/ledger.md +18 -0
- package/generated/skills/toolu--plan-review/SKILL.md +48 -0
- package/generated/skills/toolu--review-and-commit--skill/SKILL.md +10 -0
- package/generated/skills/toolu--setup/SKILL.md +24 -0
- package/generated/skills/toolu--setup/scripts/setup.sh +206 -0
- package/generated/skills/toolu--spec/SKILL.md +67 -0
- package/generated/skills/toolu--spec-review/SKILL.md +50 -0
- package/generated/skills/toolu--test/SKILL.md +49 -0
- package/package.json +51 -0
- package/plugins/agent-browser/.claude-plugin/plugin.json +18 -0
- package/plugins/agent-browser/.codex-plugin/plugin.json +7 -0
- package/plugins/agent-browser/README.md +18 -0
- package/plugins/agent-browser/hooks/hooks.json +15 -0
- package/plugins/agent-browser/hooks/session-start.sh +42 -0
- package/plugins/agent-browser/skills/agent-browser/SKILL.md +77 -0
- package/plugins/agent-browser/skills/agent-browser/scripts/agent-browser.sh +80 -0
- package/plugins/ast-grep/.claude-plugin/plugin.json +18 -0
- package/plugins/ast-grep/.codex-plugin/plugin.json +7 -0
- package/plugins/ast-grep/README.md +21 -0
- package/plugins/ast-grep/hooks/hooks.json +15 -0
- package/plugins/ast-grep/hooks/post-tools.d/byte-savings.sh +67 -0
- package/plugins/ast-grep/hooks/pre-tools.d/search-nudge.sh +170 -0
- package/plugins/ast-grep/hooks/register.sh +68 -0
- package/plugins/ast-grep/scripts/byte-savings-report.sh +28 -0
- package/plugins/ast-grep/skills/ast-grep/SKILL.md +127 -0
- package/plugins/ast-grep/skills/ast-grep/references/ast-grep-advanced.md +44 -0
- package/plugins/ast-grep/skills/ast-grep/scripts/ast-grep.sh +103 -0
- package/plugins/context7/.claude-plugin/plugin.json +18 -0
- package/plugins/context7/.codex-plugin/plugin.json +7 -0
- package/plugins/context7/README.md +19 -0
- package/plugins/context7/hooks/hooks.json +15 -0
- package/plugins/context7/hooks/session-start.sh +42 -0
- package/plugins/context7/skills/context7/SKILL.md +64 -0
- package/plugins/context7/skills/context7/scripts/search.sh +151 -0
- package/plugins/exa-search/.claude-plugin/plugin.json +18 -0
- package/plugins/exa-search/.codex-plugin/plugin.json +7 -0
- package/plugins/exa-search/README.md +19 -0
- package/plugins/exa-search/hooks/hooks.json +15 -0
- package/plugins/exa-search/hooks/session-start.sh +34 -0
- package/plugins/exa-search/skills/exa-search/SKILL.md +91 -0
- package/plugins/exa-search/skills/exa-search/scripts/search.sh +221 -0
- package/plugins/jev/.claude-plugin/plugin.json +19 -0
- package/plugins/jev/.codex-plugin/plugin.json +7 -0
- package/plugins/jev/README.md +61 -0
- package/plugins/jev/hooks/hooks.json +25 -0
- package/plugins/jev/hooks/lib/common.sh +49 -0
- package/plugins/jev/hooks/session-start.sh +45 -0
- package/plugins/jev/hooks/user-prompt-submit.sh +41 -0
- package/plugins/jev/skills/jev/SKILL.md +81 -0
- package/plugins/jev/skills/jev/evals/README.md +98 -0
- package/plugins/jev/skills/jev/references/problem-solving.md +198 -0
- package/plugins/jev/skills/jev/scripts/jev.sh +405 -0
- package/plugins/jira/.claude-plugin/plugin.json +18 -0
- package/plugins/jira/.codex-plugin/plugin.json +7 -0
- package/plugins/jira/README.md +42 -0
- package/plugins/jira/hooks/hooks.json +15 -0
- package/plugins/jira/hooks/session-start.sh +34 -0
- package/plugins/jira/skills/jira/SKILL.md +123 -0
- package/plugins/jira/skills/jira/scripts/jira.sh +70 -0
- package/plugins/jira/skills/jira/scripts/lib/adf.sh +17 -0
- package/plugins/jira/skills/jira/scripts/lib/attachment.sh +94 -0
- package/plugins/jira/skills/jira/scripts/lib/board.sh +58 -0
- package/plugins/jira/skills/jira/scripts/lib/http.sh +184 -0
- package/plugins/jira/skills/jira/scripts/lib/issue.sh +159 -0
- package/plugins/jira/skills/jira/scripts/lib/paginate.sh +45 -0
- package/plugins/jira/skills/jira/scripts/lib/plan-parse.sh +70 -0
- package/plugins/jira/skills/jira/scripts/lib/plan-run.sh +115 -0
- package/plugins/jira/skills/jira/scripts/lib/plan-store.sh +168 -0
- package/plugins/jira/skills/jira/scripts/lib/plan.sh +108 -0
- package/plugins/jira/skills/jira/scripts/lib/project.sh +42 -0
- package/plugins/jira/skills/jira/scripts/lib/raw.sh +15 -0
- package/plugins/jira/skills/jira/scripts/lib/search.sh +41 -0
- package/plugins/jira/skills/jira/scripts/lib/sprint.sh +88 -0
- package/plugins/jira/skills/jira/scripts/lib/user.sh +45 -0
- package/plugins/jira/skills/jira/scripts/lib/worklog.sh +56 -0
- package/plugins/pr-babysit/.claude-plugin/plugin.json +25 -0
- package/plugins/pr-babysit/.codex-plugin/plugin.json +7 -0
- package/plugins/pr-babysit/README.md +38 -0
- package/plugins/pr-babysit/commands/babysit.md +13 -0
- package/plugins/pr-babysit/hooks/check-toolu.sh +20 -0
- package/plugins/pr-babysit/hooks/hooks.json +15 -0
- package/plugins/pr-babysit/scripts/babysit-tick.sh +133 -0
- package/plugins/pr-babysit/scripts/collect-pr.sh +224 -0
- package/plugins/pr-babysit/scripts/lib/common.sh +146 -0
- package/plugins/pr-babysit/scripts/lib/gh.sh +150 -0
- package/plugins/pr-babysit/scripts/lib/lock.sh +84 -0
- package/plugins/pr-babysit/scripts/lib/normalize.sh +98 -0
- package/plugins/pr-babysit/scripts/lib/state.sh +37 -0
- package/plugins/pr-babysit/scripts/parse-verdict.sh +171 -0
- package/plugins/pr-babysit/scripts/record.sh +69 -0
- package/plugins/pr-babysit/scripts/reduce-state.sh +245 -0
- package/plugins/pr-babysit/scripts/reply-thread.sh +90 -0
- package/plugins/pr-babysit/scripts/resolve-thread.sh +71 -0
- package/plugins/pr-babysit/skills/babysit/SKILL.md +31 -0
- package/plugins/pr-babysit/skills/babysit/references/helper.md +209 -0
- package/plugins/pr-babysit/workflows/babysit.md +722 -0
- package/plugins/python-quality/.claude-plugin/plugin.json +24 -0
- package/plugins/python-quality/.codex-plugin/plugin.json +6 -0
- package/plugins/python-quality/README.md +23 -0
- package/plugins/python-quality/hooks/check-toolu.sh +20 -0
- package/plugins/python-quality/hooks/concerns/00-preamble.sh +85 -0
- package/plugins/python-quality/hooks/concerns/10-size-file.sh +6 -0
- package/plugins/python-quality/hooks/concerns/20-tests.sh +37 -0
- package/plugins/python-quality/hooks/concerns/30-suppression.sh +33 -0
- package/plugins/python-quality/hooks/concerns/50-size-fn.sh +49 -0
- package/plugins/python-quality/hooks/concerns/70-no-mocks.sh +76 -0
- package/plugins/python-quality/hooks/concerns/90-docs.sh +52 -0
- package/plugins/python-quality/hooks/concerns/99-finalize.sh +36 -0
- package/plugins/python-quality/hooks/hooks.json +19 -0
- package/plugins/python-quality/hooks/register.sh +65 -0
- package/plugins/rust-quality/.claude-plugin/plugin.json +24 -0
- package/plugins/rust-quality/.codex-plugin/plugin.json +6 -0
- package/plugins/rust-quality/README.md +24 -0
- package/plugins/rust-quality/hooks/check-toolu.sh +20 -0
- package/plugins/rust-quality/hooks/concerns/00-preamble.sh +93 -0
- package/plugins/rust-quality/hooks/concerns/10-size-file.sh +10 -0
- package/plugins/rust-quality/hooks/concerns/20-tests.sh +84 -0
- package/plugins/rust-quality/hooks/concerns/30-suppression.sh +26 -0
- package/plugins/rust-quality/hooks/concerns/40-unsafe.sh +39 -0
- package/plugins/rust-quality/hooks/concerns/50-size-fn.sh +38 -0
- package/plugins/rust-quality/hooks/concerns/55-size-impl.sh +28 -0
- package/plugins/rust-quality/hooks/concerns/60-error-handling.sh +149 -0
- package/plugins/rust-quality/hooks/concerns/70-no-mocks.sh +139 -0
- package/plugins/rust-quality/hooks/concerns/90-docs.sh +32 -0
- package/plugins/rust-quality/hooks/concerns/99-finalize.sh +36 -0
- package/plugins/rust-quality/hooks/hooks.json +19 -0
- package/plugins/rust-quality/hooks/register.sh +65 -0
- package/plugins/statusline/.claude-plugin/plugin.json +19 -0
- package/plugins/statusline/.codex-plugin/plugin.json +7 -0
- package/plugins/statusline/README.md +108 -0
- package/plugins/statusline/commands/setup.md +30 -0
- package/plugins/statusline/hooks/hooks.json +15 -0
- package/plugins/statusline/hooks/session-start.sh +45 -0
- package/plugins/statusline/scripts/collect-status.sh +147 -0
- package/plugins/statusline/scripts/setup.sh +93 -0
- package/plugins/statusline/scripts/status.sh +55 -0
- package/plugins/statusline/skills/status/SKILL.md +13 -0
- package/plugins/statusline/statusline.sh +177 -0
- package/plugins/toolu/.claude-plugin/plugin.json +19 -0
- package/plugins/toolu/.codex-plugin/plugin.json +7 -0
- package/plugins/toolu/README.md +35 -0
- package/plugins/toolu/agents/.gitkeep +0 -0
- package/plugins/toolu/agents/architect.md +52 -0
- package/plugins/toolu/agents/deep-explore.md +65 -0
- package/plugins/toolu/agents/implementer.md +50 -0
- package/plugins/toolu/agents/quick-task.md +54 -0
- package/plugins/toolu/agents/research-agent.md +107 -0
- package/plugins/toolu/assets/agents/architect.toml +9 -0
- package/plugins/toolu/assets/agents/deep-explore.toml +9 -0
- package/plugins/toolu/assets/agents/implementer.toml +9 -0
- package/plugins/toolu/assets/agents/quick-task.toml +9 -0
- package/plugins/toolu/assets/agents/research-agent.toml +9 -0
- package/plugins/toolu/commands/.gitkeep +0 -0
- package/plugins/toolu/commands/commit.md +5 -0
- package/plugins/toolu/commands/review-and-commit.md +5 -0
- package/plugins/toolu/hooks/docs/gates.md +157 -0
- package/plugins/toolu/hooks/docs/model-routing.md +14 -0
- package/plugins/toolu/hooks/docs/post-compaction.md +3 -0
- package/plugins/toolu/hooks/docs/push-review.md +123 -0
- package/plugins/toolu/hooks/docs/session-start-python.md +3 -0
- package/plugins/toolu/hooks/docs/session-start-rust.md +4 -0
- package/plugins/toolu/hooks/docs/session-start-ts.md +3 -0
- package/plugins/toolu/hooks/docs/session-start.md +16 -0
- package/plugins/toolu/hooks/hooks.json +76 -0
- package/plugins/toolu/hooks/lib/config.sh +355 -0
- package/plugins/toolu/hooks/lib/detect.sh +929 -0
- package/plugins/toolu/hooks/lib/diff-sha.sh +32 -0
- package/plugins/toolu/hooks/lib/dispatch.sh +365 -0
- package/plugins/toolu/hooks/lib/docs-sync-config.sh +81 -0
- package/plugins/toolu/hooks/lib/edit-records.sh +157 -0
- package/plugins/toolu/hooks/lib/gate-file.sh +201 -0
- package/plugins/toolu/hooks/lib/gate-mode.sh +244 -0
- package/plugins/toolu/hooks/lib/host.sh +205 -0
- package/plugins/toolu/hooks/lib/permissions.sh +125 -0
- package/plugins/toolu/hooks/lib/plan-ledger-parse.sh +219 -0
- package/plugins/toolu/hooks/lib/plan-ledger-preflight.sh +137 -0
- package/plugins/toolu/hooks/lib/plan-ledger.sh +749 -0
- package/plugins/toolu/hooks/lib/push-waiver.sh +116 -0
- package/plugins/toolu/hooks/lib/quality-config.sh +184 -0
- package/plugins/toolu/hooks/lib/registry.sh +72 -0
- package/plugins/toolu/hooks/lib/state-sweeper.sh +194 -0
- package/plugins/toolu/hooks/lib/telemetry.sh +94 -0
- package/plugins/toolu/hooks/lib/verdict.sh +477 -0
- package/plugins/toolu/hooks/post-tools/mod.sh +42 -0
- package/plugins/toolu/hooks/post-tools/modules/gate-status.sh +140 -0
- package/plugins/toolu/hooks/post-tools/modules/push-waiver.sh +97 -0
- package/plugins/toolu/hooks/pre-compact.sh +18 -0
- package/plugins/toolu/hooks/pre-tools/agent-tier.sh +111 -0
- package/plugins/toolu/hooks/pre-tools/mod.sh +37 -0
- package/plugins/toolu/hooks/pre-tools/modules/bash-commands.sh +187 -0
- package/plugins/toolu/hooks/pre-tools/modules/code-edit-rules.sh +78 -0
- package/plugins/toolu/hooks/pre-tools/modules/commit-gate.sh +70 -0
- package/plugins/toolu/hooks/pre-tools/modules/docs-sync.sh +137 -0
- package/plugins/toolu/hooks/pre-tools/modules/mcp-blocker.sh +151 -0
- package/plugins/toolu/hooks/pre-tools/modules/plan-ledger.sh +201 -0
- package/plugins/toolu/hooks/pre-tools/modules/protected-files.sh +177 -0
- package/plugins/toolu/hooks/pre-tools/modules/push-review.sh +273 -0
- package/plugins/toolu/hooks/pre-tools/modules/quality-gate.sh +87 -0
- package/plugins/toolu/hooks/session-start.sh +379 -0
- package/plugins/toolu/hooks/user-prompt-submit.sh +197 -0
- package/plugins/toolu/scripts/context-budget.sh +111 -0
- package/plugins/toolu/scripts/debug-log.sh +98 -0
- package/plugins/toolu/scripts/debug-stack.sh +108 -0
- package/plugins/toolu/scripts/debug-testfail.sh +97 -0
- package/plugins/toolu/settings/.gitkeep +0 -0
- package/plugins/toolu/settings/README.md +127 -0
- package/plugins/toolu/settings/bash-allowlist.txt +12 -0
- package/plugins/toolu/settings/bash-denylist.txt +25 -0
- package/plugins/toolu/settings/code-edit-rules.json +67 -0
- package/plugins/toolu/settings/commit-prefixes.txt +12 -0
- package/plugins/toolu/settings/mcp-blocklist.txt +8 -0
- package/plugins/toolu/settings/permissions.fragment.json +36 -0
- package/plugins/toolu/settings/protected-files.txt +30 -0
- package/plugins/toolu/settings/rust-unsafe-exemptions.txt +5 -0
- package/plugins/toolu/settings/toolu.config.example.json +130 -0
- package/plugins/toolu/skills/.gitkeep +0 -0
- package/plugins/toolu/skills/brainstorm/SKILL.md +57 -0
- package/plugins/toolu/skills/brainstorm/references/design-questions.md +36 -0
- package/plugins/toolu/skills/commit/SKILL.md +11 -0
- package/plugins/toolu/skills/debug/SKILL.md +54 -0
- package/plugins/toolu/skills/debug/evals/README.md +17 -0
- package/plugins/toolu/skills/debug/evals/cases.json +24 -0
- package/plugins/toolu/skills/debug/evals/results.json +34 -0
- package/plugins/toolu/skills/deep-research/SKILL.md +51 -0
- package/plugins/toolu/skills/execution/SKILL.md +77 -0
- package/plugins/toolu/skills/orchestrator/SKILL.md +145 -0
- package/plugins/toolu/skills/orchestrator/references/delegation-cost.md +104 -0
- package/plugins/toolu/skills/orchestrator/references/model-routing.md +112 -0
- package/plugins/toolu/skills/plan/SKILL.md +56 -0
- package/plugins/toolu/skills/plan/references/ledger.md +18 -0
- package/plugins/toolu/skills/plan-review/SKILL.md +48 -0
- package/plugins/toolu/skills/review-and-commit/SKILL.md +10 -0
- package/plugins/toolu/skills/setup/SKILL.md +24 -0
- package/plugins/toolu/skills/setup/scripts/setup.sh +206 -0
- package/plugins/toolu/skills/spec/SKILL.md +67 -0
- package/plugins/toolu/skills/spec-review/SKILL.md +50 -0
- package/plugins/toolu/skills/test/SKILL.md +49 -0
- package/plugins/toolu/workflows/commit.md +21 -0
- package/plugins/toolu/workflows/host-mapping.md +22 -0
- package/plugins/toolu/workflows/review-and-commit.md +54 -0
- package/plugins/toolu/workflows/semantic-judgments.md +35 -0
- package/plugins/toolu-review/.claude-plugin/plugin.json +18 -0
- package/plugins/toolu-review/.codex-plugin/plugin.json +7 -0
- package/plugins/toolu-review/README.md +17 -0
- package/plugins/toolu-review/hooks/hooks.json +15 -0
- package/plugins/toolu-review/hooks/session-start.sh +34 -0
- package/plugins/toolu-review/skills/review/SKILL.md +90 -0
- package/plugins/toolu-review/skills/review/scripts/write-state.sh +189 -0
- package/plugins/ts-quality/.claude-plugin/plugin.json +24 -0
- package/plugins/ts-quality/.codex-plugin/plugin.json +6 -0
- package/plugins/ts-quality/README.md +24 -0
- package/plugins/ts-quality/hooks/check-toolu.sh +20 -0
- package/plugins/ts-quality/hooks/concerns/00-preamble.sh +123 -0
- package/plugins/ts-quality/hooks/concerns/10-imports.sh +33 -0
- package/plugins/ts-quality/hooks/concerns/15-type-as.sh +9 -0
- package/plugins/ts-quality/hooks/concerns/20-tests.sh +26 -0
- package/plugins/ts-quality/hooks/concerns/25-size-file.sh +40 -0
- package/plugins/ts-quality/hooks/concerns/30-size-fn.sh +53 -0
- package/plugins/ts-quality/hooks/concerns/35-react-hooks.sh +7 -0
- package/plugins/ts-quality/hooks/concerns/40-factory.sh +5 -0
- package/plugins/ts-quality/hooks/concerns/45-typeguard.sh +6 -0
- package/plugins/ts-quality/hooks/concerns/50-type-dup.sh +16 -0
- package/plugins/ts-quality/hooks/concerns/55-naming.sh +11 -0
- package/plugins/ts-quality/hooks/concerns/60-console.sh +6 -0
- package/plugins/ts-quality/hooks/concerns/65-suppression.sh +12 -0
- package/plugins/ts-quality/hooks/concerns/70-ui-confirm.sh +8 -0
- package/plugins/ts-quality/hooks/concerns/72-ui-radix.sh +12 -0
- package/plugins/ts-quality/hooks/concerns/74-react-props.sh +6 -0
- package/plugins/ts-quality/hooks/concerns/76-toast.sh +10 -0
- package/plugins/ts-quality/hooks/concerns/78-error-ast.sh +242 -0
- package/plugins/ts-quality/hooks/concerns/80-throw-literal.sh +23 -0
- package/plugins/ts-quality/hooks/concerns/85-no-mocks.sh +109 -0
- package/plugins/ts-quality/hooks/concerns/90-duplication.sh +30 -0
- package/plugins/ts-quality/hooks/concerns/92-docs.sh +36 -0
- package/plugins/ts-quality/hooks/concerns/94-handler.sh +15 -0
- package/plugins/ts-quality/hooks/concerns/99-finalize.sh +46 -0
- package/plugins/ts-quality/hooks/hooks.json +19 -0
- package/plugins/ts-quality/hooks/register.sh +65 -0
- package/src/adapter/__tests__/evaluate.test.ts +82 -0
- package/src/adapter/__tests__/permission-map.test.ts +91 -0
- package/src/adapter/evaluate.ts +54 -0
- package/src/adapter/permission-map.ts +177 -0
- package/src/bootstrap/__tests__/bootstrap.test.ts +148 -0
- package/src/bootstrap/entrypoint.ts +18 -0
- package/src/bootstrap/index.ts +5 -0
- package/src/bootstrap/readiness.ts +59 -0
- package/src/bootstrap/result.ts +21 -0
- package/src/bootstrap/runtime.ts +99 -0
- package/src/bootstrap/test-helpers.ts +25 -0
- package/src/host/__tests__/host.test.ts +37 -0
- package/src/host/detect.ts +46 -0
- package/src/host/index.ts +10 -0
- package/src/host/roots.ts +59 -0
- package/src/host/types.ts +14 -0
- package/src/inventory/__tests__/inventory.test.ts +69 -0
- package/src/inventory/index.ts +9 -0
- package/src/inventory/manifest.ts +46 -0
- package/src/inventory/scan.ts +66 -0
- package/src/inventory/selection.ts +92 -0
- package/src/inventory/types.ts +22 -0
- package/src/lifecycle/__tests__/lifecycle.test.ts +7 -0
- package/src/lifecycle/index.ts +2 -0
- package/src/lifecycle/table.ts +42 -0
- package/src/plugin/__tests__/plugin-stub.test.ts +6 -0
- package/src/plugin/plugin-stub.ts +7 -0
- package/src/plugin/toolu.ts +142 -0
- package/src/preflight/__tests__/preflight.test.ts +20 -0
- package/src/preflight/check.ts +75 -0
- package/src/preflight/index.ts +2 -0
- package/src/select/__tests__/select.test.ts +52 -0
- package/src/select/index.ts +2 -0
- package/src/select/resolve.ts +87 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# project.sh — Jira project operations: list, get, versions, components. Sourced;
|
|
3
|
+
# depends on http.sh (jira_curl/jira_lean). All actions are read-only GETs.
|
|
4
|
+
|
|
5
|
+
_jira_project_path() { printf '/rest/api/%s/project' "${_JIRA_VER:-3}"; }
|
|
6
|
+
|
|
7
|
+
jira_project() {
|
|
8
|
+
local action="${1:-}"; [[ $# -gt 0 ]] && shift
|
|
9
|
+
case "$action" in
|
|
10
|
+
list) _jira_project_list "$@";;
|
|
11
|
+
get) _jira_project_get "$@";;
|
|
12
|
+
versions) _jira_project_versions "$@";;
|
|
13
|
+
components) _jira_project_components "$@";;
|
|
14
|
+
*) echo "Usage: jira project <list|get|versions|components> ..." >&2; return 1;;
|
|
15
|
+
esac
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# list: GET the project collection (a top-level array), leaned to key/name/id.
|
|
19
|
+
_jira_project_list() {
|
|
20
|
+
jira_curl GET "$(_jira_project_path)" | jira_lean '{projects:[.[]|{key, name, id}]}'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# get <KEY>: GET one project's full detail.
|
|
24
|
+
_jira_project_get() {
|
|
25
|
+
local key="${1:-}"
|
|
26
|
+
[[ -z "$key" ]] && { echo "Usage: jira project get <KEY>" >&2; return 1; }
|
|
27
|
+
jira_curl GET "$(_jira_project_path)/$key" | jira_lean '.'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# versions <KEY>: GET the project's released/unreleased versions.
|
|
31
|
+
_jira_project_versions() {
|
|
32
|
+
local key="${1:-}"
|
|
33
|
+
[[ -z "$key" ]] && { echo "Usage: jira project versions <KEY>" >&2; return 1; }
|
|
34
|
+
jira_curl GET "$(_jira_project_path)/$key/versions" | jira_lean '.'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# components <KEY>: GET the project's components.
|
|
38
|
+
_jira_project_components() {
|
|
39
|
+
local key="${1:-}"
|
|
40
|
+
[[ -z "$key" ]] && { echo "Usage: jira project components <KEY>" >&2; return 1; }
|
|
41
|
+
jira_curl GET "$(_jira_project_path)/$key/components" | jira_lean '.'
|
|
42
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# raw.sh — escape hatch: issue an arbitrary authenticated request to any Jira
|
|
3
|
+
# REST path, reaching endpoints the ergonomic families do not wrap. Sourced;
|
|
4
|
+
# depends on jira_curl/jira_lean from http.sh.
|
|
5
|
+
|
|
6
|
+
# jira_raw METHOD PATH [JSON_BODY]: METHOD in GET|POST|PUT|DELETE; PATH is
|
|
7
|
+
# relative to JIRA_BASE_URL. Prints the response body.
|
|
8
|
+
jira_raw() {
|
|
9
|
+
if [[ $# -lt 2 ]]; then
|
|
10
|
+
echo "Usage: jira raw <GET|POST|PUT|DELETE> <path> [json_body]" >&2
|
|
11
|
+
return 1
|
|
12
|
+
fi
|
|
13
|
+
local method="$1" path="$2" body="${3:-}"
|
|
14
|
+
jira_curl "$method" "$path" "$body" | jira_lean '.'
|
|
15
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# search.sh — JQL search. v3 (Cloud) POSTs to /rest/api/3/search/jql with
|
|
3
|
+
# nextPageToken paging; v2 (Server/DC) POSTs to /rest/api/2/search with startAt
|
|
4
|
+
# paging. Sourced; depends on http.sh and paginate.sh.
|
|
5
|
+
|
|
6
|
+
# jira_search -q <JQL> [-n MAX] [--all] [--fields f1,f2]
|
|
7
|
+
jira_search() {
|
|
8
|
+
local jql="" max=50 all="false" fields=""
|
|
9
|
+
while [[ $# -gt 0 ]]; do
|
|
10
|
+
case "$1" in
|
|
11
|
+
-q|--query) jql="$2"; shift 2;;
|
|
12
|
+
-n|--num) max="$2"; shift 2;;
|
|
13
|
+
--all) all="true"; shift;;
|
|
14
|
+
--fields) fields="$2"; shift 2;;
|
|
15
|
+
*) if [[ -z "$jql" ]]; then jql="$1"; shift
|
|
16
|
+
else echo "search: unknown option '$1'" >&2; return 1; fi;;
|
|
17
|
+
esac
|
|
18
|
+
done
|
|
19
|
+
[[ -z "$jql" ]] && { echo "Usage: jira search -q <JQL> [-n MAX] [--all] [--fields f1,f2]" >&2; return 1; }
|
|
20
|
+
|
|
21
|
+
local fields_json="null"
|
|
22
|
+
[[ -n "$fields" ]] && fields_json=$(jq -nc --arg f "$fields" '$f|split(",")')
|
|
23
|
+
|
|
24
|
+
local body
|
|
25
|
+
body=$(jq -nc --arg q "$jql" --argjson n "$max" --argjson f "$fields_json" \
|
|
26
|
+
'{jql:$q, maxResults:$n} | if $f then .fields=$f else . end')
|
|
27
|
+
|
|
28
|
+
local path mode
|
|
29
|
+
if [[ "${_JIRA_VER:-3}" == "2" ]]; then
|
|
30
|
+
path="/rest/api/2/search"; mode="offset"
|
|
31
|
+
else
|
|
32
|
+
path="/rest/api/3/search/jql"; mode="token"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if [[ "$all" == "true" ]]; then
|
|
36
|
+
jira_paginate "$mode" POST "$path" issues "$body" | jira_lean '.'
|
|
37
|
+
else
|
|
38
|
+
jira_curl POST "$path" "$body" \
|
|
39
|
+
| jira_lean '{issues: [.issues[] | {key, summary: .fields.summary, status: .fields.status.name}]}'
|
|
40
|
+
fi
|
|
41
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# sprint.sh — Jira Agile sprint operations: list (per board), get, issues,
|
|
3
|
+
# create, move issues, start, complete. Sourced; depends on http.sh
|
|
4
|
+
# (jira_curl/jira_lean). Agile endpoints always use /rest/agile/1.0 regardless
|
|
5
|
+
# of API version; start/complete mutate the live sprint state.
|
|
6
|
+
|
|
7
|
+
# jira_sprint <list|get|issues|create|move|start|complete> ...: dispatch a
|
|
8
|
+
# sprint sub-action; unknown/missing prints usage to stderr and returns 1.
|
|
9
|
+
jira_sprint() {
|
|
10
|
+
local action="${1:-}"; [[ $# -gt 0 ]] && shift
|
|
11
|
+
case "$action" in
|
|
12
|
+
list) _jira_sprint_list "$@";;
|
|
13
|
+
get) _jira_sprint_get "$@";;
|
|
14
|
+
issues) _jira_sprint_issues "$@";;
|
|
15
|
+
create) _jira_sprint_create "$@";;
|
|
16
|
+
move) _jira_sprint_move "$@";;
|
|
17
|
+
start) _jira_sprint_start "$@";;
|
|
18
|
+
complete) _jira_sprint_complete "$@";;
|
|
19
|
+
*) echo "Usage: jira sprint <list|get|issues|create|move|start|complete> ..." >&2; return 1;;
|
|
20
|
+
esac
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# _jira_sprint_list BOARD_ID: list the sprints on a board.
|
|
24
|
+
_jira_sprint_list() {
|
|
25
|
+
local board="${1:-}"
|
|
26
|
+
[[ -z "$board" ]] && { echo "Usage: jira sprint list <BOARD_ID>" >&2; return 1; }
|
|
27
|
+
jira_curl GET "/rest/agile/1.0/board/$board/sprint" \
|
|
28
|
+
| jira_lean '{values:[.values[]|{id,name,state}]}'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# _jira_sprint_get ID: fetch one sprint.
|
|
32
|
+
_jira_sprint_get() {
|
|
33
|
+
local id="${1:-}"
|
|
34
|
+
[[ -z "$id" ]] && { echo "Usage: jira sprint get <ID>" >&2; return 1; }
|
|
35
|
+
jira_curl GET "/rest/agile/1.0/sprint/$id" | jira_lean '.'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# _jira_sprint_issues ID: list the issues in a sprint.
|
|
39
|
+
_jira_sprint_issues() {
|
|
40
|
+
local id="${1:-}"
|
|
41
|
+
[[ -z "$id" ]] && { echo "Usage: jira sprint issues <ID>" >&2; return 1; }
|
|
42
|
+
jira_curl GET "/rest/agile/1.0/sprint/$id/issue" \
|
|
43
|
+
| jira_lean '{issues:[.issues[]|{key, summary:.fields.summary, status:.fields.status.name}]}'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# _jira_sprint_create BOARD_ID -n NAME: create a sprint on a board.
|
|
47
|
+
_jira_sprint_create() {
|
|
48
|
+
local board="${1:-}"; [[ $# -gt 0 ]] && shift
|
|
49
|
+
local name=""
|
|
50
|
+
while [[ $# -gt 0 ]]; do
|
|
51
|
+
case "$1" in
|
|
52
|
+
-n|--name) name="$2"; shift 2;;
|
|
53
|
+
*) echo "sprint create: unknown option '$1'" >&2; return 1;;
|
|
54
|
+
esac
|
|
55
|
+
done
|
|
56
|
+
[[ -z "$board" || -z "$name" ]] && {
|
|
57
|
+
echo "Usage: jira sprint create <BOARD_ID> -n <NAME>" >&2
|
|
58
|
+
return 1
|
|
59
|
+
}
|
|
60
|
+
local body
|
|
61
|
+
body=$(jq -nc --argjson b "$board" --arg n "$name" '{originBoardId:$b, name:$n}')
|
|
62
|
+
jira_curl POST "/rest/agile/1.0/sprint" "$body" | jira_lean '.'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# _jira_sprint_move SPRINT_ID KEY...: move one or more issues into a sprint.
|
|
66
|
+
_jira_sprint_move() {
|
|
67
|
+
local id="${1:-}"; [[ $# -gt 0 ]] && shift
|
|
68
|
+
[[ -z "$id" || $# -eq 0 ]] && { echo "Usage: jira sprint move <SPRINT_ID> <KEY...>" >&2; return 1; }
|
|
69
|
+
local body
|
|
70
|
+
body=$(jq -nc '{issues:$ARGS.positional}' --args "$@")
|
|
71
|
+
jira_curl POST "/rest/agile/1.0/sprint/$id/issue" "$body" | jira_lean '.'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# _jira_sprint_start ID: start a sprint (set state active).
|
|
75
|
+
_jira_sprint_start() {
|
|
76
|
+
local id="${1:-}"
|
|
77
|
+
[[ -z "$id" ]] && { echo "Usage: jira sprint start <ID>" >&2; return 1; }
|
|
78
|
+
jira_curl POST "/rest/agile/1.0/sprint/$id" '{"state":"active"}'
|
|
79
|
+
echo "started sprint $id"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# _jira_sprint_complete ID: complete a sprint (set state closed).
|
|
83
|
+
_jira_sprint_complete() {
|
|
84
|
+
local id="${1:-}"
|
|
85
|
+
[[ -z "$id" ]] && { echo "Usage: jira sprint complete <ID>" >&2; return 1; }
|
|
86
|
+
jira_curl POST "/rest/agile/1.0/sprint/$id" '{"state":"closed"}'
|
|
87
|
+
echo "completed sprint $id"
|
|
88
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# user.sh — Jira user operations: whoami, search, get. Sourced; depends on
|
|
3
|
+
# http.sh (jira_curl/jira_lean). v3 keys users by accountId, v2 by username;
|
|
4
|
+
# the user search/lookup query param is version-gated accordingly.
|
|
5
|
+
|
|
6
|
+
jira_user() {
|
|
7
|
+
local action="${1:-}"; [[ $# -gt 0 ]] && shift
|
|
8
|
+
case "$action" in
|
|
9
|
+
whoami) _jira_user_whoami "$@";;
|
|
10
|
+
search) _jira_user_search "$@";;
|
|
11
|
+
get) _jira_user_get "$@";;
|
|
12
|
+
*) echo "Usage: jira user <whoami|search|get> ..." >&2; return 1;;
|
|
13
|
+
esac
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# whoami: GET the current user, leaned to identity essentials.
|
|
17
|
+
_jira_user_whoami() {
|
|
18
|
+
jira_curl GET "/rest/api/${_JIRA_VER:-3}/myself" \
|
|
19
|
+
| jira_lean '{accountId, displayName, emailAddress}'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# search -q <QUERY>: find users; v3 keys on ?query, v2 on ?username.
|
|
23
|
+
_jira_user_search() {
|
|
24
|
+
local query=""
|
|
25
|
+
while [[ $# -gt 0 ]]; do
|
|
26
|
+
case "$1" in
|
|
27
|
+
-q|--query) query="$2"; shift 2;;
|
|
28
|
+
*) echo "user search: unknown option '$1'" >&2; return 1;;
|
|
29
|
+
esac
|
|
30
|
+
done
|
|
31
|
+
[[ -z "$query" ]] && { echo "Usage: jira user search -q <QUERY>" >&2; return 1; }
|
|
32
|
+
local param="query"
|
|
33
|
+
[[ "${_JIRA_VER:-3}" == "2" ]] && param="username"
|
|
34
|
+
jira_curl GET "/rest/api/${_JIRA_VER:-3}/user/search?${param}=$(jira_urlencode "$query")" \
|
|
35
|
+
| jira_lean '{users:[.[]|{accountId, displayName}]}'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# get <ACCOUNT_ID>: GET one user; v3 keys on ?accountId, v2 on ?username.
|
|
39
|
+
_jira_user_get() {
|
|
40
|
+
local id="${1:-}"
|
|
41
|
+
[[ -z "$id" ]] && { echo "Usage: jira user get <ACCOUNT_ID>" >&2; return 1; }
|
|
42
|
+
local param="accountId"
|
|
43
|
+
[[ "${_JIRA_VER:-3}" == "2" ]] && param="username"
|
|
44
|
+
jira_curl GET "/rest/api/${_JIRA_VER:-3}/user?${param}=$(jira_urlencode "$id")" | jira_lean '.'
|
|
45
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# worklog.sh — Jira worklog operations: add, list, delete. Sourced; depends on
|
|
3
|
+
# http.sh (jira_curl/jira_lean) and adf.sh (jira_text_to_adf). The add comment
|
|
4
|
+
# body is version-gated (ADF for v3, plain text for v2).
|
|
5
|
+
|
|
6
|
+
_jira_worklog_path() { printf '/rest/api/%s/issue' "${_JIRA_VER:-3}"; }
|
|
7
|
+
|
|
8
|
+
# jira_worklog <add|list|delete> ...: dispatch on the first arg.
|
|
9
|
+
jira_worklog() {
|
|
10
|
+
local action="${1:-}"; [[ $# -gt 0 ]] && shift
|
|
11
|
+
case "$action" in
|
|
12
|
+
add) _jira_worklog_add "$@";;
|
|
13
|
+
list) _jira_worklog_list "$@";;
|
|
14
|
+
delete) _jira_worklog_delete "$@";;
|
|
15
|
+
*) echo "Usage: jira worklog <add|list|delete> ..." >&2; return 1;;
|
|
16
|
+
esac
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# _jira_worklog_add <KEY> -t <TIME> [-c COMMENT]: log time against an issue.
|
|
20
|
+
_jira_worklog_add() {
|
|
21
|
+
local key="${1:-}"; [[ $# -gt 0 ]] && shift
|
|
22
|
+
local time="" comment="" has_comment=""
|
|
23
|
+
while [[ $# -gt 0 ]]; do
|
|
24
|
+
case "$1" in
|
|
25
|
+
-t|--time) time="$2"; shift 2;;
|
|
26
|
+
-c|--comment) comment="$2"; has_comment=1; shift 2;;
|
|
27
|
+
*) echo "worklog add: unknown option '$1'" >&2; return 1;;
|
|
28
|
+
esac
|
|
29
|
+
done
|
|
30
|
+
[[ -z "$key" || -z "$time" ]] && {
|
|
31
|
+
echo "Usage: jira worklog add <KEY> -t <TIME> [-c COMMENT]" >&2
|
|
32
|
+
return 1
|
|
33
|
+
}
|
|
34
|
+
local body
|
|
35
|
+
body=$(jq -nc --arg ts "$time" '{timeSpent:$ts}')
|
|
36
|
+
if [[ -n "$has_comment" ]]; then
|
|
37
|
+
body=$(jq -c --argjson c "$(jira_text_to_adf "$comment")" '.comment=$c' <<<"$body")
|
|
38
|
+
fi
|
|
39
|
+
jira_curl POST "$(_jira_worklog_path)/$key/worklog" "$body" | jira_lean '.'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# _jira_worklog_list <KEY>: list worklog entries for an issue.
|
|
43
|
+
_jira_worklog_list() {
|
|
44
|
+
local key="${1:-}"
|
|
45
|
+
[[ -z "$key" ]] && { echo "Usage: jira worklog list <KEY>" >&2; return 1; }
|
|
46
|
+
jira_curl GET "$(_jira_worklog_path)/$key/worklog" \
|
|
47
|
+
| jira_lean '{worklogs:[.worklogs[]|{id, author:.author.displayName, timeSpent, started}]}'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# _jira_worklog_delete <KEY> <WORKLOG_ID>: remove one worklog entry.
|
|
51
|
+
_jira_worklog_delete() {
|
|
52
|
+
local key="${1:-}" wid="${2:-}"
|
|
53
|
+
[[ -z "$key" || -z "$wid" ]] && { echo "Usage: jira worklog delete <KEY> <WORKLOG_ID>" >&2; return 1; }
|
|
54
|
+
jira_curl DELETE "$(_jira_worklog_path)/$key/worklog/$wid"
|
|
55
|
+
echo "deleted worklog $wid"
|
|
56
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pr-babysit",
|
|
3
|
+
"version": "6.8.0",
|
|
4
|
+
"description": "Babysit a PR until review threads, the review-bot verdict, and CI are clear, using Claude cron or a durable Codex goal with isolated worktrees.",
|
|
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
|
+
"pr",
|
|
15
|
+
"review",
|
|
16
|
+
"ci",
|
|
17
|
+
"automation"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": [
|
|
20
|
+
{
|
|
21
|
+
"name": "toolu",
|
|
22
|
+
"marketplace": "toolu"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pr-babysit",
|
|
3
|
+
"version": "6.8.0",
|
|
4
|
+
"description": "Babysit a PR until review threads, the review-bot verdict, and CI are clear, using Claude cron or a durable Codex goal with isolated worktrees.",
|
|
5
|
+
"skills": "./skills/",
|
|
6
|
+
"hooks": "./hooks/hooks.json"
|
|
7
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# pr-babysit
|
|
2
|
+
|
|
3
|
+
Babysit a PR for the current branch until every review thread, the review-bot
|
|
4
|
+
verdict, and CI are clear. Claude uses its cron controller; Codex uses an
|
|
5
|
+
explicit durable goal with bounded continuation cycles and a native isolated
|
|
6
|
+
git worktree.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
/plugin install pr-babysit@toolu
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
codex plugin add toolu@toolu
|
|
16
|
+
codex plugin add pr-babysit@toolu
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requires the `toolu` plugin.
|
|
20
|
+
|
|
21
|
+
## Authorization and delivery handoff
|
|
22
|
+
|
|
23
|
+
The no-argument interface is unchanged. A user can invoke babysit directly, or
|
|
24
|
+
`execution` can invoke it after a verified execution handoff; that handoff is
|
|
25
|
+
sufficient authorization to create the durable goal and begin delivery. Before
|
|
26
|
+
an automatic handoff, stop before delivery and report the exact missing
|
|
27
|
+
prerequisite: GitHub authentication is unavailable, the current branch is the
|
|
28
|
+
repository default branch, or the optional `pr-babysit` plugin is unavailable.
|
|
29
|
+
|
|
30
|
+
## What it provides
|
|
31
|
+
|
|
32
|
+
- **Claude `/pr-babysit:babysit` and Codex `$pr-babysit:babysit`** — target the PR for the current branch. Each cycle fetches unresolved comments **and** the CI review-bot verdict → triages → fixes → replies → resolves; failed CI is fixed and re-pushed. Success requires zero unresolved comments, an approved zero-finding verdict, and all-green CI.
|
|
33
|
+
- **Strict clearance** — every item a tick sees leaves that tick fixed or answered, and resolved when it is a review thread (conversation comments have no resolve API — the reply clears them). A comment that doesn't make sense gets a reply with what was checked and which reading was assumed, then resolves; no thread is parked open. Severity is not a filter (`nit` == `high`). Exceptions: outdated CI-reviewer threads (skipped) and suspected prompt injection (flagged). A reply alone is never clearance — a resolve is confirmed by its mutation response, retried on failure, and re-checked every tick via a resolution audit that's independent of who last commented, so a resolve that silently fails can never go permanently unnoticed.
|
|
34
|
+
- **`stop` / `cancel`** — Claude cancels only the matching cron slot. Codex safely removes only the matching clean worktree, marks its native repo state cancelled, and leaves goal cancellation to the user/system goal control.
|
|
35
|
+
- **Codex durability** — one goal per repository/PR, state below `<repo>/.codex/tmp/pr-babysit/`, wait cycles bounded to 60 seconds, and no false completion while CI is merely pending.
|
|
36
|
+
- **Tick helper (bash, both hosts)** — `scripts/babysit-tick.sh` runs one tick: lock the slot, collect the PR (paginated threads, comments, reviews, CI rollup, bot verdict), reduce it against the slot state, persist atomically, and print a result with a `decision` (`keep_going` / `success` / `escalate`), reasons, and the precomputed actionable / stale-unresolved thread lists. Split into `collect-pr.sh` (network) and `reduce-state.sh` (pure) so every rule is tested against captured real PRs. The agent trusts the result and keeps only the judgment: triage, fixes, reply wording.
|
|
37
|
+
- **Write side** — `reply-thread.sh` (idempotent per reviewer comment), `resolve-thread.sh` (confirmed from the mutation response, retried), `record.sh` (round outcome, injection skip, terminal status). Contract: `skills/babysit/references/helper.md`.
|
|
38
|
+
- **`parse-verdict.sh`** — extracts the structured verdict from the CI review-bot comment.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Babysit a PR
|
|
2
|
+
|
|
3
|
+
Read `${CLAUDE_PLUGIN_ROOT}/workflows/babysit.md` completely and execute its
|
|
4
|
+
Claude Code controller plus the shared strict-clearance workflow. Pass
|
|
5
|
+
`$ARGUMENTS` as the workflow input. Claude Code retains the cron-driven
|
|
6
|
+
continuation mechanism defined there.
|
|
7
|
+
|
|
8
|
+
Each tick is one command: `bash "${CLAUDE_PLUGIN_ROOT}/scripts/babysit-tick.sh"`
|
|
9
|
+
with `--state-file /tmp/pr-babysit-<slot>.json`; its result contract is
|
|
10
|
+
`${CLAUDE_PLUGIN_ROOT}/skills/babysit/references/helper.md`. Trust that
|
|
11
|
+
result — never write a polling script or controller of your own, and
|
|
12
|
+
never re-fetch with ad-hoc `gh` calls what it already reports — and act through
|
|
13
|
+
`reply-thread.sh`, `resolve-thread.sh` and `record.sh`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex lacks a plugin-dependency manifest field. Warn when this dependent
|
|
3
|
+
# plugin is installed without the toolu core, using Codex's authoritative list.
|
|
4
|
+
set -u
|
|
5
|
+
|
|
6
|
+
[ "${TOOLU_HOST_OVERRIDE:-}" != claude ] || exit 0
|
|
7
|
+
[ -n "${PLUGIN_ROOT:-}" ] || exit 0
|
|
8
|
+
command -v codex >/dev/null 2>&1 || exit 0
|
|
9
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
10
|
+
|
|
11
|
+
installed=$(codex plugin list --json 2>/dev/null) || exit 0
|
|
12
|
+
jq -e 'any(.installed[]?; .pluginId == "toolu@toolu" and
|
|
13
|
+
((has("installed") | not) or (.installed == true)) and
|
|
14
|
+
((has("enabled") | not) or (.enabled == true)))' \
|
|
15
|
+
<<<"$installed" >/dev/null 2>&1 && exit 0
|
|
16
|
+
|
|
17
|
+
jq -n '{hookSpecificOutput:{
|
|
18
|
+
hookEventName:"SessionStart",
|
|
19
|
+
additionalContext:"WARN: this plugin requires the toolu core. Install it first with: codex plugin add toolu@toolu"
|
|
20
|
+
}}'
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# babysit-tick.sh — the one command a babysit tick runs, on either host.
|
|
3
|
+
#
|
|
4
|
+
# lock the slot → (validate prior state) → collect → reduce → persist → print
|
|
5
|
+
#
|
|
6
|
+
# Usage: babysit-tick.sh --repo <owner/repo> --pr <n> --state-file <path>
|
|
7
|
+
# [--snapshot-out <path>] [--snapshot-in <path>]
|
|
8
|
+
# [--page-size N] [--timeout SECONDS] [--now <iso8601>]
|
|
9
|
+
# --state-file the host's slot path, passed verbatim by the workflow
|
|
10
|
+
# (/tmp/pr-babysit-<slot>.json on Claude,
|
|
11
|
+
# <repo>/.codex/tmp/pr-babysit/<slot>.json on Codex)
|
|
12
|
+
# --snapshot-out full snapshot location (default: beside the state file)
|
|
13
|
+
# --snapshot-in skip collection and reduce a captured snapshot (tests,
|
|
14
|
+
# replay); its repo/number must match the arguments
|
|
15
|
+
# --now timestamp override for tests (default: UTC now)
|
|
16
|
+
#
|
|
17
|
+
# stdout: exactly one JSON document — the result (exit 0) or a structured
|
|
18
|
+
# error (non-zero). stderr: diagnostics only.
|
|
19
|
+
# Exit: 0 result · 2 usage · 3 structured error, prior state preserved
|
|
20
|
+
# (pr.lastError updated when a prior state exists) · 75 slot locked.
|
|
21
|
+
# Nothing here reads a session-specific environment variable for the repo,
|
|
22
|
+
# PR, home directory or plugin root: the root comes from this file's path.
|
|
23
|
+
set -euo pipefail
|
|
24
|
+
|
|
25
|
+
PB_SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)
|
|
26
|
+
# shellcheck source=lib/common.sh
|
|
27
|
+
. "$PB_SCRIPT_DIR/lib/common.sh"
|
|
28
|
+
# shellcheck source=lib/lock.sh
|
|
29
|
+
. "$PB_SCRIPT_DIR/lib/lock.sh"
|
|
30
|
+
|
|
31
|
+
repo=""; number=""; state_file=""; snapshot_out=""; snapshot_in=""; page_size=""; timeout=""; now=""
|
|
32
|
+
while [ $# -gt 0 ]; do
|
|
33
|
+
case "$1" in
|
|
34
|
+
--repo) repo="${2:-}"; shift 2 ;;
|
|
35
|
+
--pr) number="${2:-}"; shift 2 ;;
|
|
36
|
+
--state-file) state_file="${2:-}"; shift 2 ;;
|
|
37
|
+
--snapshot-out) snapshot_out="${2:-}"; shift 2 ;;
|
|
38
|
+
--snapshot-in) snapshot_in="${2:-}"; shift 2 ;;
|
|
39
|
+
--page-size) page_size="${2:-}"; shift 2 ;;
|
|
40
|
+
--timeout) timeout="${2:-}"; shift 2 ;;
|
|
41
|
+
--now) now="${2:-}"; shift 2 ;;
|
|
42
|
+
*) pb_fail usage "babysit-tick.sh: unknown argument: $1" ;;
|
|
43
|
+
esac
|
|
44
|
+
done
|
|
45
|
+
[[ "$repo" =~ ^[^/[:space:]]+/[^/[:space:]]+$ ]] || pb_fail usage "babysit-tick.sh: --repo <owner/repo> required"
|
|
46
|
+
[[ "$number" =~ ^[0-9]+$ ]] || pb_fail usage "babysit-tick.sh: --pr <n> required"
|
|
47
|
+
[ -n "$state_file" ] || pb_fail usage "babysit-tick.sh: --state-file <path> required"
|
|
48
|
+
[ -z "$page_size" ] || [[ "$page_size" =~ ^[0-9]+$ ]] || pb_fail usage "babysit-tick.sh: --page-size must be an integer"
|
|
49
|
+
[ -z "$timeout" ] || [[ "$timeout" =~ ^[0-9]+$ ]] || pb_fail usage "babysit-tick.sh: --timeout must be an integer"
|
|
50
|
+
[ -n "$now" ] || now=$(pb_now)
|
|
51
|
+
[[ "$now" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]] || pb_fail usage "babysit-tick.sh: --now must be YYYY-MM-DDTHH:MM:SSZ"
|
|
52
|
+
[ -n "$snapshot_out" ] || snapshot_out="${state_file%.json}.snapshot.json"
|
|
53
|
+
|
|
54
|
+
pb_require jq
|
|
55
|
+
[ -n "$snapshot_in" ] || pb_require gh
|
|
56
|
+
pb_init
|
|
57
|
+
pb_mktmpdir
|
|
58
|
+
mkdir -p "$(dirname "$state_file")" || pb_fail usage "babysit-tick.sh: cannot create $(dirname "$state_file")"
|
|
59
|
+
pb_lock_acquire "$state_file" || pb_lock_fail "$state_file"
|
|
60
|
+
|
|
61
|
+
# --- prior state: validate before touching the network ----------------------
|
|
62
|
+
# reduce-state.sh repeats these checks; running them first means a malformed
|
|
63
|
+
# or foreign state file fails in milliseconds and never costs API calls.
|
|
64
|
+
have_state=0
|
|
65
|
+
if [ -e "$state_file" ]; then
|
|
66
|
+
have_state=1
|
|
67
|
+
pb_json_valid "$state_file" || pb_fail state_malformed "babysit-tick.sh: state file is not valid JSON: $state_file" '{"source":"state"}'
|
|
68
|
+
jq -e '.version == 2' "$state_file" >/dev/null 2>&1 \
|
|
69
|
+
|| pb_fail state_malformed "babysit-tick.sh: state file is not version 2: $state_file" "$(jq -c '{source:"state", version:(.version // null)}' "$state_file")"
|
|
70
|
+
jq -e --arg repo "$repo" --argjson number "$number" '.repo == $repo and .number == $number' "$state_file" >/dev/null 2>&1 \
|
|
71
|
+
|| pb_fail slot_mismatch "babysit-tick.sh: state file belongs to $(jq -r '"\(.repo)#\(.number)"' "$state_file"), asked for $repo#$number" \
|
|
72
|
+
"$(jq -c --arg repo "$repo" --argjson number "$number" '{source:"state", state:{repo, number}, requested:{repo:$repo, number:$number}}' "$state_file")"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# _record_error DOC — on a collection failure, keep the prior state but stamp
|
|
76
|
+
# pr.lastError so the next reader sees what happened and when.
|
|
77
|
+
_record_error() {
|
|
78
|
+
local doc="$1" entry
|
|
79
|
+
[ "$have_state" -eq 1 ] || return 0
|
|
80
|
+
# A structured error always carries errors[0]; anything else is recorded as
|
|
81
|
+
# an api_error with the raw text so the failure is never lost.
|
|
82
|
+
entry=$(jq -c '.errors[0] // empty' <<<"$doc" 2>/dev/null || true)
|
|
83
|
+
[ -n "$entry" ] || entry=$(jq -nc --arg m "$doc" '{code:"api_error", message:$m}')
|
|
84
|
+
pb_atomic_write_json "$state_file" jq -c --argjson e "$entry" --arg now "$now" \
|
|
85
|
+
'.pr.lastError = {code: ($e.code // "api_error"), message: ($e.message // ""), at: $now}' "$state_file" \
|
|
86
|
+
|| echo "babysit-tick.sh: could not record lastError in $state_file" >&2
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# _exit_with_doc DOC — print a structured error and exit with the code its
|
|
90
|
+
# errors[0].code maps to, so the exit code and the document never disagree.
|
|
91
|
+
_exit_with_doc() {
|
|
92
|
+
local doc="$1"
|
|
93
|
+
printf '%s\n' "$doc"
|
|
94
|
+
exit "$(pb_exit_code "$(jq -r '.errors[0].code // "api_error"' <<<"$doc")")"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# --- snapshot: collect, or take the one handed in ----------------------------
|
|
98
|
+
snap="$PB_TMPDIR/snapshot.json"
|
|
99
|
+
if [ -n "$snapshot_in" ]; then
|
|
100
|
+
[ -f "$snapshot_in" ] && pb_json_valid "$snapshot_in" || pb_fail invalid_json "babysit-tick.sh: --snapshot-in is not a JSON file: $snapshot_in" '{"source":"snapshot"}'
|
|
101
|
+
jq -e --arg repo "$repo" --argjson number "$number" '.repo == $repo and .number == $number' "$snapshot_in" >/dev/null 2>&1 \
|
|
102
|
+
|| pb_fail slot_mismatch "babysit-tick.sh: --snapshot-in is for $(jq -r '"\(.repo)#\(.number)"' "$snapshot_in"), asked for $repo#$number" '{"source":"snapshot"}'
|
|
103
|
+
cp "$snapshot_in" "$snap"
|
|
104
|
+
else
|
|
105
|
+
collect_args=(--repo "$repo" --pr "$number" --out "$snap")
|
|
106
|
+
[ -z "$page_size" ] || collect_args+=(--page-size "$page_size")
|
|
107
|
+
[ -z "$timeout" ] || collect_args+=(--timeout "$timeout")
|
|
108
|
+
rc=0
|
|
109
|
+
bash "$PB_SCRIPT_DIR/collect-pr.sh" "${collect_args[@]}" >"$PB_TMPDIR/collect.out" || rc=$?
|
|
110
|
+
if [ "$rc" -ne 0 ]; then
|
|
111
|
+
doc=$(grep '^{' "$PB_TMPDIR/collect.out" | tail -n 1 || true)
|
|
112
|
+
[ -n "$doc" ] || doc=$(pb_error api_error "babysit-tick.sh: collect-pr.sh exited $rc without a structured error" '{"source":"collect"}')
|
|
113
|
+
_record_error "$doc"
|
|
114
|
+
_exit_with_doc "$doc"
|
|
115
|
+
fi
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
# --- reduce -------------------------------------------------------------------
|
|
119
|
+
rc=0
|
|
120
|
+
bash "$PB_SCRIPT_DIR/reduce-state.sh" --snapshot "$snap" --state "$state_file" --now "$now" \
|
|
121
|
+
--state-out "$PB_TMPDIR/state.next.json" --result-out "$PB_TMPDIR/result.json" \
|
|
122
|
+
--state-path "$state_file" --snapshot-path "$snapshot_out" >"$PB_TMPDIR/reduce.out" || rc=$?
|
|
123
|
+
if [ "$rc" -ne 0 ]; then
|
|
124
|
+
doc=$(grep '^{' "$PB_TMPDIR/reduce.out" | tail -n 1 || true)
|
|
125
|
+
[ -n "$doc" ] || doc=$(pb_error invalid_json "babysit-tick.sh: reduce-state.sh exited $rc without a structured error" '{"source":"reduce"}')
|
|
126
|
+
_record_error "$doc"
|
|
127
|
+
_exit_with_doc "$doc"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# --- persist: snapshot first (the state points at it), then state -----------
|
|
131
|
+
pb_atomic_write_json "$snapshot_out" cat "$snap" || pb_fail invalid_json "babysit-tick.sh: could not write $snapshot_out" '{"source":"snapshot_out"}'
|
|
132
|
+
pb_atomic_write_json "$state_file" cat "$PB_TMPDIR/state.next.json" || pb_fail invalid_json "babysit-tick.sh: could not write $state_file" '{"source":"state"}'
|
|
133
|
+
cat "$PB_TMPDIR/result.json"
|