vigiles 2.5.0 → 3.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 (209) hide show
  1. package/.claude-plugin/plugin.json +9 -0
  2. package/README.md +73 -434
  3. package/action.yml +143 -7
  4. package/dist/action-gate.d.ts +1 -1
  5. package/dist/action-gate.js +1 -1
  6. package/dist/adapter-conformance.d.ts +30 -0
  7. package/dist/adapter-conformance.js +153 -0
  8. package/dist/adapter-registry.d.ts +42 -0
  9. package/dist/adapter-registry.js +55 -0
  10. package/dist/adapter.d.ts +26 -0
  11. package/dist/adapter.js +16 -0
  12. package/dist/adapters/claude-code/adapter.d.ts +3 -0
  13. package/dist/adapters/claude-code/adapter.js +46 -0
  14. package/dist/{agent-result.d.ts → adapters/claude-code/agent-result.d.ts} +1 -1
  15. package/dist/adapters/claude-code/dialect.d.ts +13 -0
  16. package/dist/adapters/claude-code/dialect.js +51 -0
  17. package/dist/adapters/claude-code/egress-entry.d.ts +2 -0
  18. package/dist/adapters/claude-code/egress-entry.js +115 -0
  19. package/dist/adapters/claude-code/egress-proxy.d.ts +2 -0
  20. package/dist/adapters/claude-code/egress-proxy.js +60 -0
  21. package/dist/adapters/claude-code/egress.d.ts +114 -0
  22. package/dist/adapters/claude-code/egress.js +276 -0
  23. package/dist/adapters/claude-code/eval-baseline.d.ts +68 -0
  24. package/dist/adapters/claude-code/eval-baseline.js +173 -0
  25. package/dist/{eval-cache.d.ts → adapters/claude-code/eval-cache.d.ts} +1 -1
  26. package/dist/{eval-cache.js → adapters/claude-code/eval-cache.js} +1 -1
  27. package/dist/{eval.d.ts → adapters/claude-code/eval.d.ts} +28 -4
  28. package/dist/{eval.js → adapters/claude-code/eval.js} +61 -25
  29. package/dist/{harness-test.d.ts → adapters/claude-code/harness-test.d.ts} +33 -37
  30. package/dist/{harness-test.js → adapters/claude-code/harness-test.js} +124 -43
  31. package/dist/adapters/claude-code/hook-protocol.d.ts +10 -0
  32. package/dist/adapters/claude-code/hook-protocol.js +10 -0
  33. package/dist/adapters/claude-code/layout.d.ts +8 -0
  34. package/dist/adapters/claude-code/layout.js +18 -0
  35. package/dist/{mock-model.d.ts → adapters/claude-code/mock-model.d.ts} +2 -24
  36. package/dist/adapters/claude-code/model-mock.d.ts +11 -0
  37. package/dist/adapters/claude-code/model-mock.js +10 -0
  38. package/dist/adapters/claude-code/plugin-loader.d.ts +25 -0
  39. package/dist/adapters/claude-code/plugin-loader.js +19 -0
  40. package/dist/adapters/claude-code/run-hook.d.ts +204 -0
  41. package/dist/adapters/claude-code/run-hook.js +418 -0
  42. package/dist/adapters/claude-code/run-scripts.d.ts +52 -0
  43. package/dist/adapters/claude-code/run-scripts.js +150 -0
  44. package/dist/adapters/claude-code/runtime.d.ts +16 -0
  45. package/dist/adapters/claude-code/runtime.js +39 -0
  46. package/dist/{sandbox.d.ts → adapters/claude-code/sandbox.d.ts} +45 -4
  47. package/dist/{sandbox.js → adapters/claude-code/sandbox.js} +76 -8
  48. package/dist/{skill-driver.d.ts → adapters/claude-code/skill-driver.d.ts} +1 -1
  49. package/dist/adapters/codex/adapter.d.ts +3 -0
  50. package/dist/adapters/codex/adapter.js +49 -0
  51. package/dist/adapters/codex/dialect.d.ts +10 -0
  52. package/dist/adapters/codex/dialect.js +30 -0
  53. package/dist/adapters/codex/driver.d.ts +20 -0
  54. package/dist/adapters/codex/driver.js +89 -0
  55. package/dist/adapters/codex/hook-protocol.d.ts +10 -0
  56. package/dist/adapters/codex/hook-protocol.js +18 -0
  57. package/dist/adapters/codex/layout.d.ts +16 -0
  58. package/dist/adapters/codex/layout.js +18 -0
  59. package/dist/adapters/codex/mock-model.d.ts +52 -0
  60. package/dist/adapters/codex/mock-model.js +210 -0
  61. package/dist/adapters/codex/model-mock.d.ts +11 -0
  62. package/dist/adapters/codex/model-mock.js +10 -0
  63. package/dist/adapters/codex/runtime.d.ts +38 -0
  64. package/dist/adapters/codex/runtime.js +62 -0
  65. package/dist/adapters/opencode/adapter.d.ts +3 -0
  66. package/dist/adapters/opencode/adapter.js +48 -0
  67. package/dist/adapters/opencode/dialect.d.ts +10 -0
  68. package/dist/adapters/opencode/dialect.js +36 -0
  69. package/dist/adapters/opencode/layout.d.ts +9 -0
  70. package/dist/adapters/opencode/layout.js +25 -0
  71. package/dist/adapters/opencode/model-mock.d.ts +10 -0
  72. package/dist/adapters/opencode/model-mock.js +10 -0
  73. package/dist/adapters/opencode/runtime.d.ts +9 -0
  74. package/dist/adapters/opencode/runtime.js +21 -0
  75. package/dist/claude-code.d.ts +16 -0
  76. package/dist/claude-code.js +32 -0
  77. package/dist/cli-flags.d.ts +22 -0
  78. package/dist/cli-flags.js +38 -0
  79. package/dist/cli.js +406 -206
  80. package/dist/codex.d.ts +20 -0
  81. package/dist/codex.js +36 -0
  82. package/dist/community-skills.d.ts +1 -1
  83. package/dist/community-skills.js +2 -2
  84. package/dist/core/adapter.d.ts +88 -0
  85. package/dist/core/adapter.js +3 -0
  86. package/dist/{compile.d.ts → core/compile.d.ts} +11 -2
  87. package/dist/{compile.js → core/compile.js} +68 -53
  88. package/dist/core/compose.d.ts +79 -0
  89. package/dist/core/compose.js +145 -0
  90. package/dist/core/dialect.d.ts +51 -0
  91. package/dist/core/dialect.js +3 -0
  92. package/dist/core/harness-driver.d.ts +134 -0
  93. package/dist/core/harness-driver.js +3 -0
  94. package/dist/core/hook-protocol.d.ts +28 -0
  95. package/dist/core/hook-protocol.js +3 -0
  96. package/dist/core/layout.d.ts +43 -0
  97. package/dist/core/layout.js +3 -0
  98. package/dist/core/model-mock.d.ts +27 -0
  99. package/dist/core/model-mock.js +3 -0
  100. package/dist/core/refs.d.ts +62 -0
  101. package/dist/{refs.js → core/refs.js} +49 -23
  102. package/dist/core/runtime.d.ts +38 -0
  103. package/dist/core/runtime.js +3 -0
  104. package/dist/{types.d.ts → core/types.d.ts} +29 -0
  105. package/dist/{validate.d.ts → core/validate.d.ts} +1 -1
  106. package/dist/{validate.js → core/validate.js} +41 -4
  107. package/dist/e2e.d.ts +19 -0
  108. package/dist/e2e.js +39 -0
  109. package/dist/harness-assert.d.ts +60 -11
  110. package/dist/harness-assert.js +111 -9
  111. package/dist/integration.d.ts +16 -0
  112. package/dist/integration.js +32 -0
  113. package/dist/leaderboard.d.ts +33 -0
  114. package/dist/leaderboard.js +107 -0
  115. package/dist/linting.d.ts +9 -0
  116. package/dist/linting.js +25 -0
  117. package/dist/plugin-loader.d.ts +6 -3
  118. package/dist/plugin-loader.js +101 -49
  119. package/dist/scan.d.ts +49 -0
  120. package/dist/scan.js +177 -0
  121. package/dist/setup-plan.d.ts +51 -0
  122. package/dist/setup-plan.js +85 -0
  123. package/dist/skill-test.d.ts +1 -1
  124. package/dist/skill-test.js +1 -1
  125. package/dist/test-coverage.d.ts +71 -0
  126. package/dist/test-coverage.js +228 -0
  127. package/dist/testing.d.ts +12 -0
  128. package/dist/testing.js +28 -0
  129. package/dist/unit.d.ts +17 -0
  130. package/dist/unit.js +36 -0
  131. package/hooks/refs-nudge.sh +24 -0
  132. package/package.json +35 -16
  133. package/skills/audit-feedback-loop/SKILL.md +76 -0
  134. package/skills/edit-spec/SKILL.md +131 -0
  135. package/skills/enforce-rules-format/SKILL.md +71 -0
  136. package/skills/generate-logo/SKILL.md +103 -0
  137. package/skills/generate-rule/SKILL.md +64 -0
  138. package/skills/linter-docs/clippy.md +241 -0
  139. package/skills/linter-docs/eslint.md +384 -0
  140. package/skills/linter-docs/pylint.md +288 -0
  141. package/skills/linter-docs/rubocop.md +277 -0
  142. package/skills/linter-docs/ruff.md +187 -0
  143. package/skills/linter-docs/stylelint.md +247 -0
  144. package/skills/migrate-to-spec/SKILL.md +126 -0
  145. package/skills/pr-to-lint-rule/SKILL.md +97 -0
  146. package/skills/strengthen/SKILL.md +168 -0
  147. package/skills/test-harness/SKILL.md +157 -0
  148. package/dist/action.d.ts +0 -7
  149. package/dist/action.js +0 -180
  150. package/dist/refs.d.ts +0 -44
  151. package/dist/run-hook.d.ts +0 -77
  152. package/dist/run-hook.js +0 -80
  153. package/dist/run-scripts.d.ts +0 -20
  154. package/dist/run-scripts.js +0 -70
  155. /package/dist/{agent-result.js → adapters/claude-code/agent-result.js} +0 -0
  156. /package/dist/{agent-runtime.d.ts → adapters/claude-code/agent-runtime.d.ts} +0 -0
  157. /package/dist/{agent-runtime.js → adapters/claude-code/agent-runtime.js} +0 -0
  158. /package/dist/{judge.d.ts → adapters/claude-code/judge.d.ts} +0 -0
  159. /package/dist/{judge.js → adapters/claude-code/judge.js} +0 -0
  160. /package/dist/{mock-entry.d.ts → adapters/claude-code/mock-entry.d.ts} +0 -0
  161. /package/dist/{mock-entry.js → adapters/claude-code/mock-entry.js} +0 -0
  162. /package/dist/{mock-model.js → adapters/claude-code/mock-model.js} +0 -0
  163. /package/dist/{skill-driver.js → adapters/claude-code/skill-driver.js} +0 -0
  164. /package/dist/{skill-runtime.d.ts → adapters/claude-code/skill-runtime.d.ts} +0 -0
  165. /package/dist/{skill-runtime.js → adapters/claude-code/skill-runtime.js} +0 -0
  166. /package/dist/{stats.d.ts → adapters/claude-code/stats.d.ts} +0 -0
  167. /package/dist/{stats.js → adapters/claude-code/stats.js} +0 -0
  168. /package/dist/{compile-generator.d.ts → core/compile-generator.d.ts} +0 -0
  169. /package/dist/{compile-generator.js → core/compile-generator.js} +0 -0
  170. /package/dist/{coverage.d.ts → core/coverage.d.ts} +0 -0
  171. /package/dist/{coverage.js → core/coverage.js} +0 -0
  172. /package/dist/{doc-refs.d.ts → core/doc-refs.d.ts} +0 -0
  173. /package/dist/{doc-refs.js → core/doc-refs.js} +0 -0
  174. /package/dist/{evolve.d.ts → core/evolve.d.ts} +0 -0
  175. /package/dist/{evolve.js → core/evolve.js} +0 -0
  176. /package/dist/{frontmatter.d.ts → core/frontmatter.d.ts} +0 -0
  177. /package/dist/{frontmatter.js → core/frontmatter.js} +0 -0
  178. /package/dist/{generate-schema.d.ts → core/generate-schema.d.ts} +0 -0
  179. /package/dist/{generate-schema.js → core/generate-schema.js} +0 -0
  180. /package/dist/{generate-types.d.ts → core/generate-types.d.ts} +0 -0
  181. /package/dist/{generate-types.js → core/generate-types.js} +0 -0
  182. /package/dist/{hash.d.ts → core/hash.d.ts} +0 -0
  183. /package/dist/{hash.js → core/hash.js} +0 -0
  184. /package/dist/{inline.d.ts → core/inline.d.ts} +0 -0
  185. /package/dist/{inline.js → core/inline.js} +0 -0
  186. /package/dist/{integrity.d.ts → core/integrity.d.ts} +0 -0
  187. /package/dist/{integrity.js → core/integrity.js} +0 -0
  188. /package/dist/{linters.d.ts → core/linters.d.ts} +0 -0
  189. /package/dist/{linters.js → core/linters.js} +0 -0
  190. /package/dist/{mcp.d.ts → core/mcp.d.ts} +0 -0
  191. /package/dist/{mcp.js → core/mcp.js} +0 -0
  192. /package/dist/{orphans.d.ts → core/orphans.d.ts} +0 -0
  193. /package/dist/{orphans.js → core/orphans.js} +0 -0
  194. /package/dist/{proofs.d.ts → core/proofs.d.ts} +0 -0
  195. /package/dist/{proofs.js → core/proofs.js} +0 -0
  196. /package/dist/{session.d.ts → core/session.d.ts} +0 -0
  197. /package/dist/{session.js → core/session.js} +0 -0
  198. /package/dist/{sidecar.d.ts → core/sidecar.d.ts} +0 -0
  199. /package/dist/{sidecar.js → core/sidecar.js} +0 -0
  200. /package/dist/{spec.d.ts → core/spec.d.ts} +0 -0
  201. /package/dist/{spec.js → core/spec.js} +0 -0
  202. /package/dist/{symbols.d.ts → core/symbols.d.ts} +0 -0
  203. /package/dist/{symbols.js → core/symbols.js} +0 -0
  204. /package/dist/{test-utils.d.ts → core/test-utils.d.ts} +0 -0
  205. /package/dist/{test-utils.js → core/test-utils.js} +0 -0
  206. /package/dist/{types.js → core/types.js} +0 -0
  207. /package/{.claude-plugin/hooks → hooks}/post-edit.sh +0 -0
  208. /package/{.claude-plugin/hooks → hooks}/pre-edit.sh +0 -0
  209. /package/{.claude-plugin/hooks → hooks}/session-start.sh +0 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `vigiles/codex` — the OpenAI Codex harness adapter. Sits beside
