@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,111 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# context-budget.sh — enforce context-window budgets on harness-injected text.
|
|
3
|
+
#
|
|
4
|
+
# Every session, Claude Code loads the Session Protocol + per-language docs and
|
|
5
|
+
# all skill `description` fields into the model's context. This guard caps that
|
|
6
|
+
# recurring footprint so it cannot silently regrow, and asserts that trimming
|
|
7
|
+
# never drops a skill's discriminating trigger phrases (which would stop it
|
|
8
|
+
# auto-firing).
|
|
9
|
+
#
|
|
10
|
+
# Fails CLOSED: a missing/renamed target file, or a description that can't be
|
|
11
|
+
# parsed, is RED — never a silent pass.
|
|
12
|
+
#
|
|
13
|
+
# Usage: context-budget.sh [docs|skills] (no arg = all)
|
|
14
|
+
set -u
|
|
15
|
+
|
|
16
|
+
ROOT="${CONTEXT_BUDGET_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null)}"
|
|
17
|
+
|
|
18
|
+
fail=0
|
|
19
|
+
err() { printf 'RED %s\n' "$1" >&2; fail=1; }
|
|
20
|
+
ok() { printf 'ok %s\n' "$1"; }
|
|
21
|
+
|
|
22
|
+
# count_words FILE -> prints word count; returns 1 if file missing.
|
|
23
|
+
count_words() {
|
|
24
|
+
[ -f "$1" ] || return 1
|
|
25
|
+
wc -w < "$1" | tr -d ' '
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# extract_description FILE -> prints the YAML frontmatter `description` value.
|
|
29
|
+
# Handles single-line (`description: text`) and folded/block scalars
|
|
30
|
+
# (`description: >` followed by indented lines). Returns 1 if the file is absent.
|
|
31
|
+
extract_description() {
|
|
32
|
+
[ -f "$1" ] || return 1
|
|
33
|
+
awk '
|
|
34
|
+
/^description:/ && !started {
|
|
35
|
+
started=1
|
|
36
|
+
v=$0; sub(/^description:[ \t]*/,"",v)
|
|
37
|
+
if (v=="" || v==">" || v==">-" || v=="|" || v=="|-") { folded=1; next }
|
|
38
|
+
print v; exit
|
|
39
|
+
}
|
|
40
|
+
folded {
|
|
41
|
+
if ($0=="---") exit
|
|
42
|
+
if ($0 ~ /^[A-Za-z0-9_-]+:/) exit
|
|
43
|
+
sub(/^[ \t]+/,"")
|
|
44
|
+
buf=(buf=="")?$0:buf" "$0
|
|
45
|
+
}
|
|
46
|
+
END { if (folded) print buf }
|
|
47
|
+
' "$1"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# check_doc NAME PATH BUDGET
|
|
51
|
+
check_doc() {
|
|
52
|
+
local name="$1" path="$2" budget="$3" n
|
|
53
|
+
n=$(count_words "$ROOT/$path") || { err "$name: MISSING $path"; return; }
|
|
54
|
+
if [ "$n" -le "$budget" ]; then ok "$name ${n}w (<= ${budget})"
|
|
55
|
+
else err "$name ${n}w EXCEEDS ${budget} ($path)"; fi
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# check_skill NAME PATH BUDGET PHRASES(;-separated, may be empty)
|
|
59
|
+
check_skill() {
|
|
60
|
+
local name="$1" path="$2" budget="$3" phrases="$4" desc n p
|
|
61
|
+
desc=$(extract_description "$ROOT/$path") || { err "$name: MISSING $path"; return; }
|
|
62
|
+
[ -n "$desc" ] || { err "$name: empty/unparseable description ($path)"; return; }
|
|
63
|
+
n=$(printf '%s' "$desc" | wc -w | tr -d ' ')
|
|
64
|
+
if [ "$n" -le "$budget" ]; then ok "$name desc ${n}w (<= ${budget})"
|
|
65
|
+
else err "$name desc ${n}w EXCEEDS ${budget} ($path)"; fi
|
|
66
|
+
local IFS=';'
|
|
67
|
+
for p in $phrases; do
|
|
68
|
+
[ -z "$p" ] && continue
|
|
69
|
+
case "$desc" in
|
|
70
|
+
*"$p"*) : ;;
|
|
71
|
+
*) err "$name: missing trigger phrase \"$p\" ($path)" ;;
|
|
72
|
+
esac
|
|
73
|
+
done
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
run_docs() {
|
|
77
|
+
check_doc session-start plugins/toolu/hooks/docs/session-start.md 110
|
|
78
|
+
check_doc model-routing plugins/toolu/hooks/docs/model-routing.md 90
|
|
79
|
+
check_doc post-compaction plugins/toolu/hooks/docs/post-compaction.md 28
|
|
80
|
+
check_doc session-start-ts plugins/toolu/hooks/docs/session-start-ts.md 30
|
|
81
|
+
check_doc session-start-rust plugins/toolu/hooks/docs/session-start-rust.md 36
|
|
82
|
+
check_doc session-start-python plugins/toolu/hooks/docs/session-start-python.md 36
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
run_skills() {
|
|
86
|
+
# Trimmed skills: word ceiling + trigger phrases that MUST survive the trim.
|
|
87
|
+
check_skill brainstorm plugins/toolu/skills/brainstorm/SKILL.md 90 "where do I even start;help me scope it;think through the approach and tradeoffs"
|
|
88
|
+
check_skill spec plugins/toolu/skills/spec/SKILL.md 70 "write the spec;document the design"
|
|
89
|
+
check_skill spec-review plugins/toolu/skills/spec-review/SKILL.md 60 "review the spec;poke holes in this spec"
|
|
90
|
+
check_skill deep-research plugins/toolu/skills/deep-research/SKILL.md 90 "deep research;cited report"
|
|
91
|
+
check_skill plan-review plugins/toolu/skills/plan-review/SKILL.md 55 "review the plan;poke holes in the plan"
|
|
92
|
+
check_skill toolu-review plugins/toolu-review/skills/review/SKILL.md 65 "review before push"
|
|
93
|
+
# Already-lean skills: word ceiling only, lock against regrowth.
|
|
94
|
+
check_skill plan plugins/toolu/skills/plan/SKILL.md 60 ""
|
|
95
|
+
check_skill execution plugins/toolu/skills/execution/SKILL.md 60 ""
|
|
96
|
+
check_skill test plugins/toolu/skills/test/SKILL.md 60 ""
|
|
97
|
+
check_skill ast-grep plugins/ast-grep/skills/ast-grep/SKILL.md 40 ""
|
|
98
|
+
check_skill jev plugins/jev/skills/jev/SKILL.md 60 ""
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
main() {
|
|
102
|
+
case "${1:-all}" in
|
|
103
|
+
docs) run_docs ;;
|
|
104
|
+
skills) run_skills ;;
|
|
105
|
+
all) run_docs; run_skills ;;
|
|
106
|
+
*) echo "usage: context-budget.sh [docs|skills]" >&2; exit 2 ;;
|
|
107
|
+
esac
|
|
108
|
+
[ "$fail" -eq 0 ] || exit 1
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if [ "${BASH_SOURCE[0]:-}" = "${0:-}" ]; then main "$@"; fi
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# debug-log.sh — language-agnostic log summarizer for the debug skill's Observe step.
|
|
3
|
+
# Reads a log (stdin or --file) and emits a compact, capped summary: deduped error/warning
|
|
4
|
+
# lines plus a tail of recent lines, always reporting TOTAL lines so the caller knows what was
|
|
5
|
+
# elided. Its primary job is cap enforcement — a huge log in, a small summary out, never a flood.
|
|
6
|
+
# Output stays at/under DEBUG_MAX_LINES lines AND under DEBUG_MAX_BYTES bytes.
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
usage() {
|
|
10
|
+
cat <<'EOF'
|
|
11
|
+
Usage: debug-log.sh [--file <path>] [--json]
|
|
12
|
+
Reads a log from stdin or --file and prints a compact, capped summary:
|
|
13
|
+
deduped ERROR/WARN-ish lines and a tail of the most recent lines.
|
|
14
|
+
--json Emit a JSON object {errors,tail,total_lines,truncated} instead of text.
|
|
15
|
+
Env caps (override): DEBUG_MAX_LINES=100 (max output lines) DEBUG_MAX_BYTES=65536 (hard output byte ceiling)
|
|
16
|
+
EOF
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
file=""
|
|
20
|
+
json=0
|
|
21
|
+
while [ $# -gt 0 ]; do
|
|
22
|
+
case "$1" in
|
|
23
|
+
--file) file="${2:-}"; shift 2 || { echo "debug-log.sh: --file needs a path" >&2; exit 2; } ;;
|
|
24
|
+
--json) json=1; shift ;;
|
|
25
|
+
-h|--help) usage; exit 0 ;;
|
|
26
|
+
*) echo "debug-log.sh: unknown arg: $1" >&2; usage >&2; exit 2 ;;
|
|
27
|
+
esac
|
|
28
|
+
done
|
|
29
|
+
|
|
30
|
+
if [ -n "$file" ]; then
|
|
31
|
+
[ -r "$file" ] || { echo "debug-log.sh: cannot read file: $file" >&2; exit 2; }
|
|
32
|
+
exec < "$file"
|
|
33
|
+
elif [ -t 0 ]; then
|
|
34
|
+
echo "debug-log.sh: no input (pipe a log or pass --file)" >&2
|
|
35
|
+
exit 2
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
LC_ALL=C awk -v json="$json" \
|
|
39
|
+
-v maxl="${DEBUG_MAX_LINES:-100}" \
|
|
40
|
+
-v maxb="${DEBUG_MAX_BYTES:-65536}" '
|
|
41
|
+
function jesc(s){ gsub(/\\/,"\\\\",s); gsub(/"/,"\\\"",s); gsub(/\t/," ",s); gsub(/\r/,"",s); return s }
|
|
42
|
+
# Normalize a leading timestamp to a placeholder so timestamped repeats collapse on dedup.
|
|
43
|
+
function norm(s, k){ k=s
|
|
44
|
+
sub(/^[0-9]{4}-[0-9]{2}-[0-9]{2}[T ][0-9:.]+([Zz]|[+-][0-9:]+)?/,"<TS>",k) # ISO 8601
|
|
45
|
+
sub(/^\[[0-9]{2}:[0-9]{2}:[0-9]{2}([.,][0-9]+)?\]/,"<TS>",k) # [12:00:00]
|
|
46
|
+
return k
|
|
47
|
+
}
|
|
48
|
+
{
|
|
49
|
+
total=NR
|
|
50
|
+
line=$0; sub(/\r$/,"",line)
|
|
51
|
+
tail[NR]=line # ring of recent lines (indexed by NR)
|
|
52
|
+
if (NR>maxl) delete tail[NR-maxl] # keep at most maxl tail candidates
|
|
53
|
+
if (line ~ /[Ee][Rr][Rr][Oo][Rr]|[Ww][Aa][Rr][Nn]|[Pp][Aa][Nn][Ii][Cc]|[Ff][Aa][Ii][Ll]|[Ee][Xx][Cc][Ee][Pp][Tt][Ii][Oo][Nn]|[Ff][Aa][Tt][Aa][Ll]|[Tt][Rr][Aa][Cc][Ee][Bb][Aa][Cc][Kk]/) {
|
|
54
|
+
key=norm(line)
|
|
55
|
+
if (!(key in eseen)) { eseen[key]=1; errs[++ne]=line }
|
|
56
|
+
else eskip++
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
END {
|
|
60
|
+
# Budget: errors get up to ~60% of the line cap, tail gets the rest (header lines count too).
|
|
61
|
+
emax = int(maxl*0.6); if (emax<1) emax=1
|
|
62
|
+
eshow = (ne<emax?ne:emax); eover = ne-eshow
|
|
63
|
+
# Reserve lines already spent by error section + its 2 headers; remainder for tail + its header.
|
|
64
|
+
used = eshow + (ne>0?1:0) + (eover>0?1:0) + 1 # errors + ERRORS hdr + overflow + TOTAL line
|
|
65
|
+
tmax = maxl - used - 1 # -1 for the TAIL header
|
|
66
|
+
if (tmax<0) tmax=0
|
|
67
|
+
# Tail = the last tshow of the kept tail lines.
|
|
68
|
+
tn=0; for(i=(total>maxl?total-maxl+1:1); i<=total; i++) if(i in tail) tline[++tn]=tail[i]
|
|
69
|
+
tshow = (tn<tmax?tn:tmax)
|
|
70
|
+
tstart = tn - tshow + 1; if (tstart<1) tstart=1
|
|
71
|
+
|
|
72
|
+
if (json) {
|
|
73
|
+
printf "{"
|
|
74
|
+
printf "\"errors\":["; for(i=1;i<=eshow;i++){printf "%s\"%s\"",(i>1?",":""),jesc(errs[i])} printf "],"
|
|
75
|
+
printf "\"tail\":["; for(i=tstart;i<=tn;i++){printf "%s\"%s\"",(i>tstart?",":""),jesc(tline[i])} printf "],"
|
|
76
|
+
printf "\"total_lines\":%d,", total
|
|
77
|
+
printf "\"truncated\":%s", ((eover>0 || tshow<tn || total>maxl)?"true":"false")
|
|
78
|
+
printf "}\n"
|
|
79
|
+
exit 0
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Text mode — assemble into a buffer, then enforce the byte ceiling by dropping from the end.
|
|
83
|
+
o=0
|
|
84
|
+
out[++o]="ERRORS/WARNINGS (" eshow (eover>0?"+":"") "):"
|
|
85
|
+
for(i=1;i<=eshow;i++) out[++o]=" " errs[i]
|
|
86
|
+
if (eover>0) out[++o]=" ... (+" eover " more)"
|
|
87
|
+
out[++o]="TAIL (last " tshow " of " total " lines):"
|
|
88
|
+
for(i=tstart;i<=tn;i++) out[++o]=" " tline[i]
|
|
89
|
+
out[++o]="TOTAL lines: " total
|
|
90
|
+
|
|
91
|
+
# Hard byte ceiling: count bytes (incl. newline) and drop trailing lines if we would exceed maxb.
|
|
92
|
+
bytes=0; keep=o
|
|
93
|
+
for(i=1;i<=o;i++){ bytes += length(out[i])+1; if (bytes>maxb) { keep=i-1; break } }
|
|
94
|
+
bytetrunc = (keep<o)
|
|
95
|
+
for(i=1;i<=keep;i++) print out[i]
|
|
96
|
+
if (bytetrunc) print "... (output truncated to stay under " maxb " bytes)"
|
|
97
|
+
}
|
|
98
|
+
'
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# debug-stack.sh — language-agnostic stack/backtrace summarizer for the debug skill's Observe step.
|
|
3
|
+
# Reads a stack trace / panic backtrace (stdin or --file) and surfaces APP frames first, collapsing
|
|
4
|
+
# framework/runtime/stdlib frames into a count. Never a per-language grammar — it keys on line SHAPE
|
|
5
|
+
# (a symbol and/or a file:line[:col]) and flags noise by path/symbol markers (/rustc/, node:internal,
|
|
6
|
+
# core::, std::, __rustc, <anonymous>, …). JS (symbol+loc on one line) and Rust (symbol then `at <path>`
|
|
7
|
+
# on the next line) both work. Unrecognized input → capped raw passthrough.
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
usage() {
|
|
11
|
+
cat <<'EOF'
|
|
12
|
+
Usage: debug-stack.sh [--file <path>] [--json]
|
|
13
|
+
Reads a stack trace / backtrace from stdin or --file and prints APP frames first, runtime noise collapsed.
|
|
14
|
+
--json Emit {"app_frames":[...],"noise_frames":N,"recognized":bool} instead of text.
|
|
15
|
+
Env caps (override): DEBUG_MAX_FRAMES=20 DEBUG_MAX_LINES=100
|
|
16
|
+
EOF
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
file=""
|
|
20
|
+
json=0
|
|
21
|
+
while [ $# -gt 0 ]; do
|
|
22
|
+
case "$1" in
|
|
23
|
+
--file) file="${2:-}"; shift 2 || { echo "debug-stack.sh: --file needs a path" >&2; exit 2; } ;;
|
|
24
|
+
--json) json=1; shift ;;
|
|
25
|
+
-h|--help) usage; exit 0 ;;
|
|
26
|
+
*) echo "debug-stack.sh: unknown arg: $1" >&2; usage >&2; exit 2 ;;
|
|
27
|
+
esac
|
|
28
|
+
done
|
|
29
|
+
|
|
30
|
+
if [ -n "$file" ]; then
|
|
31
|
+
[ -r "$file" ] || { echo "debug-stack.sh: cannot read file: $file" >&2; exit 2; }
|
|
32
|
+
exec < "$file"
|
|
33
|
+
elif [ -t 0 ]; then
|
|
34
|
+
echo "debug-stack.sh: no input (pipe a trace or pass --file)" >&2
|
|
35
|
+
exit 2
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
awk -v json="$json" \
|
|
39
|
+
-v maxfr="${DEBUG_MAX_FRAMES:-20}" \
|
|
40
|
+
-v maxraw="${DEBUG_MAX_LINES:-100}" '
|
|
41
|
+
function trim(s){ sub(/^[ \t]+/,"",s); sub(/[ \t]+$/,"",s); return s }
|
|
42
|
+
function jesc(s){ gsub(/\\/,"\\\\",s); gsub(/"/,"\\\"",s); gsub(/\t/," ",s); return s }
|
|
43
|
+
# A frame is NOISE when its symbol or location points into a runtime/stdlib (language-agnostic markers).
|
|
44
|
+
function isnoise(text){ return (text ~ /\/rustc\/|node:internal|node:|core::|std::|__rustc|rust_begin_unwind|panic_fmt|panic_bounds_check|FnOnce::call_once|<anonymous>/) }
|
|
45
|
+
function emit(sym,loc, txt){
|
|
46
|
+
# sym/loc are the parts; txt is what we classify on. "func @ file:line" is the rendered frame.
|
|
47
|
+
txt=sym " " loc
|
|
48
|
+
if (isnoise(txt)) { noise++; return }
|
|
49
|
+
if (sym!="" && loc!="") f=sym " @ " loc
|
|
50
|
+
else if (loc!="") f=loc
|
|
51
|
+
else f=sym
|
|
52
|
+
napp++; app[napp]=f
|
|
53
|
+
}
|
|
54
|
+
{
|
|
55
|
+
raw[NR]=$0
|
|
56
|
+
line=$0
|
|
57
|
+
|
|
58
|
+
# --- Rust continuation FIRST: ` at <location>` pairs with the pending `N: symbol` ---
|
|
59
|
+
if (pend && match(line, /^[ \t]*at[ \t]+/)) {
|
|
60
|
+
emit(pend_sym, trim(substr(line, RSTART+RLENGTH))); pend=0; pend_sym=""; next
|
|
61
|
+
}
|
|
62
|
+
# A pending Rust symbol with no following `at` line: still a frame, no location.
|
|
63
|
+
if (pend) { emit(pend_sym, ""); pend=0; pend_sym="" }
|
|
64
|
+
|
|
65
|
+
# --- JS shape: a stack frame line begins with `at <symbol> (<location>)` or `at <location>` ---
|
|
66
|
+
if (match(line, /^[ \t]*at[ \t]+/)) {
|
|
67
|
+
rest=substr(line, RSTART+RLENGTH)
|
|
68
|
+
sym=""; loc=""
|
|
69
|
+
if (match(rest, /\(.*\)[ \t]*$/)) { # at func (loc)
|
|
70
|
+
sym=trim(substr(rest, 1, RSTART-1))
|
|
71
|
+
loc=substr(rest, RSTART+1, RLENGTH-2) # strip the surrounding ()
|
|
72
|
+
sub(/[ \t]+$/,"",loc)
|
|
73
|
+
} else { # at loc (no symbol)
|
|
74
|
+
loc=trim(rest)
|
|
75
|
+
}
|
|
76
|
+
if (sym!="" || loc!="") { emit(sym, loc); next }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# --- Rust shape: ` N: <symbol>` then the NEXT line ` at <location>` ---
|
|
80
|
+
if (match(line, /^[ \t]*[0-9]+:[ \t]+/)) {
|
|
81
|
+
pend_sym=trim(substr(line, RSTART+RLENGTH)); pend=1; next
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
END {
|
|
85
|
+
if (pend) emit(pend_sym, "") # flush a trailing pending Rust frame
|
|
86
|
+
recognized = (napp + noise) > 0
|
|
87
|
+
if (json) {
|
|
88
|
+
printf "{"
|
|
89
|
+
printf "\"app_frames\":["; for(i=1;i<=napp;i++){printf "%s\"%s\"", (i>1?",":""), jesc(app[i])} printf "],"
|
|
90
|
+
printf "\"noise_frames\":%d,", noise
|
|
91
|
+
printf "\"recognized\":%s", (recognized?"true":"false")
|
|
92
|
+
printf "}\n"
|
|
93
|
+
exit 0
|
|
94
|
+
}
|
|
95
|
+
if (!recognized) {
|
|
96
|
+
print "debug-stack: no recognizable stack frames — raw input (capped):"
|
|
97
|
+
cap = (NR<maxraw?NR:maxraw)
|
|
98
|
+
for(i=1;i<=cap;i++) print raw[i]
|
|
99
|
+
if (NR>maxraw) printf "... (+%d more lines)\n", NR-maxraw
|
|
100
|
+
exit 0
|
|
101
|
+
}
|
|
102
|
+
shown = (napp<maxfr?napp:maxfr)
|
|
103
|
+
print "APP FRAMES (" napp (napp>maxfr?"+":"") "):"
|
|
104
|
+
for(i=1;i<=shown;i++) print " - " app[i]
|
|
105
|
+
if (napp>maxfr) printf " ... (+%d more)\n", napp-maxfr
|
|
106
|
+
if (noise>0) printf "(+%d framework/runtime frames collapsed)\n", noise
|
|
107
|
+
}
|
|
108
|
+
'
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# debug-testfail.sh — language-agnostic test-failure summarizer for the debug skill's Observe step.
|
|
3
|
+
# Reads a failing test transcript (stdin or --file), emits a compact, capped summary:
|
|
4
|
+
# failed test names, error/assertion lines, and code file:line locations. Never a per-language grammar —
|
|
5
|
+
# it keys on line shape only (works on bun/jest, cargo, and similar). Unrecognized input → capped raw passthrough.
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
usage() {
|
|
9
|
+
cat <<'EOF'
|
|
10
|
+
Usage: debug-testfail.sh [--file <path>] [--json]
|
|
11
|
+
Reads a test-failure transcript from stdin or --file and prints a compact summary.
|
|
12
|
+
--json Emit a JSON object {failures,errors,locations} instead of text.
|
|
13
|
+
Env caps (override): DEBUG_MAX_FAILURES=25 DEBUG_MAX_ERRORS=25 DEBUG_MAX_LOCATIONS=25 DEBUG_MAX_LINES=100
|
|
14
|
+
EOF
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
file=""
|
|
18
|
+
json=0
|
|
19
|
+
while [ $# -gt 0 ]; do
|
|
20
|
+
case "$1" in
|
|
21
|
+
--file) file="${2:-}"; shift 2 || { echo "debug-testfail.sh: --file needs a path" >&2; exit 2; } ;;
|
|
22
|
+
--json) json=1; shift ;;
|
|
23
|
+
-h|--help) usage; exit 0 ;;
|
|
24
|
+
*) echo "debug-testfail.sh: unknown arg: $1" >&2; usage >&2; exit 2 ;;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
|
|
28
|
+
if [ -n "$file" ]; then
|
|
29
|
+
[ -r "$file" ] || { echo "debug-testfail.sh: cannot read file: $file" >&2; exit 2; }
|
|
30
|
+
exec < "$file"
|
|
31
|
+
elif [ -t 0 ]; then
|
|
32
|
+
echo "debug-testfail.sh: no input (pipe a transcript or pass --file)" >&2
|
|
33
|
+
exit 2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
awk -v json="$json" \
|
|
37
|
+
-v maxf="${DEBUG_MAX_FAILURES:-25}" \
|
|
38
|
+
-v maxe="${DEBUG_MAX_ERRORS:-25}" \
|
|
39
|
+
-v maxl="${DEBUG_MAX_LOCATIONS:-25}" \
|
|
40
|
+
-v maxraw="${DEBUG_MAX_LINES:-100}" '
|
|
41
|
+
function trim(s){ sub(/^[ \t]+/,"",s); sub(/[ \t]+$/,"",s); return s }
|
|
42
|
+
function jesc(s){ gsub(/\\/,"\\\\",s); gsub(/"/,"\\\"",s); gsub(/\t/," ",s); return s }
|
|
43
|
+
function add(arr,seen,n,max,val, key){ val=trim(val); if(val=="")return n; key=val; if(key in seen)return n; if(n>=max){over[max==maxf?"f":(max==maxe?"e":"l")]++;return n} seen[key]=1; arr[++n]=val; return n }
|
|
44
|
+
{
|
|
45
|
+
raw[NR]=$0
|
|
46
|
+
line=$0
|
|
47
|
+
|
|
48
|
+
# --- failed test NAMES (line-shape, not language) ---
|
|
49
|
+
if (match(line, /\(fail\)[ \t]+/)) { # bun/jest: (fail) NAME [1ms]
|
|
50
|
+
name=substr(line, RSTART+RLENGTH); sub(/[ \t]*\[[^]]*\][ \t]*$/,"",name)
|
|
51
|
+
nf=add(fails,fseen,nf,maxf,name)
|
|
52
|
+
} else if (match(line, /(^|[ \t])test[ \t]+[^ \t]+[ \t]+\.\.\.[ \t]+FAILED/)) { # cargo: test NAME ... FAILED
|
|
53
|
+
n=line; sub(/^[ \t]*test[ \t]+/,"",n); sub(/[ \t]+\.\.\..*/,"",n)
|
|
54
|
+
nf=add(fails,fseen,nf,maxf,n)
|
|
55
|
+
} else if (match(line, /^[ \t]*(FAIL|✕|✗|×)[ \t]+/)) { # generic fail markers
|
|
56
|
+
name=substr(line, RSTART+RLENGTH)
|
|
57
|
+
nf=add(fails,fseen,nf,maxf,name)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# --- ERROR / assertion lines ---
|
|
61
|
+
if (line ~ /([Ee]rror:|panicked at|[Aa]ssertion|AssertionError|Expected:|Received:|^[ \t]*left:|^[ \t]*right:|thread .* panicked)/) {
|
|
62
|
+
ne=add(errs,eseen,ne,maxe,line)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# --- code file:line[:col] locations (path with extension + :digits) ---
|
|
66
|
+
s=line
|
|
67
|
+
while (match(s, /[A-Za-z0-9_.\/\\-]+\.[A-Za-z]+:[0-9]+(:[0-9]+)?/)) {
|
|
68
|
+
loc=substr(s, RSTART, RLENGTH)
|
|
69
|
+
nl=add(locs,lseen,nl,maxl,loc)
|
|
70
|
+
s=substr(s, RSTART+RLENGTH)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
END {
|
|
74
|
+
recognized = (nf+ne+nl) > 0
|
|
75
|
+
if (json) {
|
|
76
|
+
printf "{"
|
|
77
|
+
printf "\"failures\":["; for(i=1;i<=nf;i++){printf "%s\"%s\"", (i>1?",":""), jesc(fails[i])} printf "],"
|
|
78
|
+
printf "\"errors\":["; for(i=1;i<=ne;i++){printf "%s\"%s\"", (i>1?",":""), jesc(errs[i])} printf "],"
|
|
79
|
+
printf "\"locations\":[";for(i=1;i<=nl;i++){printf "%s\"%s\"", (i>1?",":""), jesc(locs[i])} printf "],"
|
|
80
|
+
printf "\"recognized\":%s", (recognized?"true":"false")
|
|
81
|
+
printf "}\n"
|
|
82
|
+
exit 0
|
|
83
|
+
}
|
|
84
|
+
if (!recognized) {
|
|
85
|
+
print "debug-testfail: no recognizable test failures — raw input (capped):"
|
|
86
|
+
cap = (NR<maxraw?NR:maxraw)
|
|
87
|
+
for(i=1;i<=cap;i++) print raw[i]
|
|
88
|
+
if (NR>maxraw) printf "... (+%d more lines)\n", NR-maxraw
|
|
89
|
+
exit 0
|
|
90
|
+
}
|
|
91
|
+
print "FAILED TESTS (" nf (over["f"]?"+":"") "):"
|
|
92
|
+
for(i=1;i<=nf;i++) print " - " fails[i]
|
|
93
|
+
if (over["f"]) print " ... (+" over["f"] " more)"
|
|
94
|
+
if (ne>0) { print "\nERRORS (" ne (over["e"]?"+":"") "):"; for(i=1;i<=ne;i++) print " " errs[i]; if(over["e"]) print " ... (+" over["e"] " more)" }
|
|
95
|
+
if (nl>0) { print "\nLOCATIONS (" nl (over["l"]?"+":"") "):"; for(i=1;i<=nl;i++) print " " locs[i]; if(over["l"]) print " ... (+" over["l"] " more)" }
|
|
96
|
+
}
|
|
97
|
+
'
|
|
File without changes
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# settings/
|
|
2
|
+
|
|
3
|
+
Reusable Claude Code settings fragments plus data files consumed by hooks.
|
|
4
|
+
|
|
5
|
+
## Fragments
|
|
6
|
+
|
|
7
|
+
- `permissions.fragment.json` — sanitized union of permission allowlists/denylists from the source repos. Its `deny` block is deliberately short: `permissions.deny` **overrides** a PreToolUse hook's `ask`, so a rule here silently outranks whatever `gates.<name>.mode` says. Only catastrophic, never-ask-me commands belong in it (`rm -rf /`, `mkfs`, `dd`, `sudo rm`, `chmod 777`); `git push --force` and `node -e` moved to `bash-denylist.txt`, where the gate mode decides whether they deny, ask, or pass. Most repos do not need to merge this at all — toolu writes `Bash(*)`, `Edit`, `Write` into `.claude/settings.local.json` on first run (see `permissions.autoAllow` in `docs/config.md`). This is a **dev-mode merge for the repo checkout**; the `ast-grep` wrapper allow-rules pin the full `plugins/ast-grep/` paths (repo-root and `.claude/worktrees/*` variants) so an untrusted temp/checkout directory with a same-named tail cannot satisfy the allowlist. Installed plugins are governed by Claude Code's own plugin permissions, not this fragment.
|
|
8
|
+
|
|
9
|
+
Hook wiring ships in the plugin manifest (`plugins/toolu/hooks/hooks.json`);
|
|
10
|
+
installing the plugin registers all hooks — no manual settings merge needed.
|
|
11
|
+
|
|
12
|
+
### Merge into your settings
|
|
13
|
+
|
|
14
|
+
For the permissions fragment, run from the repo root:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
jq -s '.[0] * .[1]' ~/.claude/settings.json plugins/toolu/settings/permissions.fragment.json \
|
|
18
|
+
> ~/.claude/settings.json.new && mv ~/.claude/settings.json.new ~/.claude/settings.json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
> Never add a path that contains secrets (e.g. `.env`) to `additionalDirectories`.
|
|
22
|
+
|
|
23
|
+
## Security note
|
|
24
|
+
|
|
25
|
+
The settings.json deny matcher is substring-based and unreliable for argv
|
|
26
|
+
shapes like `node -e`, `git push --force`, or `git push origin main`. The
|
|
27
|
+
`hooks/pre-tools/modules/bash-commands.sh` hook performs argv-aware
|
|
28
|
+
enforcement using `bash-denylist.txt`. Both layers must be installed for
|
|
29
|
+
the security model to hold:
|
|
30
|
+
|
|
31
|
+
- Settings denies catch obvious cases at the matcher layer.
|
|
32
|
+
- `bash-commands.sh` parses argv and reliably rejects the listed tokens
|
|
33
|
+
even when they are embedded mid-command-line.
|
|
34
|
+
|
|
35
|
+
## Data files (read by hooks)
|
|
36
|
+
|
|
37
|
+
Consumer paths below are relative to the plugin root (`plugins/toolu/`);
|
|
38
|
+
the merge commands above are written for the repo root because cwd matters
|
|
39
|
+
when you run them.
|
|
40
|
+
|
|
41
|
+
| File | Consumer | Purpose |
|
|
42
|
+
|-------------------------------|---------------------------------------------------|--------------------------------------------------------------------|
|
|
43
|
+
| `bash-allowlist.txt` | `hooks/pre-tools/modules/bash-commands.sh` | Explicit overrides on top of the denylist (deny + allow → allowed). |
|
|
44
|
+
| `bash-denylist.txt` | `hooks/pre-tools/modules/bash-commands.sh` | Tokens the bash guard rejects via argv-aware parsing. |
|
|
45
|
+
| `code-edit-rules.json` | `hooks/pre-tools/modules/code-edit-rules.sh` | Pattern rules for Write/Edit gating on source files. |
|
|
46
|
+
| `commit-prefixes.txt` | `hooks/pre-tools/modules/commit-gate.sh` | Allowed Conventional Commits prefixes for `git commit` messages. |
|
|
47
|
+
| `mcp-blocklist.txt` | `hooks/pre-tools/modules/mcp-blocker.sh` | MCP server prefixes blocked unconditionally (plain text). |
|
|
48
|
+
| `toolu.config.example.json` | (reference — copy to `~/.claude/toolu.config.json`) | Example runtime opt-out config (skills/hooks/mcp). See `docs/config.md`. |
|
|
49
|
+
| `protected-files.txt` | `hooks/pre-tools/modules/protected-files.sh` | Paths the edit guard refuses to modify (lockfiles, secrets, etc.). |
|
|
50
|
+
| `rust-unsafe-exemptions.txt` | `hooks/post-tools/modules/rust-quality.sh` | Files/paths exempt from the `unsafe` Rust check. |
|
|
51
|
+
|
|
52
|
+
Each plain-text file is one entry per line, `#` for comments. JSON files
|
|
53
|
+
follow whatever schema the consuming script documents.
|
|
54
|
+
|
|
55
|
+
### `mcp-blocklist.txt` redirect hints
|
|
56
|
+
|
|
57
|
+
A blocklist line may carry an optional `-> <text>` suffix after the server
|
|
58
|
+
prefix. When that server is denied, the text is appended to the deny reason so
|
|
59
|
+
the user is pointed at the replacement. The prefix alone drives the match; the
|
|
60
|
+
hint is ignored for matching.
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
# <server-prefix> -> <redirect text shown in the deny reason>
|
|
64
|
+
# Example (commented = inert; uncomment to actually block the Atlassian MCP and
|
|
65
|
+
# steer Jira work to the bundled jira skill):
|
|
66
|
+
# claude_ai_Atlassian -> use the `jira` skill instead
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The example is shown **commented**, so nothing is blocked out of the box — the
|
|
70
|
+
`jira`/toolu prompt nudge handles discoverability without denying the MCP.
|
|
71
|
+
Uncomment the line (in your own settings dir) only if you want a hard block too.
|
|
72
|
+
|
|
73
|
+
Allow/deny semantics for the bash guard: the denylist is checked first; a
|
|
74
|
+
command that matches a deny rule is still allowed if it also matches an
|
|
75
|
+
allowlist rule (the allowlist is an explicit override, not a default gate).
|
|
76
|
+
Commands that match no deny rule are allowed by default.
|
|
77
|
+
|
|
78
|
+
> Allowlist caveat: single-token allowlist entries match anywhere in the
|
|
79
|
+
> command string as **substrings** (only multi-token entries are argv-aware —
|
|
80
|
+
> see `bash-commands.sh`). A broad single-token entry such as `node` therefore
|
|
81
|
+
> overrides far more than intended and quietly broadens the attack surface
|
|
82
|
+
> (e.g. it would exempt `node -e '…'`). Prefer specific multi-token entries for
|
|
83
|
+
> exemptions so the override stays argv-scoped to exactly the command you mean.
|
|
84
|
+
|
|
85
|
+
Lookup order (see `toolu_settings_dir` in `hooks/lib/detect.sh`, sibling of
|
|
86
|
+
this directory inside the plugin):
|
|
87
|
+
`$TOOLU_SETTINGS_DIR` (if set) → `~/.claude/settings` (if it exists) →
|
|
88
|
+
the plugin's own `settings/` directory, resolved relative to the hooks. There is
|
|
89
|
+
no per-project `.claude/settings/` lookup — to override per project, point
|
|
90
|
+
`TOOLU_SETTINGS_DIR` at a project-local directory.
|
|
91
|
+
|
|
92
|
+
## Env vars
|
|
93
|
+
|
|
94
|
+
| Variable | Effect |
|
|
95
|
+
|---------------------------|-----------------------------------------|
|
|
96
|
+
| `TOOLU_SETTINGS_DIR` | Directory the hooks read data files from |
|
|
97
|
+
| `MY_CLAUDE_QUALITY` | `off` to disable `quality-gate.sh` |
|
|
98
|
+
| `MY_CLAUDE_COMEMORY_REPO` | Overrides the comemory `--repo` scope used by the comemory wrapper (the comemory plugin's `skills/agent-memory/scripts/comemory.sh`). Defaults to the git project name. Not read by any hook. |
|
|
99
|
+
|
|
100
|
+
## Statusline
|
|
101
|
+
|
|
102
|
+
The statusline moved to its own optional plugin, **`statusline`** — it shows
|
|
103
|
+
`model | effort | ctx | <gate> | folder | branch`, with a loud red
|
|
104
|
+
`✗ gate:failing` marker driven by the same `.claude/tmp/quality-gate-status.json`
|
|
105
|
+
the rust-quality / ts-quality / python-quality hooks write. Install it and wire `settings.json` per
|
|
106
|
+
`plugins/statusline/README.md`:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
/plugin install statusline@toolu
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{ "statusLine": { "type": "command",
|
|
114
|
+
"command": "bash ~/.claude/statusline/statusline.sh" } }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Toolu no longer ships or symlinks the statusline; on upgrade it sweeps the
|
|
118
|
+
old `~/.claude/toolu/statusline.sh` symlink it used to own. If you previously
|
|
119
|
+
wired that path, re-point it to `~/.claude/statusline/statusline.sh`.
|
|
120
|
+
|
|
121
|
+
## Runtime config
|
|
122
|
+
|
|
123
|
+
For per-skill, per-hook, or per-MCP opt-out without touching the data
|
|
124
|
+
files above, see `docs/config.md`. The config file lives at
|
|
125
|
+
`~/.claude/toolu.config.json` (or the project-local override) and is
|
|
126
|
+
deep-merged at runtime. The `mcp-blocklist.txt` blocklist still works in
|
|
127
|
+
parallel; either source can block a server.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# bash-commands.sh allowlist (one pattern per line; '#' starts a comment).
|
|
2
|
+
#
|
|
3
|
+
# IMPORTANT: deny is checked FIRST, allow second. Allow is intended for
|
|
4
|
+
# per-project override of deny rules, not for substring evasion of
|
|
5
|
+
# security-hardened blocks like `node -e`.
|
|
6
|
+
#
|
|
7
|
+
# Multi-token rules (e.g. `bun run check`) are argv-aware: the first
|
|
8
|
+
# token must equal tokens[0] AND every other rule-token must appear as
|
|
9
|
+
# a distinct later argv token. Single-token rules substring-match the
|
|
10
|
+
# full command.
|
|
11
|
+
#
|
|
12
|
+
# Currently empty — add per-project exemptions here.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# bash-commands.sh denylist (one token per line; '#' starts a comment).
|
|
2
|
+
#
|
|
3
|
+
# Each line is matched argv-aware against the parsed command:
|
|
4
|
+
# "<bin> <flag>" — bin must be the first argv token and flag must be a later
|
|
5
|
+
# argv token (covers JSON-matcher gaps).
|
|
6
|
+
# single token — substring-matched against the whole command for tokens like
|
|
7
|
+
# "biome" or "cargo test".
|
|
8
|
+
#
|
|
9
|
+
# Delivery is a MODE, not a constant: `gates.bashCommands.mode` decides whether
|
|
10
|
+
# a match here denies, asks, advises (the shipped default), or is ignored. A
|
|
11
|
+
# rule in this file means "worth telling the agent about", not "impossible".
|
|
12
|
+
# `ask` is opt-in via `gates.bashCommands.mode`.
|
|
13
|
+
#
|
|
14
|
+
# git and gh are deliberately absent. Every git operation — force pushes and
|
|
15
|
+
# pushes to the base branch included — is not this file's call to make.
|
|
16
|
+
#
|
|
17
|
+
# Security-hardened: argv-aware blocks the JSON matcher cannot reliably reject.
|
|
18
|
+
node -e
|
|
19
|
+
node -p
|
|
20
|
+
node --eval
|
|
21
|
+
node --print
|
|
22
|
+
bun -e
|
|
23
|
+
bun --eval
|
|
24
|
+
# General policy: never run cargo test (use nextest instead).
|
|
25
|
+
cargo test
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"//": "code-edit-rules.sh data file. Each entry maps a file-glob pattern to a list of one-line rule reminders. The hook joins the strings and surfaces them before edits. Schema: {rules: [{ match: string (glob), docs: [string] (one-line rule texts), when_path_matches?: [string] (extra_docs added when the file path also matches one of these), extra_docs?: [string]}]}",
|
|
3
|
+
"rules": [
|
|
4
|
+
{
|
|
5
|
+
"match": "*.rs",
|
|
6
|
+
"docs": [
|
|
7
|
+
"Rust: zero compiler/clippy warnings",
|
|
8
|
+
"no unwrap()/expect()/panic! outside tests",
|
|
9
|
+
"keep it simple — no speculative abstractions"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"match": "*.ts",
|
|
14
|
+
"docs": [
|
|
15
|
+
"TS: zero typecheck/lint errors and warnings",
|
|
16
|
+
"no `any`, @ts-ignore, or non-null assertions",
|
|
17
|
+
"keep it simple — no speculative abstractions"
|
|
18
|
+
],
|
|
19
|
+
"when_path_matches": [
|
|
20
|
+
"*/features/*",
|
|
21
|
+
"*/components/*",
|
|
22
|
+
"*/routes/*"
|
|
23
|
+
],
|
|
24
|
+
"extra_docs": [
|
|
25
|
+
"frontend: colocate by feature (components/hooks/routes per feature dir)"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"match": "*.tsx",
|
|
30
|
+
"docs": [
|
|
31
|
+
"TS: zero typecheck/lint errors and warnings",
|
|
32
|
+
"no `any`, @ts-ignore, or non-null assertions",
|
|
33
|
+
"keep it simple — no speculative abstractions"
|
|
34
|
+
],
|
|
35
|
+
"when_path_matches": [
|
|
36
|
+
"*/features/*",
|
|
37
|
+
"*/components/*",
|
|
38
|
+
"*/routes/*"
|
|
39
|
+
],
|
|
40
|
+
"extra_docs": [
|
|
41
|
+
"frontend: colocate by feature (components/hooks/routes per feature dir)"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"match": "*.js",
|
|
46
|
+
"docs": [
|
|
47
|
+
"JS: keep lint/tests green",
|
|
48
|
+
"keep it simple — no speculative abstractions"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"match": "*.jsx",
|
|
53
|
+
"docs": [
|
|
54
|
+
"JS: keep lint/tests green",
|
|
55
|
+
"keep it simple — no speculative abstractions"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"match": "*.py",
|
|
60
|
+
"docs": [
|
|
61
|
+
"Python: colocated test_<module>.py, real-data tests (no mocks)",
|
|
62
|
+
"no bare except:/blanket # noqa/bare # type: ignore — fix the cause",
|
|
63
|
+
"size limits via lang.python.* (default 400/file, 50/function)"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|