forked from bchanot/claude
chore(memory): BDR-106 superpowers vendored — contract, plan r3, oracles, TODO, journal
This commit is contained in:
@@ -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]].
|
||||
|
||||
@@ -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 `<contract>.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]]
|
||||
|
||||
@@ -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:<x>` → `<x>` 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
|
||||
|
||||
@@ -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:<x>` 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/<x>` 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/<skill>/, 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/**
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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/<sha>/skills/<skill>/<file>`,
|
||||
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/<name>/`):
|
||||
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/<x>` (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 <lock-key> [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/<name>` into `~/.claude/skills/<name>`; .gitignore lists
|
||||
`skills/<name>` (symlink) and `skills-external/<name>/` (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/<x>`, 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/<name>` lines next to the other external symlinks
|
||||
(:65-68 block) and 7 `skills-external/<name>/` 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 "<name>: 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:<x>` → `<x>` (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.
|
||||
Reference in New Issue
Block a user