From 554dc0b2cde5724aca27c4bb358b9332aa7731a9 Mon Sep 17 00:00:00 2001 From: Alexander Grebennik Date: Fri, 13 Nov 2026 18:03:32 +0100 Subject: [PATCH 1/3] address cc changelog --- .claude-plugin/marketplace.json | 4 +- .claude/rules/agent-development.md | 17 +- .claude/rules/hook-development.md | 10 + .claude/rules/skill-development.md | 6 +- .../cc-changelog/references/analysis-rules.md | 2 +- .../skills/docs-check/references/doc-pages.md | 6 +- .../docs-check/references/validation-rules.md | 6 +- .github/copilot-instructions.md | 8 +- .../plugin-review.instructions.md | 47 +--- CHANGELOG.md | 24 +- package-lock.json | 237 ++++++++++-------- package.json | 8 +- .../.claude-plugin/plugin.json | 2 +- .../ruby-grape-rails/bin/subagent-statusline | 96 ------- plugins/ruby-grape-rails/hooks/hooks.json | 6 - .../scripts/install-statusline-wrapper.sh | 72 ------ plugins/ruby-grape-rails/settings.json | 6 - .../skills/brainstorm/SKILL.md | 4 +- .../ruby-grape-rails/skills/review/SKILL.md | 8 +- scripts/fetch-claude-docs.sh | 4 +- 20 files changed, 232 insertions(+), 341 deletions(-) delete mode 100755 plugins/ruby-grape-rails/bin/subagent-statusline delete mode 100755 plugins/ruby-grape-rails/hooks/scripts/install-statusline-wrapper.sh delete mode 100644 plugins/ruby-grape-rails/settings.json diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index de2e28e0..08289001 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,7 +5,7 @@ }, "metadata": { "description": "Claude Code plugins by Alexander Grebennik", - "version": "1.16.19" + "version": "1.16.20" }, "plugins": [ { @@ -19,7 +19,7 @@ "source": "git-subdir", "url": "slbug/claude-ruby-grape-rails", "path": "plugins/ruby-grape-rails", - "ref": "v1.16.19" + "ref": "v1.16.20" }, "relevance": { "topic": "Rails", diff --git a/.claude/rules/agent-development.md b/.claude/rules/agent-development.md index bb4adb5a..736ee6f3 100644 --- a/.claude/rules/agent-development.md +++ b/.claude/rules/agent-development.md @@ -69,10 +69,19 @@ completed. ## Foreground Dispatch -Plugin agents are spawned foreground only. No skill body, fanout -template, or example MAY pass `run_in_background: true` on an -`Agent(...)` call. Parallel = multiple Agent tool calls in one -message; never the background flag. +No skill body, fanout template, or example MAY pass +`run_in_background: true` on an `Agent(...)` call. Parallel = multiple +Agent tool calls in one message; never the background flag. + +| Session | Runtime behavior | +|---|---| +| Interactive terminal, VS Code, desktop (fork mode on, the default) | Main-conversation subagents start in the background. The Agent tool exposes no `run_in_background` parameter. Completion arrives as a notification | +| `claude -p`, Agent SDK, or `CLAUDE_CODE_FORK_SUBAGENT=0` | Claude chooses foreground or background. The flag exists — the prohibition above applies | + +Every fanout skill MUST carry an explicit "wait for all agents to +complete" step between the spawn step and the first artifact read or +Artifact Recovery step. Without it, a background fanout is consolidated +before its artifacts exist. ## Memory diff --git a/.claude/rules/hook-development.md b/.claude/rules/hook-development.md index 28720795..d47270e9 100644 --- a/.claude/rules/hook-development.md +++ b/.claude/rules/hook-development.md @@ -32,6 +32,16 @@ Add or update a short policy comment near the top of the hook when behavior chan ignored on `clear`/`compact`). Use the JSON form to combine it with `additionalContext`. Read input `session_title` first to avoid clobbering a user `/rename` (see `check-scratchpad.sh`) +- `UserPromptSubmit` receives a typed skill or slash command as the + line the user typed (`/rb:plan ...`, `/ruby-grape-rails:plan ...`), + NOT the expanded skill body, and runs before the expansion. Match + both prefixes on `.prompt` (see `session-title.sh`). Use + `UserPromptExpansion` to match on the resolved command name +- `PostToolUse` command hooks get 10 seconds, whatever their `timeout`, + when the user ends the turn with `Ctrl+Enter` while the tool runs. + CC kills a hook still running at that point. Only `async: true` hooks + outlive it. Keep every blocking `PostToolUse` hook safe to kill + mid-run — no partial writes, temp files cleaned by `trap` - `SubagentStart` uses `hookSpecificOutput.additionalContext` to inject context into subagents - `PostToolUseFailure` uses `hookSpecificOutput.additionalContext` for debugging hints diff --git a/.claude/rules/skill-development.md b/.claude/rules/skill-development.md index 2b72dcd8..f3c6648d 100644 --- a/.claude/rules/skill-development.md +++ b/.claude/rules/skill-development.md @@ -83,9 +83,13 @@ skills/{name}/ subdir-per-topic (research per-aspect). See `plugins/ruby-grape-rails/references/run-manifest.md` for schema, staleness rules, and write protocol. -- Agent dispatch: foreground only. Skill bodies MUST NOT pass +- Agent dispatch: skill bodies MUST NOT pass `run_in_background: true` on any `Agent(...)` call. Parallel = many Agent tool calls in a single message, NOT the background flag. + Interactive sessions start main-conversation subagents in the + background regardless, so every fanout skill MUST state an explicit + wait-for-all-agents step before its first artifact read. See + `.claude/rules/agent-development.md` § "Foreground Dispatch". ## Colon Naming diff --git a/.claude/skills/cc-changelog/references/analysis-rules.md b/.claude/skills/cc-changelog/references/analysis-rules.md index d910ec04..0c7e9056 100644 --- a/.claude/skills/cc-changelog/references/analysis-rules.md +++ b/.claude/skills/cc-changelog/references/analysis-rules.md @@ -50,7 +50,7 @@ Imperative-only. Map CC changelog entries to specific plugin components. | `marketplace.json` schema | `.claude-plugin/marketplace.json` | | `${CLAUDE_PLUGIN_DATA}` | `plugins/ruby-grape-rails/hooks/scripts/setup-dirs.sh`, `plugins/ruby-grape-rails/hooks/scripts/log-progress.sh` | | `${CLAUDE_PLUGIN_ROOT}` | All hooks.json paths | -| `settings.json` keys | `plugins/ruby-grape-rails/settings.json` ships only `subagentStatusLine`. Documented supported keys per CC docs: `agent` + `subagentStatusLine`. New documented keys → INFO unless plugin adopts. | +| `settings.json` keys | Plugin ships no `settings.json`. `subagentStatusLine` is removed from CC (loads, no effect). A plugin's `agent` setting is deprecated. New documented plugin-level keys → INFO unless plugin adopts. | | Plugin validation changes | CI workflow | ### Tool System diff --git a/.claude/skills/docs-check/references/doc-pages.md b/.claude/skills/docs-check/references/doc-pages.md index 7f1c39c1..d78fa2b7 100644 --- a/.claude/skills/docs-check/references/doc-pages.md +++ b/.claude/skills/docs-check/references/doc-pages.md @@ -37,7 +37,7 @@ Primary cached pages (plugin-critical): | `env-vars.md` | Environment variable contract: `CLAUDE_PLUGIN_ROOT`, `CLAUDE_PLUGIN_DATA`, `CLAUDE_PROJECT_DIR`, etc. | | `errors.md` | Error taxonomy driving hook failure classification and `StopFailure` matchers | | `cli-reference.md` | `claude plugin validate`, `--plugin-dir`, flags used by eval/doctor scripts | -| `statusline.md` | Plugin-level `subagentStatusLine` setting schema | +| `statusline.md` | Status line surface — confirms no plugin-level status line setting has returned | | `discover-plugins.md` | Marketplace install flow, `git-subdir` path resolution | | `sandboxing.md` | Bash sandboxing semantics affecting hook side-effect guarantees | | `context-window.md` | PreCompact/PostCompact hook timing and payload | @@ -70,7 +70,7 @@ Additional cached pages (context/reference): | `permission-modes.md` | Permission modes and implications for plugins | | `permissions.md` | Comprehensive permissions guide | | `fast-mode.md` | `/fast` semantics and eligible models — relates to `effort: max` skill settings | -| `output-styles.md` | Output-style surface adjacent to statusline + `subagentStatusLine` | +| `output-styles.md` | Output-style surface adjacent to the status line | | `troubleshooting.md` | Hook failure diagnosis patterns | | `common-workflows.md` | Plan/Work/Review lifecycle comparison with `/rb:*` workflows | | `whats-new/index.md` | Weekly release notes index — `cc-changelog` + docs-check feed | @@ -194,7 +194,7 @@ Use: Questions this answers: - Is the `claude plugin ...` subcommand used by doctor/eval still documented? -- Does plugin-level `subagentStatusLine` match the documented schema? +- Do docs reintroduce a plugin-level status line or plugin `settings.json` key? The plugin ships none. ### Built-in Feature Overlap diff --git a/.claude/skills/docs-check/references/validation-rules.md b/.claude/skills/docs-check/references/validation-rules.md index 441bfaa3..8d0cdd87 100644 --- a/.claude/skills/docs-check/references/validation-rules.md +++ b/.claude/skills/docs-check/references/validation-rules.md @@ -313,8 +313,10 @@ Checks for `.claude-plugin/plugin.json`: - metadata: `$schema`, `name`, `displayName`, `version`, `description`, `author`, `homepage`, `repository`, `license`, `keywords`, `metadata`, `defaultEnabled`, `dependencies` - - behavior: `settings` (only `agent` and `subagentStatusLine` take - effect), `userConfig`, `channels` + - behavior: `userConfig`, `channels`. The plugin ships no + `settings.json` — `subagentStatusLine` is removed (loads, no + effect) and a plugin's `agent` setting is deprecated (warns in + `claude plugin validate`) - components: `skills`, `commands`, `agents`, `hooks`, `mcpServers`, `lspServers`, `outputStyles`, `workflows` - `experimental.themes`, `experimental.monitors`, `experimental.evals` diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 885accbd..a14d8d03 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -34,7 +34,6 @@ PR review: flag prose that violates this rule. | Hooks | `plugins/ruby-grape-rails/hooks/hooks.json` + `scripts/*` | Shell + Ruby triggered by CC events (PostToolUse, PostToolUseFailure, SessionStart, etc) | | Executables | `plugins/ruby-grape-rails/bin/*` | Plugin CLIs added to Bash PATH; no extension; chmod +x; mixed bash + Ruby | | Library | `plugins/ruby-grape-rails/lib/*.rb` | End-user runtime modules (Ruby ≥ 3.4, stdlib only) | -| Plugin settings | `plugins/ruby-grape-rails/settings.json` | Only `agent` + `subagentStatusLine` keys supported per CC docs | | Eval | `lab/eval/` | Deterministic Python eval framework for plugin quality | | Contributor tooling | `.claude/` | NOT shipped; `.claude/rules/` (auto-loaded path-scoped rules), `.claude/skills/` (contributor-only skills) | @@ -42,7 +41,6 @@ PR review: flag prose that violates this rule. | Binary | Purpose | |---|---| -| `subagent-statusline` (bash) | advisory statusline renderer; fail-open | | `detect-stack` (Ruby) | `/rb:init` stack detection | | `extract-permissions` (Ruby) | transcript-based Bash permission recommender | | `resolve-base-ref` (bash) | eval-able BASE_REF resolver for diff comparisons | @@ -151,10 +149,8 @@ the PR. `hooks/hooks.json` references, sourcing in other `*.sh` files (`source ".../LIB_NAME.sh"`), matching tests under `lab/eval/tests/test_runtime_scripts.py`. -- **`bin/` renamed / added / removed** → also check - `plugins/ruby-grape-rails/settings.json` (statusline command path), - `plugins/ruby-grape-rails/hooks/scripts/install-statusline-wrapper.sh`, - any skill/agent/script that shells out, `CLAUDE.md` "Executables" +- **`bin/` renamed / added / removed** → also check any + skill/agent/script that shells out, `CLAUDE.md` "Executables" enumeration. - **New skill / agent / hook added** → also check corresponding `lab/eval/evals/`, `lab/eval/triggers/`, `lab/eval/dimensions/` diff --git a/.github/instructions/plugin-review.instructions.md b/.github/instructions/plugin-review.instructions.md index 7e1ffd62..11ca548a 100644 --- a/.github/instructions/plugin-review.instructions.md +++ b/.github/instructions/plugin-review.instructions.md @@ -121,17 +121,14 @@ Exception files (human-facing, narrative OK): `README.md`, the shebang; rescue at process boundary, never use `Kernel#eval` / `Kernel#system` with unvalidated input (Iron Law 12) - Advisory fail-open pattern (empty stdout, exit 0 on any error) is - intentional for statusline and similar advisory executables — do NOT - flag as "missing error handling" + intentional for advisory executables — do NOT flag as "missing error + handling" - From `hooks.json`, `.mcp.json`, `monitors/monitors.json`, template expansion is supported; reference bundled scripts via `${CLAUDE_PLUGIN_ROOT}/...` ### Currently shipped binaries (plugins/ruby-grape-rails/bin/) -- `subagent-statusline` (bash) — advisory, fail-open. Empty stdout + - exit 0 on any error. Referenced from `settings.json` indirectly via - `~/.claude/ruby-grape-rails-subagent-statusline` wrapper - `detect-stack` (Ruby) — `/rb:init` stack detection. Outputs `key=value` pairs; treats unreadable manifests as absent - `extract-permissions` (Ruby) — analyzes session transcripts to @@ -288,32 +285,12 @@ Notes: ## Plugin Settings (plugins/**/settings.json) -- Only `agent` and `subagentStatusLine` keys are supported per CC docs - (`plugins-reference.md` standard plugin layout) -- Unknown keys are silently ignored by CC — do NOT flag partial coverage - of other settings fields -- `subagentStatusLine.command` does NOT expand `${CLAUDE_PLUGIN_ROOT}` - and CC does NOT export `CLAUDE_PLUGIN_ROOT` to the statusline - subprocess nor add plugin `bin/` to its PATH. Plugin-bundled - statusline scripts therefore require a SessionStart hook that writes - a small wrapper at `~/.claude/-subagent-statusline` - pointing at the current absolute plugin path. The plugin - `settings.json` then references that stable user-home path. The - wrapper must be rewritten only when its content differs from the - desired content (plugin version changes change the absolute path). - Do NOT flag this indirection as unnecessary — it is required by the - documented CC substitution scope - -### subagentStatusLine payload schema (as observed, not fully documented) - -The statusline subprocess receives base hook fields plus `columns` and a -`tasks[]` array. Each task provides `id`, `type` (e.g. `local_agent`), -`status`, `description`, `label` (usually the same text as `description`), -`startTime` as epoch milliseconds (13-digit integer), `tokenCount`, -`tokenSamples` as a number array, and `cwd`. The docs also list `.name` -but current CC payloads do NOT include it — match emoji/label from -`.label` first, falling back to `.description` and finally `.name`. Do -NOT flag the fallback chain as over-engineered. +- The plugin ships NO `settings.json`. Flag any PR that adds one +- `subagentStatusLine` is removed from CC — the key loads and has no + effect. Flag any reintroduced statusline script, wrapper, or setting +- A plugin's `agent` setting is deprecated in CC — it still applies and + warns at startup, in `claude plugin list`, and in + `claude plugin validate`. Flag any PR that adds it ## Do NOT Flag @@ -322,8 +299,6 @@ NOT flag the fallback chain as over-engineered. - `omitClaudeMd: true` on specialist agents (intentional context savings) - Colon-namespaced skill names like `rb:plan` (known compatibility item) - Advisory fail-open (empty stdout, exit 0) in `bin/` and advisory hooks -- Partial coverage in plugin `settings.json` (only `agent` and - `subagentStatusLine` are documented as supported) - Pointer-only links to `references/preferences/tool-batching.md` from skill or agent bodies (canonical examples doc for the tool-batching preference). Pointer = the link without restating @@ -399,7 +374,11 @@ NOT flag the fallback chain as over-engineered. one consolidated verdict per artifact. - `run_in_background: true` on any `Agent(...)` call in shipped skill bodies, fanout templates, or example snippets — flag as - BLOCKER. Plugin agents dispatch foreground only. + BLOCKER. +- A fanout skill whose spawn step is followed by an artifact read or + Artifact Recovery step with no explicit wait-for-all-agents step + between them. Interactive sessions run main-conversation subagents in + the background, so the read would precede the artifacts. - Raw `mv`, `cp`, `jq -i`, `rm`, or improvised shell against any `RUN-CURRENT.json` path or per-agent artifact path in shipped skill bodies, hook scripts, or examples — flag as BLOCKER. All manifest diff --git a/CHANGELOG.md b/CHANGELOG.md index 02dc0578..fddce28c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,27 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.16.20] - 2026-11-13 + +### Removed + +- Custom subagent status line. Claude Code removed the + `subagentStatusLine` setting, so subagent rows always use the default + look. The plugin no longer ships `settings.json`, + `bin/subagent-statusline`, or the `install-statusline-wrapper.sh` + `SessionStart` hook. A leftover + `~/.claude/ruby-grape-rails-subagent-statusline` wrapper is unused and + safe to delete by hand. + +### Changed + +- `/rb:review` and `/rb:brainstorm` state that reviewers and research + agents run in the background in interactive sessions and that + artifacts are read only after every agent completes. +- Contributor tooling: `markdownlint-cli` raised to `^0.50.0`, with + `overrides` pinning `minimatch` and `katex` to patched releases. + `npm audit` reports 0 vulnerabilities. + ## [1.16.19] - 2026-10-01 ### Changed @@ -3150,7 +3171,8 @@ Prevents context exhaustion with 3 compression strategies - 100+ reference documents across all skill domains - Plugin development guide with size guidelines and checklists -[Unreleased]: https://github.com/slbug/claude-ruby-grape-rails/compare/v1.16.19...HEAD +[Unreleased]: https://github.com/slbug/claude-ruby-grape-rails/compare/v1.16.20...HEAD +[1.16.20]: https://github.com/slbug/claude-ruby-grape-rails/compare/v1.16.19...v1.16.20 [1.16.19]: https://github.com/slbug/claude-ruby-grape-rails/compare/v1.16.18...v1.16.19 [1.16.18]: https://github.com/slbug/claude-ruby-grape-rails/compare/v1.16.17...v1.16.18 [1.16.17]: https://github.com/slbug/claude-ruby-grape-rails/compare/v1.16.16...v1.16.17 diff --git a/package-lock.json b/package-lock.json index b764b50f..6e5202b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,28 @@ { "name": "ruby-grape-rails-plugin", - "version": "1.16.19", + "version": "1.16.20", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ruby-grape-rails-plugin", - "version": "1.16.19", + "version": "1.16.20", "license": "MIT", "devDependencies": { "husky": "^9.1.7", - "markdownlint-cli": "^0.49.0" + "markdownlint-cli": "^0.50.0" }, "engines": { "node": ">=22.12.0" } }, + "node_modules/@isaacs/nonrecursive-glob-match": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@isaacs/nonrecursive-glob-match/-/nonrecursive-glob-match-1.1.0.tgz", + "integrity": "sha512-GPm/Dbvk5RLmhRnxXIa7nTpK0xtl4E0wj0MslsuNiJ1FIROU+2+9lgUC/dgF7Ey4QCWhfEsgxilMRMCdHPfDfw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/@types/debug": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", @@ -48,9 +55,9 @@ "license": "MIT" }, "node_modules/ansi-regex": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", - "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.6.0.tgz", + "integrity": "sha512-XZ5apbzreCbXSKwPjJstu8R0zOi247w3XYwWxtwBXgpZrCyc1Ka7p9/xY0A9/diMewmHbEKz+FIraWaEWjlN5g==", "dev": true, "license": "MIT", "engines": { @@ -61,11 +68,21 @@ } }, "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-3.0.4.tgz", + "integrity": "sha512-fwWK3Zq22l4XJJjx5mcBHGikIk+hJqO+32dPm0Jur7+rtG5x1scOjSfdT9ZKeWHPpsya/l0HHK4tDImBkTrtvA==", "dev": true, - "license": "Python-2.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "PSF-2.0" }, "node_modules/balanced-match": { "version": "4.0.4", @@ -200,13 +217,13 @@ } }, "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", + "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", "dev": true, "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -231,9 +248,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", - "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", "dev": true, "license": "MIT", "engines": { @@ -260,9 +277,9 @@ } }, "node_modules/ignore": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", - "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.14.tgz", + "integrity": "sha512-wCBiZ77u1tuWde6G/nfOtLaCTYcFDU5yCzARzK10y+rLhzYoL7a7yEemcopcc2Mzow7gZOIjnV2ym1NYmdiJOQ==", "dev": true, "license": "MIT", "engines": { @@ -328,9 +345,9 @@ } }, "node_modules/js-yaml": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.3.tgz", - "integrity": "sha512-n+mUVyUX5bVv7G/G2zyIHOhdxfuU1dY2NOFzTQUWiMUbFss8b57NFlgCCaggU78wSw5KVS9cllzeLyzyR+n5nw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.5.0.tgz", + "integrity": "sha512-paNr4LFIFPjeeSmwNYdrb8FafLLG/Cr2Af3GjbsHJ5CxIjH4r0c2emlmRdAtpPAieP1gRVzk6buBbVP5gBMGAg==", "dev": true, "funding": [ { @@ -344,7 +361,7 @@ ], "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "argparse": "^3.0.3" }, "bin": { "js-yaml": "bin/js-yaml.mjs" @@ -368,9 +385,9 @@ } }, "node_modules/katex": { - "version": "0.16.47", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", - "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.19.1.tgz", + "integrity": "sha512-jG8uKntjSEcm2EpQOh0XturpPuuC9r3Sq5HLHdsFdWZT27E672SF19QEi+of0/YeOy15lDgRhKvr5614uRrEfA==", "dev": true, "funding": [ "https://opencollective.com/katex", @@ -378,26 +395,16 @@ ], "license": "MIT", "dependencies": { - "commander": "^8.3.0" + "commander": "^15.0.0" }, "bin": { "katex": "cli.js" } }, - "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, "node_modules/linkify-it": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", - "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-6.1.0.tgz", + "integrity": "sha512-wJ/TwpSDTLepCrQoYWYIExIKg5Zchex2Nn5yk2mFnB+6PtdkHtyLx742md9csRjjOnGkKIS/RrbY7l8D6gT9Vw==", "dev": true, "funding": [ { @@ -411,13 +418,13 @@ ], "license": "MIT", "dependencies": { - "uc.micro": "^2.0.0" + "uc.micro": "^3.0.0" } }, "node_modules/markdown-it": { - "version": "14.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.2.tgz", - "integrity": "sha512-sHHjZ5fJKlgrG4qns2YwVcdNep35h5fERrfkD2YNsb9UFk0UIHarbiTaHKVMlPuWAoiilyK8Fv/jAm11slsY7Q==", + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-15.0.3.tgz", + "integrity": "sha512-+Az7Ojz3iRGu8KYMvJ6xVhvrxP3eE+vEtJX75Ow88XBpcQNV/0lGX5ZynIIBftREo4DC2jsveAMDaeltmm8QvQ==", "dev": true, "funding": [ { @@ -431,33 +438,34 @@ ], "license": "MIT", "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.5.0", - "linkify-it": "^5.0.2", - "mdurl": "^2.0.0", + "argparse": "^3.0.3", + "entities": "^8.1.0", + "linkify-it": "^6.1.0", + "mdurl": "^2.1.0", "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" + "uc.micro": "^3.0.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "node_modules/markdownlint": { - "version": "0.41.1", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.41.1.tgz", - "integrity": "sha512-qHKeU2E1bdyNAT077go2FVTNXvYcktN5IHtF6XyeD1l0PClxzSp2tUApAV14ORI8DGX4H9bNKZEzelZp4qn8IA==", + "version": "0.42.1", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.42.1.tgz", + "integrity": "sha512-Otolm9JX12iO2NG5cetlKfzGygpiLSlHuqXKxoT6HGhN5HtbxprJPicKZqqCQd88qOvUi/TEs3o1AmcYioVscA==", "dev": true, "license": "MIT", "dependencies": { - "micromark": "4.0.2", - "micromark-core-commonmark": "2.0.3", + "micromark": "4.0.3", + "micromark-core-commonmark": "2.0.4", "micromark-extension-directive": "4.0.0", "micromark-extension-gfm-autolink-literal": "2.1.0", "micromark-extension-gfm-footnote": "2.1.0", - "micromark-extension-gfm-table": "2.1.1", + "micromark-extension-gfm-table": "2.1.2", "micromark-extension-math": "3.1.0", - "micromark-util-types": "2.0.2", - "string-width": "8.2.1" + "micromark-util-types": "2.0.3", + "re2js": "2.9.1", + "string-width": "8.3.0" }, "engines": { "node": ">=22" @@ -467,23 +475,23 @@ } }, "node_modules/markdownlint-cli": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.49.1.tgz", - "integrity": "sha512-qpYqJbSYf3jv57bdnFmCaZ/Wlu6IYHp2b6SOKrKBJ7OnPrDHIKmx4NERWH49QH9viTI6yO6raVDDn5nrf60VQQ==", + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.50.0.tgz", + "integrity": "sha512-4GqP/CqpF74ihrlLTOPc3I5b/tZabiiKnIVQ27xTzsS4hjU3oIHKg1YBzWP7fsa9AH48LPF0KcmCqDccpSeMEg==", "dev": true, "license": "MIT", "dependencies": { "commander": "~15.0.0", "deep-extend": "~0.6.0", - "ignore": "~7.0.6", - "js-yaml": "~5.2.1", + "ignore": "~7.0.13", + "js-yaml": "~5.5.0", "jsonc-parser": "~3.3.1", "jsonpointer": "~5.0.1", - "markdown-it": "~14.3.0", - "markdownlint": "~0.41.1", - "minimatch": "~10.2.5", + "markdown-it": "~15.0.3", + "markdownlint": "~0.42.0", + "minimatch": "~10.2.6", "run-con": "~1.3.3", - "smol-toml": "~1.7.0", + "smol-toml": "~1.9.1", "tinyglobby": "~0.2.17" }, "bin": { @@ -501,9 +509,9 @@ "license": "MIT" }, "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.3.tgz", + "integrity": "sha512-oGYfQzHSG5dOMovQcJ3fyTmZlWAWpi0XA0sJwJs+i6OT88o1+Jtw/8z0CmdowSLxGhhFK89rQ/oXph/wN02PNw==", "dev": true, "funding": [ { @@ -527,6 +535,7 @@ "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", @@ -537,9 +546,9 @@ } }, "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.4.tgz", + "integrity": "sha512-wxEeE8v8XVvOrxn1TZj74qYhAtTQsSqufHVS3uNVyT1MupXxhyaHk8/9xDNPh9BmL77QNDgWTkZ3RsYHB2ry7w==", "dev": true, "funding": [ { @@ -557,18 +566,19 @@ "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", + "micromark-factory-space": "^2.1.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "micromark-util-types": "^2.0.3" } }, "node_modules/micromark-extension-directive": { @@ -630,9 +640,9 @@ } }, "node_modules/micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.2.tgz", + "integrity": "sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==", "dev": true, "license": "MIT", "dependencies": { @@ -713,9 +723,9 @@ } }, "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.1.0.tgz", + "integrity": "sha512-fS8hnLIjnjvdQIj39Geug8wWsR0HrYZ43KShKxNfwT7t2LOHo/LbWZEzEaSOjwtjdCsjoE6syHhonEzW0zv0+Q==", "dev": true, "funding": [ { @@ -883,6 +893,26 @@ "micromark-util-symbol": "^2.0.0" } }, + "node_modules/micromark-util-edit-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-edit-map/-/micromark-util-edit-map-1.0.0.tgz", + "integrity": "sha512-Pa2ljlsEL6sVwFaYeyrOLSYbQt73JvGbPOYFq+9AElXiSnfI5Q4465RRZ1sHv7lDjDOnGRDDaqPXqClqWK/q1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, "node_modules/micromark-util-encode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", @@ -1020,9 +1050,9 @@ "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.3.tgz", + "integrity": "sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==", "dev": true, "funding": [ { @@ -1037,16 +1067,17 @@ "license": "MIT" }, "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "11.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-11.0.8.tgz", + "integrity": "sha512-nFQuYSTVrGvysVBps5Ih+0BdnYFN/Cj3C816r6+p7yK+FHrVLGE4O4N9AFwykrlNlvM2HYt+Rad1Uiro6h88Ig==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "@isaacs/nonrecursive-glob-match": "^1.1.0", + "brace-expansion": "^5.0.12" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1112,6 +1143,16 @@ "node": ">=6" } }, + "node_modules/re2js": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/re2js/-/re2js-2.9.1.tgz", + "integrity": "sha512-JIT3bEEUZTOR2YS1walNEIfH4cF/cQeZcBUFq7ldqO6lR6g0X5CBq/S8rsa9omzZcsNf8qc36jCkWpKKtncrZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/run-con": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.3.tgz", @@ -1129,9 +1170,9 @@ } }, "node_modules/smol-toml": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.2.tgz", - "integrity": "sha512-pXFZ9B2WinEPzxWkMmlYE/oYx2BP+qLrE95wP8tCuK901uLSMGdCb6QSr82z+wnhXkG4+cO+OMLbZB2Cn+97zw==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.1.tgz", + "integrity": "sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -1142,9 +1183,9 @@ } }, "node_modules/string-width": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", - "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz", + "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1205,9 +1246,9 @@ } }, "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-3.0.0.tgz", + "integrity": "sha512-U3PppEkleoTnIfi8BozMx3yju3qc/L6SwqWo2Sw+54PX+PX0q9I+r1Um5HCmqD7n9VDX5/v3vQH/AjA6deDdtw==", "dev": true, "license": "MIT" } diff --git a/package.json b/package.json index c67928be..76323def 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ruby-grape-rails-plugin", - "version": "1.16.19", + "version": "1.16.20", "private": true, "description": "Specialist agents, Iron Laws, parallel code review, and plan→work→verify→review→compound workflow for Ruby, Rails, Grape, Sidekiq, Hotwire, Active Record, and Sequel projects.", "scripts": { @@ -56,7 +56,11 @@ }, "devDependencies": { "husky": "^9.1.7", - "markdownlint-cli": "^0.49.0" + "markdownlint-cli": "^0.50.0" + }, + "overrides": { + "minimatch": "^11.0.8", + "katex": "^0.19.1" }, "engines": { "node": ">=22.12.0" diff --git a/plugins/ruby-grape-rails/.claude-plugin/plugin.json b/plugins/ruby-grape-rails/.claude-plugin/plugin.json index 94717101..0e3fce65 100644 --- a/plugins/ruby-grape-rails/.claude-plugin/plugin.json +++ b/plugins/ruby-grape-rails/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ruby-grape-rails", - "version": "1.16.19", + "version": "1.16.20", "description": "Specialist agents, Iron Laws, parallel code review, and plan→work→verify→review→compound workflow for Ruby, Rails, Grape, Sidekiq, Hotwire, Active Record, and Sequel projects.", "keywords": ["ruby", "rails", "grape", "sidekiq", "hotwire", "turbo", "stimulus", "active-record", "sequel", "postgres", "redis", "rspec", "minitest", "brakeman", "rubocop", "karafka", "solid-queue", "tidewave", "iron-laws", "code-review", "specialist-agents", "plan-work-verify"], "author": { diff --git a/plugins/ruby-grape-rails/bin/subagent-statusline b/plugins/ruby-grape-rails/bin/subagent-statusline deleted file mode 100755 index fa5cb678..00000000 --- a/plugins/ruby-grape-rails/bin/subagent-statusline +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env bash -# Subagent status line: custom per-row rendering for the agent panel. -# -# Replaces CC's default `name · description · token count` row with: -# -# {emoji} {name} {dot} {elapsed} {tokens} {cwd_tail} -# -# Emoji maps the agent name prefix to a role (reviewer, planner, -# investigator, researcher, verifier, etc.). Status dot reflects the -# task.status field. Elapsed is derived from task.startTime (epoch seconds -# or ISO 8601 timestamp). Tokens are humanized. cwd_tail is the last path -# segment — useful when specialist agents run in parallel git worktrees. -# -# Input (stdin): JSON with `columns`, `tasks[]`, base hook fields. -# Output (stdout): one JSON line per overridden row: -# {"id": "", "content": ""} -# Omitted rows fall through to CC's default rendering. -# -# Policy: advisory — any error path exits 0 with no stdout, letting CC -# render its default rows. Requires `jq`; skips silently if absent. - -set -o nounset -set -o pipefail - -command -v jq >/dev/null 2>&1 || exit 0 - -INPUT=$(cat 2>/dev/null || true) -[[ -n "$INPUT" ]] || exit 0 -printf '%s' "$INPUT" | jq -e . >/dev/null 2>&1 || exit 0 - -printf '%s' "$INPUT" | jq -c ' - def emoji(name): - if name | test("review"; "i") then "🔍" - elif name | test("investigat"; "i") then "🐛" - elif name | test("analy"; "i") then "🔬" - elif name | test("research"; "i") then "📚" - elif name | test("verif|runner"; "i") then "✅" - elif name | test("valid"; "i") then "🛡" - elif name | test("architect|design"; "i") then "📐" - elif name | test("specialist|sidekiq"; "i") then "⚙" - elif name | test("judge|iron.?law"; "i") then "⚖" - elif name | test("advisor|runtime"; "i") then "💡" - elif name | test("trace"; "i") then "🔎" - elif name | test("supervis"; "i") then "🗂" - elif name | test("explore"; "i") then "🔭" - elif name | test("^plan|planning"; "i") then "📋" - elif name | test("security"; "i") then "🔐" - elif name | test("migration|deploy"; "i") then "🚀" - elif name | test("test"; "i") then "🧪" - else "🤖" end; - - def dot(s): - if s == "running" or s == "active" then "●" - elif s == "idle" or s == "waiting" then "○" - elif s == "done" or s == "completed" then "✓" - elif s == "error" or s == "failed" then "✗" - else "·" end; - - def toks(n): - if n >= 1000000 then "\((n / 100000 | floor) / 10)M" - elif n >= 1000 then "\((n / 100 | floor) / 10)k" - else "\(n)" - end; - - def elapsed(start; nw): - ((nw - start) | floor) as $s - | if $s < 0 then "—" - elif $s < 60 then "\($s)s" - elif $s < 3600 then "\($s / 60 | floor)m\($s % 60)s" - else "\($s / 3600 | floor)h\(($s % 3600) / 60 | floor)m" - end; - - def cwd_tail(c): - if (c // "") == "" then "" - else " " + ((c | split("/") | map(select(length > 0)) | .[-1]) // "") end; - - (now | floor) as $nw - | .tasks[]? - | select((.id // "") != "") - | (.label // .description // .name // "?") as $label - | (.startTime - | if type == "number" then - (if . > 10000000000 then . / 1000 else . end) - elif type == "string" then (fromdateiso8601? // 0) - else 0 end) as $st - | { - id: .id, - content: - "\(emoji($label))" - + " \($label)" - + " \(dot(.status // ""))" - + " \(if $st > 0 then elapsed($st; $nw) else "—" end)" - + " \(toks(.tokenCount // 0))" - + "\(cwd_tail(.cwd))" - } -' 2>/dev/null diff --git a/plugins/ruby-grape-rails/hooks/hooks.json b/plugins/ruby-grape-rails/hooks/hooks.json index e2c906fa..f37434eb 100644 --- a/plugins/ruby-grape-rails/hooks/hooks.json +++ b/plugins/ruby-grape-rails/hooks/hooks.json @@ -449,12 +449,6 @@ "args": ["${CLAUDE_PLUGIN_ROOT}/hooks/scripts/setup-dirs.sh"], "timeout": 15 }, - { - "type": "command", - "command": "bash", - "args": ["${CLAUDE_PLUGIN_ROOT}/hooks/scripts/install-statusline-wrapper.sh"], - "timeout": 10 - }, { "type": "command", "command": "bash", diff --git a/plugins/ruby-grape-rails/hooks/scripts/install-statusline-wrapper.sh b/plugins/ruby-grape-rails/hooks/scripts/install-statusline-wrapper.sh deleted file mode 100755 index 1c30a828..00000000 --- a/plugins/ruby-grape-rails/hooks/scripts/install-statusline-wrapper.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env bash -# Policy: advisory — any error path exits 0 silently. Never blocks session -# start. Plugin settings.json falls back to CC's default row when the -# wrapper is missing or broken. -# -# SessionStart hook: install/refresh a statusline wrapper in the user's home. -# -# Why this exists: -# Plugin settings.json `subagentStatusLine.command` does NOT expand -# ${CLAUDE_PLUGIN_ROOT} (unlike hooks.json, .mcp.json, monitors.json), -# and CLAUDE_PLUGIN_ROOT is NOT exported as an env var to the statusline -# subprocess. Scripts bundled in plugin bin/ therefore cannot be -# referenced directly from plugin settings.json. We work around this by -# writing a small wrapper at ~/.claude/ruby-grape-rails-subagent-statusline -# whose sole job is to `exec` the current plugin's bin/subagent-statusline -# using the now-resolved absolute path. The plugin settings.json points -# at this stable wrapper path. -# -# The absolute path of the plugin install dir changes per version (see -# ${CLAUDE_PLUGIN_ROOT}, which points into the user's plugin cache). We -# rewrite the wrapper on every SessionStart, but only when its current -# content differs from the desired content — cheap no-op on unchanged -# sessions. - -set -o nounset -set -o pipefail - -[[ -n "${CLAUDE_PLUGIN_ROOT:-}" ]] || exit 0 -[[ -n "${HOME:-}" ]] || exit 0 -BIN_PATH="${CLAUDE_PLUGIN_ROOT}/bin/subagent-statusline" -[[ -x "$BIN_PATH" && ! -L "$BIN_PATH" ]] || exit 0 - -WRAPPER_DIR="${HOME}/.claude" -WRAPPER="${WRAPPER_DIR}/ruby-grape-rails-subagent-statusline" - -[[ -d "$WRAPPER_DIR" && ! -L "$WRAPPER_DIR" ]] || exit 0 -# Refuse to replace a symlink at the target path. -[[ ! -L "$WRAPPER" ]] || exit 0 -# Refuse to replace anything other than a regular file (e.g. a directory -# would cause mv to move the temp file INTO it rather than replacing the -# wrapper). -[[ ! -e "$WRAPPER" || -f "$WRAPPER" ]] || exit 0 - -DESIRED=$(printf '#!/usr/bin/env bash\nexec %q "$@"\n' "$BIN_PATH") - -if [[ -r "$WRAPPER" && -f "$WRAPPER" ]]; then - CURRENT=$(cat -- "$WRAPPER" 2>/dev/null || true) - if [[ "$CURRENT" == "$DESIRED" ]]; then - exit 0 - fi -fi - -TMP=$(mktemp "${WRAPPER_DIR}/.tmp.statusline-wrapper.XXXXXX" 2>/dev/null) || exit 0 -if [[ ! -f "$TMP" || -L "$TMP" || "$TMP" != "${WRAPPER_DIR}/.tmp.statusline-wrapper."* ]]; then - rm -f -- "${TMP:?}" 2>/dev/null || true - exit 0 -fi - -if ! printf '%s' "$DESIRED" > "$TMP" 2>/dev/null; then - rm -f -- "${TMP:?}" 2>/dev/null || true - exit 0 -fi -if ! chmod 0755 "$TMP" 2>/dev/null; then - rm -f -- "${TMP:?}" 2>/dev/null || true - exit 0 -fi -mv -f -- "$TMP" "$WRAPPER" 2>/dev/null || { - rm -f -- "${TMP:?}" 2>/dev/null || true - exit 0 -} - -exit 0 diff --git a/plugins/ruby-grape-rails/settings.json b/plugins/ruby-grape-rails/settings.json deleted file mode 100644 index 1d9b62a7..00000000 --- a/plugins/ruby-grape-rails/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "subagentStatusLine": { - "type": "command", - "command": "~/.claude/ruby-grape-rails-subagent-statusline" - } -} diff --git a/plugins/ruby-grape-rails/skills/brainstorm/SKILL.md b/plugins/ruby-grape-rails/skills/brainstorm/SKILL.md index d10aa615..7cef8f21 100644 --- a/plugins/ruby-grape-rails/skills/brainstorm/SKILL.md +++ b/plugins/ruby-grape-rails/skills/brainstorm/SKILL.md @@ -136,7 +136,9 @@ See `references/research-integration.md` for the full pattern. "How does this codebase handle {topics}?" - **`web-researcher`** for `web-research` topic: "Ruby/Rails approaches to {topics}". - Pass each absolute path verbatim in the spawn prompt. + Pass each absolute path verbatim in the spawn prompt. Wait for both + agents to complete before step 6 — interactive sessions run them in + the background and notify on completion. 6. Apply Artifact Recovery per `${CLAUDE_PLUGIN_ROOT}/references/artifact-recovery.md` (coverage-noun `Research`). Patch each entry's `status` field with diff --git a/plugins/ruby-grape-rails/skills/review/SKILL.md b/plugins/ruby-grape-rails/skills/review/SKILL.md index 66e96bbb..ff7e5723 100644 --- a/plugins/ruby-grape-rails/skills/review/SKILL.md +++ b/plugins/ruby-grape-rails/skills/review/SKILL.md @@ -41,9 +41,11 @@ Reviewers own diff strategy. For reviewer diff discipline, see parallel. Subagents are leaf workers — they return findings; they do not spawn further agents. -**MUST spawn in foreground.** Never pass `run_in_background: true` on -any Agent call. Use parallel via multiple Agent tool calls in a single -message. +**Never request background dispatch.** Never pass +`run_in_background: true` on any Agent call. Use parallel via multiple +Agent tool calls in a single message. Interactive sessions run the +reviewers in the background regardless and notify on completion — do +NOT read artifacts or consolidate until every reviewer has completed. ### Fanout Pattern diff --git a/scripts/fetch-claude-docs.sh b/scripts/fetch-claude-docs.sh index 7519d4e8..118d9dae 100755 --- a/scripts/fetch-claude-docs.sh +++ b/scripts/fetch-claude-docs.sh @@ -77,7 +77,7 @@ PAGES=( "env-vars.md" # Environment variables including CLAUDE_PLUGIN_ROOT, CLAUDE_PLUGIN_DATA, CLAUDE_PROJECT_DIR "errors.md" # Error reference — hook failure classification and StopFailure taxonomy "cli-reference.md" # `claude plugin validate`, `--plugin-dir` contract used by eval/doctor scripts - "statusline.md" # Plugin-level subagentStatusLine setting + "statusline.md" # Status line surface — plugin ships no status line setting "discover-plugins.md" # Marketplace install flow and git-subdir path resolution "sandboxing.md" # Bash sandboxing semantics impacting hook side-effect guarantees "context-window.md" # PreCompact/PostCompact hook timing and payload context @@ -91,7 +91,7 @@ PAGES=( "remote-control.md" # CronCreate / scheduled triggers surface — schedule skill validation "model-config.md" # Agent/model frontmatter validity — accepted family aliases and pinned model IDs "fast-mode.md" # /fast model support surface — relates to effort:max skill settings - "output-styles.md" # Output-style surface adjacent to statusline + subagentStatusLine + "output-styles.md" # Output-style surface adjacent to the status line "troubleshooting.md" # Hook failure diagnosis patterns "common-workflows.md" # Plan/Work/Review lifecycle comparison with /rb: workflows "agent-sdk/hooks.md" # SDK hook interface parity check From 96fef7c3f04e93d203f21f86d18574190b40febd Mon Sep 17 00:00:00 2001 From: Alexander Grebennik Date: Fri, 13 Nov 2026 19:44:15 +0100 Subject: [PATCH 2/3] fix --- .claude/rules/agent-development.md | 11 ++++++----- .claude/rules/skill-development.md | 7 ++++--- .claude/skills/docs-check/SKILL.md | 4 ++++ .claude/skills/session-deep-dive/SKILL.md | 1 + .github/instructions/plugin-review.instructions.md | 9 +++++---- CHANGELOG.md | 14 +++++++++++--- .../ruby-grape-rails/hooks/scripts/format-ruby.sh | 8 ++++++++ .../ruby-grape-rails/skills/brainstorm/SKILL.md | 2 +- .../brainstorm/references/research-integration.md | 6 +++++- .../ruby-grape-rails/skills/investigate/SKILL.md | 4 +++- .../skills/plan/references/planning-workflow.md | 4 ++-- plugins/ruby-grape-rails/skills/research/SKILL.md | 3 ++- 12 files changed, 52 insertions(+), 21 deletions(-) diff --git a/.claude/rules/agent-development.md b/.claude/rules/agent-development.md index 736ee6f3..83b5b808 100644 --- a/.claude/rules/agent-development.md +++ b/.claude/rules/agent-development.md @@ -67,7 +67,7 @@ one model response count as one turn. The `Complete analysis by turn ~M` rule is satisfied when the agent's M-th model invocation has completed. -## Foreground Dispatch +## Agent Dispatch No skill body, fanout template, or example MAY pass `run_in_background: true` on an `Agent(...)` call. Parallel = multiple @@ -78,10 +78,11 @@ Agent tool calls in one message; never the background flag. | Interactive terminal, VS Code, desktop (fork mode on, the default) | Main-conversation subagents start in the background. The Agent tool exposes no `run_in_background` parameter. Completion arrives as a notification | | `claude -p`, Agent SDK, or `CLAUDE_CODE_FORK_SUBAGENT=0` | Claude chooses foreground or background. The flag exists — the prohibition above applies | -Every fanout skill MUST carry an explicit "wait for all agents to -complete" step between the spawn step and the first artifact read or -Artifact Recovery step. Without it, a background fanout is consolidated -before its artifacts exist. +Every skill that spawns an agent and consumes its result — fanout or +single agent — MUST carry an explicit "wait for the agent(s) to +complete" step between the spawn step and the first artifact read, +Artifact Recovery step, or use of the return text. Without it, a +background agent's result is consumed before it exists. ## Memory diff --git a/.claude/rules/skill-development.md b/.claude/rules/skill-development.md index f3c6648d..20f119d1 100644 --- a/.claude/rules/skill-development.md +++ b/.claude/rules/skill-development.md @@ -87,9 +87,10 @@ skills/{name}/ `run_in_background: true` on any `Agent(...)` call. Parallel = many Agent tool calls in a single message, NOT the background flag. Interactive sessions start main-conversation subagents in the - background regardless, so every fanout skill MUST state an explicit - wait-for-all-agents step before its first artifact read. See - `.claude/rules/agent-development.md` § "Foreground Dispatch". + background regardless, so every skill that spawns an agent and + consumes its result — fanout or single agent — MUST state an explicit + wait-for-completion step before its first artifact read. See + `.claude/rules/agent-development.md` § "Agent Dispatch". ## Colon Naming diff --git a/.claude/skills/docs-check/SKILL.md b/.claude/skills/docs-check/SKILL.md index 47a619a3..92b6b3ac 100644 --- a/.claude/skills/docs-check/SKILL.md +++ b/.claude/skills/docs-check/SKILL.md @@ -116,6 +116,10 @@ Write findings to .claude/docs-check/reports/{surface}-report.md Agent body owns BLOCKER/WARNING/INFO/PASS classification, "no large docs paste" rule, "stop after returning". Call site stays minimal. +Wait for every `docs-surface-validator` to complete before step 7 — +interactive sessions run them in the background and notify on +completion. A report is MISSING only after its worker has completed. + ### 6. Structural Baseline (Always) Keep these results in view while synthesizing: diff --git a/.claude/skills/session-deep-dive/SKILL.md b/.claude/skills/session-deep-dive/SKILL.md index 204cba77..2ac4b08f 100644 --- a/.claude/skills/session-deep-dive/SKILL.md +++ b/.claude/skills/session-deep-dive/SKILL.md @@ -81,6 +81,7 @@ Spawn one analysis subagent per transcript. Include: - reminder that metrics are heuristic Write each report to `.claude/session-analysis/{short_id}-report.md`. +Wait for every subagent to complete before step 5. ### 5. Compress When Needed diff --git a/.github/instructions/plugin-review.instructions.md b/.github/instructions/plugin-review.instructions.md index 11ca548a..273b85fc 100644 --- a/.github/instructions/plugin-review.instructions.md +++ b/.github/instructions/plugin-review.instructions.md @@ -375,10 +375,11 @@ Notes: - `run_in_background: true` on any `Agent(...)` call in shipped skill bodies, fanout templates, or example snippets — flag as BLOCKER. -- A fanout skill whose spawn step is followed by an artifact read or - Artifact Recovery step with no explicit wait-for-all-agents step - between them. Interactive sessions run main-conversation subagents in - the background, so the read would precede the artifacts. +- A skill — fanout or single agent — whose spawn step is followed by an + artifact read, Artifact Recovery step, or use of the return text with + no explicit wait-for-completion step between them. Interactive + sessions run main-conversation subagents in the background, so the + read would precede the result. - Raw `mv`, `cp`, `jq -i`, `rm`, or improvised shell against any `RUN-CURRENT.json` path or per-agent artifact path in shipped skill bodies, hook scripts, or examples — flag as BLOCKER. All manifest diff --git a/CHANGELOG.md b/CHANGELOG.md index fddce28c..75e36e58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,9 +21,17 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Changed -- `/rb:review` and `/rb:brainstorm` state that reviewers and research - agents run in the background in interactive sessions and that - artifacts are read only after every agent completes. +- `/rb:review`, `/rb:brainstorm`, `/rb:investigate`, and the + `/rb:research` provenance step state that spawned agents run in the + background in interactive sessions and that results are read only + after every agent completes. The "foreground" wording is dropped from + the `/rb:plan` and `/rb:brainstorm` spawn steps. + +### Fixed + +- `format-ruby.sh` removes its `ruby-format.*` stderr capture when the + hook is killed or exits mid-formatter, instead of only after the + formatter returns. - Contributor tooling: `markdownlint-cli` raised to `^0.50.0`, with `overrides` pinning `minimatch` and `katex` to patched releases. `npm audit` reports 0 vulnerabilities. diff --git a/plugins/ruby-grape-rails/hooks/scripts/format-ruby.sh b/plugins/ruby-grape-rails/hooks/scripts/format-ruby.sh index 20c8eb8d..ae4e7534 100755 --- a/plugins/ruby-grape-rails/hooks/scripts/format-ruby.sh +++ b/plugins/ruby-grape-rails/hooks/scripts/format-ruby.sh @@ -181,6 +181,12 @@ if [[ "$BASE_NAME" == "Gemfile" || "$BASE_NAME" == "Gemfile.lock" ]]; then fi fi +# Registered right after each mktemp so a hook killed mid-formatter does +# not leave its stderr capture behind. +cleanup_format_err_file() { + safe_remove_temp_file "${ERR_FILE:-}" "${TMPDIR:-/tmp}/ruby-format.*" || true +} + if has_gem standard; then if ! command -v bundle >/dev/null 2>&1; then echo "BLOCKED: ${HOOK_NAME} could not run automatic Ruby formatting for ${FILE_PATH} because Bundler is not available." >&2 @@ -192,6 +198,7 @@ if has_gem standard; then emit_tempfile_failure_warning exit 2 } + trap cleanup_format_err_file EXIT HUP INT TERM (cd "$REPO_ROOT" && run_with_timeout "$RUBY_PLUGIN_FORMATTER_TIMEOUT" bundle exec standardrb --fix -- "$FILE_PATH") 2>"$ERR_FILE" FMT_STATUS=$? if [[ -n "$TIMEOUT_CMD" && "$FMT_STATUS" -eq 124 ]]; then @@ -217,6 +224,7 @@ elif has_gem rubocop; then emit_tempfile_failure_warning exit 2 } + trap cleanup_format_err_file EXIT HUP INT TERM (cd "$REPO_ROOT" && run_with_timeout "$RUBY_PLUGIN_FORMATTER_TIMEOUT" bundle exec rubocop --force-exclusion -a -- "$FILE_PATH") 2>"$ERR_FILE" FMT_STATUS=$? if [[ -n "$TIMEOUT_CMD" && "$FMT_STATUS" -eq 124 ]]; then diff --git a/plugins/ruby-grape-rails/skills/brainstorm/SKILL.md b/plugins/ruby-grape-rails/skills/brainstorm/SKILL.md index 7cef8f21..951df830 100644 --- a/plugins/ruby-grape-rails/skills/brainstorm/SKILL.md +++ b/plugins/ruby-grape-rails/skills/brainstorm/SKILL.md @@ -131,7 +131,7 @@ See `references/research-integration.md` for the full pattern. 3. Patch each entry `status: in-flight` via stdin `patch`. 4. Read paths via `manifest-update spawn-paths "$MANIFEST"`. 5. Spawn both via two Agent tool calls in ONE Tool Use block - (foreground parallel, NOT `run_in_background: true`): + (parallel, NOT `run_in_background: true`): - **`rails-patterns-analyst`** for `codebase-scan` topic: "How does this codebase handle {topics}?" - **`web-researcher`** for `web-research` topic: diff --git a/plugins/ruby-grape-rails/skills/brainstorm/references/research-integration.md b/plugins/ruby-grape-rails/skills/brainstorm/references/research-integration.md index 007346c7..dcd1dba7 100644 --- a/plugins/ruby-grape-rails/skills/brainstorm/references/research-integration.md +++ b/plugins/ruby-grape-rails/skills/brainstorm/references/research-integration.md @@ -5,7 +5,7 @@ ### Step 1: Diverge (Generate Diverse Approaches) Spawn 2 agents via two Agent tool calls in ONE Tool Use block -(foreground parallel, NOT `run_in_background: true`): +(parallel, NOT `run_in_background: true`): Both agents receive their absolute artifact path from `manifest-update spawn-paths "$MANIFEST"`. Paths resolve to @@ -25,6 +25,9 @@ namespace convention. **Iron Law: MAX 2 agents in first research cycle.** Keep it fast (~2-3 min). Do NOT spawn additional specialists in the first cycle. +Wait for both agents to complete before Step 2 — interactive sessions +run them in the background and notify on completion. + ### Step 2: Evaluate (Thesis + Antithesis per Approach) Happens in main context (not subagent) — synthesize both agents' findings @@ -67,6 +70,7 @@ When user picks "Research" again after the first cycle: - Spawn 1-2 targeted agents for specific questions - Focus on gaps identified during evaluation - Deeper dives into specific libraries, patterns, or trade-offs +- Wait for every spawned agent to complete before evaluating ## Research Log diff --git a/plugins/ruby-grape-rails/skills/investigate/SKILL.md b/plugins/ruby-grape-rails/skills/investigate/SKILL.md index ccbea1e2..a4e0b3eb 100644 --- a/plugins/ruby-grape-rails/skills/investigate/SKILL.md +++ b/plugins/ruby-grape-rails/skills/investigate/SKILL.md @@ -48,7 +48,9 @@ investigation, use `deep-bug-investigator` pass an explicit output path in the prompt (`.claude/investigations/deep-bug-investigator/{slug}-{datesuffix}.md`); the agent writes its findings to that file and returns a ≤300-word chat -summary. Read the file for the full report. +summary. Wait for the agent to complete — interactive sessions run it in +the background and notify on completion — then read the file for the +full report. If the agent's return text matches the pause signature in `${CLAUDE_PLUGIN_ROOT}/references/agent-resume.md`, follow that protocol diff --git a/plugins/ruby-grape-rails/skills/plan/references/planning-workflow.md b/plugins/ruby-grape-rails/skills/plan/references/planning-workflow.md index aa70b9d0..85c9799b 100644 --- a/plugins/ruby-grape-rails/skills/plan/references/planning-workflow.md +++ b/plugins/ruby-grape-rails/skills/plan/references/planning-workflow.md @@ -110,7 +110,7 @@ agents' job -- let them handle pattern discovery. `Gemfile.lock` or gem source directly instead **CRITICAL**: Spawn ALL applicable agents via multiple Agent tool -calls in ONE Tool Use block (foreground parallel — do NOT use +calls in ONE Tool Use block (parallel — do NOT use `run_in_background: true`). Minimum 1 agent spawned. **Agent prompts must be FOCUSED.** Scope each prompt to the @@ -341,7 +341,7 @@ plan with deeper research instead of creating a new one. `manifest-update spawn-paths "$MANIFEST"` verbatim in the spawn prompt. Each agent writes its detailed output to that path and returns ONLY a 500-word summary. Spawn via multiple Agent tool - calls in ONE Tool Use block (foreground parallel — do NOT use + calls in ONE Tool Use block (parallel — do NOT use `run_in_background: true`) 4. **Wait for ALL agents** -- You'll be notified as each completes. Read each agent's output file. Do NOT proceed until all complete diff --git a/plugins/ruby-grape-rails/skills/research/SKILL.md b/plugins/ruby-grape-rails/skills/research/SKILL.md index 00125853..f74228e8 100644 --- a/plugins/ruby-grape-rails/skills/research/SKILL.md +++ b/plugins/ruby-grape-rails/skills/research/SKILL.md @@ -319,7 +319,8 @@ provenance is optional. When you use it: 1. Write the draft research artifact first. -2. Spawn `output-verifier` against that artifact. +2. Spawn `output-verifier` against that artifact. Wait for it to + complete before step 3. 3. Save the verifier result alongside the research as: - `.claude/research/{topic-slug}.provenance.md` for reusable research - `.claude/plans/{slug}/research/{topic-slug}.provenance.md` for plan-local research From 72b869d6465d93bb5a6f24f573889218763eab6b Mon Sep 17 00:00:00 2001 From: Alexander Grebennik Date: Fri, 13 Nov 2026 20:19:34 +0100 Subject: [PATCH 3/3] fix --- .claude/rules/hook-development.md | 5 ++++- plugins/ruby-grape-rails/hooks/scripts/format-ruby.sh | 10 ++++++---- plugins/ruby-grape-rails/skills/review/SKILL.md | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.claude/rules/hook-development.md b/.claude/rules/hook-development.md index d47270e9..0d7deebb 100644 --- a/.claude/rules/hook-development.md +++ b/.claude/rules/hook-development.md @@ -41,7 +41,10 @@ Add or update a short policy comment near the top of the hook when behavior chan when the user ends the turn with `Ctrl+Enter` while the tool runs. CC kills a hook still running at that point. Only `async: true` hooks outlive it. Keep every blocking `PostToolUse` hook safe to kill - mid-run — no partial writes, temp files cleaned by `trap` + mid-run — no partial writes, temp files cleaned by `trap EXIT`. + Register cleanup on `EXIT` only: bash runs the `EXIT` trap when a + signal terminates it, while a cleanup-only handler on `HUP`/`INT`/`TERM` + swallows the signal and the script continues to its normal exit - `SubagentStart` uses `hookSpecificOutput.additionalContext` to inject context into subagents - `PostToolUseFailure` uses `hookSpecificOutput.additionalContext` for debugging hints diff --git a/plugins/ruby-grape-rails/hooks/scripts/format-ruby.sh b/plugins/ruby-grape-rails/hooks/scripts/format-ruby.sh index ae4e7534..f4e31165 100755 --- a/plugins/ruby-grape-rails/hooks/scripts/format-ruby.sh +++ b/plugins/ruby-grape-rails/hooks/scripts/format-ruby.sh @@ -181,8 +181,10 @@ if [[ "$BASE_NAME" == "Gemfile" || "$BASE_NAME" == "Gemfile.lock" ]]; then fi fi -# Registered right after each mktemp so a hook killed mid-formatter does -# not leave its stderr capture behind. +# Registered on EXIT right after each mktemp so a hook killed mid-formatter +# does not leave its stderr capture behind. EXIT only: a handler on +# HUP/INT/TERM would swallow the signal and let the script run on to its +# normal result handling. cleanup_format_err_file() { safe_remove_temp_file "${ERR_FILE:-}" "${TMPDIR:-/tmp}/ruby-format.*" || true } @@ -198,7 +200,7 @@ if has_gem standard; then emit_tempfile_failure_warning exit 2 } - trap cleanup_format_err_file EXIT HUP INT TERM + trap cleanup_format_err_file EXIT (cd "$REPO_ROOT" && run_with_timeout "$RUBY_PLUGIN_FORMATTER_TIMEOUT" bundle exec standardrb --fix -- "$FILE_PATH") 2>"$ERR_FILE" FMT_STATUS=$? if [[ -n "$TIMEOUT_CMD" && "$FMT_STATUS" -eq 124 ]]; then @@ -224,7 +226,7 @@ elif has_gem rubocop; then emit_tempfile_failure_warning exit 2 } - trap cleanup_format_err_file EXIT HUP INT TERM + trap cleanup_format_err_file EXIT (cd "$REPO_ROOT" && run_with_timeout "$RUBY_PLUGIN_FORMATTER_TIMEOUT" bundle exec rubocop --force-exclusion -a -- "$FILE_PATH") 2>"$ERR_FILE" FMT_STATUS=$? if [[ -n "$TIMEOUT_CMD" && "$FMT_STATUS" -eq 124 ]]; then diff --git a/plugins/ruby-grape-rails/skills/review/SKILL.md b/plugins/ruby-grape-rails/skills/review/SKILL.md index ff7e5723..91ac0cb2 100644 --- a/plugins/ruby-grape-rails/skills/review/SKILL.md +++ b/plugins/ruby-grape-rails/skills/review/SKILL.md @@ -225,7 +225,8 @@ review itself are enough and no provenance sidecar is needed. When used: 1. write the draft consolidated review -2. run `output-verifier` against the draft +2. run `output-verifier` against the draft and wait for it to complete + before step 3 3. save the result to `.claude/reviews/{review-slug}-{datesuffix}.provenance.md` 4. remove or soften unsupported external claims before presenting the final review