3
+ * `vigiles/claude-code`: same harness-agnostic `vigiles/testing` core, a
4
+ * different transport (the `codex` binary + the OpenAI **Responses** SSE mock).
5
+ *
6
+ * Pillar 2 (harness testing) is proven here — `startCodexMock` serves the
7
+ * Responses SSE that real `codex exec` completes a turn against, keylessly (see
8
+ * `codexMockArgs`/`codexMockEnv` for the wiring). Pillar 1 instruction/skill
9
+ * *renderers* still emit the Claude-Code shape until the format-axis renderers
10
+ * land (see `research/code-adapter-architecture.md`).
11
+ */
12
+ export * from "./adapters/codex/dialect.js";
13
+ export * from "./adapters/codex/layout.js";
14
+ export * from "./adapters/codex/runtime.js";
15
+ export * from "./adapters/codex/hook-protocol.js";
16
+ export * from "./adapters/codex/model-mock.js";
17
+ export * from "./adapters/codex/mock-model.js";
18
+ export * from "./adapters/codex/driver.js";
19
+ export * from "./adapters/codex/adapter.js";
20
+ //# sourceMappingURL=codex.d.ts.map
package/dist/codex.js ADDED
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * `vigiles/codex` — the OpenAI Codex harness adapter. Sits beside
19
+ * `vigiles/claude-code`: same harness-agnostic `vigiles/testing` core, a
20
+ * different transport (the `codex` binary + the OpenAI **Responses** SSE mock).
21
+ *
22
+ * Pillar 2 (harness testing) is proven here — `startCodexMock` serves the
23
+ * Responses SSE that real `codex exec` completes a turn against, keylessly (see
24
+ * `codexMockArgs`/`codexMockEnv` for the wiring). Pillar 1 instruction/skill
25
+ * *renderers* still emit the Claude-Code shape until the format-axis renderers
26
+ * land (see `research/code-adapter-architecture.md`).
27
+ */
28
+ __exportStar(require("./adapters/codex/dialect.js"), exports);
29
+ __exportStar(require("./adapters/codex/layout.js"), exports);
30
+ __exportStar(require("./adapters/codex/runtime.js"), exports);
31
+ __exportStar(require("./adapters/codex/hook-protocol.js"), exports);
32
+ __exportStar(require("./adapters/codex/model-mock.js"), exports);
33
+ __exportStar(require("./adapters/codex/mock-model.js"), exports);
34
+ __exportStar(require("./adapters/codex/driver.js"), exports);
35
+ __exportStar(require("./adapters/codex/adapter.js"), exports);
36
+ //# sourceMappingURL=codex.js.map
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * These are exercised in community-skills.test.ts with a scripted model.
14
14
  */
