Skip to content

refactor: delete legacy per-target emitters/validators now that all targets are migrated - #17

Merged
steve-calvert-glean merged 8 commits into
mainfrom
refactor/delete-legacy-target-adapters
Jul 26, 2026
Merged

refactor: delete legacy per-target emitters/validators now that all targets are migrated#17
steve-calvert-glean merged 8 commits into
mainfrom
refactor/delete-legacy-target-adapters

Conversation

@steve-calvert-glean

Copy link
Copy Markdown
Contributor

Summary

All 5 targets (copilot, antigravity, cursor, claude, codex) now have a PluginTargetDefinition in src/targets/registry.ts, so the legacy fallback path adapters.ts existed for is dead. This is the final step of the registry migration CLAUDE.md itself flagged: "Adding a target currently touches ~5 places... consider introducing a single target registry first to localize this."

  • Deletes src/targets.ts and src/validate.ts entirely (their only remaining consumer was adapters.ts's legacyAdapters map).
  • Moves withRootFiles into src/targets/engine.ts, next to the artifact helper it depends on.
  • Tightens the registry's type from Partial<Record<TargetName, ...>> to Record<TargetName, ...> now that every target has an entry — a new TargetName won't build until it has a registry entry, the same exhaustiveness guarantee the deleted legacyAdapters map used to provide.
  • Simplifies adapters.ts to a thin emitTarget/validateOutput wrapper around the registry + engine, dropping the now-pointless TargetAdapter/adapters indirection that existed only to switch between legacy and registry per target.
  • Removes targetDefaultComponents/resolveTargetComponents from components.ts (superseded by each target's own defaultComponents).
  • Updates CLAUDE.md's Architecture/Targets sections and a couple of stale doc-comment references (emitCursor, validate.ts) to match the new file layout.

Also included (found while doing this cleanup, worth calling out separately): every migrated target's validateOutput was calling validateHooksShape, which only checked that hooks.json has a "hooks" object — narrower than the legacy per-target validateHooks it replaced, which also required each event's entries to be an array, rejected empty "command" strings, and errored if a command referenced the generated update-check script without that script being present. That depth had no regression test, so the narrowing was silent. Ported the full check into validateHooksShape once (a separate commit in this branch), so every target regains it for free, plus a new regression test.

Net: -1497 lines. The build's dist/chunk-*.js also dropped from ~105 KB to ~75 KB, confirming a real amount of dead code was removed, not just moved.

Stacking

Based on refactor/codex-target-registry (#16). Merge in order: #14#15#16 → this.

Test plan

  • npm run typecheck
  • npm run lint
  • npm test (64/64 passing)
  • npm run build
  • node dist/cli.js docs --check

steve-calvert-glean and others added 6 commits July 26, 2026 13:42
Re-checking the originally planned Cursor "fixes" against the vendored
plugin.schema.json / marketplace.schema.json (this repo's own
conformance oracle, already passing against the current shape) showed
they were wrong:

- displayName/category/tags ARE valid plugin.json fields per the
  schema (additionalProperties: false, and they're explicitly listed)
  — not marketplace-entry-only fields as previously assumed.
- Marketplace `owner` is genuinely optional (required: ["name",
  "plugins"] does not include it) — not required as previously
  assumed. Moving category/tags to the marketplace entry would have
  been actively wrong: entries only allow name/source/description
  (additionalProperties: false).

None of that is changed here. What this commit actually does:

- Migrates cursor onto PluginTargetDefinition, preserving every
  existing field and behavior (verified by the vendored-schema
  conformance test staying green).
- Fixes one genuine, low-risk issue: the manifest builder's own
  hardcoded default-components list could diverge from this target's
  actual defaultComponents (components.ts). Replaced both with one
  list of schema-valid pointer fields, checked directly against the
  plugin's real resolved componentDirs — eliminates the divergence
  risk with no observable behavior change (confirmed via a new test
  exercising the one case that could have differed: an explicit
  `components: [...]` override).
- Ports update-check's hook-injection into the new shared engine
  (src/targets/engine.ts), which previously only existed in the
  legacy emitCursor/emitClaude path — migrating cursor without this
  would have silently dropped update-check support.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
buildPluginManifest used the target-level `version` param directly
instead of `pluginConfig.version ?? version`, silently dropping a
per-plugin version override — a real regression from the pre-migration
behavior, caught by porting the equivalent test from the claude
migration (no test previously covered this for cursor specifically).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports emitClaude/validateClaude into src/targets/claude.ts as a
PluginTargetDefinition, verified directly against `claude plugin
validate --strict`: a minimal manifest with only `name` fails that
check, confirming the existing version/description/author.name
requirements already match the real CLI rather than over-constraining
it.

Applies the per-plugin version override in buildPluginManifest
(pluginConfig.version ?? version) up front, matching the identical fix
just made to cursor's copy of this pattern.
Ports emitCodex/validateCodex into src/targets/codex.ts as a
PluginTargetDefinition, correcting the plugin format's real shape —
re-verified directly against developers.openai.com/codex/plugins/build
(fetched twice, independently, for consistency) since Codex has no
CLI validator or vendored schema to check against:

- plugin.json requires only "name"; version/description/author etc.
  are optional. The previous validator wrongly required version and
  description.
- Every marketplace entry needs policy.installation,
  policy.authentication, and category — previously unvalidated, so an
  incomplete entry shipped silently. pluginpack can't infer these, so
  the base entry stays guess-free and validateOutput now errors
  clearly when an author never supplies them via the per-plugin
  `entry` passthrough (already how the existing conformance fixture
  supplies them).
- A marketplace entry's source is a bare string only for local
  plugins (the only shape pluginpack itself ever emits); url/git-subdir/npm
  sources are structured objects with an inner "source" discriminator.
  validateMarketplaceEntry now accepts either shape instead of the
  previously shared, string-only validator.
- plugin.json now declares a `hooks` pointer when hooks/ is present,
  matching skills/mcpServers (previously only skills/mcpServers were
  declared, so hooks were emitted but never referenced).

Updates CONFORMANCE.md's Codex section, which had pinned a stale,
bare-string-only shape from an earlier doc retrieval.
…tion

Every migrated target's validateOutput calls validateHooksShape (added
in the registry scaffold), which only checked that hooks.json has a
"hooks" object — narrower than the legacy per-target validateHooks it
replaced, which also required each event's entries to be an array,
rejected empty "command" strings, and errored if a command referenced
the generated update-check script without that script actually being
present. None of that depth had a regression test, so the narrowing
was silent.

Ports the full check into validateHooksShape once, so every target
that already calls it (all 5, post-migration) regains it for free
instead of needing the fix repeated per target file.
…argets are migrated

All 5 targets (copilot, antigravity, cursor, claude, codex) now have a
PluginTargetDefinition in src/targets/registry.ts, so the legacy
fallback path adapters.ts existed for is dead:

- Deletes src/targets.ts and src/validate.ts entirely (their only
  consumer was adapters.ts's legacyAdapters map).
- Moves withRootFiles into src/targets/engine.ts, next to the artifact
  helper it depends on.
- Tightens the registry's type from Partial<Record<TargetName, ...>>
  to Record<TargetName, ...> now that every target has an entry — a
  new TargetName won't build until it has a registry entry, the same
  exhaustiveness guarantee the deleted legacyAdapters map used to
  provide.
- Simplifies adapters.ts to a thin emitTarget/validateOutput wrapper
  around the registry + engine, dropping the now-pointless
  TargetAdapter/adapters indirection that existed only to switch
  between legacy and registry per target.
- Removes targetDefaultComponents/resolveTargetComponents from
  components.ts (superseded by each target's own defaultComponents).
- Updates CLAUDE.md's Architecture/Targets sections and a couple of
  stale doc-comment references to match.
Cross-references the validateHooksShape fix from the prior commit —
what it checks and where it's shared from, for the conformance doc's
own "what's actually verified and how" mandate.
@steve-calvert-glean steve-calvert-glean added the internal Internal refactoring, cleanup, or maintenance work label Jul 26, 2026
Base automatically changed from refactor/codex-target-registry to main July 26, 2026 23:13
…y-target-adapters

# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
#
# Conflicts:
#	src/targets.ts
#	src/validate.ts
@steve-calvert-glean
steve-calvert-glean merged commit 6a96abb into main Jul 26, 2026
1 check passed
@steve-calvert-glean
steve-calvert-glean deleted the refactor/delete-legacy-target-adapters branch July 26, 2026 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal Internal refactoring, cleanup, or maintenance work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant