vigiles 14.13.2 → 14.13.3

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.
@@ -12,7 +12,7 @@
12
12
  "name": "vigiles",
13
13
  "source": "./",
14
14
  "description": "Verify CLAUDE.md/AGENTS.md references, compile typed specs, and test the agent harness",
15
- "version": "3.0.0"
15
+ "version": "4.0.1"
16
16
  }
17
17
  ]
18
18
  }
package/README.md CHANGED
@@ -256,7 +256,7 @@ Targets Claude Code and Codex out of the box, or [your own harness](docs/authori
256
256
  - **Reference** — [CLI](docs/cli.md) · [rules matrix](docs/verifying-instruction-files.md#the-validation-rules--the-full-matrix) · [testing API](docs/testing-api.md) · [full API](https://zernie.github.io/vigiles/api/)
257
257
  - **Explanation** — [what it catches](docs/what-vigiles-catches.md) · [how it compares](docs/comparison.md) · [FAQ](docs/faq.md)
258
258
 
259
- **Project** — [Stability](STABILITY.md) · [Related tools](docs/comparison.md#what-vigiles-composes-with)
259
+ **Project** — [Stability](STABILITY.md) · [Related tools](docs/comparison.md#what-vigiles-composes-with) · ships as an [Agent Plugins](https://agent-plugins.org) 1.0.0 plugin ([how to do the same](docs/for-plugin-authors.md#6-ship-it-in-the-portable-agent-plugins-format))
260
260
 
261
261
  <!-- The "companion to [Feedback Loop Is All You Need](https://zernie.com/blog/feedback-loop-is-all-you-need)"
262
262
  link is temporarily removed while AgenticDev paper #1 is under blind review: repo → blog is a
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Agent Plugins — the vendor-neutral packaging standard (agent-plugins.org),
3
+ * v1.0.0. A plugin declares itself with a root `plugin.json` and puts its
4
+ * components at fixed paths: skills at `skills/<name>/SKILL.md`, MCP servers in
5
+ * a root `mcp.json`.
6
+ *
7
+ * WHY THIS IS NOT AN ADAPTER. The standard is a PACKAGING format, not a harness:
8
+ * it has no tool catalog, no hook events, no runtime — a plugin shipped this way
9
+ * still runs inside Claude Code or Codex. So it COMPLEMENTS a harness rather than
10
+ * replacing one, and a repo commonly carries both manifests side by side (vigiles
11
+ * itself does). Modelling it as a `HarnessAdapter` would mean inventing a fake
12
+ * `HarnessDialect` — exactly the half-wired port the conformance kit refuses.
13
+ *
14
+ * WHAT THIS MODULE IS FOR. The skills half already works for free: the standard's
15
+ * `skills/<name>/SKILL.md` is the layout every adapter already reads. The gap is
16
+ * MCP — the standard puts servers in a root `mcp.json`, which no harness layout
17
+ * names, so `mcp-config` / `mcp-tool-resolves` / `mcp-hook-target-resolves`
18
+ * would silently check nothing on a plugin laid out this way. This module tells
19
+ * the scanner when that file is in play.
20
+ *
21
+ * DETECTION IS BY `$schema`, NOT BY FILENAME. `plugin.json` and `mcp.json` are
22
+ * generic names other tools use too. A plugin is treated as conformant only when
23
+ * its root manifest pins an `agent-plugins.org` schema — then a sibling
24
+ * `mcp.json` is unambiguously the standard's, and is read even if it omits its
25
+ * own `$schema`. Pure (no `node:fs`): the caller injects the read, so the
26
+ * browser engine can back it with a file map.
27
+ */
28
+ /** The standard's root manifest filename. */
29
+ export declare const AGENT_PLUGINS_MANIFEST = "plugin.json";
30
+ /** The standard's root MCP-server config filename. */
31
+ export declare const AGENT_PLUGINS_MCP_CONFIG = "mcp.json";
32
+ /**
33
+ * Does this manifest text declare an Agent Plugins plugin? True only when it
34
+ * parses and its `$schema` points at the standard — a `plugin.json` belonging to
35
+ * something else is not claimed.
36
+ */
37
+ export declare function isAgentPluginsManifest(text: string): boolean;
38
+ /**
39
+ * The extra MCP config files to read for this root — `[mcp.json]` when the root
40
+ * manifest declares an Agent Plugins plugin, `[]` otherwise. `readText` returns
41
+ * the file's contents, or `undefined` when it does not exist.
42
+ */
43
+ export declare function agentPluginsMcpSources(readText: (file: string) => string | undefined): readonly string[];
44
+ //# sourceMappingURL=agent-plugins.d.ts.map
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * Agent Plugins — the vendor-neutral packaging standard (agent-plugins.org),
4
+ * v1.0.0. A plugin declares itself with a root `plugin.json` and puts its
5
+ * components at fixed paths: skills at `skills/<name>/SKILL.md`, MCP servers in
6
+ * a root `mcp.json`.
7
+ *
8
+ * WHY THIS IS NOT AN ADAPTER. The standard is a PACKAGING format, not a harness:
9
+ * it has no tool catalog, no hook events, no runtime — a plugin shipped this way
10
+ * still runs inside Claude Code or Codex. So it COMPLEMENTS a harness rather than
11
+ * replacing one, and a repo commonly carries both manifests side by side (vigiles
12
+ * itself does). Modelling it as a `HarnessAdapter` would mean inventing a fake
13
+ * `HarnessDialect` — exactly the half-wired port the conformance kit refuses.
14
+ *
15
+ * WHAT THIS MODULE IS FOR. The skills half already works for free: the standard's
16
+ * `skills/<name>/SKILL.md` is the layout every adapter already reads. The gap is
17
+ * MCP — the standard puts servers in a root `mcp.json`, which no harness layout
18
+ * names, so `mcp-config` / `mcp-tool-resolves` / `mcp-hook-target-resolves`
19
+ * would silently check nothing on a plugin laid out this way. This module tells
20
+ * the scanner when that file is in play.
21
+ *
22
+ * DETECTION IS BY `$schema`, NOT BY FILENAME. `plugin.json` and `mcp.json` are
23
+ * generic names other tools use too. A plugin is treated as conformant only when
24
+ * its root manifest pins an `agent-plugins.org` schema — then a sibling
25
+ * `mcp.json` is unambiguously the standard's, and is read even if it omits its
26
+ * own `$schema`. Pure (no `node:fs`): the caller injects the read, so the
27
+ * browser engine can back it with a file map.
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.AGENT_PLUGINS_MCP_CONFIG = exports.AGENT_PLUGINS_MANIFEST = void 0;
31
+ exports.isAgentPluginsManifest = isAgentPluginsManifest;
32
+ exports.agentPluginsMcpSources = agentPluginsMcpSources;
33
+ /** The standard's root manifest filename. */
34
+ exports.AGENT_PLUGINS_MANIFEST = "plugin.json";
35
+ /** The standard's root MCP-server config filename. */
36
+ exports.AGENT_PLUGINS_MCP_CONFIG = "mcp.json";
37
+ /** Canonical schema host — a manifest pinning one of these targets the standard. */
38
+ const SCHEMA_PREFIX = "https://agent-plugins.org/schemas/";
39
+ /**
40
+ * Does this manifest text declare an Agent Plugins plugin? True only when it
41
+ * parses and its `$schema` points at the standard — a `plugin.json` belonging to
42
+ * something else is not claimed.
43
+ */
44
+ function isAgentPluginsManifest(text) {
45
+ let parsed;
46
+ try {
47
+ parsed = JSON.parse(text);
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ if (parsed === null || typeof parsed !== "object")
53
+ return false;
54
+ const schema = parsed.$schema;
55
+ return typeof schema === "string" && schema.startsWith(SCHEMA_PREFIX);
56
+ }
57
+ /**
58
+ * The extra MCP config files to read for this root — `[mcp.json]` when the root
59
+ * manifest declares an Agent Plugins plugin, `[]` otherwise. `readText` returns
60
+ * the file's contents, or `undefined` when it does not exist.
61
+ */
62
+ function agentPluginsMcpSources(readText) {
63
+ const manifest = readText(exports.AGENT_PLUGINS_MANIFEST);
64
+ if (manifest === undefined || !isAgentPluginsManifest(manifest))
65
+ return [];
66
+ return [exports.AGENT_PLUGINS_MCP_CONFIG];
67
+ }
68
+ //# sourceMappingURL=agent-plugins.js.map
@@ -45,6 +45,7 @@ const dialect_js_1 = require("./adapters/claude-code/dialect.js");
45
45
  const hook_normalize_js_1 = require("./core/hook-normalize.js");
46
46
  const hook_events_js_1 = require("./core/hook-events.js");
47
47
  const mcp_config_js_1 = require("./core/mcp-config.js");
48
+ const agent_plugins_js_1 = require("./core/agent-plugins.js");
48
49
  const mcp_hook_js_1 = require("./core/mcp-hook.js");
49
50
  const plugin_dir_layout_js_1 = require("./core/plugin-dir-layout.js");
50
51
  const hook_block_ineffective_js_1 = require("./core/hook-block-ineffective.js");
@@ -424,8 +425,9 @@ function loadPluginFromFiles(files, layout, repoName) {
424
425
  // ---------------------------------------------------------------------------
425
426
  function collectMcpServers(files, layout) {
426
427
  const servers = {};
428
+ const read = (file) => files[file];
427
429
  const collect = (file) => {
428
- const text = files[file];
430
+ const text = read(file);
429
431
  if (text === undefined)
430
432
  return;
431
433
  try {
@@ -438,8 +440,16 @@ function collectMcpServers(files, layout) {
438
440
  /* malformed JSON is the loader's concern, not this check's */
439
441
  }
440
442
  };
441
- collect(".mcp.json");
442
- collect(layout.manifestPath);
443
+ // Mirrors the fs-backed collector in scan.ts: the layout's own locations plus
444
+ // the Agent Plugins standard's root `mcp.json` when this repo ships that
445
+ // manifest (no harness layout names it, so the MCP checks would miss it).
446
+ for (const file of [
447
+ layout.mcpConfigFile,
448
+ layout.manifestPath,
449
+ ...(0, agent_plugins_js_1.agentPluginsMcpSources)(read),
450
+ ]) {
451
+ collect(file);
452
+ }
443
453
  return servers;
444
454
  }
445
455
  // ---------------------------------------------------------------------------
@@ -502,7 +512,11 @@ function scanFiles(files, layout = layout_js_1.claudeCodeLayout, dialect = diale
502
512
  inlineHooks: inline,
503
513
  manualHookCount: manual,
504
514
  commands: Object.keys(loaded.files).filter(cls.isCommand).length,
505
- mcp: loaded.warnings.some((w) => w.includes("MCP server")),
515
+ // A declared server set counts even when the loader emitted no warning —
516
+ // otherwise a plugin whose servers come from the Agent Plugins `mcp.json`
517
+ // reports "MCP servers: no" while the report lists an MCP finding.
518
+ mcp: loaded.warnings.some((w) => w.includes("MCP server")) ||
519
+ declaredServers.length > 0,
506
520
  danglingRefs: danglingRefs(files, lay, repoName ?? (0, posix_path_js_1.basename)(exports.BROWSER_ROOT)),
507
521
  hookEventIssues,
508
522
  frontmatterIssues: remap((0, scan_core_js_1.frontmatterIssuesFor)(loaded.files, cls)),
package/dist/scan.js CHANGED
@@ -41,6 +41,7 @@ const dialect_js_1 = require("./adapters/claude-code/dialect.js");
41
41
  const plugin_loader_js_2 = require("./plugin-loader.js");
42
42
  const hook_events_js_1 = require("./core/hook-events.js");
43
43
  const mcp_config_js_1 = require("./core/mcp-config.js");
44
+ const agent_plugins_js_1 = require("./core/agent-plugins.js");
44
45
  const hook_normalize_js_1 = require("./core/hook-normalize.js");
45
46
  const mcp_js_1 = require("./core/mcp.js");
46
47
  const mcp_contract_message_js_1 = require("./core/mcp-contract-message.js");
@@ -67,12 +68,16 @@ __exportStar(require("./scan-core.js"), exports);
67
68
  */
68
69
  function collectMcpServers(root, layout) {
69
70
  const servers = {};
70
- const collect = (file) => {
71
+ const read = (file) => {
71
72
  const p = (0, node_path_1.join)(root, file);
72
- if (!(0, node_fs_1.existsSync)(p))
73
+ return (0, node_fs_1.existsSync)(p) ? (0, node_fs_1.readFileSync)(p, "utf-8") : undefined;
74
+ };
75
+ const collect = (file) => {
76
+ const text = read(file);
77
+ if (text === undefined)
73
78
  return;
74
79
  try {
75
- const parsed = JSON.parse((0, node_fs_1.readFileSync)(p, "utf-8"));
80
+ const parsed = JSON.parse(text);
76
81
  if (parsed.mcpServers !== null && typeof parsed.mcpServers === "object") {
77
82
  Object.assign(servers, parsed.mcpServers);
78
83
  }
@@ -81,8 +86,18 @@ function collectMcpServers(root, layout) {
81
86
  /* malformed JSON is the loader's concern, not this check's */
82
87
  }
83
88
  };
84
- collect(".mcp.json");
85
- collect(layout.manifestPath);
89
+ // The harness's own locations (from the layout — never a hard-coded literal),
90
+ // plus the Agent Plugins standard's root `mcp.json` when the repo ships that
91
+ // manifest. A plugin in the vendor-neutral format declares its servers there,
92
+ // which no harness layout names — without this the MCP checks would silently
93
+ // pass over it.
94
+ for (const file of [
95
+ layout.mcpConfigFile,
96
+ layout.manifestPath,
97
+ ...(0, agent_plugins_js_1.agentPluginsMcpSources)(read),
98
+ ]) {
99
+ collect(file);
100
+ }
86
101
  return servers;
87
102
  }
88
103
  // Disk-backed IO the moved detectors take by injection (they never import
@@ -172,7 +187,11 @@ function scanPlugin(dir, layout, dialect = dialect_js_1.claudeCodeDialect, opts
172
187
  inlineHooks: inline,
173
188
  manualHookCount: manual,
174
189
  commands: Object.keys(loaded.files).filter(cls.isCommand).length,
175
- mcp: loaded.warnings.some((w) => w.includes("MCP server")),
190
+ // A declared server set counts even when the loader emitted no warning —
191
+ // otherwise a plugin whose servers come from the Agent Plugins `mcp.json`
192
+ // reports "MCP servers: no" while the report lists an MCP finding.
193
+ mcp: loaded.warnings.some((w) => w.includes("MCP server")) ||
194
+ declaredServers.length > 0,
176
195
  danglingRefs: (0, plugin_loader_js_2.danglingRefs)((0, node_path_1.resolve)(dir), lay),
177
196
  hookEventIssues,
178
197
  frontmatterIssues: remap((0, scan_core_js_1.frontmatterIssuesFor)(loaded.files, cls)),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigiles",
3
- "version": "14.13.2",
3
+ "version": "14.13.3",
4
4
  "description": "Lint & test the harness your AI agent runs on — verify the references in your CLAUDE.md / AGENTS.md and test that your hooks and skills actually work.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -65,6 +65,7 @@
65
65
  "!dist/**/*.test.js",
66
66
  "!dist/**/*.test.d.ts",
67
67
  "action.yml",
68
+ "plugin.json",
68
69
  ".claude-plugin",
69
70
  "hooks",
70
71
  "skills",
package/plugin.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "vigiles",
4
+ "version": "4.0.1",
5
+ "description": "Verify CLAUDE.md/AGENTS.md references, compile typed specs, and test the agent harness",
6
+ "author": {
7
+ "name": "zernie",
8
+ "url": "https://github.com/zernie"
9
+ },
10
+ "homepage": "https://vigiles.sh",
11
+ "repository": "https://github.com/zernie/vigiles",
12
+ "license": "MIT",
13
+ "keywords": ["linting", "claude-md", "agents-md", "feedback-loops", "harness"]
14
+ }