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.
- package/README.md +1 -1
- package/dist/adapter-registry.d.ts +39 -0
- package/dist/adapter-registry.js +45 -0
- package/dist/adapter.d.ts +8 -0
- package/dist/adapter.js +10 -1
- package/dist/adapters/claude-code/adapter.js +6 -0
- package/dist/adapters/claude-code/layout.d.ts +5 -0
- package/dist/adapters/claude-code/plugin-loader.d.ts +10 -1
- package/dist/adapters/claude-code/plugin-loader.js +10 -1
- package/dist/adapters/codex/adapter.js +6 -0
- package/dist/adapters/codex/layout.d.ts +51 -5
- package/dist/adapters/codex/layout.js +13 -4
- package/dist/adapters/opencode/adapter.js +6 -0
- package/dist/audit-report.template.html +1 -1
- package/dist/audit-score.d.ts +7 -0
- package/dist/audit-score.js +49 -2
- package/dist/cli-main.js +82 -20
- package/dist/core/adapter.d.ts +23 -0
- package/dist/core/compile.js +11 -1
- package/dist/core/config-schema.d.ts +244 -0
- package/dist/core/config-schema.js +452 -0
- package/dist/core/refs.js +10 -1
- package/dist/core/surface-discovery.d.ts +270 -0
- package/dist/core/surface-discovery.js +425 -0
- package/dist/core/surface-scopes.d.ts +38 -1
- package/dist/core/surface-scopes.js +73 -1
- package/dist/core/symbols.d.ts +24 -2
- package/dist/core/symbols.js +66 -18
- package/dist/core/types.d.ts +36 -107
- package/dist/core/validate.d.ts +36 -22
- package/dist/core/validate.js +88 -176
- package/dist/exclude.d.ts +20 -0
- package/dist/exclude.js +11 -1
- package/dist/layout-registry.d.ts +14 -0
- package/dist/layout-registry.js +40 -0
- package/dist/plugin-loader.d.ts +49 -1
- package/dist/plugin-loader.js +120 -14
- package/dist/scan-core.d.ts +19 -0
- package/dist/scan-core.js +30 -0
- package/dist/scan-files.js +15 -5
- package/dist/scan.d.ts +63 -0
- package/dist/scan.js +68 -12
- package/dist/score-core.js +8 -0
- package/dist/setup-plan.d.ts +2 -1
- package/dist/setup-plan.js +7 -2
- package/dist/surface-discovery-fs.d.ts +12 -0
- package/dist/surface-discovery-fs.js +108 -0
- package/dist/vigilesrc.schema.json +1689 -0
- 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
|
package/dist/adapter-registry.js
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
-
/**
|
|
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 —
|
|
3
|
-
*
|
|
4
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
12
|
-
|
|
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: "
|
|
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.)
|