@coderifts/agent-guard 1.0.0 → 1.2.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 (84) hide show
  1. package/README.md +27 -2
  2. package/dist/cjs/artifact-resolver.d.ts +76 -0
  3. package/dist/cjs/artifact-resolver.d.ts.map +1 -0
  4. package/dist/cjs/artifact-resolver.js +413 -0
  5. package/dist/cjs/artifact-resolver.js.map +1 -0
  6. package/dist/cjs/detector.d.ts +1 -1
  7. package/dist/cjs/detector.d.ts.map +1 -1
  8. package/dist/cjs/detector.js +176 -3
  9. package/dist/cjs/detector.js.map +1 -1
  10. package/dist/cjs/enforcement-gate.d.ts +42 -0
  11. package/dist/cjs/enforcement-gate.d.ts.map +1 -0
  12. package/dist/cjs/enforcement-gate.js +106 -0
  13. package/dist/cjs/enforcement-gate.js.map +1 -0
  14. package/dist/cjs/guard.d.ts.map +1 -1
  15. package/dist/cjs/guard.js +87 -29
  16. package/dist/cjs/guard.js.map +1 -1
  17. package/dist/cjs/index.d.ts +11 -0
  18. package/dist/cjs/index.d.ts.map +1 -1
  19. package/dist/cjs/index.js +35 -1
  20. package/dist/cjs/index.js.map +1 -1
  21. package/dist/cjs/receipt-binding.d.ts +60 -0
  22. package/dist/cjs/receipt-binding.d.ts.map +1 -0
  23. package/dist/cjs/receipt-binding.js +110 -0
  24. package/dist/cjs/receipt-binding.js.map +1 -0
  25. package/dist/cjs/resolver-glob.d.ts +15 -0
  26. package/dist/cjs/resolver-glob.d.ts.map +1 -0
  27. package/dist/cjs/resolver-glob.js +65 -0
  28. package/dist/cjs/resolver-glob.js.map +1 -0
  29. package/dist/cjs/resolver-yaml.d.ts +20 -0
  30. package/dist/cjs/resolver-yaml.d.ts.map +1 -0
  31. package/dist/cjs/resolver-yaml.js +235 -0
  32. package/dist/cjs/resolver-yaml.js.map +1 -0
  33. package/dist/cjs/session-taint.d.ts +97 -0
  34. package/dist/cjs/session-taint.d.ts.map +1 -0
  35. package/dist/cjs/session-taint.js +317 -0
  36. package/dist/cjs/session-taint.js.map +1 -0
  37. package/dist/cjs/tool-registry.d.ts +88 -0
  38. package/dist/cjs/tool-registry.d.ts.map +1 -0
  39. package/dist/cjs/tool-registry.js +274 -0
  40. package/dist/cjs/tool-registry.js.map +1 -0
  41. package/dist/cjs/types.d.ts +2 -2
  42. package/dist/cjs/types.d.ts.map +1 -1
  43. package/dist/esm/artifact-resolver.d.ts +76 -0
  44. package/dist/esm/artifact-resolver.d.ts.map +1 -0
  45. package/dist/esm/artifact-resolver.js +410 -0
  46. package/dist/esm/artifact-resolver.js.map +1 -0
  47. package/dist/esm/detector.d.ts +1 -1
  48. package/dist/esm/detector.d.ts.map +1 -1
  49. package/dist/esm/detector.js +176 -3
  50. package/dist/esm/detector.js.map +1 -1
  51. package/dist/esm/enforcement-gate.d.ts +42 -0
  52. package/dist/esm/enforcement-gate.d.ts.map +1 -0
  53. package/dist/esm/enforcement-gate.js +101 -0
  54. package/dist/esm/enforcement-gate.js.map +1 -0
  55. package/dist/esm/guard.d.ts.map +1 -1
  56. package/dist/esm/guard.js +87 -29
  57. package/dist/esm/guard.js.map +1 -1
  58. package/dist/esm/index.d.ts +11 -0
  59. package/dist/esm/index.d.ts.map +1 -1
  60. package/dist/esm/index.js +13 -0
  61. package/dist/esm/index.js.map +1 -1
  62. package/dist/esm/receipt-binding.d.ts +60 -0
  63. package/dist/esm/receipt-binding.d.ts.map +1 -0
  64. package/dist/esm/receipt-binding.js +105 -0
  65. package/dist/esm/receipt-binding.js.map +1 -0
  66. package/dist/esm/resolver-glob.d.ts +15 -0
  67. package/dist/esm/resolver-glob.d.ts.map +1 -0
  68. package/dist/esm/resolver-glob.js +59 -0
  69. package/dist/esm/resolver-glob.js.map +1 -0
  70. package/dist/esm/resolver-yaml.d.ts +20 -0
  71. package/dist/esm/resolver-yaml.d.ts.map +1 -0
  72. package/dist/esm/resolver-yaml.js +229 -0
  73. package/dist/esm/resolver-yaml.js.map +1 -0
  74. package/dist/esm/session-taint.d.ts +97 -0
  75. package/dist/esm/session-taint.d.ts.map +1 -0
  76. package/dist/esm/session-taint.js +305 -0
  77. package/dist/esm/session-taint.js.map +1 -0
  78. package/dist/esm/tool-registry.d.ts +88 -0
  79. package/dist/esm/tool-registry.d.ts.map +1 -0
  80. package/dist/esm/tool-registry.js +269 -0
  81. package/dist/esm/tool-registry.js.map +1 -0
  82. package/dist/esm/types.d.ts +2 -2
  83. package/dist/esm/types.d.ts.map +1 -1
  84. package/package.json +2 -2
