vigiles 28.0.0 → 29.0.0

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.
Files changed (49) hide show
  1. package/README.md +1 -1
  2. package/dist/adapter-registry.d.ts +39 -0
  3. package/dist/adapter-registry.js +45 -0
  4. package/dist/adapter.d.ts +8 -0
  5. package/dist/adapter.js +10 -1
  6. package/dist/adapters/claude-code/adapter.js +6 -0
  7. package/dist/adapters/claude-code/layout.d.ts +5 -0
  8. package/dist/adapters/claude-code/plugin-loader.d.ts +10 -1
  9. package/dist/adapters/claude-code/plugin-loader.js +10 -1
  10. package/dist/adapters/codex/adapter.js +6 -0
  11. package/dist/adapters/codex/layout.d.ts +51 -5
  12. package/dist/adapters/codex/layout.js +13 -4
  13. package/dist/adapters/opencode/adapter.js +6 -0
  14. package/dist/audit-report.template.html +1 -1
  15. package/dist/audit-score.d.ts +7 -0
  16. package/dist/audit-score.js +49 -2
  17. package/dist/cli-main.js +82 -20
  18. package/dist/core/adapter.d.ts +23 -0
  19. package/dist/core/compile.js +11 -1
  20. package/dist/core/config-schema.d.ts +244 -0
  21. package/dist/core/config-schema.js +452 -0
  22. package/dist/core/refs.js +10 -1
  23. package/dist/core/surface-discovery.d.ts +270 -0
  24. package/dist/core/surface-discovery.js +425 -0
  25. package/dist/core/surface-scopes.d.ts +38 -1
  26. package/dist/core/surface-scopes.js +73 -1
  27. package/dist/core/symbols.d.ts +24 -2
  28. package/dist/core/symbols.js +66 -18
  29. package/dist/core/types.d.ts +36 -107
  30. package/dist/core/validate.d.ts +36 -22
  31. package/dist/core/validate.js +88 -176
  32. package/dist/exclude.d.ts +20 -0
  33. package/dist/exclude.js +11 -1
  34. package/dist/layout-registry.d.ts +14 -0
  35. package/dist/layout-registry.js +40 -0
  36. package/dist/plugin-loader.d.ts +49 -1
  37. package/dist/plugin-loader.js +120 -14
  38. package/dist/scan-core.d.ts +19 -0
  39. package/dist/scan-core.js +30 -0
  40. package/dist/scan-files.js +15 -5
  41. package/dist/scan.d.ts +63 -0
  42. package/dist/scan.js +68 -12
  43. package/dist/score-core.js +8 -0
  44. package/dist/setup-plan.d.ts +2 -1
  45. package/dist/setup-plan.js +7 -2
  46. package/dist/surface-discovery-fs.d.ts +12 -0
  47. package/dist/surface-discovery-fs.js +108 -0
  48. package/dist/vigilesrc.schema.json +1689 -0
  49. package/package.json +10 -6