15
- import { type SkillProgram } from "./skill-driver.js";
15
+ import { type SkillProgram } from "./adapters/claude-code/skill-driver.js";
16
16
  /** COLLECT → BATCH → FIX rounds; ceiling 7; exit when no actionable feedback. */
17
17
  export declare const prReviewLoop: SkillProgram;
18
18
  /** Red → Green → Refactor, once per behavior until done. */
@@ -15,8 +15,8 @@ exports.subagentDriven = exports.tdd = exports.prReviewLoop = void 0;
15
15
  *
16
16
  * These are exercised in community-skills.test.ts with a scripted model.
17
17
  */
18
- const skill_driver_js_1 = require("./skill-driver.js");
19
- const spec_js_1 = require("./spec.js");
18
+ const skill_driver_js_1 = require("./adapters/claude-code/skill-driver.js");
19
+ const spec_js_1 = require("./core/spec.js");
20
20
  /** COLLECT → BATCH → FIX rounds; ceiling 7; exit when no actionable feedback. */
21
21
  const prReviewLoop = function* () {
22
22
  let round = 0;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * HarnessAdapter — the bundle that makes a harness a single, addable unit.
3
+ *
4
+ * Each port (HarnessDialect, PluginLayout, HarnessRuntime, HookProtocol,
5
+ * ModelMock) decouples one axis of Claude-Code coupling. A `HarnessAdapter`
6
+ * groups a harness's five port implementations plus a `detect` predicate, so
7
+ * **adding a harness is writing one object** — `codexAdapter`, `geminiAdapter`,
8
+ * `myHarnessAdapter` — not editing the core. The library stays import-named
9
+ * (`import { claudeCodeAdapter } from "vigiles/claude-code"`); the bundle is the
10
+ * thing the CLI auto-detects and the conformance kit checks.
11
+ *
12
+ * See `docs/authoring-an-adapter.md` (third-party guide) and
13
+ * `research/code-adapter-architecture.md` (the design).
14
+ */
15
+ import type { HarnessDialect } from "./dialect.js";
16
+ import type { PluginLayout } from "./layout.js";
17
+ import type { HarnessRuntime } from "./runtime.js";
18
+ import type { HookProtocol } from "./hook-protocol.js";
19
+ import type { ModelMock } from "./model-mock.js";
20
+ import type { HarnessTestDriver } from "./harness-driver.js";
21
+ /**
22
+ * Which vigiles pillars/tiers a harness can drive — the capability matrix made
23
+ * executable (see `docs/harnesses.md`). Not every harness reaches every tier:
24
+ * a closed, un-mockable one (Cursor, Devin, Amp, Amazon Q) can only ever do
25
+ * pillar 1, and a harness whose hooks are in-process code modules (OpenCode)
26
+ * has no shell-hook tier. Declaring this lets the conformance kit relax the
27
+ * port requirements for what an adapter says it can't do (instead of forcing a
28
+ * fake `runtime`/`modelMock`/`hookProtocol`), and lets the pillar-2 runners
29
+ * refuse — rather than mysteriously hang on — an adapter that can't be mocked.
30
+ */
31
+ export interface AdapterCapabilities {
32
+ /**
33
+ * Pillar 1 — reference verification (dialect + layout). Always `true`: every
34
+ * harness with an instruction-file format can have its references verified.
35
+ */
36
+ readonly referenceVerification: true;
37
+ /**
38
+ * Pillar 2 — deterministic harness tests + evals: the binary can be spawned
39
+ * and pointed at a mock model. Requires `runtime` + `modelMock`. `false` for
40
+ * closed harnesses that route through a fixed backend (no BYOM): Cursor,
41
+ * Devin, Amp, Amazon Q — they are pillar-1-only adapters.
42
+ */
43
+ readonly harnessTesting: boolean;
44
+ /**
45
+ * Hooks are shell processes speaking the exit-code/env block protocol —
46
+ * Claude Code, Codex, Crush. Requires `hookProtocol`. `false` when hooks are
47
+ * in-process code modules (OpenCode's TS plugins), so the `run-hook` unit
48
+ * tier and the `HookProtocol` port do not apply.
49
+ */
50
+ readonly shellHooks: boolean;
51
+ }
52
+ export interface HarnessAdapter {
53
+ /** Stable identifier, e.g. "claude-code". The CLI/registry key. */
54
+ readonly name: string;
55
+ /** What this harness can drive — gates which ports below are required. */
56
+ readonly capabilities: AdapterCapabilities;
57
+ /** Format axis: tool catalog, hook events, instruction targets, plugin-root token. */
58
+ readonly dialect: HarnessDialect;
59
+ /** Layout axis: where the instruction file / skills / agents / hooks live on disk. */
60
+ readonly layout: PluginLayout;
61
+ /** Transport axis: the agent binary to spawn + the mock-model env. Present iff
62
+ * `capabilities.harnessTesting`. */
63
+ readonly runtime?: HarnessRuntime;
64
+ /** Transport axis: how a hook signals a block/deny. Present iff
65
+ * `capabilities.shellHooks`. */
66
+ readonly hookProtocol?: HookProtocol;
67
+ /** Transport axis: the mock model's wire format + endpoints. Present iff
68
+ * `capabilities.harnessTesting`. */
69
+ readonly modelMock?: ModelMock;
70
+ /**
71
+ * Pillar-2 deterministic-runner driver: how `runHarnessTest` builds this
72
+ * harness's argv, starts its scripted mock, and parses its stdout. Present iff
73
+ * `capabilities.harnessTesting` (it composes the runtime + modelMock into the
74
+ * one seam the runner dispatches through). Carried on the bundle so the runner
75
+ * never imports a sibling adapter to find it.
76
+ */
77
+ readonly harnessTestDriver?: HarnessTestDriver;
78
+ /**
79
+ * How strongly a repo at `root` looks like it targets this harness — the CLI
80
+ * uses it to auto-detect which adapter to use (the library selects by import).
81
+ * Returns a **specificity score**: 0 = not this harness; higher = a more
82
+ * specific match. The registry picks the highest scorer, so a strong signal
83
+ * (a `.claude-plugin/` manifest) beats a weak one (a bare `CLAUDE.md`, or an
84
+ * `AGENTS.md` that many harnesses share) regardless of registration order.
85
+ */
86
+ detect(root: string): number;
87
+ }
88
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=adapter.js.map
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { ClaudeSpec, SkillSpec, AgentSpec, Railway } from "./spec.js";
8
8
  import type { LinterCheckResult } from "./linters.js";
9
+ import type { HarnessDialect } from "./dialect.js";
9
10
  /** @internal Compute SHA-256 hash of content (excluding any existing hash line). */
10
11
  export declare function computeHash(content: string): string;
11
12
  /** @internal Prepend a hash comment to compiled content. */
@@ -44,6 +45,8 @@ export interface CompileClaudeResult {
44
45
  export interface CompileClaudeOptions {
45
46
  basePath?: string;
46
47
  specFile?: string;
48
+ /** Injected harness dialect; its instructionTargets[0] is the default target. */
49
+ dialect?: HarnessDialect;
47
50
  /** Maximum number of rules allowed. Compilation fails if exceeded. */
48
51
  maxRules?: number;
49
52
  /** Maximum estimated tokens for compiled output. */
@@ -78,6 +81,9 @@ export interface CompileSkillResult {
78
81
  export declare function compileSkill(spec: SkillSpec, options?: {
79
82
  basePath?: string;
80
83
  specFile?: string;
84
+ /** The harness dialect — selects the SKILL.md frontmatter profile. Omitting
85
+ * it defaults to the Claude Code profile, so existing callers are unchanged. */
86
+ dialect?: HarnessDialect;
81
87
  }): CompileSkillResult;
82
88
  export interface CompileAgentResult {
83
89
  markdown: string;
@@ -88,9 +94,12 @@ export interface CompileAgentResult {
88
94
  * Verifies the tool contract and the body's references; the marks the body
89
95
  * carries (`vigiles:symbol`, file/cmd refs) are the same ones `audit` re-checks.
90
96
  */
91
- export declare function compileAgent(spec: AgentSpec, options?: {
97
+ export declare function compileAgent(spec: AgentSpec, options: {
92
98
  basePath?: string;
93
99
  specFile?: string;
100
+ /** The harness dialect to verify the tool contract against (required — the
101
+ * core defines no default dialect; the adapter/composition root injects it). */
102
+ dialect: HarnessDialect;
94
103
  }): CompileAgentResult;
95
104
  export interface CompileRailwayOptions {
96
105
  /** Names of compiled agents, to resolve `delegate` targets. Skipped if omitted. */
@@ -130,5 +139,5 @@ export interface AdoptResult {
130
139
  * Compare a generated file against what the spec would produce.
131
140
  * Returns the diff so users can see what was manually changed.
132
141
  */
133
- export declare function adoptDiff(filePath: string, spec: ClaudeSpec | SkillSpec | AgentSpec, basePath: string): AdoptResult;
142
+ export declare function adoptDiff(filePath: string, spec: ClaudeSpec | SkillSpec | AgentSpec, basePath: string, dialect: HarnessDialect): AdoptResult;
134
143
  //# sourceMappingURL=compile.d.ts.map
@@ -26,6 +26,10 @@ const node_path_1 = require("node:path");
26
26
  const hash_js_1 = require("./hash.js");
27
27
  const symbols_js_1 = require("./symbols.js");
28
28
  const linters_js_1 = require("./linters.js");
29
+ // vigiles's default compile target when a spec names none and no dialect is
30
+ // injected — a product convention (vigiles emits CLAUDE.md by default), not a
31
+ // harness dialect. When a dialect IS injected its instructionTargets win.
32
+ const DEFAULT_TARGET = "CLAUDE.md";
29
33
  // ---------------------------------------------------------------------------
30
34
  // Hash utilities
31
35
  // ---------------------------------------------------------------------------
@@ -388,8 +392,14 @@ function compileRulesSection(spec, basePath, options) {
388
392
  * Returns the compiled markdown, validation errors, and linter check results.
389
393
  * The markdown is generated even if there are errors (with warnings).
390
394
  */
395
+ // The instruction-file renderer is format-neutral: it emits plain markdown (h1
396
+ // from the dialect's instructionTargets, prose/Key-Files/Commands/Rules sections,
397
+ // and the trailing integrity-hash comment). That is exactly the AGENTS.md shape
398
+ // (no frontmatter), so Codex/OpenCode reuse it unchanged — only the h1 target
399
+ // differs, which already comes from the injected dialect. Nothing here is
400
+ // CC-only, so there is no per-dialect branch to gate.
391
401
  function compileClaude(spec, options = {}) {
392
- const targets = spec.target ?? "CLAUDE.md";
402
+ const targets = spec.target ?? options.dialect?.instructionTargets[0] ?? DEFAULT_TARGET;
393
403
  const target = Array.isArray(targets) ? targets[0] : targets;
394
404
  const basePath = options.basePath ?? process.cwd();
395
405
  const specFile = options.specFile ?? `${target}.spec.ts`;
@@ -546,22 +556,32 @@ function collectSkillRefs(spec) {
546
556
  refs.push(spec.result);
547
557
  return refs;
548
558
  }
549
- /** Build the SKILL.md YAML frontmatter block. */
550
- function renderSkillFrontmatter(spec) {
559
+ /**
560
+ * Build the SKILL.md YAML frontmatter block under the harness's frontmatter
561
+ * profile. The `"minimal"` profile (Codex/OpenCode) emits ONLY name +
562
+ * description; `"claude-code"` adds the CC-only keys (disable-model-invocation,
563
+ * argument-hint). Default is `"claude-code"` so callers that pass no dialect get
564
+ * byte-identical output to before.
565
+ */
566
+ function renderSkillFrontmatter(spec, profile = "claude-code") {
551
567
  const fm = [
552
568
  "---",
553
569
  "",
554
570
  `name: ${spec.name}`,
555
571
  `description: ${spec.description}`,
556
572
  ];
557
- if (spec.disableModelInvocation !== undefined) {
558
- fm.push(`disable-model-invocation: ${String(spec.disableModelInvocation)}`);
559
- }
560
- const argHint = spec.inputs && spec.inputs.length > 0
561
- ? renderArgumentHint(spec.inputs)
562
- : spec.argumentHint;
563
- if (argHint)
564
- fm.push(`argument-hint: ${argHint}`);
573
+ // The CC-only keys below are inert in a minimal (Codex/OpenCode) SKILL.md, so
574
+ // they're omitted entirely under that profile.
575
+ if (profile === "claude-code") {
576
+ if (spec.disableModelInvocation !== undefined) {
577
+ fm.push(`disable-model-invocation: ${String(spec.disableModelInvocation)}`);
578
+ }
579
+ const argHint = spec.inputs && spec.inputs.length > 0
580
+ ? renderArgumentHint(spec.inputs)
581
+ : spec.argumentHint;
582
+ if (argHint)
583
+ fm.push(`argument-hint: ${argHint}`);
584
+ }
565
585
  fm.push("", "---");
566
586
  return fm.join("\n");
567
587
  }
@@ -621,6 +641,7 @@ function checkInlineCode(markdown, max) {
621
641
  function compileSkill(spec, options = {}) {
622
642
  const basePath = options.basePath ?? process.cwd();
623
643
  const specFile = options.specFile ?? "SKILL.md.spec.ts";
644
+ const profile = options.dialect?.skillFrontmatter ?? "claude-code";
624
645
  const errors = [];
625
646
  // Verify spec file naming
626
647
  if (!specFile.endsWith(".spec.ts")) {
@@ -641,45 +662,29 @@ function compileSkill(spec, options = {}) {
641
662
  errors.push(...validateRefs(collectSkillRefs(spec), basePath));
642
663
  const sections = renderSkillSections(spec);
643
664
  errors.push(...checkInlineCode(sections, spec.maxInlineCodeLines ?? DEFAULT_MAX_INLINE_CODE_LINES));
644
- const content = renderSkillFrontmatter(spec) + "\n\n" + sections.trim() + "\n";
665
+ const content = renderSkillFrontmatter(spec, profile) + "\n\n" + sections.trim() + "\n";
645
666
  return { markdown: addHash(content, specFile), errors };
646
667
  }
647
668
  // ---------------------------------------------------------------------------
648
669
  // Compile a subagent spec → agents/<name>.md
649
670
  // ---------------------------------------------------------------------------
650
- // The tool contract a subagent may declare the rails it runs on. Anything
651
- // else must be an MCP tool (mcp__server__tool), else it's a typo / nonexistent
652
- // tool the dispatched worker could never call.
653
- const KNOWN_AGENT_TOOLS = [
654
- "Read",
655
- "Write",
656
- "Edit",
657
- "Bash",
658
- "Grep",
659
- "Glob",
660
- "WebSearch",
661
- "WebFetch",
662
- "NotebookEdit",
663
- "TodoWrite",
664
- "Task",
665
- "Skill",
666
- ];
667
- const MCP_TOOL_RE = /^mcp__[a-z0-9_-]+__[a-z0-9_-]+$/i;
668
- // Tools the platform never exposes to a subagent, whatever the list says — so a
669
- // subagent listing one is a guaranteed-dead reference only a compiler catches.
670
- const NEVER_AVAILABLE_TOOLS = new Set([
671
- "Agent",
672
- "AskUserQuestion",
673
- "EnterPlanMode",
674
- "ExitPlanMode",
675
- "ScheduleWakeup",
676
- "WaitForMcpServers",
677
- ]);
671
+ // The subagent tool catalog (built-in / never-available / MCP shape) is the
672
+ // harness's format-axis vocabulary it lives in the HarnessDialect port
673
+ // (src/core/dialect.ts), injected here, never hard-coded for one harness.
674
+ //
675
+ // SCOPE: compileAgent renders vigiles's agent() — a VERIFIED TOOL CONTRACT — to
676
+ // a Claude-Code-shaped subagent markdown file. Compiling that to Codex is a
677
+ // deliberate NON-GOAL, not a missing renderer: a Codex "subagent" is an
678
+ // [agents.<name>] TOML concurrency table (max_threads / max_depth), which is a
679
+ // runtime-orchestration knob, NOT a tool contract. The two models don't map, so
680
+ // vigiles does not emit a TOML [agents] block. The Codex dialect still verifies
681
+ // an agent()'s tool contract (its built-in catalog) — only the OUTPUT renderer
682
+ // is CC-only here. See research/codex-prototype-findings.md (gaps).
678
683
  /** Closest known tool by edit distance (≤ 3), for a "did you mean" hint. */
679
- function closestTool(tool) {
684
+ function closestTool(tool, dialect) {
680
685
  let best = null;
681
686
  let bestDistance = Infinity;
682
- for (const known of KNOWN_AGENT_TOOLS) {
687
+ for (const known of dialect.builtinAgentTools) {
683
688
  const d = (0, linters_js_1.editDistance)(tool.toLowerCase(), known.toLowerCase());
684
689
  if (d < bestDistance) {
685
690
  bestDistance = d;
@@ -689,25 +694,26 @@ function closestTool(tool) {
689
694
  return bestDistance <= 3 ? best : null;
690
695
  }
691
696
  /** Verify a subagent's allowed-tools contract — the rails are real tools. */
692
- function validateAgentTools(tools) {
697
+ function validateAgentTools(tools, dialect) {
698
+ const never = new Set(dialect.neverAvailableTools);
693
699
  const errors = [];
694
700
  for (const tool of tools) {
695
- if (NEVER_AVAILABLE_TOOLS.has(tool)) {
701
+ if (never.has(tool)) {
696
702
  errors.push({
697
703
  type: "unknown-tool",
698
704
  message: `Tool "${tool}" is never available to a subagent — remove it from the tools list.`,
699
705
  });
700
706
  continue;
701
707
  }
702
- if (KNOWN_AGENT_TOOLS.includes(tool))
708
+ if (dialect.builtinAgentTools.includes(tool))
703
709
  continue;
704
- if (MCP_TOOL_RE.test(tool))
710
+ if (dialect.mcpToolPattern.test(tool))
705
711
  continue;
706
- const near = closestTool(tool);
712
+ const near = closestTool(tool, dialect);
707
713
  const hint = near ? ` Did you mean "${near}"?` : "";
708
714
  errors.push({
709
715
  type: "unknown-tool",
710
- message: `Unknown tool "${tool}" in agent tools — use a built-in tool (${KNOWN_AGENT_TOOLS.join(", ")}) or an MCP tool (mcp__server__tool).${hint}`,
716
+ message: `Unknown tool "${tool}" in agent tools — use a built-in tool (${dialect.builtinAgentTools.join(", ")}) or an MCP tool (mcp__server__tool).${hint}`,
711
717
  });
712
718
  }
713
719
  return errors;
@@ -798,9 +804,10 @@ function renderAgentRules(rules) {
798
804
  * Verifies the tool contract and the body's references; the marks the body
799
805
  * carries (`vigiles:symbol`, file/cmd refs) are the same ones `audit` re-checks.
800
806
  */
801
- function compileAgent(spec, options = {}) {
807
+ function compileAgent(spec, options) {
802
808
  const basePath = options.basePath ?? process.cwd();
803
809
  const specFile = options.specFile ?? "agent.md.spec.ts";
810
+ const dialect = options.dialect;
804
811
  const errors = [];
805
812
  if (!specFile.endsWith(".spec.ts")) {
806
813
  errors.push({
@@ -815,7 +822,7 @@ function compileAgent(spec, options = {}) {
815
822
  });
816
823
  }
817
824
  if (spec.tools)
818
- errors.push(...validateAgentTools(spec.tools));
825
+ errors.push(...validateAgentTools(spec.tools, dialect));
819
826
  if (Array.isArray(spec.body)) {
820
827
  errors.push(...validateRefs(spec.body, basePath));
821
828
  }
@@ -921,7 +928,7 @@ function checkFileHash(filePath) {
921
928
  * Compare a generated file against what the spec would produce.
922
929
  * Returns the diff so users can see what was manually changed.
923
930
  */
924
- function adoptDiff(filePath, spec, basePath) {
931
+ function adoptDiff(filePath, spec, basePath, dialect) {
925
932
  const fullPath = (0, node_path_1.resolve)(basePath, filePath);
926
933
  const currentContent = (0, node_fs_1.existsSync)(fullPath)
927
934
  ? (0, node_fs_1.readFileSync)(fullPath, "utf-8")
@@ -930,7 +937,11 @@ function adoptDiff(filePath, spec, basePath) {
930
937
  // Compile the spec to get what it WOULD produce
931
938
  let compiledContent = null;
932
939
  if (spec._specType === "claude") {
933
- const { markdown } = compileClaude(spec, { basePath, specFile: filePath });
940
+ const { markdown } = compileClaude(spec, {
941
+ basePath,
942
+ specFile: filePath,
943
+ dialect,
944
+ });
934
945
  compiledContent = markdown;
935
946
  }
936
947
  else if (spec._specType === "skill") {
@@ -938,7 +949,11 @@ function adoptDiff(filePath, spec, basePath) {
938
949
  compiledContent = markdown;
939
950
  }
940
951
  else if (spec._specType === "agent") {
941
- const { markdown } = compileAgent(spec, { basePath, specFile: filePath });
952
+ const { markdown } = compileAgent(spec, {
953
+ basePath,
954
+ specFile: filePath,
955
+ dialect,
956
+ });
942
957
  compiledContent = markdown;
943
958
  }
944
959
  // Simple line-based diff
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Sync-tool compatibility detector — keep vigiles composable with the rule-sync
3
+ * tools (Ruler, rulesync) instead of fighting them for the same files.
4
+ *
5
+ * Both vigiles and a sync tool want to *write* CLAUDE.md / AGENTS.md. That
6
+ * collision is the whole compatibility problem: vigiles stamps a SHA-256
7
+ * integrity header on line 1 (see `integrity.ts`), but Ruler concatenates its
8
+ * source files into CLAUDE.md (prepending `<!-- Source: … -->`) and rulesync
9
+ * regenerates it — either way the hash silently goes stale. The clean topology
10
+ * is "vigiles upstream": compile into the tool's *source slot* and let the tool
11
+ * distribute (see `research/sync-tool-compatibility.md`).
12
+ *
13
+ * This detector is pure filesystem inspection — the same deterministic-detector
14
+ * shape as `orphans.ts` / `test-coverage.ts`. It reports which tools are present
15
+ * and any target that collides with a file the tool regenerates, so `vigiles
16
+ * audit` can warn before the integrity guarantee is lost.
17
+ */
18
+ /** A rule-sync tool vigiles should compose with rather than reimplement. */
19
+ export type SyncToolName = "ruler" | "rulesync";
20
+ export interface DetectedSyncTool {
21
+ readonly name: SyncToolName;
22
+ /**
23
+ * Where vigiles should compile its canonical output so the tool picks it up
24
+ * as a source (Topology A), e.g. `.ruler/AGENTS.md`.
25
+ */
26
+ readonly sourceSlot: string;
27
+ /**
28
+ * Files the tool regenerates/concatenates as distribution output. A vigiles
29
+ * compile target that lands in this set collides (the integrity hazard).
30
+ */
31
+ readonly distributes: readonly string[];
32
+ }
33
+ export interface ComposeCollision {
34
+ readonly tool: SyncToolName;
35
+ /** The vigiles compile target that the tool also owns. */
36
+ readonly target: string;
37
+ /** The source slot to compile into instead. */
38
+ readonly redirectTo: string;
39
+ readonly reason: string;
40
+ }
41
+ /** CLAUDE.md and AGENTS.md recognized as one artifact (symlinked or synced). */
42
+ export interface InstructionMirror {
43
+ /** The two instruction filenames that mirror each other. */
44
+ readonly files: readonly [string, string];
45
+ /** How they're kept identical: a symlink, or byte-identical synced content. */
46
+ readonly kind: "symlink" | "identical-content";
47
+ /** For `kind: "symlink"`, which filename is the link and which is the real file. */
48
+ readonly link?: string;
49
+ readonly realTarget?: string;
50
+ readonly reason: string;
51
+ }
52
+ /**
53
+ * Detect the rule-sync tools configured in the repo at `root`. Ruler is keyed
54
+ * on its `.ruler/` source dir or a `ruler.toml`; rulesync on its `.rulesync/`
55
+ * dir. Returns each tool's recommended source slot and the files it owns as
56
+ * distribution output (used to find collisions).
57
+ */
58
+ export declare function detectSyncTools(root: string): DetectedSyncTool[];
59
+ /**
60
+ * Detect whether `CLAUDE.md` and `AGENTS.md` at `root` are ONE artifact, not two
61
+ * — a symlink in either direction (`ln -s CLAUDE.md AGENTS.md`) or byte-identical
62
+ * content (a sync tool keeping them in lockstep). Claude Code reads CLAUDE.md
63
+ * only ([anthropics/claude-code#34235]); users bridge to the AGENTS.md tools this
64
+ * way (see `research/sync-tool-compatibility.md` requirement 7). When mirrored,
65
+ * vigiles must treat them as the same file — hash + `require-spec` run once on the
66
+ * real one, and the mirror is never flagged as a second, spec-less instruction
67
+ * file. Returns null when one is absent, or both exist but genuinely differ.
68
+ */
69
+ export declare function detectInstructionMirror(root: string): InstructionMirror | null;
70
+ /**
71
+ * Given the repo `root` and the spec's compile `targets`, report every case
72
+ * where a target is also a file a detected sync tool regenerates. Each
73
+ * collision carries the source slot to compile into instead — the actionable
74
+ * fix that preserves the integrity hash (the tool distributes from there).
75
+ *
76
+ * No detected tool, or no overlapping target, yields an empty list.
77
+ */
78
+ export declare function composeCollisions(root: string, targets: readonly string[]): ComposeCollision[];
79
+ //# sourceMappingURL=compose.d.ts.map