@@ -0,0 +1,229 @@
1
+ /**
2
+ * resolver-yaml — a MINIMAL, deterministic YAML/JSON reader for the artifact resolver's $ref bundler.
3
+ *
4
+ * The guard package has no YAML dependency; the resolver only needs to parse the constrained YAML
5
+ * that appears in OpenAPI/AsyncAPI contract docs (block mappings, flow mappings, quoted keys, scalar
6
+ * values, and `$ref` strings) to inline external file refs into a deterministic JSON bundle (§4.3).
7
+ * It is NOT a general YAML engine — anything outside the supported subset throws, and the resolver
8
+ * turns that into a `parse_error` unresolved entry (never a fabricated document).
9
+ *
10
+ * Determinism: plain scalars are kept as raw strings (no lossy type coercion), so parse→serialize is
11
+ * byte-stable per input.
12
+ */
13
+ export class YamlLiteError extends Error {
14
+ constructor(message) { super(message); this.name = 'YamlLiteError'; }
15
+ }
16
+ /** Parse a JSON or (subset) YAML document to a plain JS value. Throws YamlLiteError on unsupported input. */
17
+ export function parseDoc(text) {
18
+ const trimmed = text.trimStart();
19
+ if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
20
+ try {
21
+ return JSON.parse(text);
22
+ }
23
+ catch (e) {
24
+ throw new YamlLiteError(`invalid JSON: ${e.message}`);
25
+ }
26
+ }
27
+ const lines = [];
28
+ for (const raw of text.split('\n')) {
29
+ const trimmedLine = raw.trim();
30
+ if (trimmedLine === '' || trimmedLine.startsWith('#'))
31
+ continue;
32
+ lines.push({ indent: raw.length - raw.trimStart().length, text: trimmedLine });
33
+ }
34
+ if (lines.length === 0)
35
+ return null;
36
+ const [value] = parseBlock(lines, 0, lines[0].indent);
37
+ return value;
38
+ }
39
+ function parseBlock(lines, start, indent) {
40
+ if (start >= lines.length)
41
+ return [null, start];
42
+ const first = lines[start];
43
+ if (first.text === '-' || first.text.startsWith('- '))
44
+ return parseSequence(lines, start, indent);
45
+ return parseMapping(lines, start, indent);
46
+ }
47
+ function parseMapping(lines, start, indent) {
48
+ const obj = {};
49
+ let i = start;
50
+ while (i < lines.length && lines[i].indent === indent) {
51
+ const { key, rest } = splitKeyValue(lines[i].text);
52
+ i += 1;
53
+ if (rest === '') {
54
+ if (i < lines.length && lines[i].indent > indent) {
55
+ const [child, next] = parseBlock(lines, i, lines[i].indent);
56
+ obj[key] = child;
57
+ i = next;
58
+ }
59
+ else {
60
+ obj[key] = null;
61
+ }
62
+ }
63
+ else {
64
+ obj[key] = parseScalarOrFlow(rest);
65
+ }
66
+ }
67
+ return [obj, i];
68
+ }
69
+ function parseSequence(lines, start, indent) {
70
+ const arr = [];
71
+ let i = start;
72
+ while (i < lines.length && lines[i].indent === indent && (lines[i].text === '-' || lines[i].text.startsWith('- '))) {
73
+ const itemText = lines[i].text.slice(1).trim();
74
+ i += 1;
75
+ if (itemText === '') {
76
+ if (i < lines.length && lines[i].indent > indent) {
77
+ const [child, next] = parseBlock(lines, i, lines[i].indent);
78
+ arr.push(child);
79
+ i = next;
80
+ }
81
+ else {
82
+ arr.push(null);
83
+ }
84
+ }
85
+ else {
86
+ arr.push(parseScalarOrFlow(itemText));
87
+ }
88
+ }
89
+ return [arr, i];
90
+ }
91
+ /** Split "key: rest" honoring a quoted key; the separator is the first top-level colon. */
92
+ function splitKeyValue(text) {
93
+ let key;
94
+ let idx;
95
+ if (text[0] === "'" || text[0] === '"') {
96
+ const q = text[0];
97
+ let j = 1;
98
+ while (j < text.length && text[j] !== q)
99
+ j += 1;
100
+ key = text.slice(1, j);
101
+ idx = text.indexOf(':', j);
102
+ }
103
+ else {
104
+ idx = text.indexOf(':');
105
+ key = idx === -1 ? text : text.slice(0, idx);
106
+ }
107
+ if (idx === -1)
108
+ return { key: key.trim(), rest: '' };
109
+ return { key: key.trim(), rest: text.slice(idx + 1).trim() };
110
+ }
111
+ function parseScalarOrFlow(s) {
112
+ const t = s.trim();
113
+ if (t === '' || t === '~' || t === 'null')
114
+ return null;
115
+ if (t[0] === '{' || t[0] === '[')
116
+ return parseFlow(t).value;
117
+ if (t[0] === "'" || t[0] === '"')
118
+ return unquote(t);
119
+ return t;
120
+ }
121
+ function unquote(t) {
122
+ const q = t[0];
123
+ let j = 1;
124
+ let out = '';
125
+ while (j < t.length && t[j] !== q) {
126
+ out += t[j];
127
+ j += 1;
128
+ }
129
+ return out;
130
+ }
131
+ function parseFlow(s) {
132
+ if (s[0] === '{')
133
+ return parseFlowMap(s);
134
+ if (s[0] === '[')
135
+ return parseFlowSeq(s);
136
+ throw new YamlLiteError(`not a flow collection: ${s.slice(0, 20)}`);
137
+ }
138
+ function parseFlowMap(s) {
139
+ const obj = {};
140
+ let i = 1;
141
+ while (i < s.length) {
142
+ while (i < s.length && (s[i] === ' ' || s[i] === ','))
143
+ i += 1;
144
+ if (s[i] === '}')
145
+ return { value: obj, end: i + 1 };
146
+ let key;
147
+ if (s[i] === "'" || s[i] === '"') {
148
+ const q = s[i];
149
+ let j = i + 1;
150
+ let k = '';
151
+ while (j < s.length && s[j] !== q) {
152
+ k += s[j];
153
+ j += 1;
154
+ }
155
+ key = k;
156
+ i = j + 1;
157
+ }
158
+ else {
159
+ let k = '';
160
+ while (i < s.length && s[i] !== ':' && s[i] !== '}' && s[i] !== ',') {
161
+ k += s[i];
162
+ i += 1;
163
+ }
164
+ key = k.trim();
165
+ }
166
+ while (i < s.length && (s[i] === ' ' || s[i] === ':'))
167
+ i += 1;
168
+ const [val, next] = readFlowValue(s, i);
169
+ obj[key] = val;
170
+ i = next;
171
+ }
172
+ throw new YamlLiteError(`unterminated flow map: ${s.slice(0, 40)}`);
173
+ }
174
+ function parseFlowSeq(s) {
175
+ const arr = [];
176
+ let i = 1;
177
+ while (i < s.length) {
178
+ while (i < s.length && (s[i] === ' ' || s[i] === ','))
179
+ i += 1;
180
+ if (s[i] === ']')
181
+ return { value: arr, end: i + 1 };
182
+ const [val, next] = readFlowValue(s, i);
183
+ arr.push(val);
184
+ i = next;
185
+ }
186
+ throw new YamlLiteError(`unterminated flow seq: ${s.slice(0, 40)}`);
187
+ }
188
+ function readFlowValue(s, start) {
189
+ let i = start;
190
+ while (i < s.length && s[i] === ' ')
191
+ i += 1;
192
+ if (s[i] === '{' || s[i] === '[') {
193
+ const { value, end } = parseFlow(s.slice(i));
194
+ return [value, i + end];
195
+ }
196
+ if (s[i] === "'" || s[i] === '"') {
197
+ const q = s[i];
198
+ let j = i + 1;
199
+ let out = '';
200
+ while (j < s.length && s[j] !== q) {
201
+ out += s[j];
202
+ j += 1;
203
+ }
204
+ return [out, j + 1];
205
+ }
206
+ let out = '';
207
+ while (i < s.length && s[i] !== ',' && s[i] !== '}' && s[i] !== ']') {
208
+ out += s[i];
209
+ i += 1;
210
+ }
211
+ return [out.trim(), i];
212
+ }
213
+ /** Deterministic JSON serialization with recursively sorted object keys (byte-stable — §4.3, A6). */
214
+ export function stableStringify(value) {
215
+ return JSON.stringify(sortKeys(value));
216
+ }
217
+ function sortKeys(value) {
218
+ if (Array.isArray(value))
219
+ return value.map(sortKeys);
220
+ if (value && typeof value === 'object') {
221
+ const out = {};
222
+ for (const k of Object.keys(value).sort()) {
223
+ out[k] = sortKeys(value[k]);
224
+ }
225
+ return out;
226
+ }
227
+ return value;
228
+ }
229
+ //# sourceMappingURL=resolver-yaml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver-yaml.js","sourceRoot":"","sources":["../../src/resolver-yaml.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @coderifts/agent-guard — process-local session-taint detector (SEPARATE surface).
3
+ *
4
+ * Implements session-taint-detector-SPEC.md verbatim: a multi-call taint tracker that flags when a
5
+ * session both accumulates contract taint AND emits an SSOT sink — closing the gap where a sequence
6
+ * passes single-call DG-1 yet mutates SSOT. Additive: the frozen `builtinDetector.detect()` is NOT
7
+ * touched. Versioned SEPARATELY (session-taint/1.0.0), monotonic toward caution.
8
+ *
9
+ * Normative: flag ⇔ ssot_sink_events ≠ ∅ ∧ tainted. Fixture-faithful classifier order (§1.6: NON_SINK
10
+ * first, so snapshot/prettier stay under-set — a documented, Peter-accepted quirk; flag unaffected).
11
+ */
12
+ import type { ToolCallDescriptor } from './types.js';
13
+ export declare const SESSION_TAINT_VERSION = "session-taint/1.0.0";
14
+ export type PathClass = 'prose' | 'scratch' | 'migration' | 'ssot' | 'code_or_config' | 'other';
15
+ export declare function pathClass(p: string): PathClass;
16
+ export type PendingRename = {
17
+ from: string;
18
+ to: string;
19
+ } | {
20
+ drop: string;
21
+ };
22
+ export interface SessionState {
23
+ scratch_writes: string[];
24
+ contract_looking_scratch: string[];
25
+ encoded_fragments: string[];
26
+ intermediate_artifacts: string[];
27
+ pending_renames: PendingRename[];
28
+ optional_fields_added: string[];
29
+ required_fields_declared: string[];
30
+ ssot_paths_touched: string[];
31
+ ssot_sink_events: string[];
32
+ ssot_invalidated: boolean;
33
+ reverse_snapshot: boolean;
34
+ formatter_only_ssot: boolean;
35
+ store_keys: string[];
36
+ tainted: boolean;
37
+ }
38
+ export declare function emptySessionState(): SessionState;
39
+ /** Serialize to the fixture's projected form (pending_renames -> "from->to" | "drop:name"). */
40
+ export declare function projectState(s: SessionState): Record<string, unknown>;
41
+ export type CmdClass = 'non_sink' | 'ssot_invalidate' | 'ssot_sink' | 'reverse_snapshot' | 'formatter' | 'unknown_script';
42
+ export declare function classifyCommand(command: string, action: string, cfg?: SessionTaintConfig): CmdClass;
43
+ export declare function updateSession(state: SessionState, call: {
44
+ toolName?: string;
45
+ arguments?: unknown;
46
+ }, cfg?: SessionTaintConfig): SessionState;
47
+ export declare function computeTainted(s: SessionState): boolean;
48
+ export interface SessionEval {
49
+ flag: boolean;
50
+ trip: boolean;
51
+ key_signal: string | null;
52
+ }
53
+ export declare function deriveKeySignal(s: SessionState): string;
54
+ /** flag ⇔ (ssot_sink_events ≠ ∅ || sink_seen) ∧ (tainted || overflow). */
55
+ export declare function evaluate(state: SessionState, prevFlagged?: boolean, opts?: {
56
+ overflow?: boolean;
57
+ sinkSeen?: boolean;
58
+ }): SessionEval;
59
+ export interface SessionTaintConfig {
60
+ extraSinkPatterns?: RegExp[];
61
+ extraNonSinkPatterns?: RegExp[];
62
+ maxCalls?: number;
63
+ maxPathsTracked?: number;
64
+ maxSinkEvents?: number;
65
+ maxStateBytes?: number;
66
+ ttlMs?: number;
67
+ bindCwd?: boolean;
68
+ sessionId?: string;
69
+ sessionTaintSeverity?: 'caution' | 'stop';
70
+ }
71
+ export interface SessionTaintObservation {
72
+ flag: boolean;
73
+ trip: boolean;
74
+ key_signal: string | null;
75
+ state: Readonly<SessionState>;
76
+ version: typeof SESSION_TAINT_VERSION;
77
+ overflow: boolean;
78
+ severity: 'caution' | 'stop';
79
+ }
80
+ export declare class SessionTaintTracker {
81
+ readonly version = "session-taint/1.0.0";
82
+ private state;
83
+ private prevFlag;
84
+ private callCount;
85
+ private overflow;
86
+ private sinkSeen;
87
+ private lastObserveAt;
88
+ private cfg;
89
+ constructor(config?: SessionTaintConfig);
90
+ private pathTotal;
91
+ observe(call: ToolCallDescriptor): SessionTaintObservation;
92
+ status(): SessionTaintObservation;
93
+ reset(): void;
94
+ private snapshot;
95
+ private now;
96
+ }
97
+ //# sourceMappingURL=session-taint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-taint.d.ts","sourceRoot":"","sources":["../../src/session-taint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,305 @@
1
+ /**
2
+ * @coderifts/agent-guard — process-local session-taint detector (SEPARATE surface).
3
+ *
4
+ * Implements session-taint-detector-SPEC.md verbatim: a multi-call taint tracker that flags when a
5
+ * session both accumulates contract taint AND emits an SSOT sink — closing the gap where a sequence
6
+ * passes single-call DG-1 yet mutates SSOT. Additive: the frozen `builtinDetector.detect()` is NOT
7
+ * touched. Versioned SEPARATELY (session-taint/1.0.0), monotonic toward caution.
8
+ *
9
+ * Normative: flag ⇔ ssot_sink_events ≠ ∅ ∧ tainted. Fixture-faithful classifier order (§1.6: NON_SINK
10
+ * first, so snapshot/prettier stay under-set — a documented, Peter-accepted quirk; flag unaffected).
11
+ */
12
+ export const SESSION_TAINT_VERSION = 'session-taint/1.0.0';
13
+ // ── §1.3 classifiers ─────────────────────────────────────────────────────────────────────────
14
+ const NON_SSOT_RE = /(^|\/)(tests?|__tests__|fixtures?|__mocks__|src\/internal)\//i;
15
+ const PIPELINE_SCRATCH_RE = /(^|\/)(build|\.cache|codegen|idl)(\/|$)/i;
16
+ const PROSE_RE = /(^|\/)(README|CHANGELOG|LICENSE)(\.\w+)?$|\.md$/i;
17
+ const SSOT_PATH_RE = /(^|\/)(openapi|swagger|asyncapi)[^/]*\.(ya?ml|json)$|(^|\/)mcp\.json$|\.graphql$|\.gql$|(^|\/)idl\/.*\.proto$|(^|\/)specs?\/.*\.(ya?ml|json)$|openapi\.yaml|schema\.graphql|asyncapi\.yaml/i;
18
+ const MIGRATION_RE = /(^|\/)migrations?\//i;
19
+ const CODE_OR_CONFIG_RE = /\.(ts|tsx|js|jsx)$/i;
20
+ const CONTRACT_CONTENT_RE = /\bopenapi\s*[:=]|\bswagger\s*[:=]|\basyncapi\s*[:=]|syntax\s*=\s*["']proto3|["']inputSchema["']|\btype\s+Query\b|(^|\n)\s*paths\s*:/i;
21
+ const STAGING_NAME_RE = /\.b64$|enc\/|field-map|flags\.json|optional_fields|required_fields|service\.idl|frags\/|BREAKING_DROP/i;
22
+ const NON_SINK_RE = /validate-frags|gen-docs|reload-flags|snapshot-spec|prettier|npm test|npm install|npx prettier/i;
23
+ const SSOT_INVALIDATE_RE = /archive-old-spec/i;
24
+ const SSOT_SINK_RE = /dsl-to-openapi|merge-spec|publish-fixture|promote-spec|sync-graphql|b64join-write|decode-promote|apply-field-map|render-openapi|idl\/compile|generate-and-test|compile_spec_bundle|install-proto|install-mcp|promote-asyncapi|repack-extract|codegen\/build\.js|codegen\/apply|codegen\/render/i;
25
+ export function pathClass(p) {
26
+ if (PROSE_RE.test(p))
27
+ return 'prose';
28
+ if (NON_SSOT_RE.test(p) || PIPELINE_SCRATCH_RE.test(p))
29
+ return 'scratch';
30
+ if (MIGRATION_RE.test(p))
31
+ return 'migration';
32
+ if (SSOT_PATH_RE.test(p))
33
+ return 'ssot';
34
+ if (CODE_OR_CONFIG_RE.test(p) || p.startsWith('src/') || p.startsWith('config/') || p === 'package.json')
35
+ return 'code_or_config';
36
+ return 'other';
37
+ }
38
+ export function emptySessionState() {
39
+ return {
40
+ scratch_writes: [], contract_looking_scratch: [], encoded_fragments: [], intermediate_artifacts: [],
41
+ pending_renames: [], optional_fields_added: [], required_fields_declared: [], ssot_paths_touched: [],
42
+ ssot_sink_events: [], ssot_invalidated: false, reverse_snapshot: false, formatter_only_ssot: false,
43
+ store_keys: [], tainted: false,
44
+ };
45
+ }
46
+ /** Serialize to the fixture's projected form (pending_renames -> "from->to" | "drop:name"). */
47
+ export function projectState(s) {
48
+ return {
49
+ scratch_writes: s.scratch_writes.slice(),
50
+ encoded_fragments: s.encoded_fragments.slice(),
51
+ pending_renames: s.pending_renames.map((r) => ('drop' in r ? `drop:${r.drop}` : `${r.from}->${r.to}`)),
52
+ optional_fields_added: s.optional_fields_added.slice(),
53
+ required_fields_declared: s.required_fields_declared.slice(),
54
+ ssot_paths_touched: s.ssot_paths_touched.slice(),
55
+ contract_looking_scratch: s.contract_looking_scratch.slice(),
56
+ intermediate_artifacts: s.intermediate_artifacts.slice(),
57
+ ssot_sink_events: s.ssot_sink_events.slice(),
58
+ ssot_invalidated: s.ssot_invalidated,
59
+ reverse_snapshot: s.reverse_snapshot,
60
+ formatter_only_ssot: s.formatter_only_ssot,
61
+ store_keys: s.store_keys.slice(),
62
+ tainted: s.tainted,
63
+ };
64
+ }
65
+ // ── §2.2 extractors ──────────────────────────────────────────────────────────────────────────
66
+ function asRecord(args) { return args && typeof args === 'object' ? args : {}; }
67
+ function extractPaths(args) {
68
+ const a = asRecord(args);
69
+ const out = [];
70
+ for (const k of ['path', 'target', 'file', 'dest', 'filename', 'destination'])
71
+ if (typeof a[k] === 'string')
72
+ out.push(a[k]);
73
+ return out;
74
+ }
75
+ function extractContent(args) {
76
+ const a = asRecord(args);
77
+ const parts = [];
78
+ for (const k of ['contents', 'content', 'new_string', 'old_string', 'patch', 'value', 'command'])
79
+ if (typeof a[k] === 'string')
80
+ parts.push(a[k]);
81
+ return parts.join('\n');
82
+ }
83
+ // ── §2.3 encoded-fragment heuristic (fixture-faithful — do not "fix" without regenerating) ──────
84
+ function isEncodedFragment(path, content) {
85
+ if (path && /part\.|enc\/|\.b64$|pkg\.part/i.test(path))
86
+ return true;
87
+ const c = content.replace(/\s+/g, '');
88
+ if (c.length >= 8 && c.length < 80 && /^[A-Za-z0-9+/=]+$/.test(c))
89
+ return true;
90
+ return false;
91
+ }
92
+ export function classifyCommand(command, action, cfg = {}) {
93
+ const s = `${command || ''} ${action || ''}`;
94
+ const extraNon = cfg.extraNonSinkPatterns || [];
95
+ const extraSink = cfg.extraSinkPatterns || [];
96
+ if (NON_SINK_RE.test(s) || extraNon.some((r) => r.test(s)))
97
+ return 'non_sink';
98
+ if (SSOT_INVALIDATE_RE.test(s))
99
+ return 'ssot_invalidate';
100
+ if (SSOT_SINK_RE.test(s) || action === 'compile_spec_bundle' || extraSink.some((r) => r.test(s)))
101
+ return 'ssot_sink';
102
+ if (/snapshot/i.test(s))
103
+ return 'reverse_snapshot';
104
+ if (/prettier|format/i.test(s))
105
+ return 'formatter';
106
+ return 'unknown_script';
107
+ }
108
+ function pushUniq(arr, v) { if (v != null && !arr.includes(v))
109
+ arr.push(v); }
110
+ // ── §2.5 transition ────────────────────────────────────────────────────────────────────────────
111
+ export function updateSession(state, call, cfg = {}) {
112
+ const s = JSON.parse(JSON.stringify(state)); // pure: new state
113
+ const args = asRecord(call && call.arguments);
114
+ const paths = extractPaths(args);
115
+ const content = extractContent(args);
116
+ const tool = call && call.toolName;
117
+ // store
118
+ if (tool === 'store' && typeof args.key === 'string') {
119
+ pushUniq(s.store_keys, args.key);
120
+ if (/spec_|api_|openapi|schema/i.test(args.key) || /BREAKING|ROUTE|FIELD|REMOVE|MANDATORY|required|optional/i.test(String(args.value))) {
121
+ pushUniq(s.intermediate_artifacts, `store:${args.key}`);
122
+ }
123
+ }
124
+ // apply
125
+ if (tool === 'apply' && typeof args.action === 'string') {
126
+ if (classifyCommand('', args.action, cfg) === 'ssot_sink')
127
+ s.ssot_sink_events.push(args.action);
128
+ }
129
+ // Bash / command
130
+ if (tool === 'Bash' || typeof args.command === 'string') {
131
+ const cmd = typeof args.command === 'string' ? args.command : '';
132
+ const kind = classifyCommand(cmd, '', cfg);
133
+ if (kind === 'ssot_sink')
134
+ s.ssot_sink_events.push(cmd);
135
+ if (kind === 'ssot_invalidate')
136
+ s.ssot_invalidated = true;
137
+ if (kind === 'reverse_snapshot')
138
+ s.reverse_snapshot = true;
139
+ if (kind === 'formatter' && (SSOT_PATH_RE.test(cmd) || /openapi|swagger|asyncapi|\.graphql|\.gql|mcp\.json|schema/i.test(cmd)))
140
+ s.formatter_only_ssot = true;
141
+ }
142
+ // path-bearing writes/edits
143
+ for (const p of paths) {
144
+ const pc = pathClass(p);
145
+ const isScratch = pc === 'scratch' || NON_SSOT_RE.test(p) || PIPELINE_SCRATCH_RE.test(p);
146
+ if (isScratch) {
147
+ pushUniq(s.scratch_writes, p);
148
+ if (CONTRACT_CONTENT_RE.test(content) || STAGING_NAME_RE.test(p + content))
149
+ pushUniq(s.contract_looking_scratch, p);
150
+ if (PIPELINE_SCRATCH_RE.test(p))
151
+ pushUniq(s.intermediate_artifacts, p);
152
+ if (isEncodedFragment(p, content) || /\.b64$/i.test(p) || /enc\//i.test(p) || /pkg\.part/i.test(p))
153
+ pushUniq(s.encoded_fragments, p);
154
+ if (/field-map|flags\.json|optional_fields|required_fields|\.idl$/i.test(p))
155
+ pushUniq(s.intermediate_artifacts, p);
156
+ }
157
+ if (pc === 'ssot' && !(tool === 'Bash' && /prettier/i.test(typeof args.command === 'string' ? args.command : '')))
158
+ pushUniq(s.ssot_paths_touched, p);
159
+ // field-map JSON
160
+ if (/field-map/i.test(p)) {
161
+ let obj;
162
+ try {
163
+ obj = JSON.parse(content);
164
+ }
165
+ catch {
166
+ obj = null;
167
+ }
168
+ if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
169
+ for (const [k, v] of Object.entries(obj)) {
170
+ if (k === '__drop' && Array.isArray(v)) {
171
+ for (const d of v)
172
+ s.pending_renames.push({ drop: String(d) });
173
+ }
174
+ else if (typeof v === 'string')
175
+ s.pending_renames.push({ from: k, to: v });
176
+ }
177
+ }
178
+ }
179
+ // flags.json optional/required
180
+ if (/flags\.json/i.test(p)) {
181
+ for (const m of content.matchAll(/"(\w+)":\s*"optional"/g))
182
+ pushUniq(s.optional_fields_added, m[1]);
183
+ for (const m of content.matchAll(/"(\w+)":\s*"required"/g))
184
+ pushUniq(s.required_fields_declared, m[1]);
185
+ }
186
+ // list files
187
+ if (/optional_fields/i.test(p))
188
+ for (const line of content.split('\n'))
189
+ if (line.trim())
190
+ pushUniq(s.optional_fields_added, line.trim());
191
+ if (/required_fields/i.test(p))
192
+ for (const line of content.split('\n'))
193
+ if (line.trim())
194
+ pushUniq(s.required_fields_declared, line.trim());
195
+ // ST-009 yaml heuristics
196
+ if (NON_SSOT_RE.test(p) && /required:\s*\[[^\]]*owner_id/.test(content))
197
+ pushUniq(s.required_fields_declared, 'owner_id');
198
+ if (NON_SSOT_RE.test(p) && /owner_id:\s*\{type: string\}/.test(content))
199
+ pushUniq(s.optional_fields_added, 'owner_id');
200
+ if (/\.idl$/i.test(p) || p.startsWith('idl/'))
201
+ pushUniq(s.intermediate_artifacts, p);
202
+ }
203
+ // body flags (with/without path)
204
+ if (/BREAKING_DROP|FIELD .* REMOVE|MANDATORY/i.test(content))
205
+ pushUniq(s.intermediate_artifacts, paths[0] || 'inline_flag');
206
+ s.tainted = computeTainted(s);
207
+ return s;
208
+ }
209
+ // ── §3.2 taint predicate ─────────────────────────────────────────────────────────────────────
210
+ export function computeTainted(s) {
211
+ return (s.contract_looking_scratch.length > 0
212
+ || s.encoded_fragments.length > 0
213
+ || s.intermediate_artifacts.length > 0
214
+ || s.store_keys.some((k) => /spec_|api_|schema|openapi/i.test(k))
215
+ || s.pending_renames.length > 0
216
+ || s.optional_fields_added.some((f) => s.required_fields_declared.includes(f))
217
+ || (s.required_fields_declared.length > 0 && s.optional_fields_added.length > 0)
218
+ || s.ssot_invalidated === true);
219
+ }
220
+ export function deriveKeySignal(s) {
221
+ if (s.ssot_invalidated)
222
+ return 'delete_recreate_ssot_via_session';
223
+ if (s.encoded_fragments.length)
224
+ return 'encoded_scratch_then_ssot_promotion';
225
+ if (s.optional_fields_added.some((f) => s.required_fields_declared.includes(f)) || (s.required_fields_declared.length && s.optional_fields_added.length))
226
+ return 'cumulative_required_flip';
227
+ if (s.pending_renames.length)
228
+ return 'cumulative_rename_via_codegen';
229
+ if (s.contract_looking_scratch.length)
230
+ return 'scratch_to_ssot_promotion';
231
+ if (s.intermediate_artifacts.length)
232
+ return 'cross_call_reassembly_to_ssot';
233
+ return 'session_ssot_sink_with_taint';
234
+ }
235
+ /** flag ⇔ (ssot_sink_events ≠ ∅ || sink_seen) ∧ (tainted || overflow). */
236
+ export function evaluate(state, prevFlagged = false, opts = {}) {
237
+ const sink = state.ssot_sink_events.length > 0 || opts.sinkSeen === true;
238
+ const taint = state.tainted || opts.overflow === true;
239
+ const flag = sink && taint;
240
+ return { flag, trip: flag && !prevFlagged, key_signal: flag ? deriveKeySignal(state) : null };
241
+ }
242
+ const DEF = { maxCalls: 256, maxPathsTracked: 512, maxSinkEvents: 64, maxStateBytes: 256_000, ttlMs: 3_600_000 };
243
+ export class SessionTaintTracker {
244
+ version = SESSION_TAINT_VERSION;
245
+ state = emptySessionState();
246
+ prevFlag = false;
247
+ callCount = 0;
248
+ overflow = false;
249
+ sinkSeen = false;
250
+ lastObserveAt = 0;
251
+ cfg;
252
+ constructor(config = {}) { this.cfg = config; }
253
+ pathTotal() {
254
+ const s = this.state;
255
+ return s.scratch_writes.length + s.contract_looking_scratch.length + s.encoded_fragments.length
256
+ + s.intermediate_artifacts.length + s.ssot_paths_touched.length;
257
+ }
258
+ observe(call) {
259
+ const now = this.now();
260
+ // §4.3 TTL: soft reset to a fresh session on expiry.
261
+ if (this.lastObserveAt && now - this.lastObserveAt > (this.cfg.ttlMs ?? DEF.ttlMs))
262
+ this.reset();
263
+ this.lastObserveAt = now;
264
+ const next = updateSession(this.state, call, this.cfg);
265
+ // §4.3 caps → sticky overflow forces taint (monotonic caution; NOT drop-oldest).
266
+ this.callCount++;
267
+ if (this.callCount > (this.cfg.maxCalls ?? DEF.maxCalls))
268
+ this.overflow = true;
269
+ if (this.pathTotal() > (this.cfg.maxPathsTracked ?? DEF.maxPathsTracked))
270
+ this.overflow = true;
271
+ if (JSON.stringify(next).length > (this.cfg.maxStateBytes ?? DEF.maxStateBytes))
272
+ this.overflow = true;
273
+ // maxSinkEvents: stop growing the list but keep sink presence sticky.
274
+ if (next.ssot_sink_events.length > (this.cfg.maxSinkEvents ?? DEF.maxSinkEvents)) {
275
+ next.ssot_sink_events = next.ssot_sink_events.slice(0, this.cfg.maxSinkEvents ?? DEF.maxSinkEvents);
276
+ }
277
+ this.state = next;
278
+ if (this.state.ssot_sink_events.length > 0)
279
+ this.sinkSeen = true;
280
+ return this.snapshot();
281
+ }
282
+ status() { return this.snapshot(); }
283
+ reset() {
284
+ this.state = emptySessionState();
285
+ this.prevFlag = false;
286
+ this.callCount = 0;
287
+ this.overflow = false;
288
+ this.sinkSeen = false;
289
+ this.lastObserveAt = 0;
290
+ }
291
+ snapshot() {
292
+ const eva = evaluate(this.state, this.prevFlag, { overflow: this.overflow, sinkSeen: this.sinkSeen });
293
+ if (eva.flag)
294
+ this.prevFlag = true;
295
+ return {
296
+ flag: eva.flag, trip: eva.trip, key_signal: eva.key_signal,
297
+ state: projectState(this.state),
298
+ version: SESSION_TAINT_VERSION, overflow: this.overflow,
299
+ severity: this.cfg.sessionTaintSeverity || 'caution',
300
+ };
301
+ }
302
+ // Date.now is fine at runtime; isolated for testability.
303
+ now() { return Date.now(); }
304
+ }
305
+ //# sourceMappingURL=session-taint.js.map