agent-gov-core 0.3.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Conal Hg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # agent-gov-core
2
+
3
+ [![npm](https://img.shields.io/npm/v/agent-gov-core)](https://www.npmjs.com/package/agent-gov-core)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
+
6
+ Shared primitives for the AI-agent governance suite — a small library that ScopeTrail, PolicyMesh, CapabilityEcho, TaskBound, and SessionTrail all consume so common parsers, locators, and the `Finding` schema live in one place instead of five.
7
+
8
+ Zero runtime dependencies. ESM, TypeScript, target ES2022.
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ npm install agent-gov-core
14
+ ```
15
+
16
+ ## The canonical Finding
17
+
18
+ Every tool in the suite emits findings against the same schema. The `kind` field is a namespaced string `<tool>.<slug>` so a downstream meta-reviewer can dedupe across tools.
19
+
20
+ ```ts
21
+ import { kind, type Finding } from 'agent-gov-core';
22
+
23
+ const finding: Finding = {
24
+ tool: 'scope_trail',
25
+ kind: kind('scope_trail', 'permission_allow_widened'),
26
+ severity: 'high',
27
+ message: 'Claude permission allowlist now includes Bash(npm *).',
28
+ location: { file: '.claude/settings.json', line: 12 },
29
+ };
30
+ ```
31
+
32
+ The JSON schema at [`schemas/finding.schema.json`](./schemas/finding.schema.json) enforces the dotted-kind shape — any tool emitting unprefixed kinds will fail validation.
33
+
34
+ ## What's in the library
35
+
36
+ ### Finding schema and helpers
37
+ - `Finding`, `Severity`, `ToolKind`, `FindingLocation` — canonical types
38
+ - `SEVERITIES`, `TOOL_KINDS` — runtime arrays of the enum values
39
+ - `isSeverity(v)`, `isToolKind(v)`, `isNamespacedKind(v)` — type guards
40
+ - `kind(tool, name)` — build a namespaced kind without hand-assembling the dotted string
41
+ - `createFinding({tool, name, severity, message, ...})` — convenience constructor that calls `kind()` and `fingerprintFinding()` for you
42
+ - `fingerprintFinding(finding)` — 16-character hex hash of `(kind, file, line, column)`. Stable across runs and message rewordings, so a meta-reviewer can dedupe
43
+ - `validateFinding(value)` — runtime check against `schemas/finding.schema.json`, returns `{ ok, errors[] }`
44
+
45
+ ### Config readers
46
+ - `readJsonObjectWithSource(path)` — JSONC reader, string-aware comment + trailing-comma stripping, position-preserving
47
+ - `stripJsonComments(text)` — same logic exposed for in-memory text
48
+ - `readTomlObject(path)` — TOML reader (sections, arrays of tables, inline tables, multi-line strings, dotted/quoted keys)
49
+ - `parseToml(text)` — same exposed for text
50
+
51
+ ### Line locators
52
+ - `lineOfJsonKey(text, key)` — 1-based line of `"key":`
53
+ - `lineOfJsonStringValue(text, value, scope?)` — 1-based line of a JSON-encoded value, optionally scoped to a byte range
54
+ - `lineOfTomlKey(text, dottedKey)` — 1-based line of a TOML key
55
+
56
+ ### MCP command normalization
57
+ - `normalizeMcpCommand({ command, args, url, serverUrl, env, cwd })` — canonical identity string for an MCP server entry. Drops neutral flags (`-y`, `--yes`), resolves npx/uvx invocations, includes env+cwd in the identity. Used to dedupe `mcp_command_mismatch` false positives when servers are equivalent but syntactically different (`npx -y foo@1.2.3` vs `npx foo@1.2.3`).
58
+
59
+ ### Shell tokenization
60
+ - `tokenizeShell(command)` — quote-aware split on `;`, `|`, `&&`, `||` plus trivial obfuscation neutralization (`c""url` → `curl`, `c\\url` → `curl`)
61
+ - `getCommandHead(subcommand)` — extract the leading verb after tokenization
62
+
63
+ ### GitHub Action helpers
64
+ - `rankSeverity(s)` — numeric rank `none=0 … critical=4`
65
+ - `passesSeverityThreshold(s, threshold)`, `anyAtOrAbove(findings, threshold)` — fail-on plumbing
66
+ - `emitFindingAnnotation(f)` — render a Finding as a `::warning file=…,line=…,title=…::…` GitHub workflow annotation
67
+
68
+ ### Test fixtures (`agent-gov-core/test-utils`)
69
+ Secondary entry point used by consumer test suites. Zero overhead in production — only loaded when test files import it.
70
+
71
+ - `writeFiles(dir, { relPath: content })` — write a map of files under `dir`, creating parent directories
72
+ - `makeGitRepo({ initialFiles?, initialMessage? })` → `{ repo, commit, head, git, cleanup }` — temp repo on branch `main` with placeholder identity; `commit()` writes files and commits, returning the new SHA
73
+ - `makeOldNewFixture({ old, new })` → `{ old, new, cleanup }` — two sibling temp directories for diff-mode CLI tests
74
+
75
+ ## Principles
76
+
77
+ - **Zero runtime dependencies.** Real TOML, JSONC, MCP normalization, shell tokenization — all hand-written or vendored, no transitive supply chain.
78
+ - **MIT.** No telemetry. No network calls anywhere in the library.
79
+ - **Semver, with the contract frozen at v1.0.** Until then, minor versions may include breaking changes (the v0.2 schema regex tightening is one example).
80
+ - **Per-tool reasoning stays in each tool.** This library is the substrate, not the orchestrator.
81
+
82
+ ## Used by
83
+
84
+ - [ScopeTrail](https://github.com/Conalh/ScopeTrail) — agent permission drift in PRs (`scope_trail.*` findings)
85
+ - [PolicyMesh](https://github.com/Conalh/PolicyMesh) — cross-surface agent policy contradictions (`policy_mesh.*`)
86
+ - [CapabilityEcho](https://github.com/Conalh/CapabilityEcho) — capability drift through code, not config (`capability_echo.*`)
87
+ - [TaskBound](https://github.com/Conalh/TaskBound) — scope creep after the agent runs (`task_bound.*`)
88
+ - [SessionTrail](https://github.com/Conalh/SessionTrail) — runtime behavior across agent session transcripts (`session_trail.*`)
89
+
90
+ ## License
91
+
92
+ MIT.
@@ -0,0 +1,31 @@
1
+ import type { Finding, Severity } from './finding.js';
2
+ /** Numeric rank: low=1, medium=2, high=3, critical=4. */
3
+ export declare function rankSeverity(severity: Severity): number;
4
+ /**
5
+ * `true` when `severity` is at least as severe as `threshold` — i.e. the run
6
+ * should FAIL. Returns `false` (= pass) if `severity` is below threshold.
7
+ */
8
+ export declare function passesSeverityThreshold(severity: Severity, threshold: Severity): boolean;
9
+ /**
10
+ * Returns true if any finding meets or exceeds the threshold.
11
+ */
12
+ export declare function anyAtOrAbove(findings: readonly Finding[], threshold: Severity): boolean;
13
+ /**
14
+ * Build a GitHub Actions workflow command line for a finding.
15
+ *
16
+ * `critical` and `high` map to `::error`; everything else maps to `::warning`.
17
+ * `notice` is intentionally not used — surfacing low findings as `warning` makes
18
+ * them visible in the Files Changed tab.
19
+ *
20
+ * @example
21
+ * emitFindingAnnotation({
22
+ * tool: 'capability_echo',
23
+ * kind: 'capability_echo.workflow_permission_write',
24
+ * severity: 'high',
25
+ * message: 'Workflow grants contents: write to PR-triggered jobs.',
26
+ * location: { file: '.github/workflows/ci.yml', line: 12 },
27
+ * });
28
+ * // → '::error file=.github/workflows/ci.yml,line=12,title=[capability_echo.workflow_permission_write] high::Workflow grants contents: write to PR-triggered jobs.'
29
+ */
30
+ export declare function emitFindingAnnotation(finding: Finding): string;
31
+ //# sourceMappingURL=action.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAStD,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAEvD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAExF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAKvF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAe9D"}
package/dist/action.js ADDED
@@ -0,0 +1,79 @@
1
+ const SEVERITY_RANK = {
2
+ low: 1,
3
+ medium: 2,
4
+ high: 3,
5
+ critical: 4,
6
+ };
7
+ /** Numeric rank: low=1, medium=2, high=3, critical=4. */
8
+ export function rankSeverity(severity) {
9
+ return SEVERITY_RANK[severity];
10
+ }
11
+ /**
12
+ * `true` when `severity` is at least as severe as `threshold` — i.e. the run
13
+ * should FAIL. Returns `false` (= pass) if `severity` is below threshold.
14
+ */
15
+ export function passesSeverityThreshold(severity, threshold) {
16
+ return rankSeverity(severity) >= rankSeverity(threshold);
17
+ }
18
+ /**
19
+ * Returns true if any finding meets or exceeds the threshold.
20
+ */
21
+ export function anyAtOrAbove(findings, threshold) {
22
+ for (const f of findings) {
23
+ if (passesSeverityThreshold(f.severity, threshold))
24
+ return true;
25
+ }
26
+ return false;
27
+ }
28
+ /**
29
+ * Build a GitHub Actions workflow command line for a finding.
30
+ *
31
+ * `critical` and `high` map to `::error`; everything else maps to `::warning`.
32
+ * `notice` is intentionally not used — surfacing low findings as `warning` makes
33
+ * them visible in the Files Changed tab.
34
+ *
35
+ * @example
36
+ * emitFindingAnnotation({
37
+ * tool: 'capability_echo',
38
+ * kind: 'capability_echo.workflow_permission_write',
39
+ * severity: 'high',
40
+ * message: 'Workflow grants contents: write to PR-triggered jobs.',
41
+ * location: { file: '.github/workflows/ci.yml', line: 12 },
42
+ * });
43
+ * // → '::error file=.github/workflows/ci.yml,line=12,title=[capability_echo.workflow_permission_write] high::Workflow grants contents: write to PR-triggered jobs.'
44
+ */
45
+ export function emitFindingAnnotation(finding) {
46
+ const level = finding.severity === 'critical' || finding.severity === 'high'
47
+ ? 'error'
48
+ : 'warning';
49
+ const params = [];
50
+ if (finding.location?.file)
51
+ params.push(`file=${escapeProperty(finding.location.file)}`);
52
+ if (finding.location?.line != null)
53
+ params.push(`line=${finding.location.line}`);
54
+ if (finding.location?.column != null)
55
+ params.push(`col=${finding.location.column}`);
56
+ if (finding.location?.endLine != null)
57
+ params.push(`endLine=${finding.location.endLine}`);
58
+ if (finding.location?.endColumn != null)
59
+ params.push(`endColumn=${finding.location.endColumn}`);
60
+ params.push(`title=${escapeProperty(`[${finding.kind}] ${finding.severity}`)}`);
61
+ const message = escapeData(finding.message);
62
+ return `::${level} ${params.join(',')}::${message}`;
63
+ }
64
+ // per GitHub Actions docs
65
+ function escapeData(s) {
66
+ return s
67
+ .replace(/%/g, '%25')
68
+ .replace(/\r/g, '%0D')
69
+ .replace(/\n/g, '%0A');
70
+ }
71
+ function escapeProperty(s) {
72
+ return s
73
+ .replace(/%/g, '%25')
74
+ .replace(/\r/g, '%0D')
75
+ .replace(/\n/g, '%0A')
76
+ .replace(/:/g, '%3A')
77
+ .replace(/,/g, '%2C');
78
+ }
79
+ //# sourceMappingURL=action.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAEA,MAAM,aAAa,GAA6B;IAC9C,GAAG,EAAE,CAAC;IACN,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;IACP,QAAQ,EAAE,CAAC;CACZ,CAAC;AAEF,yDAAyD;AACzD,MAAM,UAAU,YAAY,CAAC,QAAkB;IAC7C,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAkB,EAAE,SAAmB;IAC7E,OAAO,YAAY,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,SAAS,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAA4B,EAAE,SAAmB;IAC5E,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,uBAAuB,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC;YAAE,OAAO,IAAI,CAAC;IAClE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,UAAU,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM;QAC1E,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,QAAQ,EAAE,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzF,IAAI,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjF,IAAI,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACpF,IAAI,OAAO,CAAC,QAAQ,EAAE,OAAO,IAAI,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1F,IAAI,OAAO,CAAC,QAAQ,EAAE,SAAS,IAAI,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,aAAa,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IAChG,MAAM,CAAC,IAAI,CAAC,SAAS,cAAc,CAAC,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IAEhF,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,KAAK,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC;AACtD,CAAC;AAED,0BAA0B;AAC1B,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,115 @@
1
+ export type Severity = 'low' | 'medium' | 'high' | 'critical';
2
+ /**
3
+ * Closed set of tool identifiers in the AI-agent governance suite. Adding a new
4
+ * tool requires updating this union, {@link TOOL_KINDS}, the `tool` enum in
5
+ * `schemas/finding.schema.json`, and the `kind` pattern regex in both this file
6
+ * and the schema — they are kept in lockstep by the test suite.
7
+ */
8
+ export type ToolKind = 'scope_trail' | 'policy_mesh' | 'capability_echo' | 'task_bound' | 'session_trail';
9
+ export interface FindingLocation {
10
+ file: string;
11
+ line?: number;
12
+ column?: number;
13
+ endLine?: number;
14
+ endColumn?: number;
15
+ }
16
+ export interface Finding {
17
+ /** Originating tool. */
18
+ tool: ToolKind;
19
+ /** Namespaced kind: `<tool_kind>.<short_slug>` (e.g. `scope_trail.permission_allow_widened`). */
20
+ kind: string;
21
+ severity: Severity;
22
+ /** Human-readable headline. Single line. */
23
+ message: string;
24
+ /** Optional longer-form explanation; can be multi-line. */
25
+ detail?: string;
26
+ location?: FindingLocation;
27
+ /** Stable identifier for dedupe across runs. Recommended: hash of (kind, location, salient fields). */
28
+ fingerprint?: string;
29
+ /** Optional structured metadata; downstream meta-reviewers may inspect it. */
30
+ data?: Record<string, unknown>;
31
+ }
32
+ export declare const SEVERITIES: readonly Severity[];
33
+ export declare const TOOL_KINDS: readonly ToolKind[];
34
+ export declare function isSeverity(value: unknown): value is Severity;
35
+ export declare function isToolKind(value: unknown): value is ToolKind;
36
+ /**
37
+ * Build a namespaced finding kind like `scope_trail.permission_allow_widened`
38
+ * without hand-assembling the dotted string. The `name` slug must match
39
+ * `[a-z0-9_]+` — the same pattern the JSON schema enforces.
40
+ *
41
+ * @throws if `name` contains characters outside the allowed slug class.
42
+ */
43
+ export declare function kind<T extends ToolKind>(tool: T, name: string): `${T}.${string}`;
44
+ /**
45
+ * Runtime guard matching the JSON schema's `kind` pattern. Useful for
46
+ * tools that want to assert their finding constructors produce valid
47
+ * namespaced kinds before emit.
48
+ */
49
+ export declare function isNamespacedKind(value: unknown): value is `${ToolKind}.${string}`;
50
+ /** Constructor spec for {@link createFinding}. */
51
+ export interface CreateFindingSpec {
52
+ tool: ToolKind;
53
+ /** Slug appended to `tool` to form `kind`. Must match `[a-z0-9_]+`. */
54
+ name: string;
55
+ severity: Severity;
56
+ message: string;
57
+ detail?: string;
58
+ location?: FindingLocation;
59
+ data?: Record<string, unknown>;
60
+ /** Optional explicit fingerprint. If omitted, {@link fingerprintFinding} is computed. */
61
+ fingerprint?: string;
62
+ }
63
+ /**
64
+ * Convenience constructor that assembles a {@link Finding} with a validated
65
+ * namespaced `kind` and a deterministic fingerprint. Equivalent to building the
66
+ * object literal by hand plus calling {@link kind} and {@link fingerprintFinding}.
67
+ *
68
+ * @example
69
+ * const f = createFinding({
70
+ * tool: 'scope_trail',
71
+ * name: 'permission_allow_widened',
72
+ * severity: 'high',
73
+ * message: 'Claude Code allow rule widened to Bash(npm *)',
74
+ * location: { file: '.claude/settings.json', line: 12 },
75
+ * });
76
+ * // f.kind === 'scope_trail.permission_allow_widened'
77
+ * // f.fingerprint === '<stable hex>'
78
+ */
79
+ export declare function createFinding(spec: CreateFindingSpec): Finding;
80
+ /**
81
+ * Stable 16-character hex fingerprint for a finding, derived from its routing
82
+ * fields (`kind`, `location.file`, `location.line`, `location.column`). Two
83
+ * findings emitted by the same tool against the same site collapse to the same
84
+ * fingerprint, so a downstream meta-reviewer can dedupe across runs.
85
+ *
86
+ * The fingerprint deliberately ignores `message`, `detail`, and `data` — those
87
+ * fields can drift across versions without changing the underlying issue.
88
+ *
89
+ * @example
90
+ * fingerprintFinding({
91
+ * tool: 'task_bound',
92
+ * kind: 'task_bound.out_of_scope_file',
93
+ * severity: 'medium',
94
+ * message: 'Touched file outside stated task',
95
+ * location: { file: 'src/index.ts', line: 42 },
96
+ * });
97
+ * // → '7e1c9b3a4d8f6e02'
98
+ */
99
+ export declare function fingerprintFinding(finding: Finding): string;
100
+ export interface FindingValidationResult {
101
+ ok: boolean;
102
+ errors: string[];
103
+ }
104
+ /**
105
+ * Runtime check that a value conforms to the canonical Finding schema
106
+ * (`schemas/finding.schema.json`). Returns the first error per offending
107
+ * field rather than throwing — meta-reviewers can collect errors across a
108
+ * batch and report them in aggregate.
109
+ *
110
+ * @example
111
+ * const result = validateFinding(jsonFromDisk);
112
+ * if (!result.ok) console.error(result.errors.join('\n'));
113
+ */
114
+ export declare function validateFinding(value: unknown): FindingValidationResult;
115
+ //# sourceMappingURL=finding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding.d.ts","sourceRoot":"","sources":["../src/finding.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAChB,aAAa,GACb,aAAa,GACb,iBAAiB,GACjB,YAAY,GACZ,eAAe,CAAC;AAEpB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,wBAAwB;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,iGAAiG;IACjG,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,uGAAuG;IACvG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,eAAO,MAAM,UAAU,EAAE,SAAS,QAAQ,EAA0C,CAAC;AAErF,eAAO,MAAM,UAAU,EAAE,SAAS,QAAQ,EAMzC,CAAC;AAEF,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,IAAI,MAAM,EAAE,CAOhF;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,GAAG,QAAQ,IAAI,MAAM,EAAE,CAEjF;AAED,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,yFAAyF;IACzF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAY9D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAQ3D;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAeD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAkCvE"}
@@ -0,0 +1,177 @@
1
+ import { createHash } from 'node:crypto';
2
+ export const SEVERITIES = ['low', 'medium', 'high', 'critical'];
3
+ export const TOOL_KINDS = [
4
+ 'scope_trail',
5
+ 'policy_mesh',
6
+ 'capability_echo',
7
+ 'task_bound',
8
+ 'session_trail',
9
+ ];
10
+ export function isSeverity(value) {
11
+ return typeof value === 'string' && SEVERITIES.includes(value);
12
+ }
13
+ export function isToolKind(value) {
14
+ return typeof value === 'string' && TOOL_KINDS.includes(value);
15
+ }
16
+ /**
17
+ * Build a namespaced finding kind like `scope_trail.permission_allow_widened`
18
+ * without hand-assembling the dotted string. The `name` slug must match
19
+ * `[a-z0-9_]+` — the same pattern the JSON schema enforces.
20
+ *
21
+ * @throws if `name` contains characters outside the allowed slug class.
22
+ */
23
+ export function kind(tool, name) {
24
+ if (!/^[a-z0-9_]+$/.test(name)) {
25
+ throw new Error(`agent-gov-core/kind: name '${name}' must match [a-z0-9_]+ (kebab, camelCase, and dots are rejected)`);
26
+ }
27
+ return `${tool}.${name}`;
28
+ }
29
+ const KIND_PATTERN = /^(scope_trail|policy_mesh|capability_echo|task_bound|session_trail)\.[a-z0-9_]+$/;
30
+ /**
31
+ * Runtime guard matching the JSON schema's `kind` pattern. Useful for
32
+ * tools that want to assert their finding constructors produce valid
33
+ * namespaced kinds before emit.
34
+ */
35
+ export function isNamespacedKind(value) {
36
+ return typeof value === 'string' && KIND_PATTERN.test(value);
37
+ }
38
+ /**
39
+ * Convenience constructor that assembles a {@link Finding} with a validated
40
+ * namespaced `kind` and a deterministic fingerprint. Equivalent to building the
41
+ * object literal by hand plus calling {@link kind} and {@link fingerprintFinding}.
42
+ *
43
+ * @example
44
+ * const f = createFinding({
45
+ * tool: 'scope_trail',
46
+ * name: 'permission_allow_widened',
47
+ * severity: 'high',
48
+ * message: 'Claude Code allow rule widened to Bash(npm *)',
49
+ * location: { file: '.claude/settings.json', line: 12 },
50
+ * });
51
+ * // f.kind === 'scope_trail.permission_allow_widened'
52
+ * // f.fingerprint === '<stable hex>'
53
+ */
54
+ export function createFinding(spec) {
55
+ const finding = {
56
+ tool: spec.tool,
57
+ kind: kind(spec.tool, spec.name),
58
+ severity: spec.severity,
59
+ message: spec.message,
60
+ };
61
+ if (spec.detail !== undefined)
62
+ finding.detail = spec.detail;
63
+ if (spec.location !== undefined)
64
+ finding.location = spec.location;
65
+ if (spec.data !== undefined)
66
+ finding.data = spec.data;
67
+ finding.fingerprint = spec.fingerprint ?? fingerprintFinding(finding);
68
+ return finding;
69
+ }
70
+ /**
71
+ * Stable 16-character hex fingerprint for a finding, derived from its routing
72
+ * fields (`kind`, `location.file`, `location.line`, `location.column`). Two
73
+ * findings emitted by the same tool against the same site collapse to the same
74
+ * fingerprint, so a downstream meta-reviewer can dedupe across runs.
75
+ *
76
+ * The fingerprint deliberately ignores `message`, `detail`, and `data` — those
77
+ * fields can drift across versions without changing the underlying issue.
78
+ *
79
+ * @example
80
+ * fingerprintFinding({
81
+ * tool: 'task_bound',
82
+ * kind: 'task_bound.out_of_scope_file',
83
+ * severity: 'medium',
84
+ * message: 'Touched file outside stated task',
85
+ * location: { file: 'src/index.ts', line: 42 },
86
+ * });
87
+ * // → '7e1c9b3a4d8f6e02'
88
+ */
89
+ export function fingerprintFinding(finding) {
90
+ const parts = [
91
+ finding.kind,
92
+ finding.location?.file ?? '',
93
+ finding.location?.line ?? '',
94
+ finding.location?.column ?? '',
95
+ ];
96
+ return createHash('sha256').update(parts.join('|')).digest('hex').slice(0, 16);
97
+ }
98
+ const FINDING_ALLOWED_KEYS = new Set([
99
+ 'tool',
100
+ 'kind',
101
+ 'severity',
102
+ 'message',
103
+ 'detail',
104
+ 'location',
105
+ 'fingerprint',
106
+ 'data',
107
+ ]);
108
+ const LOCATION_ALLOWED_KEYS = new Set(['file', 'line', 'column', 'endLine', 'endColumn']);
109
+ /**
110
+ * Runtime check that a value conforms to the canonical Finding schema
111
+ * (`schemas/finding.schema.json`). Returns the first error per offending
112
+ * field rather than throwing — meta-reviewers can collect errors across a
113
+ * batch and report them in aggregate.
114
+ *
115
+ * @example
116
+ * const result = validateFinding(jsonFromDisk);
117
+ * if (!result.ok) console.error(result.errors.join('\n'));
118
+ */
119
+ export function validateFinding(value) {
120
+ const errors = [];
121
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
122
+ return { ok: false, errors: ['finding must be a plain object'] };
123
+ }
124
+ const v = value;
125
+ if (!isToolKind(v.tool))
126
+ errors.push(`tool must be one of: ${TOOL_KINDS.join(', ')}`);
127
+ if (!isNamespacedKind(v.kind))
128
+ errors.push("kind must match '<tool>.<slug>' (e.g. 'scope_trail.permission_allow_widened')");
129
+ if (!isSeverity(v.severity))
130
+ errors.push(`severity must be one of: ${SEVERITIES.join(', ')}`);
131
+ if (typeof v.message !== 'string' || v.message.length === 0)
132
+ errors.push('message must be a non-empty string');
133
+ if (isToolKind(v.tool) && isNamespacedKind(v.kind) && !v.kind.startsWith(`${v.tool}.`)) {
134
+ errors.push(`kind '${v.kind}' must start with tool '${v.tool}.'`);
135
+ }
136
+ if (v.detail !== undefined && typeof v.detail !== 'string') {
137
+ errors.push('detail must be a string when present');
138
+ }
139
+ if (v.fingerprint !== undefined && typeof v.fingerprint !== 'string') {
140
+ errors.push('fingerprint must be a string when present');
141
+ }
142
+ if (v.data !== undefined && (v.data === null || typeof v.data !== 'object' || Array.isArray(v.data))) {
143
+ errors.push('data must be an object when present');
144
+ }
145
+ if (v.location !== undefined) {
146
+ errors.push(...validateLocation(v.location));
147
+ }
148
+ for (const key of Object.keys(v)) {
149
+ if (!FINDING_ALLOWED_KEYS.has(key))
150
+ errors.push(`unknown property: ${key}`);
151
+ }
152
+ return { ok: errors.length === 0, errors };
153
+ }
154
+ function validateLocation(value) {
155
+ const errors = [];
156
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
157
+ return ['location must be an object when present'];
158
+ }
159
+ const loc = value;
160
+ if (typeof loc.file !== 'string' || loc.file.length === 0) {
161
+ errors.push('location.file must be a non-empty string');
162
+ }
163
+ for (const field of ['line', 'column', 'endLine', 'endColumn']) {
164
+ if (loc[field] !== undefined) {
165
+ const n = loc[field];
166
+ if (typeof n !== 'number' || !Number.isInteger(n) || n < 1) {
167
+ errors.push(`location.${field} must be a positive integer when present`);
168
+ }
169
+ }
170
+ }
171
+ for (const key of Object.keys(loc)) {
172
+ if (!LOCATION_ALLOWED_KEYS.has(key))
173
+ errors.push(`unknown location property: ${key}`);
174
+ }
175
+ return errors;
176
+ }
177
+ //# sourceMappingURL=finding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding.js","sourceRoot":"","sources":["../src/finding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export type { Finding, FindingLocation, Severity, ToolKind, CreateFindingSpec, FindingValidationResult, } from './finding.js';
2
+ export { SEVERITIES, TOOL_KINDS, isSeverity, isToolKind, isNamespacedKind, kind, createFinding, fingerprintFinding, validateFinding, } from './finding.js';
3
+ export type { JsonObjectWithSource } from './jsonc.js';
4
+ export { readJsonObjectWithSource, stripJsonComments } from './jsonc.js';
5
+ export type { TomlObjectWithSource } from './toml.js';
6
+ export { readTomlObject, parseToml } from './toml.js';
7
+ export type { ByteRange } from './locators.js';
8
+ export { lineOfJsonKey, lineOfJsonStringValue, lineOfTomlKey, } from './locators.js';
9
+ export type { McpCommandSpec } from './mcp.js';
10
+ export { normalizeMcpCommand } from './mcp.js';
11
+ export { tokenizeShell, getCommandHead } from './shell.js';
12
+ export { rankSeverity, passesSeverityThreshold, anyAtOrAbove, emitFindingAnnotation, } from './action.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,OAAO,EACP,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,IAAI,EACJ,aAAa,EACb,kBAAkB,EAClB,eAAe,GAChB,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEzE,YAAY,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtD,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,YAAY,EACZ,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { SEVERITIES, TOOL_KINDS, isSeverity, isToolKind, isNamespacedKind, kind, createFinding, fingerprintFinding, validateFinding, } from './finding.js';
2
+ export { readJsonObjectWithSource, stripJsonComments } from './jsonc.js';
3
+ export { readTomlObject, parseToml } from './toml.js';
4
+ export { lineOfJsonKey, lineOfJsonStringValue, lineOfTomlKey, } from './locators.js';
5
+ export { normalizeMcpCommand } from './mcp.js';
6
+ export { tokenizeShell, getCommandHead } from './shell.js';
7
+ export { rankSeverity, passesSeverityThreshold, anyAtOrAbove, emitFindingAnnotation, } from './action.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,IAAI,EACJ,aAAa,EACb,kBAAkB,EAClB,eAAe,GAChB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGzE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtD,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,aAAa,GACd,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,YAAY,EACZ,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,20 @@
1
+ export interface JsonObjectWithSource {
2
+ /** Parsed JSON value, or `undefined` if parsing failed. */
3
+ json: unknown;
4
+ /** Raw file text (untouched). */
5
+ text: string;
6
+ /** Set when parsing failed. */
7
+ parseError?: Error;
8
+ }
9
+ /**
10
+ * Strip `//` line comments, `/* ... *\/` block comments, and trailing commas from JSONC,
11
+ * preserving byte offsets (replacement is space-filled, newlines preserved) so downstream
12
+ * line locators still match the original `text`.
13
+ */
14
+ export declare function stripJsonComments(input: string): string;
15
+ /**
16
+ * Read a JSONC file and return both the parsed value and the original text.
17
+ * The original text is preserved exactly so line locators can operate on it.
18
+ */
19
+ export declare function readJsonObjectWithSource(path: string): JsonObjectWithSource;
20
+ //# sourceMappingURL=jsonc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonc.d.ts","sourceRoot":"","sources":["../src/jsonc.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,IAAI,EAAE,OAAO,CAAC;IACd,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,UAAU,CAAC,EAAE,KAAK,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAoEvD;AA8BD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAS3E"}