vigiles 29.1.0 → 30.0.1
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/dist/adapter-conformance.d.ts +1 -1
- package/dist/adapter-conformance.js +106 -25
- package/dist/adapter-registry.d.ts +61 -14
- package/dist/adapter-registry.js +78 -10
- package/dist/adapter.d.ts +23 -2
- package/dist/adapter.js +13 -1
- package/dist/adapters/claude-code/adapter.d.ts +32 -2
- package/dist/adapters/claude-code/adapter.js +44 -23
- package/dist/adapters/claude-code/agent-runtime.js +3 -1
- package/dist/adapters/claude-code/dialect.js +87 -21
- package/dist/adapters/claude-code/effect-region.js +3 -1
- package/dist/adapters/claude-code/hook-protocol.js +16 -0
- package/dist/adapters/claude-code/instruction-chain.d.ts +25 -0
- package/dist/adapters/claude-code/instruction-chain.js +626 -0
- package/dist/adapters/claude-code/layout.d.ts +2 -2
- package/dist/adapters/claude-code/layout.js +42 -8
- package/dist/adapters/claude-code/model-access.d.ts +41 -0
- package/dist/adapters/claude-code/model-access.js +46 -0
- package/dist/adapters/claude-code/skill-reachability.d.ts +125 -0
- package/dist/adapters/claude-code/skill-reachability.js +111 -0
- package/dist/adapters/claude-code/skill-runtime.js +3 -1
- package/dist/adapters/codex/adapter.d.ts +39 -2
- package/dist/adapters/codex/adapter.js +29 -29
- package/dist/adapters/codex/dialect.js +11 -6
- package/dist/adapters/codex/eval.d.ts +10 -0
- package/dist/adapters/codex/eval.js +48 -1
- package/dist/adapters/codex/hook-protocol.d.ts +2 -1
- package/dist/adapters/codex/hook-protocol.js +10 -0
- package/dist/adapters/codex/instruction-chain.d.ts +40 -0
- package/dist/adapters/codex/instruction-chain.js +105 -0
- package/dist/adapters/codex/layout.d.ts +1 -1
- package/dist/adapters/codex/layout.js +41 -14
- package/dist/adapters/opencode/adapter.d.ts +33 -2
- package/dist/adapters/opencode/adapter.js +36 -36
- package/dist/adapters/opencode/dialect.js +2 -2
- package/dist/adapters/opencode/instruction-chain.d.ts +37 -0
- package/dist/adapters/opencode/instruction-chain.js +70 -0
- package/dist/adapters/opencode/layout.d.ts +19 -0
- package/dist/adapters/opencode/layout.js +34 -15
- package/dist/adoptability.d.ts +31 -1
- package/dist/adoptability.js +57 -0
- package/dist/cli-main.js +185 -102
- package/dist/core/adapter.d.ts +213 -61
- package/dist/core/compile.d.ts +2 -2
- package/dist/core/compile.js +57 -46
- package/dist/core/compose.d.ts +5 -3
- package/dist/core/compose.js +5 -3
- package/dist/core/config-schema.d.ts +14 -2
- package/dist/core/config-schema.js +20 -7
- package/dist/core/dialect.d.ts +54 -12
- package/dist/core/dialect.js +56 -0
- package/dist/core/eval-driver.d.ts +194 -0
- package/dist/core/eval-driver.js +3 -0
- package/dist/core/frontmatter-read.d.ts +10 -0
- package/dist/core/frontmatter-read.js +30 -3
- package/dist/core/guards.js +3 -1
- package/dist/core/hook-program.d.ts +27 -2
- package/dist/core/hook-program.js +29 -24
- package/dist/core/hook-protocol.d.ts +54 -0
- package/dist/core/install-reader.d.ts +18 -0
- package/dist/core/install-reader.js +88 -0
- package/dist/core/instruction-chain.d.ts +444 -0
- package/dist/core/instruction-chain.js +292 -0
- package/dist/core/instruction-weight.d.ts +96 -14
- package/dist/core/instruction-weight.js +65 -30
- package/dist/core/layout.d.ts +220 -33
- package/dist/core/layout.js +115 -1
- package/dist/core/lethal-trifecta.d.ts +12 -7
- package/dist/core/lethal-trifecta.js +13 -13
- package/dist/core/live-driver.d.ts +137 -0
- package/dist/core/live-driver.js +14 -0
- package/dist/core/markdown.d.ts +23 -0
- package/dist/core/markdown.js +77 -28
- package/dist/core/orphans.js +9 -7
- package/dist/core/settings-codec.d.ts +17 -0
- package/dist/core/settings-codec.js +56 -0
- package/dist/core/surface-discovery.d.ts +2 -2
- package/dist/core/surface-discovery.js +24 -12
- package/dist/core/surface-scopes.d.ts +26 -6
- package/dist/core/surface-scopes.js +52 -11
- package/dist/core/validate.js +16 -3
- package/dist/coverage-artifact.d.ts +3 -2
- package/dist/coverage-artifact.js +6 -5
- package/dist/eval-cache.d.ts +6 -1
- package/dist/eval-cache.js +11 -1
- package/dist/eval.d.ts +16 -108
- package/dist/eval.js +36 -2
- package/dist/harness-test.d.ts +3 -63
- package/dist/hook-install.d.ts +12 -1
- package/dist/hook-install.js +12 -1
- package/dist/hook-runtime.js +4 -2
- package/dist/hook-state-store.js +3 -1
- package/dist/local-files-tracked.d.ts +17 -0
- package/dist/local-files-tracked.js +70 -0
- package/dist/local-files.d.ts +62 -0
- package/dist/local-files.js +183 -0
- package/dist/observe.d.ts +3 -2
- package/dist/observe.js +7 -6
- package/dist/plugin-loader.d.ts +1 -1
- package/dist/plugin-loader.js +43 -36
- package/dist/scan-behavioral.d.ts +34 -25
- package/dist/scan-behavioral.js +122 -58
- package/dist/scan-core.js +37 -18
- package/dist/scan-files.d.ts +1 -1
- package/dist/scan-files.js +53 -33
- package/dist/scan-trigger-suggest.d.ts +0 -21
- package/dist/scan-trigger-suggest.js +0 -23
- package/dist/scan.d.ts +4 -4
- package/dist/scan.js +120 -84
- package/dist/skill-harness.d.ts +21 -5
- package/dist/skill-harness.js +29 -11
- package/dist/surface-discovery-fs.d.ts +2 -0
- package/dist/surface-discovery-fs.js +108 -6
- package/dist/test-coverage-files.js +24 -17
- package/dist/test-coverage.d.ts +9 -3
- package/dist/test-coverage.js +32 -22
- package/dist/verify-plugin-guards.js +1 -1
- package/package.json +1 -1
- package/dist/skill-reachability.d.ts +0 -68
- package/dist/skill-reachability.js +0 -205
- /package/dist/{dialect-drift.d.ts → adapters/claude-code/dialect-drift.d.ts} +0 -0
- /package/dist/{dialect-drift.js → adapters/claude-code/dialect-drift.js} +0 -0
|
@@ -58,10 +58,10 @@ const node_crypto_1 = require("node:crypto");
|
|
|
58
58
|
const node_fs_1 = require("node:fs");
|
|
59
59
|
const node_path_1 = require("node:path");
|
|
60
60
|
const coverage_evidence_js_1 = require("./coverage-evidence.js");
|
|
61
|
+
const local_files_js_1 = require("./local-files.js");
|
|
62
|
+
Object.defineProperty(exports, "COVERAGE_ARTIFACT_FILE", { enumerable: true, get: function () { return local_files_js_1.COVERAGE_ARTIFACT_FILE; } });
|
|
61
63
|
/** Bumped when the record shape changes in a non-additive way. */
|
|
62
64
|
exports.COVERAGE_ARTIFACT_VERSION = 1;
|
|
63
|
-
/** The artifact filename under `.vigiles/`. */
|
|
64
|
-
exports.COVERAGE_ARTIFACT_FILE = "coverage.json";
|
|
65
65
|
/**
|
|
66
66
|
* Every {@link RunAttribution}, as data — the artifact's validator reads it, so
|
|
67
67
|
* the accepted set and the type cannot drift apart into a record shape the
|
|
@@ -576,7 +576,7 @@ function mergeRuns(previous, next, executed) {
|
|
|
576
576
|
}
|
|
577
577
|
/** Read the artifact, or `undefined` when there is none / it is not one. */
|
|
578
578
|
function readCoverageArtifact(root) {
|
|
579
|
-
const file = (0, node_path_1.resolve)(root,
|
|
579
|
+
const file = (0, node_path_1.resolve)(root, local_files_js_1.VIGILES_DIR, local_files_js_1.COVERAGE_ARTIFACT_FILE);
|
|
580
580
|
if (!(0, node_fs_1.existsSync)(file))
|
|
581
581
|
return undefined;
|
|
582
582
|
let value;
|
|
@@ -618,9 +618,10 @@ function isCoverageRun(value) {
|
|
|
618
618
|
/** Write the artifact. Best-effort: recording must never fail a green run. */
|
|
619
619
|
function writeCoverageArtifact(root, artifact) {
|
|
620
620
|
try {
|
|
621
|
-
const dir = (0, node_path_1.resolve)(root,
|
|
621
|
+
const dir = (0, node_path_1.resolve)(root, local_files_js_1.VIGILES_DIR);
|
|
622
622
|
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
623
|
-
(0,
|
|
623
|
+
(0, local_files_js_1.ensureLocalFilesIgnored)(dir);
|
|
624
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.resolve)(dir, local_files_js_1.COVERAGE_ARTIFACT_FILE), JSON.stringify(artifact, null, 2) + "\n");
|
|
624
625
|
}
|
|
625
626
|
catch {
|
|
626
627
|
/* best-effort — a scratch-dir failure is not a test failure */
|
package/dist/eval-cache.d.ts
CHANGED
|
@@ -74,7 +74,12 @@ export declare function cacheKey(input: CacheKeyInput): SHA256Hash;
|
|
|
74
74
|
* gate must surface, not mask. The message tells you how to recover.
|
|
75
75
|
*/
|
|
76
76
|
export declare function readCache(dir: string, key: SHA256Hash): CacheRecord | null;
|
|
77
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* Write a cached record by key (creating the cache dir as needed). When `dir` is
|
|
79
|
+
* the default `.vigiles/eval-cache`, the recorded runs are per-checkout, so the
|
|
80
|
+
* `.vigiles/.gitignore` is kept current; a `cacheDir` the spec chose elsewhere is
|
|
81
|
+
* the author's to place and is left alone.
|
|
82
|
+
*/
|
|
78
83
|
export declare function writeCache(dir: string, key: SHA256Hash, record: CacheRecord): void;
|
|
79
84
|
/** Snapshot the text files under `cwd` as `relativePath → contents` (bounded). */
|
|
80
85
|
export declare function snapshotDir(cwd: string): Record<string, string>;
|
package/dist/eval-cache.js
CHANGED
|
@@ -28,6 +28,7 @@ exports.hashDir = hashDir;
|
|
|
28
28
|
const node_fs_1 = require("node:fs");
|
|
29
29
|
const node_path_1 = require("node:path");
|
|
30
30
|
const hash_js_1 = require("./core/hash.js");
|
|
31
|
+
const local_files_js_1 = require("./local-files.js");
|
|
31
32
|
const MAX_SNAPSHOT_FILE_BYTES = 1024 * 1024;
|
|
32
33
|
const SKIP_DIRS = new Set(["node_modules", ".git"]);
|
|
33
34
|
/**
|
|
@@ -113,9 +114,18 @@ function readCache(dir, key) {
|
|
|
113
114
|
throw new Error(`eval cache: corrupt record ${path} (invalid JSON) — delete it or clear the cache dir`);
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Write a cached record by key (creating the cache dir as needed). When `dir` is
|
|
119
|
+
* the default `.vigiles/eval-cache`, the recorded runs are per-checkout, so the
|
|
120
|
+
* `.vigiles/.gitignore` is kept current; a `cacheDir` the spec chose elsewhere is
|
|
121
|
+
* the author's to place and is left alone.
|
|
122
|
+
*/
|
|
117
123
|
function writeCache(dir, key, record) {
|
|
118
124
|
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
125
|
+
if ((0, node_path_1.basename)(dir) === local_files_js_1.EVAL_CACHE_DIR &&
|
|
126
|
+
(0, node_path_1.basename)((0, node_path_1.dirname)(dir)) === local_files_js_1.VIGILES_DIR) {
|
|
127
|
+
(0, local_files_js_1.ensureLocalFilesIgnored)((0, node_path_1.dirname)(dir));
|
|
128
|
+
}
|
|
119
129
|
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, `${key}.json`), JSON.stringify(record));
|
|
120
130
|
}
|
|
121
131
|
/** Snapshot the text files under `cwd` as `relativePath → contents` (bounded). */
|
package/dist/eval.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { HarnessLiveDriver } from "./core/live-driver.js";
|
|
2
|
+
import type { AgentRunArgs, AgentRunner, EvalDriver, EvalUsage, ModelOutputParser, ParsedModelRun, RunOut } from "./core/eval-driver.js";
|
|
3
|
+
export type { AgentRunArgs, AgentRunner, EvalDriver, EvalUsage, ModelOutputParser, ParsedModelRun, RunOut, } from "./core/eval-driver.js";
|
|
4
|
+
import { type ToolCall, type Trace } from "./harness-test.js";
|
|
2
5
|
import { type CacheMode } from "./eval-cache.js";
|
|
3
6
|
import { type EvalLockOptions } from "./eval-lock.js";
|
|
4
7
|
import type { Check, CheckJSON } from "./check.js";
|
|
@@ -54,20 +57,6 @@ export interface EvalArm {
|
|
|
54
57
|
*/
|
|
55
58
|
readonly effort?: string | number;
|
|
56
59
|
}
|
|
57
|
-
/** Per-run resource use, parsed from the terminal `result` event (0 when absent). */
|
|
58
|
-
export interface EvalUsage {
|
|
59
|
-
/** `total_cost_usd` reported by claude. */
|
|
60
|
-
readonly costUsd: number;
|
|
61
|
-
/** Wall-clock `duration_ms` of the run. */
|
|
62
|
-
readonly durationMs: number;
|
|
63
|
-
/** Fresh (uncached) input tokens, billed at full input price. */
|
|
64
|
-
readonly inputTokens: number;
|
|
65
|
-
readonly outputTokens: number;
|
|
66
|
-
/** Tokens written to the prompt cache this run (~1.25× input price). */
|
|
67
|
-
readonly cacheCreationTokens: number;
|
|
68
|
-
/** Tokens served from the prompt cache this run (~0.1× input price). */
|
|
69
|
-
readonly cacheReadTokens: number;
|
|
70
|
-
}
|
|
71
60
|
/**
|
|
72
61
|
* Context handed to `measure` after a run, to compute that run's metrics. It is
|
|
73
62
|
* a `Trace` (so the bare predicates `usedTool` / `skillResolved` / `toolCount` /
|
|
@@ -231,52 +220,6 @@ export interface EvalReport {
|
|
|
231
220
|
/** True if a `maxCostUsd` budget cap stopped the run before all trials ran. */
|
|
232
221
|
readonly aborted: boolean;
|
|
233
222
|
}
|
|
234
|
-
/** The raw output of one trial: the agent's exit code + captured streams. */
|
|
235
|
-
export interface RunOut {
|
|
236
|
-
code: number;
|
|
237
|
-
stdout: string;
|
|
238
|
-
/** Captured stderr, when the runner provides it (used for rate-limit detection). */
|
|
239
|
-
stderr?: string;
|
|
240
|
-
}
|
|
241
|
-
/** The per-trial arguments handed to an {@link AgentRunner}. */
|
|
242
|
-
export interface AgentRunArgs {
|
|
243
|
-
readonly task: string;
|
|
244
|
-
readonly cwd: string;
|
|
245
|
-
readonly model: string;
|
|
246
|
-
/**
|
|
247
|
-
* Reasoning-budget level for the run (`claude --effort`). Part of the
|
|
248
|
-
* MEASUREMENT, not a run knob: it changes the model's output distribution, not
|
|
249
|
-
* the sample size — so it lives on the spec next to `model` (never an env),
|
|
250
|
-
* and it is hashed into both the cache key and the eval lock. Deliberately
|
|
251
|
-
* `string | number` rather than a literal union: the binary accepts an alias
|
|
252
|
-
* map, is case-insensitive, and takes an integer budget, and its own valid set
|
|
253
|
-
* MOVED between builds (2.1.42 had no `xhigh`, 2.1.257 does) — a hard-coded
|
|
254
|
-
* union would reject a valid level after any upstream addition. A wrong value
|
|
255
|
-
* is caught at RUNTIME instead, by {@link effortRejection}, which is what the
|
|
256
|
-
* binary actually tells us. Omit for the harness default.
|
|
257
|
-
*/
|
|
258
|
-
readonly effort?: string | number;
|
|
259
|
-
readonly tools: readonly string[];
|
|
260
|
-
readonly hasSettings: boolean;
|
|
261
|
-
readonly pluginDir: string | undefined;
|
|
262
|
-
readonly timeoutMs: number;
|
|
263
|
-
/** Extra env layered over `process.env` for this run (e.g. `VIGILES_INTERCEPT_TOOLS`). */
|
|
264
|
-
readonly env?: Record<string, string>;
|
|
265
|
-
/**
|
|
266
|
-
* When true, `env` is the COMPLETE spawn environment (an ephemeral run env from
|
|
267
|
-
* `ephemeralRunEnv`) — the runner does NOT prepend `process.env`, so the
|
|
268
|
-
* real `$HOME` / secrets are scrubbed. Default false: `env` is an overlay over
|
|
269
|
-
* `process.env` (the byte-identical-to-today path). Set only by `ephemeralEnv`.
|
|
270
|
-
*/
|
|
271
|
-
readonly replaceEnv?: boolean;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Runs one trial and returns its raw output. The default (`spawnAgent`)
|
|
275
|
-
* drives the real `claude` CLI; `runEvalWith` takes one explicitly, so the eval
|
|
276
|
-
* orchestration is testable without a model (pass a fake returning canned
|
|
277
|
-
* stream-json) and a custom runtime can be plugged in.
|
|
278
|
-
*/
|
|
279
|
-
export type AgentRunner = (args: AgentRunArgs) => Promise<RunOut>;
|
|
280
223
|
/**
|
|
281
224
|
* Resolve the environment a trial's subprocess actually runs with — the
|
|
282
225
|
* SECURITY-CRITICAL decision behind `ephemeralEnv`. When `replaceEnv` is set, the
|
|
@@ -528,22 +471,6 @@ export declare function checkReportToJUnit(report: CheckReport, opts?: {
|
|
|
528
471
|
}): string;
|
|
529
472
|
/** Parse per-run cost/latency/tokens from a stream — pure, model-free. */
|
|
530
473
|
export declare function parseUsage(stdout: string): EvalUsage;
|
|
531
|
-
/**
|
|
532
|
-
* The harness-specific half of a run trace: how a real model's raw stdout maps
|
|
533
|
-
* to the common fields. Claude Code's `parseClaudeRun` reads its stream-json; a
|
|
534
|
-
* second harness (Codex) supplies its own parser of `codex exec --json` JSONL, so
|
|
535
|
-
* the eval tier (`measureTriggerRate`/`runEval`) isn't bound to Claude's format.
|
|
536
|
-
* The non-harness fields (cwd/exitCode/stdout/file/sh) stay in `makeContext`.
|
|
537
|
-
*/
|
|
538
|
-
export interface ParsedModelRun {
|
|
539
|
-
readonly turns: number;
|
|
540
|
-
readonly output: string;
|
|
541
|
-
readonly toolCalls: ReturnType<typeof parseToolCalls>;
|
|
542
|
-
readonly hooks: ReturnType<typeof parseHooks>;
|
|
543
|
-
readonly subagents: ReturnType<typeof parseSubagents>;
|
|
544
|
-
readonly usage: EvalUsage;
|
|
545
|
-
}
|
|
546
|
-
export type ModelOutputParser = (out: RunOut) => ParsedModelRun;
|
|
547
474
|
/** Parse Claude Code's stream-json stdout into the common trace fields. */
|
|
548
475
|
export declare function parseClaudeRun(out: RunOut): ParsedModelRun;
|
|
549
476
|
/**
|
|
@@ -864,37 +791,6 @@ export interface TriggerRateReport {
|
|
|
864
791
|
*/
|
|
865
792
|
readonly experimental?: string;
|
|
866
793
|
}
|
|
867
|
-
/**
|
|
868
|
-
* An eval-tier transport: how to RUN a real harness turn and PARSE its output.
|
|
869
|
-
* The default is Claude Code (`claudeEvalDriver`); a second harness supplies its
|
|
870
|
-
* own (e.g. `codexEvalDriver` from `vigiles/codex`) and passes it as
|
|
871
|
-
* `measureTriggerRate(spec, { evalDriver })` — the eval-tier analog of
|
|
872
|
-
* `runHarnessTest`'s `{ adapter }`. `runError` lets the loop drop an
|
|
873
|
-
* errored/rate-limited turn instead of scoring it as a miss.
|
|
874
|
-
*/
|
|
875
|
-
export interface EvalDriver {
|
|
876
|
-
readonly runner: AgentRunner;
|
|
877
|
-
readonly parse: ModelOutputParser;
|
|
878
|
-
readonly runError?: (out: RunOut) => string | null;
|
|
879
|
-
/**
|
|
880
|
-
* The harness this driver runs (e.g. `"claude-code"`, `"codex"`). Folded into a
|
|
881
|
-
* trigger-rate eval's LOCK hash so a report recorded on one harness is marked
|
|
882
|
-
* STALE if the eval is later switched to another (a different harness can fire a
|
|
883
|
-
* skill differently). Optional for back-compat — absent defaults to
|
|
884
|
-
* `"claude-code"`, so an existing single-harness lock is unaffected.
|
|
885
|
-
*/
|
|
886
|
-
readonly harness?: string;
|
|
887
|
-
/**
|
|
888
|
-
* When set, this driver's trigger-rate number is EXPERIMENTAL and not
|
|
889
|
-
* validated — the string is the human caveat explaining why (e.g. Codex has no
|
|
890
|
-
* skill-selection event, so firing is inferred from a SKILL.md read, which can
|
|
891
|
-
* be wrong in both directions). Absent = supported/trustworthy (the default,
|
|
892
|
-
* Claude Code). `measureTriggerRate` copies it onto the report and warns; the
|
|
893
|
-
* formatter prints it. Precision-first: never let a possibly-wrong number read
|
|
894
|
-
* as a measurement.
|
|
895
|
-
*/
|
|
896
|
-
readonly experimental?: string;
|
|
897
|
-
}
|
|
898
794
|
/**
|
|
899
795
|
* The default (Claude Code) eval driver: real `claude` + stream-json parsing.
|
|
900
796
|
*
|
|
@@ -909,6 +805,18 @@ export interface EvalDriver {
|
|
|
909
805
|
* The asymmetry reflects default-vs-injected, not a hexagonal violation.
|
|
910
806
|
*/
|
|
911
807
|
export declare const claudeEvalDriver: EvalDriver;
|
|
808
|
+
/**
|
|
809
|
+
* The Claude Code {@link HarnessLiveDriver} — the EXECUTING tiers' side of the
|
|
810
|
+
* adapter, reached through `claudeCodeAdapter.liveDriver()`.
|
|
811
|
+
*
|
|
812
|
+
* It lives HERE, at the composition root, for exactly the reason
|
|
813
|
+
* `claudeEvalDriver` above does: it is assembled from the wired default runner
|
|
814
|
+
* and `whichSkillsFired`, and moving it into `src/adapters/claude-code/` would
|
|
815
|
+
* make `eval.ts → adapters/claude-code → eval.ts` a cycle. The adapter reaches
|
|
816
|
+
* it through a dynamic `import()`, so nothing pays for this graph until an
|
|
817
|
+
* executing tier actually runs.
|
|
818
|
+
*/
|
|
819
|
+
export declare const claudeCodeLiveDriver: HarnessLiveDriver;
|
|
912
820
|
/**
|
|
913
821
|
* Package loose `<skillsDir>/<name>/SKILL.md` skills into a throwaway plugin dir
|
|
914
822
|
* that `claude --plugin-dir` accepts — so repo-local skills (e.g. `.claude/skills`)
|
package/dist/eval.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.claudeEvalDriver = exports.EPHEMERAL_HOME_KEEP = exports.spawnAgent = exports.EFFORT_ENV_VAR = void 0;
|
|
3
|
+
exports.claudeCodeLiveDriver = exports.claudeEvalDriver = exports.EPHEMERAL_HOME_KEEP = exports.spawnAgent = exports.EFFORT_ENV_VAR = void 0;
|
|
4
4
|
exports.resolveSpawnEnv = resolveSpawnEnv;
|
|
5
5
|
exports.pinEffortEnv = pinEffortEnv;
|
|
6
6
|
exports.effortRejection = effortRejection;
|
|
@@ -76,8 +76,10 @@ const plugin_loader_js_1 = require("./adapters/claude-code/plugin-loader.js");
|
|
|
76
76
|
const runtime_js_1 = require("./adapters/claude-code/runtime.js");
|
|
77
77
|
const eval_cost_js_1 = require("./eval-cost.js");
|
|
78
78
|
const proofs_js_1 = require("./core/proofs.js");
|
|
79
|
+
const model_access_js_1 = require("./adapters/claude-code/model-access.js");
|
|
79
80
|
const harness_test_js_1 = require("./harness-test.js");
|
|
80
81
|
const eval_cache_js_1 = require("./eval-cache.js");
|
|
82
|
+
const local_files_js_1 = require("./local-files.js");
|
|
81
83
|
const eval_lock_js_1 = require("./eval-lock.js");
|
|
82
84
|
const stats_js_1 = require("./stats.js");
|
|
83
85
|
const check_count_js_1 = require("./check-count.js");
|
|
@@ -1330,7 +1332,7 @@ async function runEvalWith(spec, runner) {
|
|
|
1330
1332
|
tools: spec.allowedTools ?? ["Read", "Edit", "Write", "Bash"],
|
|
1331
1333
|
timeoutMs: spec.timeoutMs ?? 240000,
|
|
1332
1334
|
cache: spec.cache ?? "off",
|
|
1333
|
-
cacheDir: spec.cacheDir ?? (0, node_path_1.resolve)(process.cwd(),
|
|
1335
|
+
cacheDir: spec.cacheDir ?? (0, node_path_1.resolve)(process.cwd(), local_files_js_1.VIGILES_DIR, local_files_js_1.EVAL_CACHE_DIR),
|
|
1334
1336
|
};
|
|
1335
1337
|
if (cfg.cache !== "off" && !isDatedModel(cfg.model)) {
|
|
1336
1338
|
warnFloatingModel(cfg.model);
|
|
@@ -1413,6 +1415,38 @@ exports.claudeEvalDriver = {
|
|
|
1413
1415
|
parse: parseClaudeRun,
|
|
1414
1416
|
harness: "claude-code",
|
|
1415
1417
|
};
|
|
1418
|
+
/**
|
|
1419
|
+
* The Claude Code {@link HarnessLiveDriver} — the EXECUTING tiers' side of the
|
|
1420
|
+
* adapter, reached through `claudeCodeAdapter.liveDriver()`.
|
|
1421
|
+
*
|
|
1422
|
+
* It lives HERE, at the composition root, for exactly the reason
|
|
1423
|
+
* `claudeEvalDriver` above does: it is assembled from the wired default runner
|
|
1424
|
+
* and `whichSkillsFired`, and moving it into `src/adapters/claude-code/` would
|
|
1425
|
+
* make `eval.ts → adapters/claude-code → eval.ts` a cycle. The adapter reaches
|
|
1426
|
+
* it through a dynamic `import()`, so nothing pays for this graph until an
|
|
1427
|
+
* executing tier actually runs.
|
|
1428
|
+
*/
|
|
1429
|
+
exports.claudeCodeLiveDriver = {
|
|
1430
|
+
evalDriver: exports.claudeEvalDriver,
|
|
1431
|
+
// Env-only, and never a spent token: deciding whether to OFFER a measurement
|
|
1432
|
+
// must not cost one. The three arms are what the consent prompt words
|
|
1433
|
+
// differently — a key bills per token, a session is $0 metered, and neither
|
|
1434
|
+
// present means the tier is skipped with `fix` printed.
|
|
1435
|
+
access: (env) => (0, model_access_js_1.isMeteredAccess)(env)
|
|
1436
|
+
? { kind: "metered" }
|
|
1437
|
+
: (0, model_access_js_1.hasModelAccess)(env)
|
|
1438
|
+
? { kind: "subscription" }
|
|
1439
|
+
: { kind: "none", fix: model_access_js_1.CLAUDE_CODE_ACCESS_FIX },
|
|
1440
|
+
// A discrete `Skill` tool_use in the trace says WHICH skill was selected, so
|
|
1441
|
+
// the selection-collision matrix and the adversarial gate can run here.
|
|
1442
|
+
firing: { kind: "event" },
|
|
1443
|
+
// Claude Code namespaces a plugin's skill as `<plugin>:<skill>`; the manifest
|
|
1444
|
+
// name is handed in by the domain, which read it off the layout.
|
|
1445
|
+
firedFor: (skill, plugin) => (t) => whichSkillsFired(t).includes(plugin.name ? `${plugin.name}:${skill}` : skill),
|
|
1446
|
+
// The probe may rebuild the plugin to skills-only stubs: this is the harness
|
|
1447
|
+
// whose plugin shape vigiles packages, so a stubbed rebuild is validated.
|
|
1448
|
+
installsStubs: true,
|
|
1449
|
+
};
|
|
1416
1450
|
/**
|
|
1417
1451
|
* Is this directory entry a skill DIRECTORY — following a symlink to one?
|
|
1418
1452
|
*
|
package/dist/harness-test.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { HarnessAdapter } from "./core/adapter.js";
|
|
2
|
-
import type { HarnessTestDriver, ToolCall, HookFire, ParsedRun, ModelTurn
|
|
2
|
+
import type { HarnessTestDriver, ToolCall, HookFire, ParsedRun, ModelTurn } from "./core/harness-driver.js";
|
|
3
|
+
import type { Trace, SubagentTrace } from "./core/eval-driver.js";
|
|
4
|
+
export type { Trace, SubagentTrace } from "./core/eval-driver.js";
|
|
3
5
|
import { type SandboxMode } from "./sandbox.js";
|
|
4
6
|
export { scriptModel } from "./mock-model.js";
|
|
5
7
|
export type { ModelTurn, ModelRequest, ToolCall, HookFire, HarnessTestDriver, } from "./core/harness-driver.js";
|
|
@@ -56,68 +58,6 @@ export interface HarnessTestSpec {
|
|
|
56
58
|
*/
|
|
57
59
|
readonly sandbox?: SandboxMode;
|
|
58
60
|
}
|
|
59
|
-
/**
|
|
60
|
-
* The observable record of ONE run — the unified shape produced by BOTH testing
|
|
61
|
-
* tiers: `runHarnessTest`'s result and `runEval`'s `measure` ctx (`eval.ts`)
|
|
62
|
-
* both satisfy it. That's what lets the bare predicates in `harness-assert.ts`
|
|
63
|
-
* (`usedTool` / `skillResolved` / `toolCount` / `toolUsedWith` / `hookFired` /
|
|
64
|
-
* `outputContains`) run over either, with the testing helpers asserting and eval
|
|
65
|
-
* measuring over the same vocabulary.
|
|
66
|
-
*/
|
|
67
|
-
export interface Trace {
|
|
68
|
-
/**
|
|
69
|
-
* The tools the agent invoked, each paired with its result — parsed from the
|
|
70
|
-
* transcript. Empty unless the run captured the stream (`transcript: true` on
|
|
71
|
-
* the harness tier; always on the eval tier). Lets a test assert on the
|
|
72
|
-
* agent's *actions* (skills, MCP tools, subagents) instead of grepping stdout.
|
|
73
|
-
*/
|
|
74
|
-
readonly toolCalls: readonly ToolCall[];
|
|
75
|
-
/**
|
|
76
|
-
* The hooks that fired during the run, each with its decision — parsed from
|
|
77
|
-
* the CLI's `hook_response` stream events. Same capture requirement as
|
|
78
|
-
* `toolCalls` (empty without the stream). Lets a test assert hook firing
|
|
79
|
-
* honestly instead of via a marker file.
|
|
80
|
-
*/
|
|
81
|
-
readonly hooks: readonly HookFire[];
|
|
82
|
-
/** The agent's final answer text (the terminal `result` event), or "". */
|
|
83
|
-
readonly output: string;
|
|
84
|
-
/**
|
|
85
|
-
* The requests the model received, captured by the scripted mock — each with
|
|
86
|
-
* its `system` prompt and `messages`, flattened to text. Lets a test assert
|
|
87
|
-
* what actually reached the model (a SessionStart hook's injected context, a
|
|
88
|
-
* slash command's expansion), not just that a hook fired. **Harness tier
|
|
89
|
-
* only**: the mock sees the requests, so this is populated by `runHarnessTest`
|
|
90
|
-
* (with or without `transcript`); the eval tier drives the real API, so its
|
|
91
|
-
* `modelRequests` is always empty.
|
|
92
|
-
*/
|
|
93
|
-
readonly modelRequests: readonly ModelRequest[];
|
|
94
|
-
/** Number of model turns. */
|
|
95
|
-
readonly turns: number;
|
|
96
|
-
/**
|
|
97
|
-
* Sub-agent (`Task`) runs as nested traces, keyed by `subagent_type`. A
|
|
98
|
-
* subagent runs its own session; CC tags its events with `parent_tool_use_id`
|
|
99
|
-
* (= the `Task` tool call) so its tool calls are recovered into a sub-trace
|
|
100
|
-
* here, lettng a test assert what the subagent DID (not just that `Task` fired).
|
|
101
|
-
* Empty unless the stream was captured / the harness emits subagent events.
|
|
102
|
-
*/
|
|
103
|
-
readonly subagents?: readonly SubagentTrace[];
|
|
104
|
-
/** Final contents of a file under the working dir, or null if absent. */
|
|
105
|
-
file(path: string): string | null;
|
|
106
|
-
}
|
|
107
|
-
/** A sub-agent (`Task`) run as a nested trace: its name + the tools it used. */
|
|
108
|
-
export interface SubagentTrace {
|
|
109
|
-
/** The `subagent_type` from the `Task` tool input. */
|
|
110
|
-
readonly name: string;
|
|
111
|
-
/** The tools the subagent invoked (events tagged with the Task's id). */
|
|
112
|
-
readonly toolCalls: readonly ToolCall[];
|
|
113
|
-
/**
|
|
114
|
-
* The subagent's RETURNED text — the dispatch tool_result the orchestrator
|
|
115
|
-
* receives back. This is where a `result()` contract's `vigiles:ok`/`vigiles:err`
|
|
116
|
-
* block lands, so `subagent(name, [output(/vigiles:ok/)])` can assert the typed
|
|
117
|
-
* outcome. "" if not captured.
|
|
118
|
-
*/
|
|
119
|
-
readonly output: string;
|
|
120
|
-
}
|
|
121
61
|
export interface HarnessTestResult extends Trace {
|
|
122
62
|
readonly exitCode: number;
|
|
123
63
|
readonly stdout: string;
|
package/dist/hook-install.d.ts
CHANGED
|
@@ -128,7 +128,18 @@ interface ConfigToml {
|
|
|
128
128
|
}
|
|
129
129
|
/** The TOML sibling of {@link mergeHooksJson} (Codex `[[hooks.<event>]]`). */
|
|
130
130
|
export declare function mergeHooksToml(existing: ConfigToml, compiled: CompiledHooks, hookPath: string): ConfigToml;
|
|
131
|
-
/**
|
|
131
|
+
/**
|
|
132
|
+
* Serialize a merged config back to its on-disk text.
|
|
133
|
+
*
|
|
134
|
+
* ⚠️ DEPRECATED IN PLACE, not deleted, and the distinction matters: the
|
|
135
|
+
* harness-driven path (`installHookFile` in `cli-main.ts`) goes through
|
|
136
|
+
* `PluginLayout.settings.render` now, so no adapter's encoding is decided here
|
|
137
|
+
* any more. The one remaining caller is `cli-main.ts`'s Codex-plugin wiring,
|
|
138
|
+
* which writes `.codex/config.toml` for a harness it names ITSELF, at the
|
|
139
|
+
* composition root — a caller that already knows the encoding, rather than one
|
|
140
|
+
* branching on a layout field. Its `format` argument is therefore a literal at
|
|
141
|
+
* the call site, not a value read off a port.
|
|
142
|
+
*/
|
|
132
143
|
export declare function serializeConfig(merged: Record<string, unknown>, format: "json" | "toml"): string;
|
|
133
144
|
export {};
|
|
134
145
|
//# sourceMappingURL=hook-install.d.ts.map
|
package/dist/hook-install.js
CHANGED
|
@@ -298,7 +298,18 @@ function mergeHooksToml(existing, compiled, hookPath) {
|
|
|
298
298
|
]));
|
|
299
299
|
return { ...existing, hooks: { ...before, ...rewritten } };
|
|
300
300
|
}
|
|
301
|
-
/**
|
|
301
|
+
/**
|
|
302
|
+
* Serialize a merged config back to its on-disk text.
|
|
303
|
+
*
|
|
304
|
+
* ⚠️ DEPRECATED IN PLACE, not deleted, and the distinction matters: the
|
|
305
|
+
* harness-driven path (`installHookFile` in `cli-main.ts`) goes through
|
|
306
|
+
* `PluginLayout.settings.render` now, so no adapter's encoding is decided here
|
|
307
|
+
* any more. The one remaining caller is `cli-main.ts`'s Codex-plugin wiring,
|
|
308
|
+
* which writes `.codex/config.toml` for a harness it names ITSELF, at the
|
|
309
|
+
* composition root — a caller that already knows the encoding, rather than one
|
|
310
|
+
* branching on a layout field. Its `format` argument is therefore a literal at
|
|
311
|
+
* the call site, not a value read off a port.
|
|
312
|
+
*/
|
|
302
313
|
function serializeConfig(merged, format) {
|
|
303
314
|
return format === "toml"
|
|
304
315
|
? stringifyToml(merged).trimEnd() + "\n"
|
package/dist/hook-runtime.js
CHANGED
|
@@ -50,6 +50,7 @@ const hook_install_js_1 = require("./hook-install.js");
|
|
|
50
50
|
const hook_providers_js_1 = require("./core/hook-providers.js");
|
|
51
51
|
const hook_state_store_js_1 = require("./hook-state-store.js");
|
|
52
52
|
const observe_js_1 = require("./observe.js");
|
|
53
|
+
const local_files_js_1 = require("./local-files.js");
|
|
53
54
|
const load_hook_js_1 = require("./load-hook.js");
|
|
54
55
|
const event_capability_js_1 = require("./core/event-capability.js");
|
|
55
56
|
/**
|
|
@@ -168,8 +169,9 @@ async function loadProviderRegistry(root) {
|
|
|
168
169
|
/** Append an observe-mode record to `.vigiles/hook-observations.jsonl` (best-effort). */
|
|
169
170
|
function recordObservation(file, on, would, reason, root) {
|
|
170
171
|
try {
|
|
171
|
-
const dir = (0, node_path_1.resolve)(root,
|
|
172
|
+
const dir = (0, node_path_1.resolve)(root, local_files_js_1.VIGILES_DIR);
|
|
172
173
|
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
174
|
+
(0, local_files_js_1.ensureLocalFilesIgnored)(dir);
|
|
173
175
|
const line = JSON.stringify({
|
|
174
176
|
ts: new Date().toISOString(),
|
|
175
177
|
hook: file,
|
|
@@ -177,7 +179,7 @@ function recordObservation(file, on, would, reason, root) {
|
|
|
177
179
|
would,
|
|
178
180
|
reason,
|
|
179
181
|
}) + "\n";
|
|
180
|
-
(0, node_fs_1.appendFileSync)((0, node_path_1.resolve)(dir,
|
|
182
|
+
(0, node_fs_1.appendFileSync)((0, node_path_1.resolve)(dir, local_files_js_1.HOOK_OBSERVATIONS_FILE), line);
|
|
181
183
|
}
|
|
182
184
|
catch {
|
|
183
185
|
/* recording is best-effort — never let it break a live session */
|
package/dist/hook-state-store.js
CHANGED
|
@@ -57,6 +57,7 @@ const node_path_1 = require("node:path");
|
|
|
57
57
|
const hash_js_1 = require("./core/hash.js");
|
|
58
58
|
const hook_state_js_1 = require("./core/hook-state.js");
|
|
59
59
|
const hook_install_js_1 = require("./hook-install.js");
|
|
60
|
+
const local_files_js_1 = require("./local-files.js");
|
|
60
61
|
/**
|
|
61
62
|
* The directory a hook's recorded facts live in — the SCOPE of `state()`/`record()`.
|
|
62
63
|
*
|
|
@@ -78,7 +79,7 @@ function hookStateDir(file, cwd = process.cwd()) {
|
|
|
78
79
|
const dir = (0, node_path_1.dirname)((0, node_path_1.resolve)(cwd, file));
|
|
79
80
|
const rel = (0, node_path_1.relative)(cwd, dir);
|
|
80
81
|
const inside = rel !== "" && !rel.startsWith("..") && !(0, node_path_1.isAbsolute)(rel);
|
|
81
|
-
return (0, node_path_1.resolve)(cwd,
|
|
82
|
+
return (0, node_path_1.resolve)(cwd, local_files_js_1.VIGILES_DIR, local_files_js_1.HOOK_STATE_DIR, inside ? rel : `external-${(0, hash_js_1.sha256short)(dir)}`);
|
|
82
83
|
}
|
|
83
84
|
/** Read one recorded fact for a hook, or `null` if it was never recorded. */
|
|
84
85
|
function readHookState(file, key, cwd = process.cwd()) {
|
|
@@ -112,6 +113,7 @@ function writeHookState(file, w, opts = {}) {
|
|
|
112
113
|
by: (0, hook_install_js_1.normalizeHookRef)(file, cwd),
|
|
113
114
|
};
|
|
114
115
|
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
116
|
+
(0, local_files_js_1.ensureLocalFilesIgnored)((0, node_path_1.resolve)(cwd, local_files_js_1.VIGILES_DIR));
|
|
115
117
|
const tmp = `${target}.${String(process.pid)}.tmp`;
|
|
116
118
|
(0, node_fs_1.writeFileSync)(tmp, JSON.stringify(entry, null, 2) + "\n");
|
|
117
119
|
(0, node_fs_1.renameSync)(tmp, target);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-checkout files under `<root>/.vigiles/` that git tracks, as
|
|
3
|
+
* repo-relative paths from `root`. Empty when nothing is tracked, when `root` is
|
|
4
|
+
* not in a git work tree, or when `git` is missing — silence is the answer to
|
|
5
|
+
* every "cannot tell".
|
|
6
|
+
*/
|
|
7
|
+
export declare function trackedLocalFiles(root: string): string[];
|
|
8
|
+
/**
|
|
9
|
+
* The one-line warning for {@link trackedLocalFiles}, or `null` when there is
|
|
10
|
+
* nothing to say. Files inside a tracked local DIRECTORY (`state/`,
|
|
11
|
+
* `eval-cache/`) are named by that directory, so one line stays one line and the
|
|
12
|
+
* command it prints untracks all of them.
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatTrackedLocalFiles(tracked: readonly string[]): string | null;
|
|
15
|
+
/** Print the warning for `root` to stderr when there is one. CLI-only. */
|
|
16
|
+
export declare function warnTrackedLocalFiles(root: string): void;
|
|
17
|
+
//# sourceMappingURL=local-files-tracked.d.ts.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trackedLocalFiles = trackedLocalFiles;
|
|
4
|
+
exports.formatTrackedLocalFiles = formatTrackedLocalFiles;
|
|
5
|
+
exports.warnTrackedLocalFiles = warnTrackedLocalFiles;
|
|
6
|
+
/**
|
|
7
|
+
* The half `.gitignore` cannot do: tell the owner when a per-checkout file under
|
|
8
|
+
* `.vigiles/` is ALREADY tracked.
|
|
9
|
+
*
|
|
10
|
+
* `ensureLocalFilesIgnored` (`local-files.ts`) keeps new copies out of git, but
|
|
11
|
+
* an ignore rule does not untrack a file git already follows — a repo that
|
|
12
|
+
* committed `.vigiles/coverage.json` before this existed keeps committing every
|
|
13
|
+
* rewrite of it. Only the owner can fix that (`git rm --cached`), and changing
|
|
14
|
+
* the index is theirs to decide, so this reports and never acts.
|
|
15
|
+
*
|
|
16
|
+
* CLI-only, by construction: it spawns `git`, and a hook decision must never pay
|
|
17
|
+
* for a child process. That is why it is a separate module from the ignore half,
|
|
18
|
+
* which hook runtimes import.
|
|
19
|
+
*/
|
|
20
|
+
const node_child_process_1 = require("node:child_process");
|
|
21
|
+
const node_path_1 = require("node:path");
|
|
22
|
+
const local_files_js_1 = require("./local-files.js");
|
|
23
|
+
/**
|
|
24
|
+
* The per-checkout files under `<root>/.vigiles/` that git tracks, as
|
|
25
|
+
* repo-relative paths from `root`. Empty when nothing is tracked, when `root` is
|
|
26
|
+
* not in a git work tree, or when `git` is missing — silence is the answer to
|
|
27
|
+
* every "cannot tell".
|
|
28
|
+
*/
|
|
29
|
+
function trackedLocalFiles(root) {
|
|
30
|
+
const specs = local_files_js_1.LOCAL_FILES.map((f) => node_path_1.posix.join(local_files_js_1.VIGILES_DIR, f.name));
|
|
31
|
+
try {
|
|
32
|
+
const r = (0, node_child_process_1.spawnSync)("git", ["ls-files", "-z", "--", ...specs], {
|
|
33
|
+
cwd: root,
|
|
34
|
+
encoding: "utf-8",
|
|
35
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
36
|
+
});
|
|
37
|
+
if (r.status !== 0 || typeof r.stdout !== "string")
|
|
38
|
+
return [];
|
|
39
|
+
return r.stdout.split("\0").filter((p) => p !== "");
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The one-line warning for {@link trackedLocalFiles}, or `null` when there is
|
|
47
|
+
* nothing to say. Files inside a tracked local DIRECTORY (`state/`,
|
|
48
|
+
* `eval-cache/`) are named by that directory, so one line stays one line and the
|
|
49
|
+
* command it prints untracks all of them.
|
|
50
|
+
*/
|
|
51
|
+
function formatTrackedLocalFiles(tracked) {
|
|
52
|
+
if (tracked.length === 0)
|
|
53
|
+
return null;
|
|
54
|
+
// `.vigiles/state/.claude/hooks/x.json` → `.vigiles/state`: the list entry.
|
|
55
|
+
const entries = [
|
|
56
|
+
...new Set(tracked.map((p) => p.split("/").slice(0, 2).join("/"))),
|
|
57
|
+
];
|
|
58
|
+
const one = entries.length === 1;
|
|
59
|
+
return (`⚠ ${entries.join(", ")} ${one ? "is" : "are"} tracked by git, but ` +
|
|
60
|
+
`${local_files_js_1.VIGILES_DIR}/ local files describe one checkout and would credit a ` +
|
|
61
|
+
`machine where nothing ran. .gitignore does not untrack a tracked file; ` +
|
|
62
|
+
`untrack ${one ? "it" : "them"} once: git rm -r --cached ${entries.join(" ")}`);
|
|
63
|
+
}
|
|
64
|
+
/** Print the warning for `root` to stderr when there is one. CLI-only. */
|
|
65
|
+
function warnTrackedLocalFiles(root) {
|
|
66
|
+
const line = formatTrackedLocalFiles(trackedLocalFiles(root));
|
|
67
|
+
if (line)
|
|
68
|
+
process.stderr.write(line + "\n");
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=local-files-tracked.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** vigiles's own directory in a project. */
|
|
2
|
+
export declare const VIGILES_DIR = ".vigiles";
|
|
3
|
+
/** The execution tier of coverage (`coverage-artifact.ts`). */
|
|
4
|
+
export declare const COVERAGE_ARTIFACT_FILE = "coverage.json";
|
|
5
|
+
/** The flight-recorder ledger (`observe.ts`). */
|
|
6
|
+
export declare const LEDGER_FILE = "runs.jsonl";
|
|
7
|
+
/** Compiled hooks' named state, `record()`/`state()` (`hook-state-store.ts`). */
|
|
8
|
+
export declare const HOOK_STATE_DIR = "state";
|
|
9
|
+
/** The skill in progress (`adapters/claude-code/skill-runtime.ts`). */
|
|
10
|
+
export declare const ACTIVE_SKILL_FILE = "active-skill.json";
|
|
11
|
+
/** The subagent stack in progress (`adapters/claude-code/agent-runtime.ts`). */
|
|
12
|
+
export declare const ACTIVE_AGENT_FILE = "active-agent.json";
|
|
13
|
+
/** Inside-an-effect-boundary marker (`adapters/claude-code/effect-region.ts`). */
|
|
14
|
+
export declare const EFFECT_ACTIVE_FILE = "effect-active.json";
|
|
15
|
+
/** The calls a guard allowed this session (`core/guards.ts`). */
|
|
16
|
+
export declare const GUARD_LEDGER_FILE = "guard-ledger.json";
|
|
17
|
+
/** What an `observe`-mode hook would have blocked (`hook-runtime.ts`). */
|
|
18
|
+
export declare const HOOK_OBSERVATIONS_FILE = "hook-observations.jsonl";
|
|
19
|
+
/** Recorded model runs for eval replay, the default `cacheDir` (`eval.ts`). */
|
|
20
|
+
export declare const EVAL_CACHE_DIR = "eval-cache";
|
|
21
|
+
/** One per-checkout path under `.vigiles/`. */
|
|
22
|
+
export interface LocalFile {
|
|
23
|
+
/** The name directly under `.vigiles/`. */
|
|
24
|
+
readonly name: string;
|
|
25
|
+
/** A directory (its whole subtree is local) rather than a single file. */
|
|
26
|
+
readonly dir: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Every per-checkout path vigiles writes under `.vigiles/`. The one list. */
|
|
29
|
+
export declare const LOCAL_FILES: readonly LocalFile[];
|
|
30
|
+
/**
|
|
31
|
+
* The names under `.vigiles/` that ARE the project's and must stay committable.
|
|
32
|
+
* Not used at runtime — it is the other half of the classification the guard in
|
|
33
|
+
* `local-files.test.ts` holds the source to, and the list that test checks is
|
|
34
|
+
* NOT ignored.
|
|
35
|
+
*/
|
|
36
|
+
export declare const COMMITTED_PATHS: readonly string[];
|
|
37
|
+
/** The header comment on a `.vigiles/.gitignore` vigiles creates. */
|
|
38
|
+
export declare const LOCAL_GITIGNORE_HEADER: readonly string[];
|
|
39
|
+
/** The ignore lines, in order: every local path, then the file itself. */
|
|
40
|
+
export declare function localIgnoreEntries(): string[];
|
|
41
|
+
/**
|
|
42
|
+
* Keep `<vigilesDir>/.gitignore` listing every local path. Call it where a
|
|
43
|
+
* local file is written — not from `vigiles init`, which a project may never
|
|
44
|
+
* run, while the write always happens.
|
|
45
|
+
*
|
|
46
|
+
* - Absent → created with {@link LOCAL_GITIGNORE_HEADER} and every entry.
|
|
47
|
+
* - Every entry IN EFFECT → not touched (no rewrite, no mtime change).
|
|
48
|
+
* - Otherwise the entries not in effect are appended and nothing is removed
|
|
49
|
+
* or reordered. Appending is enough because git's last matching rule wins.
|
|
50
|
+
*
|
|
51
|
+
* "In effect" is judged the way git reads the file, not by text membership:
|
|
52
|
+
* lines in order, a later `!/entry` cancels an earlier `/entry`, and leading
|
|
53
|
+
* whitespace is part of the pattern (only trailing whitespace is dropped).
|
|
54
|
+
* Both cases were measured with `git check-ignore`: `/coverage.json` followed
|
|
55
|
+
* by `!/coverage.json`, and ` /coverage.json`, each leave the file NOT
|
|
56
|
+
* ignored while a trimmed set would call the entry present.
|
|
57
|
+
*
|
|
58
|
+
* Costs one read on the hot path. Best-effort: any fs error is swallowed —
|
|
59
|
+
* keeping git tidy must never break a hook, a test run or an audit.
|
|
60
|
+
*/
|
|
61
|
+
export declare function ensureLocalFilesIgnored(vigilesDir: string): void;
|
|
62
|
+
//# sourceMappingURL=local-files.d.ts.map
|