mirror of
https://github.com/zernie/vigiles.git
synced 2026-09-14 20:53:57 +08:00
effed2afcc
* fix(dialect): vocabulary is a status per name, not membership in two lists Three checks answered "does this string look like something I recognise?" instead of "is this string valid?", and decided what to SAY about an unrecognised name by its EDIT DISTANCE to a hand-kept list. Measured against the vendor docs (claude-code 2.1.233, read 2026-08-17): - `Setup`, a documented hook event, was reported as "a hook here never fires" and told to become `Stop` — a different event with different semantics. It was caught only because `setup` sits 2 edits from `stop`. - The catalog held 9 of the vendor's 31 events. The other 22 were not "accepted"; 21 were unrecognised and >2 away from anything, so nothing was said. `SubagentStart` and `PostCompact` sat at 3 — one character from becoming the next `Setup`. - `Agent` was on the never-available denylist while its own deprecated alias `Task` sat in the built-in catalog. The vendor renamed it the other way in 2.1.63 and ships `tools: Agent, Read, Bash` as a worked example, so vigiles told delegating subagents to drop the one tool they exist to use. - `MultiEdit`, `BashOutput`, `KillBash`, `LS` appear zero times across six vendor doc pages. They were in the catalog; four real tools were not. So a valid name got an accusation or silence by spelling luck. The fix is not a longer array: `classify` returns one of four verdicts — available / withheld / conditional / unrecognised — and no near-match is in scope where the report-or-skip decision is made. `unrecognised` is the third option between silence and accusation: an advisory that names vigiles's own capture as the possibly-stale party, surfaced and never scored. The ≤2 threshold was not merely loose, it was set at the width of the collision: over 465 event pairs and 741 tool pairs, ZERO are 1 edit apart and exactly one pair in each is 2 apart — one of them being `Setup`/`Stop`. So distance 1 is scored as a typo and distance 2 stays advisory, and a test pins that measurement so a future catalog entry landing 1 edit from an existing name fails here rather than in someone's repo. Subtracts `confidentToolIssues` / `confidentHookEventIssues`: severity now travels on the issue, so scan, lint and compileAgent cannot disagree about which findings count. `builtinAgentTools` / `neverAvailableTools` / `sideEffectingTools` become projections of one authored vocabulary, and the conformance kit rejects a dialect that contradicts itself — the invariant whose absence let `Agent` sit in two lists while dialect-drift read it out of the vendor's own sdk-tools.d.ts every run. Also fixes an unrelated defect found on the way: the dialect-drift hook-event test never applied the stale-leftover reconciliation its sibling applies, so it only ever ran against whatever old package was lying around. Grades on faithful reductions that reproduce the recorded before-state exactly: SethGammon/Citadel F(57) -> C(73), thedotmack/claude-mem F(55) -> C(70). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uvk2Zx66BAuxuLGLFL2umd * fix(site): keep the browser engine's graph node-free; retire LS in the type test collectVocabularyNotes lived in scan.ts and scan-files.ts imported it as a VALUE, which pulled the node-only graph into the browser bundle: dist/scan-files.js → dist/scan.js → core/mcp.js → core/refs.js → core/symbols.js → @ast-grep/napi (a native .node binding esbuild has no loader for) Measured by walking the built CJS require graph, and confirmed by mutation: restoring the scan.js import makes the chain above reappear, removing it makes @ast-grep/napi unreachable. The functions are pure data transforms and now sit in scan-core.ts, the module whose stated job is to be node-free. test/types/purity.ts still declared LS, which left the catalog on 2026-08-17. It is now a negative case instead: a retired name has to FAIL at tsc time, since its absence from a list proves nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uvk2Zx66BAuxuLGLFL2umd * chore: regenerate the browser-parity fixture for the vocabulary message The one changed line is the finding this PR exists to fix: the old rationale dumped the whole catalog at the reader — including MultiEdit, BashOutput, KillBash and LS, which are not Claude Code tools — instead of saying what is wrong with the name it was given. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uvk2Zx66BAuxuLGLFL2umd --------- Co-authored-by: Claude <noreply@anthropic.com>
4.4 KiB
4.4 KiB
API Report File for "vigiles-adapter"
Do not edit this file. It is a report generated by API Extractor.
// @public
export interface AdapterCapabilities {
readonly harnessTesting: boolean;
readonly referenceVerification: true;
readonly shellHooks: boolean;
readonly subagents: boolean;
}
// @public
export const ADAPTERS: readonly HarnessAdapter[];
// @public
export function assertAdapterConformance(adapter: HarnessAdapter): void;
// @public
export function assertAdapterLoadsHooks(adapter: HarnessAdapter): void;
// @public
export function assertHarnessTestable(adapter: HarnessAdapter): {
runtime: NonNullable<HarnessAdapter["runtime"]>;
modelMock: NonNullable<HarnessAdapter["modelMock"]>;
};
// @public
export function checkAdapterConformance(adapter: HarnessAdapter): ConformanceResult;
// @public (undocumented)
export interface ConformanceResult {
// (undocumented)
readonly failures: readonly string[];
// (undocumented)
readonly ok: boolean;
}
// @public
export const defaultAdapter: HarnessAdapter;
// @public
export function detectAdapter(root: string): HarnessAdapter;
// @public
export function detectAdapterResult(root: string): DetectResult;
// @public
export interface DetectResult {
// (undocumented)
readonly adapter: HarnessAdapter;
readonly ambiguousWith: readonly string[];
readonly fallback: boolean;
}
// @public
export function getAdapter(name: string): HarnessAdapter | undefined;
// @public (undocumented)
export interface HarnessAdapter {
readonly capabilities: AdapterCapabilities;
detect(root: string): number;
readonly dialect: HarnessDialect;
readonly harnessTestDriver?: HarnessTestDriver;
readonly hookProtocol?: HookProtocol;
readonly layout: PluginLayout;
readonly modelMock?: ModelMock;
readonly name: string;
readonly runtime?: HarnessRuntime;
}
// @public (undocumented)
export interface HarnessDialect {
readonly builtinAgentTools: readonly string[];
readonly hookEvents: readonly string[];
readonly hookEventVocabulary?: HarnessVocabulary;
readonly instructionTargets: readonly string[];
readonly knownMcpServers?: readonly string[];
readonly mcpToolPattern: RegExp;
readonly name: string;
readonly neverAvailableTools: readonly string[];
readonly noEffectHookEvents?: readonly string[];
readonly permissionDecisionHookEvents?: readonly string[];
readonly pluginRootToken: string;
readonly sideEffectingTools?: readonly string[];
readonly skillFrontmatter: SkillFrontmatterProfile;
readonly subagentToolVocabulary?: HarnessVocabulary;
}
// @public
export interface HarnessRuntime {
readonly agentBinary: string;
readonly mockApiKey: string;
readonly modelApiKeyEnv: string;
readonly modelBaseUrlEnv: string;
readonly name: string;
versionKey(raw: string): string;
wireMock(baseUrl: string): {
readonly args: readonly string[];
readonly env: Record<string, string>;
};
}
// @public
export interface HookProtocol {
readonly blockExitCode: number;
readonly denyDecisionValues: readonly string[];
readonly eventEnvVars: readonly string[];
readonly injectableEvents: readonly string[];
readonly matcherStyle?: "exact" | "regex";
readonly name: string;
}
// @public
export interface ModelMock {
readonly countTokensEndpoint?: string;
readonly modelEndpoint: string;
readonly name: string;
readonly wireApi: string;
}
// @public
export interface PluginLayout {
readonly agentDir: string;
readonly commandDir: string;
readonly hooksConventionPath: string;
readonly instructionFile: string;
readonly intraRefDirs: readonly string[];
readonly manifestPath: string;
readonly materializeRoot: string;
readonly mcpConfigFile: string;
readonly mcpManifestKey: string;
readonly name: string;
readonly pluginRootToken: string;
readonly projectRootTokens?: readonly string[];
readonly settingsFormat: "json" | "toml";
readonly settingsPath: string;
readonly skillDir: string;
readonly surfaceDirs: readonly string[];
readonly userSurfaceRoot?: string;
}
// @public
export function resolveAdapter(root: string, harness?: string): HarnessAdapter;
// (No @packageDocumentation comment for this package)