Skip to content

fix: scope suit inject to named components; add --skill/--hook#74

Merged
danmestas merged 1 commit into
mainfrom
feat/inject-scoped-emit
May 25, 2026
Merged

fix: scope suit inject to named components; add --skill/--hook#74
danmestas merged 1 commit into
mainfrom
feat/inject-scoped-emit

Conversation

@danmestas

Copy link
Copy Markdown
Owner

Increment 3 of suit inject (follows #66, #73). Fixes a real over-emission bug and adds the --skill/--hook sugar — they share one mechanism.

The bug

suit inject --accessory philosophy materialized the entire wardrobe — 108 skills + all hooks/agents — into the target home, not just philosophy's 6 declared skills + 1 agent. Root cause: inject composes with no outfit, so effectiveCategories is null and computeSkillsDrop drops nothing; emitForTarget only filters skills by the drop-set and emits every non-skill component unconditionally. Nothing scoped the output.

The fix (+ feature)

Thread an optional restrictTo keep-set (<type>:<name> keys) through composeBundleemitForTarget. When present, a component is emitted only if it's named in the keep-set; when absent, suit up/suit prepare behave exactly as before (verified — they pass nothing). All post-processing (dedupe, additive marker-wrap, redirects) is preserved, so off-cleanup + idempotency keep working.

suit inject computes the keep-set from:

  • --accessory/--bundle X → X's include block (skills/rules/hooks/agents/commands).
  • --skill X / --hook X (new) → the single component.

Exactly one of --accessory/--bundle/--skill/--hook is required (exit 2); unknown component → exit 1 with a clear message; lockfile provenance label qualifies bare components (skill:<name>).

Verification

  • npm run typecheck, npm run build, npm test629 tests pass (+ bug-regression, --skill, --hook, exactly-one-kind ×2, not-found).
  • Smoke: inject --accessory philosophy6 skills + architect-review agent (was 108 skills); golang-patterns/publish-to-npm absent. --skill ousterhout → exactly ousterhout (tigerstyle absent). Exit codes: no-kind 2, two-kind 2, not-found 1.

Note

This corrects behavior shipped in #66 (increment 1). Reload still aggregates to restart-required whenever the target set includes codex/gemini/pi (unchanged).

Next (deferred)

NATS --target discovery (#68), reload emit-side (#69), reload-verb research (#70), docs (#72).

suit inject --accessory X over-emitted the ENTIRE wardrobe (108 skills +
all hooks/agents) into the target home, not just X's declared components.
Root cause: with no outfit effectiveCategories is null so nothing is
dropped, and emitForTarget only filters skills by the drop-set — every
non-skill component emitted unconditionally.

Fix: thread an optional restrictTo keep-set (<type>:<name> keys) through
composeBundle into emitForTarget. When present, a component is emitted
ONLY if named in the keep-set; when absent, suit up/prepare behave
exactly as before. inject computes the keep-set from the accessory's
include block (--accessory/--bundle) or the single component (--skill/
--hook), validated against the catalog.

- add --skill <name> / --hook <name> (inject one bare component); exactly
  one of --accessory/--bundle/--skill/--hook required (exit 2 otherwise)
- unknown component name -> exit 1 with a clear message
- lockfile provenance label qualifies bare components (skill:<name>)

Verified: inject --accessory philosophy now emits 6 skills + 1 agent (was
108 skills), --skill ousterhout emits exactly ousterhout. 629 tests pass.
@danmestas danmestas merged commit 1e92e4b into main May 25, 2026
1 check passed
@danmestas danmestas deleted the feat/inject-scoped-emit branch May 25, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant