@jini-ai/agent-plugins 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.4 — 2026-10-12 — Agent Plugins 1.1.0
4
+
5
+ - `parseAgentPluginManifest()` / `parseAgentPluginMcpConfig()` (and so the installer and MCP
6
+ projection) select the grammar by `$schema` and accept Agent Plugins 1.1.0 identifiers alongside
7
+ 1.0.0. 1.1.0 changes only the version identifiers, so both map to the same validator; 1.0.0
8
+ behavior is unchanged. When a `plugin.json` is supplied, `mcp.json` must target the same version
9
+ (§10).
10
+ - Forward-compatible within major 1 (owner decision): an unknown 1.x (e.g. 1.2.0) is validated with
11
+ the newest known (1.1.0) grammar and reports one warning naming the version. A different major
12
+ (2.x, 0.x) is refused as an unsupported major version; a non-canonical `$schema` is refused with
13
+ the accepted identifiers listed.
14
+
3
15
  ## 0.4.2
4
16
 
5
17
  - Use shared plugin identity metadata with a required `@jini-ai/core` peer at `^0.4.2`. Repair identity-lock publication syntax and isolate unreadable or invalid installed manifests with warnings so one damaged install cannot block healthy installs or bundled seeding.
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  > **Leon, this is you from the past. Do not try to merge `plugins` and `agent-plugins`.**
4
4
 
5
- Support for **Agent Plugins**, an open, vendor-neutral spec (v1.0.0, published 2026-08-06) for
6
- bundling Agent Skills and MCP servers into one portable directory. Published by a Technical
7
- Steering Committee with maintainers from Amazon, Cursor, Google, Microsoft, OpenAI, and Vercel.
5
+ Support for **Agent Plugins**, an open, vendor-neutral spec (v1.0.0, published 2026-08-06; v1.1.0 and
6
+ later 1.x manifests are also accepted) for bundling Agent Skills and MCP servers into one portable
7
+ directory. Published by a Technical Steering Committee with maintainers from Amazon, Cursor, Google, Microsoft, OpenAI, and Vercel.
8
8
  Source: https://developers.googleblog.com/agent-plugins-package-your-skills-tools-and-more/
9
9
 
10
10
  If you are an agent reading this cold: this document is written so you don't need the source
@@ -2,7 +2,7 @@ export { validatePluginManifest, validateMcpManifest } from '../manifest.js';
2
2
  export type { PluginManifest, McpManifest, McpServerEntry } from '../manifest.js';
3
3
  import type { PluginManifestAuthor } from '../manifest.js';
4
4
  export type { PluginManifestAuthor } from '../manifest.js';
5
- /** Agent Plugins 1.0.0 parsing, with application metadata confined to an explicit namespace. */
5
+ /** Agent Plugins 1.0.0/1.1.0 parsing, with application metadata confined to an explicit namespace. */
6
6
  export type AgentPluginServerMetadataReader = (required: {
7
7
  readonly serverId: string;
8
8
  readonly value: Readonly<Record<string, unknown>>;
@@ -29,7 +29,7 @@ export type ParseAgentPluginManifestResult = {
29
29
  readonly errors: readonly string[];
30
30
  };
31
31
  /**
32
- * Validates an already-`JSON.parse`d `plugin.json` value against the v1.0.0 grammar.
32
+ * Validates an already-`JSON.parse`d `plugin.json` value against the 1.0.0/1.1.0 grammar.
33
33
  *
34
34
  * @throws Nothing — every failure is reported via the returned `errors`, matching this codebase's
35
35
  * own convention for expected validation outcomes (`plugin-runtime/manifest.ts`,
@@ -42,7 +42,7 @@ export declare function parseAgentPluginManifest({ value }: {
42
42
  readonly identityNamespace?: string;
43
43
  }): ParseAgentPluginManifestResult;
44
44
  /**
45
- * The three closed transport variants `mcp.schema.json` v1.0.0 defines. See this file's header for
45
+ * The three closed transport variants `mcp.schema.json` 1.0.0/1.1.0 defines. See this file's header for
46
46
  * the verified field shape of each.
47
47
  */
48
48
  export declare const MCP_SERVER_TRANSPORTS: readonly ["stdio", "streamable-http", "sse"];
@@ -134,9 +134,10 @@ export type ParseAgentPluginMcpConfigResult = {
134
134
  readonly errors: readonly string[];
135
135
  };
136
136
  /**
137
- * Validates an already-`JSON.parse`d `mcp.json` value against the v1.0.0 top-level shape:
137
+ * Validates an already-`JSON.parse`d `mcp.json` value against the 1.0.0/1.1.0 top-level shape:
138
138
  * `{ "$schema": ..., "mcpServers": { "<server-id>": {...} } }`, then validates each declared
139
- * server's own transport shape (see this file's header for the three variants).
139
+ * server's own transport shape (see this file's header for the three variants). When
140
+ * `pluginManifest` declares a supported version, `mcp.json` must declare the same one (§10).
140
141
  *
141
142
  * @throws Nothing — see {@link parseAgentPluginManifest}.
142
143
  * @complexity O(s) in the number of declared servers.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @file `parseAgentPluginManifest()` / `parseAgentPluginMcpConfig()` — the Agent Plugins v1.0.0
2
+ * @file `parseAgentPluginManifest()` / `parseAgentPluginMcpConfig()` — the Agent Plugins 1.0.0/1.1.0
3
3
  * `plugin.json` / `mcp.json` grammar (agent-plugins.org/specification), verified against the live
4
4
  * spec rather than inferred from an example manifest.
5
5
  *
@@ -10,13 +10,15 @@
10
10
  * shares none of those fields and defines no execution/trust/capability model at all — see this
11
11
  * feature's own header comment in `install.ts` for why the two formats cannot be unified.
12
12
  *
13
- * Pinned v1.0.0 rules from agent-plugins.org/specification:
13
+ * Pinned 1.0.0/1.1.0 rules from agent-plugins.org/specification:
14
14
  * - `plugin.json`'s `name`: 1-64 chars, lowercase alphanumeric/hyphen/period only, must start and
15
15
  * end alphanumeric, no `--` or `..` consecutive delimiters (§5.5). Valid: `my-plugin`,
16
16
  * `acme.tools`, `lint3r`, `a`. Invalid: `My-Plugin`, `-start`, `has--double`.
17
- * - `plugin.json`'s `$schema` MUST equal `https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`
18
- * for this pinned version; `mcp.json`'s MUST equal
19
- * `https://agent-plugins.org/schemas/1.0.0/mcp.schema.json`.
17
+ * - `plugin.json`'s `$schema` MUST be a recognized canonical identifier
18
+ * (`https://agent-plugins.org/schemas/<version>/plugin.schema.json`); `mcp.json`'s likewise
19
+ * (`.../<version>/mcp.schema.json`), and when both are present their versions MUST match (§10).
20
+ * 1.0.0 and 1.1.0 are recognized; an unknown 1.x is read with the newest known grammar plus one
21
+ * warning; any other major is refused — see `KNOWN_SPEC_VERSIONS`.
20
22
  * - Unknown top-level `plugin.json` fields produce warnings but do not block loading — this module
21
23
  * returns them as `warnings`, never as a rejection reason.
22
24
  * - `mcp.json`'s top-level shape is `{ "$schema": ..., "mcpServers": { "<server-id>": {...} } }` —
@@ -55,11 +57,44 @@
55
57
  import { readPluginIdentity, validatePluginIdentity } from "@jini-ai/core/plugin-directory";
56
58
  export { validatePluginManifest, validateMcpManifest } from '../manifest.js';
57
59
  /**
58
- * The one plugin.json schema version this loader understands. A manifest declaring any other
59
- * value is rejected outright rather than guessed at: pinning the grammar must survive spec churn.
60
+ * The Agent Plugins versions whose schemas have been diffed against this file's grammar. 1.1.0's
61
+ * spec text and both schemas differ from 1.0.0 only in the version identifiers, so both map to the
62
+ * one grammar below — §5.1 allows mapping explicitly recognized compatible versions to one
63
+ * implementation. Add a version here only after diffing its schemas against this grammar.
60
64
  */
61
- const PLUGIN_SCHEMA_1_0_0 = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json";
62
- const MCP_SCHEMA_1_0_0 = "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json";
65
+ const KNOWN_SPEC_VERSIONS = ["1.0.0", "1.1.0"];
66
+ const SUPPORTED_MAJOR = "1";
67
+ /**
68
+ * Owner decision (2026-10-12): any other 1.x is accepted with the newest known grammar and one
69
+ * warning, so a minor spec release does not lock out packages that target it. This goes beyond
70
+ * §5.1, which says a client MUST reject a version it does not explicitly recognize. Unknown fields
71
+ * stay tolerated only where the known grammar already allows them (unknown top-level fields warn,
72
+ * `extensions` is opaque). A different major is refused, since majors may break the grammar.
73
+ */
74
+ const SCHEMA_URL_PATTERN = /^https:\/\/agent-plugins\.org\/schemas\/((\d+)\.\d+\.\d+)\/(plugin|mcp)\.schema\.json$/;
75
+ /** The canonical `$schema` identifier for one spec version's `plugin.json` or `mcp.json`. */
76
+ function schemaUrl(version, file) {
77
+ return `https://agent-plugins.org/schemas/${version}/${file}.schema.json`;
78
+ }
79
+ /**
80
+ * Reads the spec version `value` names as `file`'s canonical schema identifier: a known version,
81
+ * an unknown 1.x (with its warning), or the error for a different major or a non-canonical value.
82
+ */
83
+ function readSpecVersion(value, file) {
84
+ const match = typeof value === "string" ? SCHEMA_URL_PATTERN.exec(value) : null;
85
+ if (!match || match[3] !== file) {
86
+ const accepted = KNOWN_SPEC_VERSIONS.map((version) => `'${schemaUrl(version, file)}'`).join(" or ");
87
+ return { error: `${file}.json '$schema' must be ${accepted} (Agent Plugins ${KNOWN_SPEC_VERSIONS.join(", ")}, or another ${SUPPORTED_MAJOR}.x), got '${String(value)}'` };
88
+ }
89
+ const version = match[1];
90
+ if (match[2] !== SUPPORTED_MAJOR) {
91
+ return { error: `${file}.json targets Agent Plugins ${version}, an unsupported major version (supported: ${SUPPORTED_MAJOR}.x)` };
92
+ }
93
+ if (KNOWN_SPEC_VERSIONS.includes(version))
94
+ return { version };
95
+ const newest = KNOWN_SPEC_VERSIONS[KNOWN_SPEC_VERSIONS.length - 1];
96
+ return { version, warning: `${file}.json targets Agent Plugins ${version}, newer than this loader knows; validated with the ${newest} grammar` };
97
+ }
63
98
  /**
64
99
  * §5.5's grammar as one regex: alnum runs separated by single `-`/`.` delimiters. This shape alone
65
100
  * guarantees start/end are alphanumeric (the regex can only start and end on `[a-z0-9]+`) AND that
@@ -114,7 +149,7 @@ function resolveManifestName(raw) {
114
149
  return { name };
115
150
  }
116
151
  /**
117
- * Validates an already-`JSON.parse`d `plugin.json` value against the v1.0.0 grammar.
152
+ * Validates an already-`JSON.parse`d `plugin.json` value against the 1.0.0/1.1.0 grammar.
118
153
  *
119
154
  * @throws Nothing — every failure is reported via the returned `errors`, matching this codebase's
120
155
  * own convention for expected validation outcomes (`plugin-runtime/manifest.ts`,
@@ -127,9 +162,11 @@ export function parseAgentPluginManifest({ value }, { identityNamespace = "tovu"
127
162
  const raw = value;
128
163
  const errors = [];
129
164
  const warnings = [];
130
- if (raw.$schema !== PLUGIN_SCHEMA_1_0_0) {
131
- errors.push(`plugin.json '$schema' must be '${PLUGIN_SCHEMA_1_0_0}', got '${String(raw.$schema)}'`);
132
- }
165
+ const specVersion = readSpecVersion(raw.$schema, "plugin");
166
+ if (specVersion.error)
167
+ errors.push(specVersion.error);
168
+ else if (specVersion.warning)
169
+ warnings.push(specVersion.warning);
133
170
  if (raw.extensions !== undefined && !isJsonObject(raw.extensions))
134
171
  errors.push("plugin.json extensions must be an object");
135
172
  const nameResult = resolveManifestName(raw);
@@ -158,7 +195,7 @@ export function parseAgentPluginManifest({ value }, { identityNamespace = "tovu"
158
195
  return { ok: true, manifest, warnings };
159
196
  }
160
197
  /**
161
- * The three closed transport variants `mcp.schema.json` v1.0.0 defines. See this file's header for
198
+ * The three closed transport variants `mcp.schema.json` 1.0.0/1.1.0 defines. See this file's header for
162
199
  * the verified field shape of each.
163
200
  */
164
201
  export const MCP_SERVER_TRANSPORTS = ["stdio", "streamable-http", "sse"];
@@ -348,9 +385,10 @@ function parseMcpServerConfig(value, extension) {
348
385
  return null;
349
386
  }
350
387
  /**
351
- * Validates an already-`JSON.parse`d `mcp.json` value against the v1.0.0 top-level shape:
388
+ * Validates an already-`JSON.parse`d `mcp.json` value against the 1.0.0/1.1.0 top-level shape:
352
389
  * `{ "$schema": ..., "mcpServers": { "<server-id>": {...} } }`, then validates each declared
353
- * server's own transport shape (see this file's header for the three variants).
390
+ * server's own transport shape (see this file's header for the three variants). When
391
+ * `pluginManifest` declares a supported version, `mcp.json` must declare the same one (§10).
354
392
  *
355
393
  * @throws Nothing — see {@link parseAgentPluginManifest}.
356
394
  * @complexity O(s) in the number of declared servers.
@@ -362,8 +400,14 @@ export function parseAgentPluginMcpConfig({ value, extensionNamespace }, optiona
362
400
  return { ok: false, errors: ["mcp.json must be a JSON object"] };
363
401
  const raw = value;
364
402
  const errors = [];
365
- if (raw.$schema !== MCP_SCHEMA_1_0_0) {
366
- errors.push(`mcp.json '$schema' must be '${MCP_SCHEMA_1_0_0}', got '${String(raw.$schema)}'`);
403
+ // plugin.json already reports an unknown-1.x warning; mcp.json adds none of its own.
404
+ const mcpSpec = readSpecVersion(raw.$schema, "mcp");
405
+ const mcpVersion = mcpSpec.version;
406
+ const pluginVersion = isJsonObject(optional.pluginManifest) ? readSpecVersion(optional.pluginManifest.$schema, "plugin").version : undefined;
407
+ if (mcpSpec.error)
408
+ errors.push(mcpSpec.error);
409
+ else if (pluginVersion !== undefined && pluginVersion !== mcpVersion) {
410
+ errors.push(`mcp.json targets Agent Plugins ${mcpVersion} but plugin.json targets ${pluginVersion}; the versions must match`);
367
411
  }
368
412
  const mcpServers = raw.mcpServers;
369
413
  if (typeof mcpServers !== "object" || mcpServers === null || Array.isArray(mcpServers)) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jini-ai/agent-plugins",
3
- "version": "0.4.3",
4
- "description": "Support for Agent Plugins, the open, vendor-neutral spec (v1.0.0, published 2026-08-06, Technical Steering Committee with maintainers from Amazon, Cursor, Google, Microsoft, OpenAI, and Vercel) for bundling Agent Skills and MCP servers into one portable directory: PluginManifest/McpManifest types + structural validators on the package root, plus the bundled plugins themselves, each on a subpath named for itself (./ui-ux-design). Extracted 2026-08-18 from @jini-ai/plugins, which now only reserves the unrelated, unimplemented ./host format.",
3
+ "version": "0.4.4",
4
+ "description": "Support for Agent Plugins, the open, vendor-neutral spec (v1.0.0, published 2026-08-06; v1.1.0 and later 1.x manifests are also accepted; Technical Steering Committee with maintainers from Amazon, Cursor, Google, Microsoft, OpenAI, and Vercel) for bundling Agent Skills and MCP servers into one portable directory: PluginManifest/McpManifest types + structural validators on the package root, plus the bundled plugins themselves, each on a subpath named for itself (./ui-ux-design). Extracted 2026-08-18 from @jini-ai/plugins, which now only reserves the unrelated, unimplemented ./host format.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",