Skip to content

Commit 82cc4ca

Browse files
author
Cherrypick Bot
committed
Merge origin/main into eshwar/per-target-mcp-and-plugin-root-files
Reconcile the per-target MCP override + plugin-root files features with main's target-registry refactor (src/targets.ts -> src/targets/). - source.ts: kept main's resolveTargetOverride-based readPluginFiles; re-added the plugin.pluginpack.json "files" map emission and threaded "target" into readMcpServers so targets/<host>/.mcp.json overrides the base .mcp.json. - targets.ts deleted (accepted main's refactor); the resolveMcpServers call moved to src/targets/engine.ts and now passes "target". - render.ts/types.ts/schema.ts: target param on readMcpServers/resolveMcpServers and the "files" field on sourcePluginManifestSchema merged cleanly. - tests/core.test.ts: kept all of main's tests; re-added the 4 feature tests (per-target MCP override, plugin-root files, collision guard, missing source). npm run test:all green (80 tests, format/lint/typecheck/build/docs).
2 parents 701c608 + 0f11dc2 commit 82cc4ca

42 files changed

Lines changed: 5770 additions & 2104 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
matrix:
1313
node-version: [24]
1414
steps:
15-
- uses: actions/checkout@v6
15+
- uses: actions/checkout@v7
1616

1717
- name: Set up Node
1818
uses: actions/setup-node@v6
@@ -26,5 +26,8 @@ jobs:
2626
- name: Check
2727
run: npm run check
2828

29+
- name: Audit production dependencies
30+
run: npm run audit
31+
2932
- name: Verify package contents
3033
run: npm pack --dry-run

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ examples/glean/plugins/
55
examples/basic/dist/
66
package-lock.json
77
tests/fixtures/cursor/*.schema.json
8+
CHANGELOG.md

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
# Changelog
22

3+
## v0.8.0 (2026-07-27)
4+
5+
#### :rocket: Enhancement
6+
7+
- [#18](https://github.com/gleanwork/pluginpack/pull/18) feat: add install-info command and buildInstallSnippet API ([@steve-calvert-glean](https://github.com/steve-calvert-glean))
8+
- [#12](https://github.com/gleanwork/pluginpack/pull/12) feat: add opt-in update-check hook for claude and cursor targets ([@steve-calvert-glean](https://github.com/steve-calvert-glean))
9+
10+
#### :bug: Bug Fix
11+
12+
- [#20](https://github.com/gleanwork/pluginpack/pull/20) fix(deps): resolve brace-expansion DoS advisory; scope audit to production deps ([@steve-calvert-glean](https://github.com/steve-calvert-glean))
13+
- [#16](https://github.com/gleanwork/pluginpack/pull/16) fix: correct Codex plugin output for the target registry ([@steve-calvert-glean](https://github.com/steve-calvert-glean))
14+
- [#13](https://github.com/gleanwork/pluginpack/pull/13) fix: correct Copilot and Antigravity plugin output + polymorphic target registry ([@steve-calvert-glean](https://github.com/steve-calvert-glean))
15+
16+
#### :house: Internal
17+
18+
- [#17](https://github.com/gleanwork/pluginpack/pull/17) refactor: delete legacy per-target emitters/validators now that all targets are migrated ([@steve-calvert-glean](https://github.com/steve-calvert-glean))
19+
- [#19](https://github.com/gleanwork/pluginpack/pull/19) refactor: migrate claude to the target registry (no behavior change) ([@steve-calvert-glean](https://github.com/steve-calvert-glean))
20+
- [#14](https://github.com/gleanwork/pluginpack/pull/14) refactor: migrate cursor to the target registry ([@steve-calvert-glean](https://github.com/steve-calvert-glean))
21+
22+
#### Committers: 1
23+
24+
- Steve Calvert ([@steve-calvert-glean](https://github.com/steve-calvert-glean))
25+
26+
27+
328
## 0.7.0 (2026-07-13)
429

530
- Add a native Codex target that emits `.agents/plugins/marketplace.json`,

CLAUDE.md

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ manager or publisher.
1313
tests run the real built binary (`dist/cli.js`) via `bintastic`.
1414
- `npm run check` — the full gate (`test:all`): `format:check``lint`
1515
`typecheck``test``build``docs`. Run this before considering work done.
16+
- `npm run audit``npm audit --omit=dev`, also run in CI. Scoped to production
17+
dependencies on purpose: devDependencies (eslint, test fixtures, etc.) never
18+
ship in the published package, so a vulnerability there isn't a risk to
19+
consumers — don't add fixes/overrides for dev-only findings.
1620
- `npm run build` — bundle with tsup.
1721
- After changing CLI commands/options, regenerate the README CLI reference with
1822
`node dist/cli.js docs` (the gate's `docs --check` fails if it is stale).
@@ -37,25 +41,35 @@ diff, prune, and validate all derive from it.
3741
generated output is never misread as source), and the root-skills plugin.
3842
- `src/render.ts``collectPluginFiles` (component dirs + static files, with
3943
`targets/<name>/` override resolution) and `resolveMcpServers`.
40-
- `src/targets.ts``emitTarget` + per-target emitters. `cursor`/`claude`/
41-
`antigravity` share the `emitPlugins` engine via callbacks; `emitCopilot` is
42-
bespoke (no per-plugin manifest, dual marketplace). Manifest builders live here
43-
too.
44+
- `src/targets/registry.ts``targets: Record<TargetName, PluginTargetDefinition>`,
45+
one file per target (`src/targets/<name>.ts`). Everything that varies by
46+
target — default components, manifest/marketplace builders, output paths,
47+
validation, install snippet — lives on that target's own
48+
`PluginTargetDefinition` (`src/targets/types.ts`).
49+
- `src/targets/engine.ts``emitFromDefinition`/`validateFromDefinition`: the
50+
one emit/validate engine every target runs through, driven by its
51+
`PluginTargetDefinition`. Also `withRootFiles` (injects per-target
52+
repo-root files into the artifact).
53+
- `src/targets/validation-shared.ts` — validators shared across targets whose
54+
shape actually matches (bare-string marketplace `source`, hooks.json shape,
55+
frontmatter conventions); a target with a genuinely different shape (e.g.
56+
Codex's structured `source`) writes its own instead of forcing a fit.
57+
- `src/adapters.ts``emitTarget`/`validateOutput`/`targetNames`, thin
58+
wrappers around the registry + engine.
4459
- `src/build.ts``build()`: emit all targets → `assertNoCrossTargetCollisions`
4560
→ write/prune/manifest. Holds the delete guard.
4661
- `src/managed.ts` — the managed-file manifest (`.pluginpack/<target>.json`),
4762
`prune`/`clean`, the delete guard, and path-safety checks.
4863
- `src/diff.ts``diffTarget`: build to a temp dir and compare against an
4964
existing target repo (the CI staleness gate).
50-
- `src/validate.ts` — per-target output validation.
5165

5266
## Targets
5367

54-
`cursor`, `claude`, `antigravity`, `copilot`. Adding a target currently touches ~5
55-
places: the `TargetName` union (`types.ts`), the `targets` array + `parseTarget`
56-
(`cli.ts`), `allTargets` (`build.ts`), the `emitters` map + a new `emitFoo`
57-
(`targets.ts`), and a branch + `validateFoo` (`validate.ts`). If you are adding a
58-
target, consider introducing a single target registry first to localize this.
68+
`copilot`, `antigravity`, `cursor`, `claude`, `codex`. Adding a target means one
69+
new file implementing `PluginTargetDefinition` (`src/targets/<name>.ts`) plus one
70+
new entry in `src/targets/registry.ts``TargetName` (`types.ts`) is still a
71+
separate union to extend, but everything else (CLI `--target` choices, `build()`'s
72+
target set, emit/validate dispatch) derives from the registry automatically.
5973

6074
## Conformance
6175

@@ -80,6 +94,7 @@ schemas at runtime — vendor a pinned copy with recorded provenance.
8094

8195
## Conventions
8296

83-
- Strict TypeScript, no `any` (the one exception is `readJson` in `validate.ts`).
97+
- Strict TypeScript, no `any` (the one exception is `readJson` in
98+
`src/targets/validation-shared.ts`).
8499
- Prettier + eslint enforced by the gate.
85100
- Conventional commits. Keep the README CLI reference regenerated.

CONFORMANCE.md

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Each app's source of truth is something other than a stable schema URL:
1414
| `cursor` | Glean-authored schemas in `gleanwork/cursor-plugins/schemas/` | **No upstream.** The schema `$id` (`https://cursor.com/schemas/cursor-plugin/...`) 500s; no Cursor-published schema found. |
1515
| `antigravity` | Antigravity CLI plugin docs (`plugin.json`, optional `mcp_config.json`) | **No.** Defined by product docs and observed CLI layout, not a published schema. |
1616
| `copilot` | [`github/copilot-plugins`](https://github.com/github/copilot-plugins) — a Claude-marketplace-derived format | **Structural.** Copilot shares the Claude marketplace base but extends entries (`skills[]`, `mcpServers` as a path), which `claude plugin validate` rejects — so conformance is asserted structurally against the official format. |
17-
| `codex` | [OpenAI Codex CLI plugin docs](https://developers.openai.com/codex/plugins/build) (`.codex-plugin/plugin.json` + `.agents/plugins/marketplace.json`) | **No published schema.** Defined by product docs; conformance is asserted structurally against the documented format (retrieved 2026-06-17). |
17+
| `codex` | [OpenAI Codex CLI plugin docs](https://developers.openai.com/codex/plugins/build) (`.codex-plugin/plugin.json` + `.agents/plugins/marketplace.json`) | **No published schema.** Defined by product docs; conformance is asserted structurally against the documented format (retrieved 2026-07-26). |
1818

1919
## Oracles the harness uses
2020

@@ -48,14 +48,80 @@ against a temp fixture via [`bintastic`](https://github.com/scalvert/bintastic).
4848
`tests/core.test.ts` (required `plugin.json` fields present; optional
4949
`mcp_config.json` written when MCP servers are present). Antigravity CLI does
5050
not expose a published schema to validate against.
51-
- **codex** — asserted structurally in `tests/conformance.test.ts` against the
52-
[documented Codex plugin format](https://developers.openai.com/codex/plugins/build):
53-
a repo-scoped `.agents/plugins/marketplace.json` (`{ name, interface, plugins }`)
54-
plus a per-plugin `.codex-plugin/plugin.json` (`{ name, version, description,
55-
skills }`) and optional `.mcp.json`. No published JSON Schema exists; the test
56-
pins the documented shape and confirms a per-plugin `entry` passthrough lands in
57-
the marketplace entry. Codex shares no marketplace path with the other targets,
58-
so it needs no separate output root.
51+
- **codex** — asserted structurally in `tests/conformance.test.ts` and
52+
`tests/core.test.ts` against the
53+
[documented Codex plugin format](https://developers.openai.com/codex/plugins/build)
54+
(re-verified 2026-07-26 via direct fetch, twice, for consistency): a
55+
repo-scoped `.agents/plugins/marketplace.json` (`{ name, interface, plugins }`,
56+
no `owner` field) plus a per-plugin `.codex-plugin/plugin.json` where only
57+
`name` is required — `version`/`description`/`skills`/`hooks`/`mcpServers` are
58+
optional pointers to bundled components. Every marketplace entry must carry
59+
`policy.installation`, `policy.authentication`, and `category`; pluginpack has
60+
no way to infer these, so the base entry stays guess-free and `validateOutput`
61+
errors clearly if an author never supplies them via the per-plugin `entry`
62+
passthrough. An entry's `source` is a bare string only for local plugins (the
63+
only shape pluginpack itself ever emits); a `url`/`git-subdir`/`npm` source
64+
added via `entry` is a structured object with an inner `source` discriminator
65+
(e.g. `{ source: "git-subdir", url, path, ref }`), validated by shape rather
66+
than requiring a local directory to exist. No published JSON Schema exists.
67+
Codex shares no marketplace path with the other targets, so it needs no
68+
separate output root.
69+
70+
## Update-check hook facts
71+
72+
The generated update-check hook (`updateCheck` config, claude/cursor targets)
73+
relies on two upstream hook behaviors that have no referenceable schema. Both
74+
were verified against product docs on 2026-07-22:
75+
76+
- **Claude Code** — a `SessionStart` hook may print JSON whose top-level
77+
`systemMessage` field is shown directly to the user (separate from model
78+
context), and plugin hooks are auto-discovered from `hooks/hooks.json` with
79+
`${CLAUDE_PLUGIN_ROOT}` substituted in commands.
80+
Source: <https://code.claude.com/docs/en/hooks>.
81+
- **Cursor** — the `sessionStart` hook supports only `additional_context`
82+
(injected into the agent's context); there is no user-visible message field,
83+
so the cursor nudge asks the agent to relay it. Plugin hooks live in a
84+
`hooks.json` (`{ "version": 1, "hooks": { "sessionStart": [...] } }`)
85+
referenced from the plugin manifest, with commands relative to the plugin
86+
root. Source: <https://cursor.com/docs/agent/hooks>.
87+
88+
The emitted `hooks/hooks.json` shapes are covered by the conformance suite (the
89+
cursor manifest's `hooks` key validates against the vendored plugin schema, and
90+
`claude plugin validate --strict` exercises the claude hooks file when the CLI
91+
is present).
92+
93+
Every target's `validateOutput` shares one `validateHooksShape`
94+
(`src/targets/validation-shared.ts`) for the parts of a hooks file that are
95+
target-agnostic: each event's entries must be an array, no `command` string
96+
may be empty, and any command referencing the generated update-check script
97+
(`scripts/pluginpack-update-check.sh`) must ship that script.
98+
99+
## Install-snippet facts
100+
101+
`pluginpack install-info` (and the `buildInstallSnippet` library function)
102+
prints the real command or URL a user needs to add a pluginpack-built
103+
marketplace. Each target's snippet and citation live on its own
104+
`PluginTargetDefinition.installSnippet` in `src/targets/<name>.ts`, verified
105+
directly against product docs:
106+
107+
| Target | Snippet | Source | Verified |
108+
| ------------- | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ---------- |
109+
| `claude` | `/plugin marketplace add <repo>` then `/plugin install <name>@<marketplace>` (slash-only) | <https://code.claude.com/docs/en/plugins-reference#cli-commands-reference> | 2026-07-25 |
110+
| `codex` | `codex plugin marketplace add <repo>` | <https://learn.chatgpt.com/codex/developer-commands> | 2026-07-25 |
111+
| `copilot` | `copilot plugin marketplace add <repo>` then `copilot plugin install <name>@<marketplace>` | <https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/plugins-finding-installing> | 2026-07-25 |
112+
| `antigravity` | `git clone <repo> plugin-source && cd plugin-source && agy plugin install <pluginPath>` | <https://antigravity.google/docs/cli/plugins> | 2026-07-25 |
113+
| `cursor` | No CLI equivalent exists. Prints the repo URL, pasted into Dashboard → Plugins → Team Marketplaces → "Import from Repo." | <https://cursor.com/docs/plugins> | 2026-07-25 |
114+
115+
`claude`'s two-step sequence is not symmetric with `codex`/`copilot`'s shell
116+
commands: `/plugin marketplace add` is slash-only inside an active Claude Code
117+
session, with no shell equivalent — but once a marketplace is already added,
118+
`claude plugin install <name>@<marketplace>` does work as a standalone shell
119+
command, surfaced as a secondary `note`.
120+
121+
Every target resolves to `userConfigurable: true` today;
122+
`getUnsupportedInstallTargets()` returns `[]`. The `false` branch of the
123+
`InstallSnippet` union exists for forward-compatibility, not because any
124+
target needs it now.
59125

60126
## Refreshing vendored schemas
61127

0 commit comments

Comments
 (0)