From 7177258f3d41e47e248131e625a4b7374ee2cec8 Mon Sep 17 00:00:00 2001 From: bastien Date: Mon, 28 Sep 2026 14:54:53 +0200 Subject: [PATCH] =?UTF-8?q?chore(memory):=20BDR-106=20superpowers=20vendor?= =?UTF-8?q?ed=20=E2=80=94=20contract,=20plan=20r3,=20oracles,=20TODO,=20jo?= =?UTF-8?q?urnal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/memory/decisions.md | 10 + .claude/memory/journal.md | 1 + .claude/tasks/TODO.md | 20 ++ .../2026-09-28-superpowers-vendored-1357.md | 69 +++++ .../c1.py | 16 ++ .../c2.py | 17 ++ .../2026-09-28-superpowers-vendored-1357.md | 271 ++++++++++++++++++ 7 files changed, 404 insertions(+) create mode 100644 .claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.md create mode 100644 .claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c1.py create mode 100644 .claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c2.py create mode 100644 .claude/tasks/plans/2026-09-28-superpowers-vendored-1357.md diff --git a/.claude/memory/decisions.md b/.claude/memory/decisions.md index 4e06f58..2d32cd3 100644 --- a/.claude/memory/decisions.md +++ b/.claude/memory/decisions.md @@ -127,6 +127,7 @@ rules: | BDR-103 | 2026-09-27 | 6-repo review: 5 verdicts, 3 criteria (grep-verified coverage, per-session cost, doctrine conflict); stars decided nothing | accepted | | BDR-104 | 2026-09-28 | MengTo motion pack: vendor 5 scroll skills pinned via shared lib/vendor-skills.sh + build personal skill site-motion; 17 skipped | accepted | | BDR-105 | 2026-09-28 | skill-catalog prune: 9 gstack out via GSTACK_REMOVED, full ⊇ every profile, max = everything, brightdata + frontend-design plugin off, security-guidance Stop review off, design gate asks `21st login` and waits | accepted | +| BDR-106 | 2026-09-28 | superpowers: 7 wired skills vendored at v6.4.1 via lib/vendor-skills.sh (always_on lock class), plugin + marketplace dropped, citers by bare name, doctrine map for the 4 non-vendored refs | accepted | --- @@ -1319,3 +1320,12 @@ Branch feature/user-writing-web-rules, UNMERGED (human gate). - **Alternatives rejected**: rm symlinks by hand (set/reset re-materialize, `gstack on` restores everything → denylist instead); per-skill toggles inside ui-ux-pro-max (all-or-nothing, unverified); drop superpowers in the same run (7 skills wired in ship-feature/init-project → tier 2, own branch); keep the 21st trio in design profiles (redundant with impeccable + ui-ux-pro-max, CLI signed out); raise `SLASH_COMMAND_TOOL_CHAR_BUDGET` (costs context, the opposite goal); keep the official frontend-design plugin and drop the copy (copy is profile-managed and gate-checked); shared 21st auth helper across 3 scripts (breaks 4 fixture suites, changes installer semantics — [[LRN-178]]); in-session `export TWENTYFIRST_TOKEN` remedy (env does not persist across tool calls). - **Caveats**: kept gstack skills still route to removed names in their upstream prose (Skill call fails, doctrine applies); helper tree links every top-level submodule entry (no SKILL.md exposed, asserted); security-guidance commit review quota unmeasured; doctor constants rebased on 2026-09-28 measures; `apply` is additive → other machines run `set full`, not `apply`. - **Reference**: f83f8f7 02b62f7 4c86d6d 729d715 (prune), bd3e525 132bcdf (21st gate); contracts `2026-09-28-skill-catalog-prune-0554` (18 criteria, oracles in `.oracles/`) and `2026-09-28-21st-signin-gate-1215` (7); plans r4 / r3 after 3 challengers + 1 confirmation each; GATE 0 MET, verifiers CONFORME (iter 2 / iter 1), security PASS ×2; 42 suites green minus 2 pre-existing T16a. Links [[BDR-030]] [[BDR-101]] [[BDR-093]] [[BDR-095]] [[BDR-080]] [[BDR-025]] [[BDR-070]] [[LRN-175]] [[LRN-176]] [[LRN-177]] [[LRN-178]] [[BLK-023]] [[EVAL-034]]. + +## BDR-106 — superpowers: 7 skills vendored at v6.4.1, plugin dropped +- **Date**: 2026-09-28 +- **Status**: accepted, feature/superpowers-vendored, UNMERGED (human gate) +- **Decision**: (1) plugins.lock.json `superpowers` entry (obra/superpowers @ 5bf4e78 = tag v6.4.1, path `skills`, per-skill file lists, `always_on: true`), fetched byte-for-byte by lib/vendor-skills.sh: brainstorming, writing-plans, subagent-driven-development, test-driven-development, requesting-code-review, using-git-worktrees, writing-skills; STEP 8e vendors, update-all refreshes at the pin, link.sh links, .gitignore ignores. (2) Plugin + marketplace uninstalled (one shot by hand after the fetch proved byte-identical), settings.json keys removed by hand, PROTECTED_PLUGINS = security-guidance only; `detect_superpowers` = `[ -f ~/.claude/skills/brainstorming/SKILL.md ]`, no plugin fallback; doctor/session-start no longer charge the injection. (3) doctor-vendored `always_on` class: third lock column, `_dv_check_link` 5th param — always-on externals are link-checked, never "parked". (4) Citers call the bare names; CLAUDE.global.md maps the four non-vendored skills the vendored text still references (executing-plans → SDD, finishing-a-development-branch → gitflow finish, systematic-debugging → bugfix, verification-before-completion → verifier gates). Vendored text never edited (BDR-104 rule). +- **Why**: 7 skills wired (ship-feature, init-project, writing-skills TDD), 8 duplicate personal flows; SessionStart injection 3.6 KB per start/clear/compact + a competing router ("1 % → MUST invoke", BDR-080 conflict); 15 descriptions → 7. Tier 2 of [[BDR-105]]. +- **Alternatives rejected**: shared auth/detect helpers sourced at top level (break the fixture `cp` suites, [[LRN-178]]); installer-side uninstall (plugin gone before the fetch on a network failure; precedent = comment only, one-shot by hand); detect with plugin-cache fallback (the marketplace dir matches `*superpowers*` → "vendored" on a plugin-only machine, fail-open); rewriting vendored text to fix cross-refs; vendoring all 15; map text spelling the colon form or wrapping identifiers (criteria 3/7 grep line by line — both caught by challengers). +- **Caveats**: upstream cross-refs to the plugin prefix and the 8 dropped skills remain in the vendored text (a call on a dropped name fails, doctrine map applies); no upstream auto-update (bump the pin deliberately); the harness hot-loaded the 7 bare names in the running session after link.sh, the plugin names leave at restart; `superpowers-marketplace` cache dir may linger empty; other machines: `make plugin` (vendors) + `make link`, then uninstall the cached plugin by hand (CHANGELOG). +- **Reference**: 18f8c89 (wiring), ddea411 (citers/docs/settings); contract `2026-09-28-superpowers-vendored-1357` (12 criteria, oracles in `.oracles/`), plan r3 after 3 challengers (simplicity CONCERNS(2), robustness CONCERNS(3), correctness FATAL(5)) + confirmation CONCERNS(1); executors 2/2 DONE first pass; GATE 0 MET, verifier CONFORME 12/12, security PASS; catalog 82 skills, plugin passive cost 670 t (ui-ux-pro-max only). Links [[BDR-105]] [[BDR-102]] [[BDR-104]] [[BDR-065]] [[LRN-178]] [[EVAL-034]]. diff --git a/.claude/memory/journal.md b/.claude/memory/journal.md index 27d1327..3948d22 100644 --- a/.claude/memory/journal.md +++ b/.claude/memory/journal.md @@ -538,3 +538,4 @@ rules: - Skill-catalog audit (user: "tour des skills, doublons, économiser tokens"): 5 analyzers over 150 skills / 53.5k chars desc; 78 listed name-only this session (listing budget ≈1 % ctx, least-invoked lose desc → gain = routing quality + no broken 100 KB body invoked, not listing chars). Found: frontend-design plugin byte-dup of managed copy; brightdata 21 skills keyless + hostile WebFetch routing; gstack ship trunk-based (origin/HEAD=main), land-and-deploy auto-merge+deploy, autoplan/make-pdf/diagram/careful/guard/freeze dead paths (only bin + browse/dist linked); security-guidance = Opus call per code turn + agentic commit review, 0 findings/6 days; doctor.sh undercount ×6. User go: tier 1, superpowers vendor-7 (tier 2 later), 21st trio parked (CLI `Not logged in`), rule "full ⊇ every profile, max = everything". Live: brightdata disabled, frontend-design plugin uninstalled, `set full` → 75 skills (was 89). - /feat by hand on feature/skill-catalog-prune: contract 18 criteria; plan r1→r4 (3 challengers, confirmation FATAL(4): nested SKILL.md in browser-skills/openclaw/node_modules, ./setup global symlink, update-all 3rd copy); 4 feater parallel DONE; GATE 0 UNMET(4) = MY heredoc CHECKs (gates.sh single-line) → oracles to `.oracles/*.py` → MET; verifier ECARTS(1) = floor-guard `xit(` false-positive on `sys.exit(` → restructure → CONFORME; security PASS. 41 suites green minus 2 pre-existing T16a, shellcheck clean. UNMERGED — human gate. Registries pending user approval. - User: "quand on détecte qu'on a besoin de 21st, on demande de log si c'est pas fait et on attend". /feat by hand on the same branch: design gate gains exit 12 `SIGN-IN REQUIRED` (three-state whoami probe, unknown → 11 with diagnostic, explicit "proceed without 21st" only skip); challenge round dropped my shared-helper idea (would break 4 fixture suites + change installer semantics) and my in-session `export TWENTYFIRST_TOKEN` remedy (env does not persist across tool calls). Executor DONE first pass, GATE 0 MET, verifier CONFORME 7/7, security PASS, 8/8 hermetic. Gate now exits 12 live here until `21st login`. +- User go "merge le tout, écris les registres, fais le tier 2": tier 1 registries (BDR-105, LRN-175..178, BLK-023, EVAL-034) written, feature/skill-catalog-prune finished → develop c39c0e1. Tier 2 on feature/superpowers-vendored: 7 superpowers skills vendored at v6.4.1 through lib/vendor-skills.sh (`always_on` lock class for doctor-vendored), plugin + marketplace uninstalled, settings.json hand-edited, citers by bare name, doctrine map. Challenge round: correctness FATAL(5) caught my map text containing the forbidden `superpowers` colon form; confirmation caught an identifier wrapped across lines (grep is line-based). Executors 2/2 DONE, GATE 0 MET, verifier CONFORME 12/12, security PASS. Catalog 82 skills, passive plugin cost 670 t, injection gone; harness hot-loaded the bare names in-session. 18f8c89 ddea411. UNMERGED — human gate. [[BDR-106]] diff --git a/.claude/tasks/TODO.md b/.claude/tasks/TODO.md index 5c672d2..0a494e5 100644 --- a/.claude/tasks/TODO.md +++ b/.claude/tasks/TODO.md @@ -1,5 +1,25 @@ # TODO +## 2026-09-28 — tier 2: vendor 7 superpowers skills, drop the plugin (feature/superpowers-vendored) +User go "fais le tier 2" (decision 2026-09-28, batch 1). Contract +`.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.md`. +- [x] V1 plugins.lock.json `superpowers` entry (obra/superpowers @ 5bf4e78 = v6.4.1, + path skills, dict of 7 file lists); install-plugins.sh STEP 5 stops installing + the plugin, STEP 8e vendors it; update-all.sh refresh; link.sh EXTERNAL_SKILLS; + .gitignore; profile.sh PROTECTED_PLUGINS; detect-plugins/session-start/doctor + read the vendored dir, injection cost gone. +- [x] V2 citers: `superpowers:` → `` in ship-feature, init-project, tour, deploy, + audit-delta, lib/analyze-before-plan, plugin-advisor; finishing-a-development- + branch prose in capitalize-commit/doc-commit/gitflow; CLAUDE.global.md routing + map for the 8 dropped skills; README/USAGE/plugin-advisor/profile SKILL.md; + CHANGELOG. +- [x] V3 plan r1→r3 (3 challengers + confirmation), 2 feater DONE, live vendor + link + (VENDORED_LINKED), settings.json hand-edited, plugin + marketplace uninstalled, + GATE 0 MET 10/10, verifier CONFORME 12/12, security PASS; 18f8c89 ddea411; BDR-106. + Catalog 82 skills, passive plugins 670 t. UNMERGED — human gate. Other machines: + `make plugin` + `make link`, uninstall the cached plugin by hand. User: remove + `/tmp/tmp.PKDTRyaCw8` `/tmp/tmp.99Fu0dm8ll` (executor fixtures, rm refused). + ## 2026-09-28 — design gate asks for `21st login` and waits (feature/skill-catalog-prune) User: "si on veut l'utiliser, on demande à l'utilisateur de se log, plus simple que dire c'est pas logged on utilise pas… on demande de log si c'est pas fait et on diff --git a/.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.md b/.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.md new file mode 100644 index 0000000..c49515e --- /dev/null +++ b/.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.md @@ -0,0 +1,69 @@ +# CONTRACT — superpowers-vendored +- date: 2026-09-28 | flow: feat (ad-hoc dispatch, /feat gates replayed by the orchestrator, 2 parallel feater executors) | branch: feature/superpowers-vendored +- status: active + +## REQUEST (verbatim — IMMUTABLE) +> ok merge le tout et écris les registres puis fais le tier 2 + +Tier 2 as decided 2026-09-28 (batch 1, option "Vendoriser 7, retirer le plugin (Recommended)"): vendor brainstorming, writing-plans, subagent-driven-development, test-driven-development, requesting-code-review, using-git-worktrees, writing-skills from obra/superpowers at the v6.4.1 commit via `lib/vendor-skills.sh`, drop the superpowers plugin (its 8 other skills and its session-start injection), rename the `superpowers:` citers. + +## CLARIFICATIONS +- Pass A: none — request complete (the decision batch fixed scope and outcome). +- Pass B: no visible / public-name choice left open — the vendored skills keep their upstream names (bare, no `superpowers:` prefix; renaming would break their internal cross-references), the lock key is `superpowers`, the always-on status is inherited (not in MANAGED_EXTERNALS, like darwin-skill). Proceeds silently. +- Byte-for-byte upstream text (BDR-104 convention): the vendored files are never edited, so their internal `superpowers:` mentions and references to the 8 dropped skills (executing-plans, finishing-a-development-branch, systematic-debugging, verification-before-completion, dispatching-parallel-agents, receiving-code-review, using-superpowers, diagnosing-superpowers) stay in the text; CLAUDE.global.md carries the routing map (bare names; executing-plans → subagent-driven-development; finishing-a-development-branch → `gitflow finish` on a human signal; systematic-debugging → bugfix; verification-before-completion → the verifier gates). Known residual, documented. +- Scripts inside the vendored skills are invoked as `bash scripts/` upstream: no exec bit needed after curl. +- `docs/superpowers/{specs,plans}` stays the transient path (brainstorming/writing-plans still write there; gitflow purge unchanged, BDR-065). +- Live steps are the orchestrator's: criterion 2 runs the vendor helper (network) + link.sh; the plugin uninstall (`claude plugin uninstall superpowers@superpowers-marketplace`) runs AFTER the 7 skills are linked, then criterion 8 checks the catalog. Executors never run `claude plugin …`, the vendor helper against the network, link.sh, `profile.sh set`, never commit. +- [challenge 2026-09-28, 3 lenses: simplicity CONCERNS(2), robustness CONCERNS(3), correctness FATAL(5); every BLOCKER/MAJOR closed by a named plan change, r2] (a) CLAUDE.global.md map never spells the colon form; (b) `always_on` lock field + doctor-vendored always-on class, test case; (c) no uninstall code in the installer, one-shot by the orchestrator after criterion 2, marketplace removed too, rollback step; (d) settings.json hand-edited (enabledPlugins key + marketplace block) and committed; (e) detect_superpowers = file test on the linked skill, no fallback, negative control in criterion 5; (f) map trimmed, lock note trimmed, session-start line deleted plainly. +- [confirmation pass 2026-09-28, correctness CONCERNS(1), all closed by named changes, r3] map identifiers kept whole per line (grep is line-based); `always_on` mechanism pinned (third lock column, 5th `_dv_check_link` param, headers); settings.json edited by the orchestrator only after criterion 2 is green; stale installer edge case removed; doctor pass line worded on what it proves. +- Functions ≤ 25 logic lines, 80-char lines, shellcheck clean. + +## ACCEPTANCE CRITERIA +1. plugins.lock.json carries the `superpowers` entry: obra/superpowers, commit 5bf4e78011075bcfc0dc295f0724994cd123ee71 (v6.4.1), path `skills`, dict of exactly the 7 skills with every upstream file listed (SKILL.md each; SDD scripts, code-reviewer.md, anthropic-best-practices.md included). + CHECK: python3 .claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c1.py + EXPECT: LOCK_OK + EVIDENCE: MET exit=0 marker-found :: LOCK_OK +2. Vendored + linked live: every listed file is under skills-external//, byte-identical to the plugin cache copy, and the 7 symlinks resolve under ~/.claude/skills. + CHECK: bash -c 'source lib/vendor-skills.sh; vendor_pinned_skills superpowers' >/dev/null 2>&1; bash link.sh >/dev/null 2>&1; python3 .claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c2.py + EXPECT: VENDORED_LINKED + EVIDENCE: MET exit=0 marker-found :: VENDORED_LINKED +3. No `superpowers:` prefix remains in the personal catalog, agents, lib, hooks or doctrine (fixtures excluded; positive control first). + CHECK: echo 'x superpowers:brainstorming' | grep -q 'superpowers:' || exit 1; if git grep -n 'superpowers:' -- skills agents lib hooks CLAUDE.global.md ':!lib/tests/fixtures' | grep -v '^skills/synced'; then exit 1; fi; echo NO_PREFIX + EXPECT: NO_PREFIX + EVIDENCE: MET exit=0 marker-found :: NO_PREFIX +4. Installers and link wired: install-plugins.sh no longer installs/enables the plugin and vendors `superpowers` in STEP 8e; update-all.sh refreshes it; link.sh EXTERNAL_SKILLS lists the 7; .gitignore ignores the 7 skill symlinks and the 7 skills-external dirs. + CHECK: ! grep -qE 'install_plugin +"superpowers"|enable_plugin +"superpowers"' install-plugins.sh && grep -q 'vendor_pinned_skills superpowers' install-plugins.sh && grep -q 'vendor_pinned_skills superpowers refresh' update-all.sh && for s in brainstorming writing-plans subagent-driven-development test-driven-development requesting-code-review using-git-worktrees writing-skills; do grep -qE "^skills/$s\$" .gitignore || { echo "gitignore skills/$s"; exit 1; }; grep -qE "^skills-external/$s/\$" .gitignore || { echo "gitignore ext $s"; exit 1; }; sed -n '/^EXTERNAL_SKILLS=(/,/)/p' link.sh | grep -qw "$s" || { echo "link $s"; exit 1; }; done && echo WIRED + EXPECT: WIRED + EVIDENCE: MET exit=0 marker-found :: WIRED +5. profile.sh no longer protects the plugin; detect_superpowers is true on the linked vendored skill alone and false under an empty HOME (no plugin-cache glob, no claude call). [challenge r2] + CHECK: ! grep -q 'superpowers@superpowers-marketplace' lib/profile.sh && bash -c 'source lib/detect-plugins.sh; detect_superpowers' && E=$(mktemp -d) && ! HOME="$E" bash -c 'source lib/detect-plugins.sh; detect_superpowers' && rmdir "$E" && ! grep -qE 'compgen.*superpowers|plugin list.*superpowers' lib/detect-plugins.sh && echo DETECT_OK + EXPECT: DETECT_OK + EVIDENCE: MET exit=0 marker-found :: DETECT_OK +6. Suites and shellcheck: vendor-skills, doctor-vendored (with the new ALWAYS_ON_LINK_CHECKED case), doctrine-citers, skill-routing-census (live catalog with the 7), profile-default, profile-set-managed green; shellcheck clean on every touched shell file. [challenge r2] + CHECK: shellcheck install-plugins.sh update-all.sh link.sh lib/profile.sh lib/detect-plugins.sh hooks/session-start.sh doctor.sh lib/doctor-vendored.sh lib/vendor-skills.sh lib/tests/doctor-vendored.test.sh && out=$(make test suite=lib/tests/doctor-vendored.test.sh 2>&1) && echo "$out" | grep -q 'PASS ALWAYS_ON_LINK_CHECKED' && for s in vendor-skills doctor-vendored doctrine-citers skill-routing-census profile-default profile-set-managed; do out=$(make test suite=lib/tests/$s.test.sh 2>&1) || { echo "$s rc"; exit 1; }; echo "$out" | grep -qE 'FAIL=[1-9]|^FAIL ' && { echo "$s FAIL"; exit 1; }; done; echo SUITES_OK + EXPECT: SUITES_OK + EVIDENCE: MET exit=0 marker-found :: SUITES_OK +7. CLAUDE.global.md Skill routing carries the map for the dropped skills and says the seven are vendored, bare names. + CHECK: grep -q 'finishing-a-development-branch' CLAUDE.global.md && grep -q 'executing-plans' CLAUDE.global.md && grep -q 'systematic-debugging' CLAUDE.global.md && grep -qi 'vendored' CLAUDE.global.md && echo ROUTING_OK + EXPECT: ROUTING_OK + EVIDENCE: MET exit=0 marker-found :: ROUTING_OK +8. Live after the orchestrator's uninstall + marketplace removal: no superpowers plugin installed, no enabledPlugins key, no extraKnownMarketplaces block, the 7 skills still resolve, `make doctor` reports superpowers as vendored, not failed. [challenge r2] + CHECK: ! claude plugin list 2>/dev/null | grep -q 'superpowers@superpowers-marketplace' && python3 -c "import json,sys;d=json.load(open('settings.json'));assert 'superpowers@superpowers-marketplace' not in d['enabledPlugins'];assert 'superpowers-marketplace' not in d.get('extraKnownMarketplaces',{})" && for s in brainstorming writing-plans subagent-driven-development test-driven-development requesting-code-review using-git-worktrees writing-skills; do [ -f "$HOME/.claude/skills/$s/SKILL.md" ] || { echo "missing $s"; exit 1; }; done && bash doctor.sh 2>/dev/null | grep -qi 'superpowers.*vendored' && ! bash doctor.sh 2>/dev/null | grep -qi 'Superpowers not detected' && echo PLUGIN_GONE + EXPECT: PLUGIN_GONE + EVIDENCE: MET exit=0 marker-found :: PLUGIN_GONE +9. doctor.sh and session-start.sh stop charging the plugin injection (no `+ 1500` / `+ 800` superpowers constant; doctor message names the vendored skills). + CHECK: ! grep -qE 'detect_superpowers.*\+ ?(1500|800)' doctor.sh hooks/session-start.sh && grep -qi 'vendored' doctor.sh && echo DOCTOR_OK + EXPECT: DOCTOR_OK + EVIDENCE: MET exit=0 marker-found :: DOCTOR_OK +10. Docs: README component table row (vendored skills, pinned v6.4.1, lock entry), USAGE.md mentions of "superpowers" as a plugin or a passive cost reworded, agents/plugin-advisor.md compatibility/recommended-set rows and the "not active → install" remedy reworded, skills/profile/SKILL.md:59 always-on sentence updated, CHANGELOG `[Unreleased]` entry (Changed: superpowers plugin → 7 vendored skills; Removed: the 8 other skills + injection; Known residual: upstream cross-references). +11. lib/capitalize-commit.md, lib/doc-commit.md, lib/analyze-before-plan.md and skills/gitflow/SKILL.md describe finishing-a-development-branch as the upstream skill this config does not vendor (gitflow finish replaces it), not as an active skill. +12. doctor-vendored treats the 7 as always-on: `bash doctor.sh` prints a pass line for each of the 7 (linked) and never "parked" for them. [challenge r2] + CHECK: out=$(bash doctor.sh 2>/dev/null); for s in brainstorming writing-plans subagent-driven-development test-driven-development requesting-code-review using-git-worktrees writing-skills; do echo "$out" | grep -qE "✓.*\b$s\b" || { echo "no pass for $s"; exit 1; }; echo "$out" | grep -qE "$s.*parked" && { echo "parked $s"; exit 1; }; done; echo ALWAYS_ON_OK + EXPECT: ALWAYS_ON_OK + EVIDENCE: MET exit=0 marker-found :: ALWAYS_ON_OK + +## FILE SCOPE +- plugins.lock.json, install-plugins.sh (STEP 5 superpowers block, STEP 8e, summary lines), update-all.sh (7.3), link.sh (EXTERNAL_SKILLS), .gitignore, lib/profile.sh (PROTECTED_PLUGINS + comments), lib/detect-plugins.sh, hooks/session-start.sh, doctor.sh, lib/doctor-vendored.sh, lib/tests/doctor-vendored.test.sh, lib/vendor-skills.sh (lock-shape header comment line) +- skills/{ship-feature,init-project,tour,deploy,audit-delta,gitflow,profile}/SKILL.md, lib/{analyze-before-plan,capitalize-commit,doc-commit}.md, agents/plugin-advisor.md, CLAUDE.global.md (Skill routing lines), README.md, USAGE.md, CHANGELOG.md +- Orchestrator-only, after criterion 2: settings.json (enabledPlugins key + extraKnownMarketplaces block, hand edit), `claude plugin uninstall` + `claude plugin marketplace remove` (cache), rollback if criterion 8 fails; skills-external/<7> (gitignored, curl) and ~/.claude/skills symlinks are written by criterion 2 +- Orchestrator-only: .claude/tasks/**, .claude/memory/** diff --git a/.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c1.py b/.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c1.py new file mode 100644 index 0000000..6d85327 --- /dev/null +++ b/.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c1.py @@ -0,0 +1,16 @@ +import json,re +d=json.load(open('plugins.lock.json')) +e=d['superpowers'] +assert e['source']=='https://github.com/obra/superpowers', e['source'] +assert e['commit']=='5bf4e78011075bcfc0dc295f0724994cd123ee71', e['commit'] +assert e['path']=='skills', e.get('path') +assert e.get('managed_by')=='curl' +want={'brainstorming','writing-plans','subagent-driven-development','test-driven-development','requesting-code-review','using-git-worktrees','writing-skills'} +assert set(e['skills'])==want, set(e['skills'])^want +for k,files in e['skills'].items(): + assert 'SKILL.md' in files, k + for f in files: assert re.fullmatch(r'[A-Za-z0-9._/-]+',f) and '..' not in f, f +assert 'scripts/sdd-workspace' in e['skills']['subagent-driven-development'] +assert 'code-reviewer.md' in e['skills']['requesting-code-review'] +assert 'anthropic-best-practices.md' in e['skills']['writing-skills'] +print('LOCK_OK') diff --git a/.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c2.py b/.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c2.py new file mode 100644 index 0000000..566a4b0 --- /dev/null +++ b/.claude/tasks/contracts/2026-09-28-superpowers-vendored-1357.oracles/c2.py @@ -0,0 +1,17 @@ +import json,os,hashlib,glob +H=os.path.expanduser('~') +e=json.load(open('plugins.lock.json'))['superpowers'] +cache=glob.glob(H+'/.claude/plugins/cache/superpowers-marketplace/superpowers/6.4.1/skills') +missing=[];mism=[] +for k,files in e['skills'].items(): + for f in files: + p=f'skills-external/{k}/{f}' + if not os.path.isfile(p): missing.append(p); continue + if cache: + c=f'{cache[0]}/{k}/{f}' + if os.path.isfile(c) and hashlib.md5(open(p,'rb').read()).hexdigest()!=hashlib.md5(open(c,'rb').read()).hexdigest(): mism.append(p) + link=f'{H}/.claude/skills/{k}' + if not (os.path.islink(link) and os.path.isfile(link+'/SKILL.md')): missing.append(link) +assert not missing, missing +assert not mism, ('byte mismatch vs plugin cache',mism) +print('VENDORED_LINKED') diff --git a/.claude/tasks/plans/2026-09-28-superpowers-vendored-1357.md b/.claude/tasks/plans/2026-09-28-superpowers-vendored-1357.md new file mode 100644 index 0000000..43c2ab8 --- /dev/null +++ b/.claude/tasks/plans/2026-09-28-superpowers-vendored-1357.md @@ -0,0 +1,271 @@ +# PLAN — superpowers-vendored (feat, ad-hoc dispatch) — r3 (after confirmation pass) +- r3 closes the confirmation pass (correctness CONCERNS(1)): MAJOR 1 — the + CLAUDE.global.md map keeps every skill identifier whole on one line (grep + is line-based); MINOR 2 — `always_on` mechanism pinned: the python lock + reader emits a third column, `_dv_check_link` gets a 5th param, headers + updated, a helper extracted if `check_vendored_skills` would exceed 5 + locals; MINOR 3 — stale "uninstall || true" edge case deleted; MINOR 4 — + settings.json edit moves to the orchestrator, AFTER criterion 2 is green + (a disabled plugin + a failed fetch must never coincide); MINOR 5 — + profile.sh comments located by grep, doctor pass line worded on what is + proven. +- r2 closes: correctness BLOCKER 1 (the CLAUDE.global.md map never spells the + colon form — criterion 3 greps it), MAJOR 2 (doctor-vendored gains an + always-on class driven by a lock field `always_on`, so the 7 are + link-checked instead of "parked"), MAJOR 3 + robustness MAJOR 1 (NO + uninstall code in the installer — comment only, one-shot by the + orchestrator after criterion 2 is green), MAJOR 4 + robustness MAJOR 3 + (settings.json hand-edited: enabledPlugins key and + extraKnownMarketplaces.superpowers-marketplace block removed, committed), + MAJOR 5 + robustness MAJOR 2 + simplicity MAJOR 1 (detect_superpowers = + one file test on the linked skill, no plugin fallback, no new global), + simplicity MAJOR 2 (same: no installer uninstall), MINORs: session-start + line deleted plainly, map trimmed to the four referenced skills, lock note + kept to maintainer facts, summary line placement pinned, rollback step, + mixed-version rollback note. +- date: 2026-09-28 | contract: contracts/2026-09-28-superpowers-vendored-1357.md +- branch: feature/superpowers-vendored +- executors: 2 feater (sonnet-pinned), parallel, disjoint file sets + +## Ground truth (verified 2026-09-28) +- Plugin superpowers 6.4.1 installed at + `~/.claude/plugins/cache/superpowers-marketplace/superpowers/6.4.1/` + (gitCommitSha 5bf4e78011075bcfc0dc295f0724994cd123ee71 = upstream tag + v6.4.1 on obra/superpowers; raw files served at + `https://raw.githubusercontent.com/obra/superpowers//skills//`, + brainstorming/SKILL.md md5 identical local vs raw). Enabled in settings.json + (`superpowers@superpowers-marketplace: true`), PROTECTED in lib/profile.sh, + installed + enabled by install-plugins.sh STEP 5 (marketplace add, + install_plugin, enable_plugin), summary line "ALWAYS ON … superpowers". + Its hooks.json SessionStart (startup|clear|compact) injects + using-superpowers (~3.6 KB) every start. +- The 7 skills to vendor and their files (upstream layout `skills//`): + brainstorming: SKILL.md, spec-document-reviewer-prompt.md, visual-companion.md, + scripts/frame-template.html, scripts/helper.js, scripts/server.cjs, + scripts/start-server.sh, scripts/stop-server.sh + writing-plans: SKILL.md, plan-document-reviewer-prompt.md + subagent-driven-development: SKILL.md, implementer-prompt.md, + re-review-prompt.md, task-reviewer-prompt.md, scripts/review-package, + scripts/sdd-workspace, scripts/task-brief + test-driven-development: SKILL.md, writing-good-tests.md + requesting-code-review: SKILL.md, code-reviewer.md + using-git-worktrees: SKILL.md + writing-skills: SKILL.md, anthropic-best-practices.md, + examples/CLAUDE_MD_TESTING.md, graphviz-conventions.dot, + persuasion-principles.md, render-graphs.js, testing-skills-with-subagents.md + Scripts are invoked upstream as `bash scripts/` (SDD lines 137, 252, + 290…; brainstorming visual-companion.md) → no exec bit needed. +- Internal cross-references that will dangle (byte-for-byte text): + writing-plans → superpowers:subagent-driven-development, superpowers:executing-plans (dropped), superpowers:using-git-worktrees; + SDD → superpowers:finishing-a-development-branch ×4 (dropped), superpowers:using-git-worktrees, superpowers:requesting-code-review, executing-plans ×2; + TDD → superpowers:writing-skills; writing-skills → superpowers:test-driven-development ×4, superpowers:systematic-debugging (dropped), using-superpowers, verification-before-completion. +- `lib/vendor-skills.sh` `vendor_pinned_skills [refresh]`: lock + entry `{source, commit (40 hex), path, skills: {name: [files]}, managed_by}`; + files must match `[A-Za-z0-9._/-]+`, no `..`; tmp+mv; skips existing files + unless `refresh`. install-plugins.sh STEP 8e calls it for agent-skills and + mengto-skills with `EXT_SKILL_NAMES` symlink check; update-all.sh 7.3 calls + it with `refresh`. link.sh `EXTERNAL_SKILLS=(…)` symlinks + `skills-external/` into `~/.claude/skills/`; .gitignore lists + `skills/` (symlink) and `skills-external//` (vendored text) per + external. lib/doctor-vendored.sh reads the lock + EXTERNAL_SKILLS generically. +- lib/profile.sh: `PROTECTED_PLUGINS=("security-guidance@claude-code-plugins" + "superpowers@superpowers-marketplace")`; MANAGED_EXTERNALS is the allowlist + `set` parks — the 7 are NOT added (always on, like darwin-skill). +- lib/detect-plugins.sh `detect_superpowers`: plugin cache glob then `claude + plugin list`. Consumers: hooks/session-start.sh:122 (`+ 800` passive), + doctor.sh:225-228 (pass/fail "Superpowers plugin detected / not detected — + orchestrators will fail") and :423 (`+ 1500`). +- `superpowers:` citers (personal): skills/ship-feature:103,117,176,237; + skills/init-project:71,182,215,259; skills/tour:318; skills/deploy:515; + skills/audit-delta:321; lib/analyze-before-plan.md:106; + lib/capitalize-commit.md:20 (finishing-a-development-branch); + agents/plugin-advisor.md:182. Prose mentions of + finishing-a-development-branch: lib/capitalize-commit.md:68, + lib/doc-commit.md:84, lib/analyze-before-plan.md:108, skills/gitflow:16,110. + Docs: README.md:121 (component table), USAGE.md ×19 (plugin/cost + narrative), agents/plugin-advisor.md ×19 (matrix, recommended sets, remedy + :324), skills/profile/SKILL.md:59, install-plugins.sh:1210 summary. + `docs/superpowers/` paths (CLAUDE.md, gitflow, onboard) stay: brainstorming + and writing-plans still write there. +- lib/tests: gitflow-test.sh mentions superpowers only through the purge + path (unchanged). No suite asserts PROTECTED_PLUGINS content. + +## Approach + +### E1 — wiring (lock, installers, link, gitignore, profile, detect, doctor) +Files: plugins.lock.json, install-plugins.sh, update-all.sh, link.sh, +.gitignore, lib/profile.sh, lib/detect-plugins.sh, hooks/session-start.sh, +doctor.sh, lib/doctor-vendored.sh, lib/tests/doctor-vendored.test.sh, +lib/vendor-skills.sh (header comment line only). +1. plugins.lock.json: new entry `"superpowers"` after `"mengto-skills"`: + source `https://github.com/obra/superpowers`, commit + `5bf4e78011075bcfc0dc295f0724994cd123ee71`, path `skills`, `skills` = the + dict above (exact file lists), managed_by `curl`, `"always_on": true`, + note (maintainer facts only, history lives in CHANGELOG/BDR-106): "Seven + superpowers skills vendored byte-for-byte at the v6.4.1 tag commit + (obra/superpowers), always on (no profile lists them). Bump the commit + deliberately. Scripts inside run as `bash scripts/`, no exec bit + needed. Upstream cross-references to the plugin prefix and to the 8 + non-vendored skills stay in the text; CLAUDE.global.md Skill routing maps + them." +2. install-plugins.sh STEP 5: delete the three superpowers lines (marketplace + add, install_plugin, enable_plugin) and replace with a 3-line comment + "Superpowers plugin removed 2026-09-28 (tier 2 of the skill-catalog prune): + its 7 wired skills are vendored in Step 8e (plugins.lock.json + 'superpowers'); a still-cached plugin is uninstalled by hand once + (claude plugin uninstall superpowers@superpowers-marketplace), never here". + NO uninstall code in the installer (precedent: frontend-design, caveman). + Update the `enable_plugin` comment (:490) to name only security-guidance. + STEP 8e: heading/comment mention superpowers; `EXT_SKILL_NAMES` += the 7; + `vendor_pinned_skills superpowers` after mengto. Summary: replace line + ~1210 ("✅ superpowers — brainstorm/plan/implement/debug workflow", ALWAYS + ON block) by "✅ superpowers skills — 7 vendored (brainstorming, + writing-plans, subagent-driven-development, test-driven-development, + requesting-code-review, using-git-worktrees, writing-skills), pinned + v6.4.1, curl → symlink, no plugin, no session injection"; add one "at:" + line right after the mengto "at:" line (~1234): "Superpowers skills at: + ~/.claude/skills/{brainstorming,…}/ (symlink → skills-external)". +3. update-all.sh 7.3: `echo "── Updating superpowers skills (obra/superpowers)..."` + + `vendor_pinned_skills superpowers refresh`; comment names it. +4. link.sh EXTERNAL_SKILLS += the 7 (keep the array multi-line ≤ 80 chars). +5. .gitignore: 7 `skills/` lines next to the other external symlinks + (:65-68 block) and 7 `skills-external//` lines next to the mengto + block (:203-207), each block with a one-line comment "superpowers, vendored + (plugins.lock.json 'superpowers')". +6. lib/profile.sh: PROTECTED_PLUGINS keeps only security-guidance; every + comment naming superpowers as an always-on plugin (`grep -n superpowers + lib/profile.sh`, currently ~:22 and ~:65) reworded ("superpowers is + vendored skills now, not a plugin"). +7. lib/detect-plugins.sh `detect_superpowers`: exactly + `[ -f "$HOME/.claude/skills/brainstorming/SKILL.md" ]` (the linked + vendored skill: proves vendored AND linked; no plugin cache glob, no + `claude plugin list`, no new global, no fallback). Comment: "superpowers + = 7 vendored skills since 2026-09-28; the plugin is gone". A negative + control (empty HOME) must return 1. +7b. lib/doctor-vendored.sh: lock entries may carry `"always_on": true` + (the `superpowers` entry does). Skills of such an entry are expected + LINKED whatever the active profile says (today every EXTERNAL_SKILLS name + absent from the profile is reported `parked`, link unchecked — the 7 are + in no profile by design). Mechanism: `_dv_lock_expectations` (python) + prints a THIRD column `name\tfile\t1` for skills of an `always_on` entry + (awk `$1==n {print $2}` in `_dv_check_files` keeps working unchanged); + `check_vendored_skills` reads the flag and passes it as a 5th parameter to + `_dv_check_link`, which treats `1` as "expected linked whatever the + profile says". If `check_vendored_skills` would exceed 5 locals, extract + the per-name dispatch into a helper (≤ 25 logic lines each). Update the + file header ("A name absent from the profile is reported parked" → "… + unless its lock entry is always_on") and the test header. Message + unchanged for the linked case, fail ": symlink missing/wrong — run: + make link" when absent. Add a case + `ALWAYS_ON_LINK_CHECKED` to lib/tests/doctor-vendored.test.sh (fixture + entry with always_on true, name absent from the profile, link missing → + fail line, never `parked`). Document the field in lib/vendor-skills.sh's + lock-shape header comment (one line: ignored by the vendor helper, read + by doctor-vendored). +8. hooks/session-start.sh: delete line 122 (`detect_superpowers … + 800`) + outright — the banner's ALWAYS_ON list comes from detect_rtk + settings + enabledPlugins (lines ~147-160), not from this call. doctor.sh :225-228: + pass "superpowers: 7 skills vendored + linked (plugins.lock.json, v6.4.1)" + / fail "superpowers skills not linked — run: make plugin && make link"; + the pass line is worded on what `detect_superpowers` proves + ("superpowers skills linked (brainstorming found); per-skill check under + Vendored skills"); :423 delete the `+ 1500` line (comment: counted by the + skill catalog stats). +9. settings.json: NOT an executor file any more — the orchestrator edits it + after criterion 2 is green (see Orchestrator steps), so a disabled plugin + never coincides with a failed fetch. + +### E2 — citers, routing map, docs +Files: skills/{ship-feature,init-project,tour,deploy,audit-delta,gitflow,profile}/SKILL.md, +lib/{analyze-before-plan,capitalize-commit,doc-commit}.md, +agents/plugin-advisor.md, CLAUDE.global.md, README.md, USAGE.md, CHANGELOG.md. +1. `superpowers:` → `` (bare) in ship-feature ×4, init-project ×4, + tour:318, deploy:515, audit-delta:321, lib/analyze-before-plan.md:106, + agents/plugin-advisor.md:182. Wording around them: "Invoke `brainstorming` + (vendored superpowers skill)" on first mention per file, bare afterwards. +2. finishing-a-development-branch prose: lib/capitalize-commit.md:20 → "Orchestrators + that integrate via `gitflow finish` (the upstream + finishing-a-development-branch is not vendored)"; :68, lib/doc-commit.md:84, + lib/analyze-before-plan.md:108, skills/gitflow:16,110 → say "upstream + superpowers skill, not vendored here; `gitflow finish` is the only + integration path" where they present it as available. +3. CLAUDE.global.md § Skill routing, after the "Before /clear or /compact" + line, ≤ 80 chars per line, about 4 lines, and NEVER the literal + "superpowers" followed by a colon (criterion 3 greps that string): + "- superpowers skills are vendored, called by bare name; an upstream + `superpowers` prefix means the bare skill. Not vendored: + executing-plans → subagent-driven-development; + finishing-a-development-branch → `gitflow finish` (human signal); + systematic-debugging → bugfix; verification-before-completion → the + verifier gates." + Every skill identifier stays WHOLE on its line (criterion 7 greps + `finishing-a-development-branch`, `executing-plans`, `systematic-debugging` + line by line); wrap at spaces only. +4. README.md:121 row → "**Superpowers skills** | Vendored (7, always on) | + brainstorming, writing-plans, subagent-driven development, TDD, code + review request, git worktrees, writing-skills — pinned v6.4.1 in + plugins.lock.json, no plugin, no session injection | obra/superpowers". + README:208 unchanged. +5. USAGE.md: every line presenting superpowers as a plugin to keep ON/OFF or + as ~800 t passive (184-185, 589, 650, 751, 864, 959-965, 971, 995, 1018) + → "skills superpowers (vendorisés, toujours actifs, 0 t passif)" or the + equivalent in the sentence's French; keep the narrative otherwise. +6. agents/plugin-advisor.md: rows 177-182 (compat matrix) → "superpowers + skills (vendored)" wording, drop the plugin-dev overlap row's "plugin" + framing; recommended-set table 190-198: replace "superpowers" by + "(superpowers skills always on)" in the ON column and subtract ~800 t from + each cost; :80, :146, :242, :254, :298 reword; :324 remedy → "Superpowers + skills missing → `make plugin` (vendors them) then `make link`". +7. skills/profile/SKILL.md:59: "Always-on plugins (`security-guidance`) and + the vendored superpowers skills are never toggled by a profile". +8. CHANGELOG `[Unreleased]`: Changed (superpowers plugin → 7 vendored skills, + pinned, always on; `superpowers:` citers renamed), Removed (plugin, its 8 + duplicate skills, the SessionStart injection), Known residual (upstream + cross-references inside the vendored text; CLAUDE.global.md map). + +## Orchestrator steps +- Criterion 2 vendors + links live (network fetch of 30 files); only when + every file is present and byte-identical (c2.py) does the next step run. +- Then the orchestrator edits settings.json by hand: remove the + `"superpowers@superpowers-marketplace": true` key from `enabledPlugins` and + the whole `extraKnownMarketplaces."superpowers-marketplace"` block, nothing + else; validate with `python3 -c 'import json;json.load(open("settings.json"))'`. +- Then, one shot by hand: `claude plugin uninstall superpowers@superpowers-marketplace` + and `claude plugin marketplace remove superpowers-marketplace`; re-check + `git diff settings.json` afterwards (the CLI must not have re-added + anything), then criterion 8. +- Rollback if criterion 8 fails: `claude plugin marketplace add + obra/superpowers-marketplace && claude plugin install superpowers@superpowers-marketplace`, + `git checkout -- settings.json`, stop and report. +- Verifier; security; commit; BDR-106 + journal. + +## Edge cases +- Mid-migration machine (plugin cached, skills not yet vendored): doctor + fails "not vendored or linked — run make plugin && make link"; the user + uninstalls the plugin by hand (CHANGELOG says so). No fallback that could + print "vendored" for a plugin-only machine. +- Mixed-version rollback (an older checkout re-installs the plugin while the + 7 symlinks are still linked → duplicate descriptions): CHANGELOG note + "after a rollback, delete skills/<7> symlinks or re-run the new make plugin". +- The running session keeps the plugin's `superpowers` skills until restart; + the bare names appear after `make link` + a new session. +- Fresh clone: link.sh symlinks a non-existent skills-external dir only if + present (existing `[ -d ]` guard). +- skill-routing-census live run gains 7 descriptions: brainstorming's "You + MUST use this before any creative work" vs personal descriptions — the + suite's live FAIL threshold must not trip (check by running it). + +## Tests +- make test suite= vendor-skills, doctor-vendored (with the new + ALWAYS_ON_LINK_CHECKED case), doctrine-citers, skill-routing-census, + profile-default, profile-set-managed. +- shellcheck on every touched shell file. + +## Disposition (RELATED MEMORY) +- honors BDR-102 / BDR-104 — vendor over plugin, shared helper, pinned commit, + byte-for-byte text. +- honors BDR-105 — tier 2 of the prune decision. +- honors BDR-065 — docs/superpowers transient path unchanged. +- honors LRN-178 — no new top-level `source`; detect-plugins reads a path. +- honors BDR-077 — requesting-code-review's reviewer dispatch keeps the + model-routing note in ship-feature/init-project.