package/README.md CHANGED
@@ -260,7 +260,7 @@ Targets Claude Code and Codex out of the box, or [your own harness](docs/authori
260
260
  **[vigiles.sh](https://vigiles.sh)** is the live demo — grade any repo in your browser. The **[docs index](docs/README.md)** is the full map, grouped by what you're doing:
261
261
 
262
262
  - **Guides** — [verify instruction files](docs/verifying-instruction-files.md) · [test your harness](docs/harness-testing.md) · [measure a skill](docs/measuring-skills.md) · [ship a plugin](docs/for-plugin-authors.md) · [Codex & other harnesses](docs/harnesses.md)
263
- - **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/)
263
+ - **Reference** — [CLI](docs/cli.md) · [configuration](docs/configuration.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/)
264
264
  - **Explanation** — [what it catches](docs/what-vigiles-catches.md) · [how it compares](docs/comparison.md) · [FAQ](docs/faq.md)
265
265
 
266
266
  > **A name starting with `experimental_` is not covered by semver.** It may change
@@ -11,6 +11,7 @@
11
11
  * wins regardless of order.
12
12
  */
13
13
  import type { HarnessAdapter } from "./core/adapter.js";
14
+ import type { HarnessDeclaration } from "./core/types.js";
14
15
  /** The default adapter when detection finds no harness markers. */
15
16
  export declare const defaultAdapter: HarnessAdapter;
16
17
  /** All registered adapters. detect() specificity (not order) breaks ties. */
@@ -113,4 +114,42 @@ export declare function resolveHarnessAdapters(opts: {
113
114
  flag?: string;
114
115
  configHarness?: string | readonly string[];
115
116
  }): HarnessAdapter[];
117
+ /**
118
+ * One declared harness, resolved: the adapter its KEY names, and the extra
119
+ * surface roots declared under it, normalized.
120
+ *
121
+ * The pair is the whole point of the nested shape. Under the two flat keys the
122
+ * roots were global and the harness list was ordered, so the layout a root was
123
+ * read under was decided by array position; here the layout comes from the key
124
+ * the root sits under, so there is no order to get wrong and nothing to guess.
125
+ */
126
+ export interface DeclaredHarness {
127
+ readonly adapter: HarnessAdapter;
128
+ /** Normalized `.vigilesrc.json#harnesses.<name>.roots`, in declaration order. */
129
+ readonly roots: readonly string[];
130
+ }
131
+ /**
132
+ * The declared harness NAMES, in declaration order — the `string[]` every
133
+ * existing single-dialect picker already takes.
134
+ *
135
+ * Deliberately NOT resolving adapters: `resolveHarnessSelection` /
136
+ * `resolveHarnessAdapters` resolve (and throw on) an unknown name themselves,
137
+ * and two places deciding what an unknown name means is how the two error
138
+ * wordings would drift.
139
+ */
140
+ export declare function declaredHarnessNames(harnesses?: Readonly<Record<string, HarnessDeclaration>>): string[];
141
+ /**
142
+ * Every declared harness with its roots, in declaration order.
143
+ *
144
+ * Throws on an unknown key, through the SAME `resolveAdapter` the `--harness=`
145
+ * flag goes through — so `{"claud-code": {}}` fails with the identical
146
+ * `Unknown harness "claud-code". Known: claude-code, codex.` a bad flag gets.
147
+ * That was already the loud half of the old shape and it is kept verbatim.
148
+ *
149
+ * Aliases collapse: `{"claude": {"roots":["a"]}, "claude-code": {"roots":["b"]}}`
150
+ * is ONE Claude Code declaration reading both roots, not two competing ones —
151
+ * the same de-duplication `resolveHarnessAdapters` does, extended to carry the
152
+ * union of what each spelling declared.
153
+ */
154
+ export declare function resolveDeclaredHarnesses(root: string, harnesses?: Readonly<Record<string, HarnessDeclaration>>): DeclaredHarness[];
116
155
  //# sourceMappingURL=adapter-registry.d.ts.map
@@ -10,6 +10,9 @@ exports.resolveAdapter = resolveAdapter;
10
10
  exports.normalizeHarnessList = normalizeHarnessList;
11
11
  exports.resolveHarnessSelection = resolveHarnessSelection;
12
12
  exports.resolveHarnessAdapters = resolveHarnessAdapters;
13
+ exports.declaredHarnessNames = declaredHarnessNames;
14
+ exports.resolveDeclaredHarnesses = resolveDeclaredHarnesses;
15
+ const surface_scopes_js_1 = require("./core/surface-scopes.js");
13
16
  const compose_js_1 = require("./core/compose.js");
14
17
  const adapter_js_1 = require("./adapters/claude-code/adapter.js");
15
18
  const adapter_js_2 = require("./adapters/codex/adapter.js");
@@ -181,4 +184,46 @@ function resolveHarnessAdapters(opts) {
181
184
  const seen = new Set();
182
185
  return adapters.filter((a) => !seen.has(a.name) && seen.add(a.name));
183
186
  }
187
+ /**
188
+ * The declared harness NAMES, in declaration order — the `string[]` every
189
+ * existing single-dialect picker already takes.
190
+ *
191
+ * Deliberately NOT resolving adapters: `resolveHarnessSelection` /
192
+ * `resolveHarnessAdapters` resolve (and throw on) an unknown name themselves,
193
+ * and two places deciding what an unknown name means is how the two error
194
+ * wordings would drift.
195
+ */
196
+ function declaredHarnessNames(harnesses) {
197
+ return normalizeHarnessList(Object.keys(harnesses ?? {}));
198
+ }
199
+ /**
200
+ * Every declared harness with its roots, in declaration order.
201
+ *
202
+ * Throws on an unknown key, through the SAME `resolveAdapter` the `--harness=`
203
+ * flag goes through — so `{"claud-code": {}}` fails with the identical
204
+ * `Unknown harness "claud-code". Known: claude-code, codex.` a bad flag gets.
205
+ * That was already the loud half of the old shape and it is kept verbatim.
206
+ *
207
+ * Aliases collapse: `{"claude": {"roots":["a"]}, "claude-code": {"roots":["b"]}}`
208
+ * is ONE Claude Code declaration reading both roots, not two competing ones —
209
+ * the same de-duplication `resolveHarnessAdapters` does, extended to carry the
210
+ * union of what each spelling declared.
211
+ */
212
+ function resolveDeclaredHarnesses(root, harnesses) {
213
+ const out = [];
214
+ for (const [key, decl] of Object.entries(harnesses ?? {})) {
215
+ const adapter = resolveAdapter(root, key);
216
+ const roots = [...(0, surface_scopes_js_1.normalizeSurfaceRoots)(decl?.roots)];
217
+ const prev = out.find((d) => d.adapter.name === adapter.name);
218
+ if (prev) {
219
+ for (const r of roots)
220
+ if (!prev.roots.includes(r))
221
+ prev.roots.push(r);
222
+ }
223
+ else {
224
+ out.push({ adapter, roots });
225
+ }
226
+ }
227
+ return out;
228
+ }
184
229
  //# sourceMappingURL=adapter-registry.js.map
package/dist/adapter.d.ts CHANGED
@@ -21,6 +21,14 @@ export type { PluginLayout } from "./core/layout.js";
21
21
  export type { HarnessRuntime } from "./core/runtime.js";
22
22
  export type { HookProtocol } from "./core/hook-protocol.js";
23
23
  export type { ModelMock } from "./core/model-mock.js";
24
+ /**
25
+ * The `claims(path)` helper every shipped adapter uses: derive "is this path
26
+ * mine?" from the adapter's own `PluginLayout`, so a layout that moves takes its
27
+ * claim with it. Override `claims` by hand only for a location the layout fields
28
+ * cannot express. See `core/surface-discovery.ts` for why a claim is a question
29
+ * about a PATH and never about a root.
30
+ */
31
+ export { layoutClaims } from "./core/surface-discovery.js";
24
32
  export { checkAdapterConformance, assertAdapterConformance, assertAdapterLoadsHooks, assertHarnessTestable, type ConformanceResult, } from "./adapter-conformance.js";
25
33
  export { ADAPTERS, defaultAdapter, detectAdapter, detectAdapterResult, resolveAdapter, getAdapter, type DetectResult, } from "./adapter-registry.js";
26
34
  //# sourceMappingURL=adapter.d.ts.map
package/dist/adapter.js CHANGED
@@ -1,6 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAdapter = exports.resolveAdapter = exports.detectAdapterResult = exports.detectAdapter = exports.defaultAdapter = exports.ADAPTERS = exports.assertHarnessTestable = exports.assertAdapterLoadsHooks = exports.assertAdapterConformance = exports.checkAdapterConformance = void 0;
3
+ exports.getAdapter = exports.resolveAdapter = exports.detectAdapterResult = exports.detectAdapter = exports.defaultAdapter = exports.ADAPTERS = exports.assertHarnessTestable = exports.assertAdapterLoadsHooks = exports.assertAdapterConformance = exports.checkAdapterConformance = exports.layoutClaims = void 0;
4
+ /**
5
+ * The `claims(path)` helper every shipped adapter uses: derive "is this path
6
+ * mine?" from the adapter's own `PluginLayout`, so a layout that moves takes its
7
+ * claim with it. Override `claims` by hand only for a location the layout fields
8
+ * cannot express. See `core/surface-discovery.ts` for why a claim is a question
9
+ * about a PATH and never about a root.
10
+ */
11
+ var surface_discovery_js_1 = require("./core/surface-discovery.js");
12
+ Object.defineProperty(exports, "layoutClaims", { enumerable: true, get: function () { return surface_discovery_js_1.layoutClaims; } });
4
13
  var adapter_conformance_js_1 = require("./adapter-conformance.js");
5
14
  Object.defineProperty(exports, "checkAdapterConformance", { enumerable: true, get: function () { return adapter_conformance_js_1.checkAdapterConformance; } });
6
15
  Object.defineProperty(exports, "assertAdapterConformance", { enumerable: true, get: function () { return adapter_conformance_js_1.assertAdapterConformance; } });
@@ -11,6 +11,7 @@ const node_fs_1 = require("node:fs");
11
11
  const node_path_1 = require("node:path");
12
12
  const dialect_js_1 = require("./dialect.js");
13
13
  const layout_js_1 = require("./layout.js");
14
+ const surface_discovery_js_1 = require("../../core/surface-discovery.js");
14
15
  const runtime_js_1 = require("./runtime.js");
15
16
  const hook_protocol_js_1 = require("./hook-protocol.js");
16
17
  const model_mock_js_1 = require("./model-mock.js");
@@ -32,6 +33,11 @@ exports.claudeCodeAdapter = {
32
33
  // Imported inside the thunk, not at the top: a top-level import runs at module
33
34
  // init and would pull the whole test/compiler graph back in.
34
35
  harnessTestDriver: async () => (await import("../../harness-test.js")).claudeCodeDriver,
36
+ // Derived from the layout, never listed again here — see `claims` on
37
+ // `HarnessAdapter` for why this method takes a PATH and not a root.
38
+ claims(path) {
39
+ return (0, surface_discovery_js_1.layoutClaims)(layout_js_1.claudeCodeLayout, path);
40
+ },
35
41
  detect(root) {
36
42
  // Most specific signal wins: a plugin manifest (3) > repo settings (2) >
37
43
  // a bare CLAUDE.md (1, weak — many tools also read it / AGENTS.md).
@@ -2,6 +2,11 @@
2
2
  * claudeCodeLayout — the Claude Code plugin/repo layout (the `PluginLayout`
3
3
  * port's reference implementation). `loadPlugin` defaults to it; a Codex adapter
4
4
  * defines a sibling `codexLayout` and passes it to the same loader.
5
+ * 🔴 THE PATHS BELOW ARE DOCUMENTED IN `docs/configuration.md`. Change any of
6
+ * them — `instructionFile`, `surfaceDirs`, `userSurfaceRoot`, `rulesDir` — and
7
+ * that page is wrong until you edit it too. The page marks this symbol with
8
+ * `vigiles:symbol`, so RENAMING it turns `vigiles lint` red and forces the
9
+ * edit; changing a VALUE in place does not, and nothing today catches that.
5
10
  */
6
11
  import type { PluginLayout } from "../../core/layout.js";
7
12
  export declare const claudeCodeLayout: PluginLayout;
@@ -10,7 +10,16 @@
10
10
  import type { PluginLayout } from "../../core/layout.js";
11
11
  import { loadPlugin as loadPluginWith, resolveHarness as resolveHarnessWith } from "../../plugin-loader.js";
12
12
  export type { LoadedPlugin } from "../../plugin-loader.js";
13
- /** Load the real Claude Code harness at `pluginPath` (defaults to `claudeCodeLayout`). */
13
+ /**
14
+ * Load the real Claude Code harness at `pluginPath` (defaults to `claudeCodeLayout`).
15
+ *
16
+ * 🔴 DELIBERATELY NOT FORWARDING an `ExcludeSet`. The generic loader takes one
17
+ * (`.vigilesrc.json#exclude` filters surface discovery), but this is the PUBLIC
18
+ * `vigiles/claude-code` face, and a parameter whose type and constructor are both
19
+ * internal would land in the published surface as a name no consumer can write.
20
+ * In-repo callers that hold an ExcludeSet — `scan.ts` — import the composition
21
+ * root directly, which is where the layout is required anyway.
22
+ */
14
23
  export declare function loadPlugin(pluginPath: string, layout?: PluginLayout): ReturnType<typeof loadPluginWith>;
15
24
  /**
16
25
  * Resolve the effective harness for a test/eval (arm) under the Claude Code
@@ -4,7 +4,16 @@ exports.loadPlugin = loadPlugin;
4
4
  exports.resolveHarness = resolveHarness;
5
5
  const plugin_loader_js_1 = require("../../plugin-loader.js");
6
6
  const layout_js_1 = require("./layout.js");
7
- /** Load the real Claude Code harness at `pluginPath` (defaults to `claudeCodeLayout`). */
7
+ /**
8
+ * Load the real Claude Code harness at `pluginPath` (defaults to `claudeCodeLayout`).
9
+ *
10
+ * 🔴 DELIBERATELY NOT FORWARDING an `ExcludeSet`. The generic loader takes one
11
+ * (`.vigilesrc.json#exclude` filters surface discovery), but this is the PUBLIC
12
+ * `vigiles/claude-code` face, and a parameter whose type and constructor are both
13
+ * internal would land in the published surface as a name no consumer can write.
14
+ * In-repo callers that hold an ExcludeSet — `scan.ts` — import the composition
15
+ * root directly, which is where the layout is required anyway.
16
+ */
8
17
  function loadPlugin(pluginPath, layout = layout_js_1.claudeCodeLayout) {
9
18
  return (0, plugin_loader_js_1.loadPlugin)(pluginPath, layout);
10
19
  }
@@ -17,6 +17,7 @@ const node_fs_1 = require("node:fs");
17
17
  const node_path_1 = require("node:path");
18
18
  const dialect_js_1 = require("./dialect.js");
19
19
  const layout_js_1 = require("./layout.js");
20
+ const surface_discovery_js_1 = require("../../core/surface-discovery.js");
20
21
  const runtime_js_1 = require("./runtime.js");
21
22
  const hook_protocol_js_1 = require("./hook-protocol.js");
22
23
  const model_mock_js_1 = require("./model-mock.js");
@@ -38,6 +39,11 @@ exports.codexAdapter = {
38
39
  hookProtocol: hook_protocol_js_1.codexHookProtocol,
39
40
  modelMock: model_mock_js_1.codexModelMock,
40
41
  harnessTestDriver: async () => (await import("./driver.js")).codexDriver,
42
+ // Derived from the layout, never listed again here — see `claims` on
43
+ // `HarnessAdapter` for why this method takes a PATH and not a root.
44
+ claims(path) {
45
+ return (0, surface_discovery_js_1.layoutClaims)(layout_js_1.codexLayout, path);
46
+ },
41
47
  detect(root) {
42
48
  // A `.codex/config.toml` is a strong signal; a bare AGENTS.md is weak (many
43
49
  // harnesses read it). (Unused while unregistered — kept for symmetry.)
@@ -1,15 +1,61 @@
1
1
  /**
2
- * codexLayout — EXPERIMENTAL, internal-only. A prototype `PluginLayout` for
3
- * Codex: `.codex/` conventions, `config.toml` (TOML) hooks, `AGENTS.md`,
4
- * `${PLUGIN_ROOT}`. Validates the layout port + the settings-format axis against
5
- * real Codex shapes. NOT exported / NOT registered.
2
+ * codexLayout — the OpenAI Codex `PluginLayout`: `.agents/skills` skills,
3
+ * `.codex/config.toml` (TOML) settings/hooks, `AGENTS.md`, `${PLUGIN_ROOT}`.
4
+ * Exported as `vigiles/codex` and registered in `src/adapter-registry.ts`.
6
5
  *
7
- * Findings surfaced by writing it (see research/codex-prototype-findings.md):
6
+ * 🔴 SKILLS LIVE AT `.agents/skills`, NOT `.codex/skills`. This descriptor said
7
+ * `.codex` + `skills` until 2026-09-21 — so the loader read `<root>/skills` and
8
+ * reported it under a `.codex/skills/…` key, and a real Codex repo's skills were
9
+ * read as ZERO. Verbatim from the vendor page
10
+ * (`https://learn.chatgpt.com/docs/build-skills`, redirected from
11
+ * `developers.openai.com/codex/skills`), fetched 2026-09-21:
12
+ *
13
+ * > Codex scans `.agents/skills` in every directory from your current working
14
+ * > directory up to the repository root.
15
+ *
16
+ * The same page lists `$HOME/.agents/skills` ("any skills checked into the
17
+ * user's personal folder") and `/etc/codex/skills` as the other scopes, and
18
+ * never mentions `.codex/skills` at all. Corroborated in-repo by
19
+ * `src/cli-install.e2e.test.ts`, which drives the real `skills` CLI and finds the
20
+ * install at `~/.agents/skills/`.
21
+ *
22
+ * 🔴 KNOWN LIMITATION — WALK-UP IS STILL NOT EXPRESSED, AND NOT BY OVERSIGHT.
23
+ * The vendor scans `.agents/skills` in EVERY directory from the cwd up to the
24
+ * repository root; `PluginLayout` names a single root-relative dir, so this
25
+ * descriptor covers only `<root>/.agents/skills`. A skill in a SUBDIRECTORY's own
26
+ * `.agents/skills` is still invisible.
27
+ *
28
+ * The 2026-09-21 discovery refactor (`src/core/surface-discovery.ts`) did NOT
29
+ * close it, and the reason is the refactor's own bound: discovery looks in the
30
+ * repo root and its depth-1 dot-directories, because an unbounded walk grades
31
+ * vendored third-party trees as the project's own work (#240, measured by the
32
+ * reporter at 53 vendored skills beside 37 real ones). Reaching a subpackage's
33
+ * `.agents/skills` means walking arbitrary directories, which is exactly what
34
+ * that bound refuses, so the gap is a deliberate trade and not a TODO.
35
+ *
36
+ * What it costs in practice: for `vigiles audit` AT THE REPO ROOT — the normal
37
+ * invocation — the root IS the whole walk-up chain, so nothing is missed. The
38
+ * gap is a monorepo subpackage keeping its own `.agents/skills`; point vigiles
39
+ * at that subdirectory to audit it.
40
+ *
41
+ * ⚠️ `installCodexSkills` (`./eval.ts`) still writes the eval tier's skills to
42
+ * `<cwd>/.codex/skills/`, and its comment claims that path was validated live
43
+ * against the binary (`eval.test.ts` carries a captured transcript reading
44
+ * `/tmp/cxreal/.codex/skills/…`). That is MEASURED evidence for an older Codex
45
+ * and it contradicts the page above; it is deliberately left alone until someone
46
+ * re-measures against the current binary. Do not "align" it from the docs alone.
47
+ *
48
+ * Other findings from the prototype (see research/codex-prototype-findings.md):
8
49
  * - Codex has no separate JSON *manifest* — `config.toml` carries everything; we
9
50
  * point `manifestPath` at it (its JSON parse simply fails → the loader falls
10
51
  * through to the TOML `settingsPath`). The manifest field is CC-JSON-shaped.
11
52
  * - MCP detection (`mcpConfigFile`/`mcpManifestKey`) is JSON-shaped, so it won't
12
53
  * see Codex's `[mcp_servers]` TOML table — a known layout-port gap.
54
+ * 🔴 THE PATHS BELOW ARE DOCUMENTED IN `docs/configuration.md`. Change any of
55
+ * them — `instructionFile`, `surfaceDirs`, `userSurfaceRoot`, `rulesDir` — and
56
+ * that page is wrong until you edit it too. The page marks this symbol with
57
+ * `vigiles:symbol`, so RENAMING it turns `vigiles lint` red and forces the
58
+ * edit; changing a VALUE in place does not, and nothing today catches that.
13
59
  */
14
60
  import type { PluginLayout } from "../../core/layout.js";
15
61
  export declare const codexLayout: PluginLayout;
@@ -8,14 +8,23 @@ exports.codexLayout = {
8
8
  settingsPath: ".codex/config.toml",
9
9
  settingsFormat: "toml",
10
10
  instructionFile: "AGENTS.md",
11
- surfaceDirs: ["skills", "prompts"],
12
- skillDir: "skills",
11
+ // Surfaces carry their OWN prefix and `materializeRoot` is "" — the OpenCode
12
+ // style, not the Claude Code one. Codex's skills and its prompts do NOT share a
13
+ // parent (`.agents/` vs `.codex/`), so no single `materializeRoot` can name
14
+ // both; spelling each dir in full is the only shape that keeps the reported key
15
+ // equal to the real on-disk path.
16
+ surfaceDirs: [".agents/skills", "prompts"],
17
+ skillDir: ".agents/skills",
13
18
  agentDir: "", // Codex `[agents]` is a TOML concurrency table, not a subagent dir
19
+ // Custom prompts are documented ONLY at `~/.codex/prompts` (user-global,
20
+ // top-level `.md`, and marked deprecated in favour of skills). No repo-level
21
+ // location is documented, so this prototype's root-level `prompts/` is left as
22
+ // it was rather than moved on a guess.
14
23
  commandDir: "prompts",
15
- materializeRoot: ".codex",
24
+ materializeRoot: "",
16
25
  pluginRootToken: "${PLUGIN_ROOT}",
17
26
  mcpConfigFile: ".mcp.json",
18
27
  mcpManifestKey: "mcp_servers",
19
- intraRefDirs: ["skills", "prompts", "hooks"],
28
+ intraRefDirs: [".agents/skills", "prompts", "hooks"],
20
29
  };
21
30
  //# sourceMappingURL=layout.js.map
@@ -19,6 +19,7 @@ const node_fs_1 = require("node:fs");
19
19
  const node_path_1 = require("node:path");
20
20
  const dialect_js_1 = require("./dialect.js");
21
21
  const layout_js_1 = require("./layout.js");
22
+ const surface_discovery_js_1 = require("../../core/surface-discovery.js");
22
23
  const runtime_js_1 = require("./runtime.js");
23
24
  const model_mock_js_1 = require("./model-mock.js");
24
25
  exports.opencodeAdapter = {
@@ -36,6 +37,11 @@ exports.opencodeAdapter = {
36
37
  runtime: runtime_js_1.opencodeRuntime,
37
38
  modelMock: model_mock_js_1.opencodeModelMock,
38
39
  // No hookProtocol: OpenCode hooks are code modules, not shell processes.
40
+ // Derived from the layout, never listed again here — see `claims` on
41
+ // `HarnessAdapter` for why this method takes a PATH and not a root.
42
+ claims(path) {
43
+ return (0, surface_discovery_js_1.layoutClaims)(layout_js_1.opencodeLayout, path);
44
+ },
39
45
  detect(root) {
40
46
  // An `opencode.json` is a strong signal; a bare AGENTS.md is weak (many
41
47
  // harnesses read it). (Unused while unregistered — kept for symmetry.)