@martinloop/mcp 0.3.3 → 0.3.4

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 (55) hide show
  1. package/README.md +112 -107
  2. package/dist/discovery-support.js +2 -2
  3. package/dist/resources.js +147 -147
  4. package/dist/server-validation.js +2 -0
  5. package/dist/server.js +1 -1
  6. package/dist/tools/eval.js +29 -5
  7. package/dist/tools/execution-policy.d.ts +11 -0
  8. package/dist/tools/execution-policy.js +47 -0
  9. package/dist/tools/run-dossier.js +2 -2
  10. package/dist/tools/run-loop.d.ts +1 -0
  11. package/dist/tools/run-loop.js +15 -2
  12. package/dist/tools/run-store.js +4 -4
  13. package/dist/tools/tool-support.d.ts +1 -1
  14. package/dist/tools/tool-support.js +111 -18
  15. package/dist/tools/triage-runs.js +31 -6
  16. package/dist/vendor/adapters/claude-cli.js +69 -19
  17. package/dist/vendor/adapters/cli-bridge.d.ts +6 -0
  18. package/dist/vendor/adapters/cli-bridge.js +62 -2
  19. package/dist/vendor/adapters/codex-launcher.js +65 -8
  20. package/dist/vendor/adapters/openai-compatible.js +6 -6
  21. package/dist/vendor/contracts/adapter-capabilities.d.ts +17 -0
  22. package/dist/vendor/contracts/adapter-capabilities.js +35 -0
  23. package/dist/vendor/contracts/context-graph.d.ts +48 -0
  24. package/dist/vendor/contracts/context-graph.js +26 -0
  25. package/dist/vendor/contracts/execution-policy.d.ts +62 -0
  26. package/dist/vendor/contracts/execution-policy.js +34 -0
  27. package/dist/vendor/contracts/governance.d.ts +6 -3
  28. package/dist/vendor/contracts/identity.d.ts +29 -0
  29. package/dist/vendor/contracts/identity.js +30 -0
  30. package/dist/vendor/contracts/index.d.ts +13 -2
  31. package/dist/vendor/contracts/index.js +4 -0
  32. package/dist/vendor/contracts/observation.d.ts +21 -0
  33. package/dist/vendor/contracts/observation.js +27 -0
  34. package/dist/vendor/contracts/trajectory.d.ts +26 -0
  35. package/dist/vendor/contracts/trajectory.js +27 -0
  36. package/dist/vendor/contracts/verification.d.ts +28 -0
  37. package/dist/vendor/contracts/verification.js +7 -0
  38. package/dist/vendor/core/context-graph.d.ts +3 -0
  39. package/dist/vendor/core/context-graph.js +371 -0
  40. package/dist/vendor/core/identity.d.ts +20 -0
  41. package/dist/vendor/core/identity.js +86 -0
  42. package/dist/vendor/core/index.d.ts +9 -2
  43. package/dist/vendor/core/index.js +67 -11
  44. package/dist/vendor/core/persistence/integrity.js +2 -2
  45. package/dist/vendor/core/persistence/store.js +0 -13
  46. package/dist/vendor/core/policy-compiler.d.ts +2 -0
  47. package/dist/vendor/core/policy-compiler.js +195 -0
  48. package/dist/vendor/core/policy.d.ts +2 -0
  49. package/dist/vendor/core/policy.js +71 -4
  50. package/dist/vendor/core/rollback.d.ts +0 -4
  51. package/dist/vendor/core/rollback.js +32 -27
  52. package/dist/vendor/core/trajectory.d.ts +18 -0
  53. package/dist/vendor/core/trajectory.js +295 -0
  54. package/package.json +76 -75
  55. package/server.json +21 -21
@@ -0,0 +1,28 @@
1
+ export type VerifierExitReason = "passed" | "non_zero_exit" | "timed_out" | "spawn_error" | "invalid_command";
2
+ export type VerifierStepType = "lint" | "typecheck" | "test_targeted" | "test_full" | "custom";
3
+ export interface VerifierStepSnapshot {
4
+ command: string;
5
+ type: VerifierStepType;
6
+ fastFail: boolean;
7
+ passed: boolean;
8
+ exitCode: number;
9
+ exitReason: VerifierExitReason;
10
+ startedAt: string;
11
+ completedAt: string;
12
+ durationMs: number;
13
+ stdout?: string;
14
+ stderr?: string;
15
+ }
16
+ export interface VerifierSnapshot {
17
+ passed: boolean;
18
+ summary: string;
19
+ startedAt: string;
20
+ completedAt: string;
21
+ durationMs: number;
22
+ stepCount: number;
23
+ failedStepCount: number;
24
+ commands: string[];
25
+ steps: VerifierStepSnapshot[];
26
+ combinedOutput?: string;
27
+ }
28
+ export declare function cloneVerifierSnapshot(snapshot: VerifierSnapshot): VerifierSnapshot;
@@ -0,0 +1,7 @@
1
+ export function cloneVerifierSnapshot(snapshot) {
2
+ return {
3
+ ...snapshot,
4
+ commands: [...snapshot.commands],
5
+ steps: snapshot.steps.map((step) => ({ ...step }))
6
+ };
7
+ }
@@ -0,0 +1,3 @@
1
+ import { type ContextGraphBuildOptions, type ContextGraphHit, type ContextGraphSnapshot, type ContextQuery } from "../contracts/index.js";
2
+ export declare function buildContextGraphSnapshot(repoRoot: string, options?: ContextGraphBuildOptions): Promise<ContextGraphSnapshot>;
3
+ export declare function queryContextGraph(snapshot: ContextGraphSnapshot, query: ContextQuery): ContextGraphHit[];
@@ -0,0 +1,371 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { extname, join, posix, relative, resolve } from "node:path";
3
+ import { cloneContextGraphSnapshot } from "../contracts/index.js";
4
+ const TEXT_EXTENSIONS = new Set([
5
+ ".ts",
6
+ ".tsx",
7
+ ".js",
8
+ ".jsx",
9
+ ".mjs",
10
+ ".cjs",
11
+ ".json",
12
+ ".md",
13
+ ".yaml",
14
+ ".yml",
15
+ ".txt",
16
+ ".py",
17
+ ".go",
18
+ ".rs",
19
+ ".java",
20
+ ".sh"
21
+ ]);
22
+ const IGNORED_DIRS = new Set([
23
+ ".git",
24
+ "node_modules",
25
+ "dist",
26
+ "build",
27
+ ".next",
28
+ ".turbo",
29
+ "coverage",
30
+ ".pnpm-store",
31
+ ".npm-cache"
32
+ ]);
33
+ export async function buildContextGraphSnapshot(repoRoot, options = {}) {
34
+ const normalizedRoot = resolve(repoRoot);
35
+ const maxFiles = options.maxFiles ?? 600;
36
+ const maxFileBytes = options.maxFileBytes ?? 96_000;
37
+ const nodes = [];
38
+ const state = { count: 0, truncated: false };
39
+ await walkContextGraph(normalizedRoot, normalizedRoot, nodes, state, { maxFiles, maxFileBytes });
40
+ const edges = buildContextGraphEdges(nodes);
41
+ return cloneContextGraphSnapshot({
42
+ schemaVersion: "martin.context-graph.v1",
43
+ repoRoot: normalizedRoot,
44
+ createdAt: new Date().toISOString(),
45
+ nodeCount: nodes.length,
46
+ edgeCount: edges.length,
47
+ truncated: state.truncated,
48
+ nodes,
49
+ edges
50
+ });
51
+ }
52
+ export function queryContextGraph(snapshot, query) {
53
+ const terms = normalizeQueryTerms(query);
54
+ const pathPrefix = query.pathPrefix?.replace(/\\/gu, "/").replace(/^\.\/+/u, "");
55
+ const limit = query.limit ?? 8;
56
+ return snapshot.nodes
57
+ .filter((node) => {
58
+ if (query.kinds && !query.kinds.includes(node.kind)) {
59
+ return false;
60
+ }
61
+ if (pathPrefix && !node.path.startsWith(pathPrefix)) {
62
+ return false;
63
+ }
64
+ return true;
65
+ })
66
+ .map((node) => scoreContextNode(node, terms))
67
+ .filter((hit) => hit !== undefined)
68
+ .sort((left, right) => right.score - left.score || left.path.localeCompare(right.path))
69
+ .slice(0, limit);
70
+ }
71
+ async function walkContextGraph(repoRoot, currentDir, nodes, state, options) {
72
+ if (state.count >= options.maxFiles) {
73
+ state.truncated = true;
74
+ return;
75
+ }
76
+ const entries = await readdir(currentDir, { withFileTypes: true });
77
+ for (const entry of entries) {
78
+ if (state.count >= options.maxFiles) {
79
+ state.truncated = true;
80
+ break;
81
+ }
82
+ const absPath = join(currentDir, entry.name);
83
+ if (entry.isDirectory()) {
84
+ if (!IGNORED_DIRS.has(entry.name)) {
85
+ await walkContextGraph(repoRoot, absPath, nodes, state, options);
86
+ }
87
+ continue;
88
+ }
89
+ if (!entry.isFile()) {
90
+ continue;
91
+ }
92
+ const extension = extname(entry.name).toLowerCase();
93
+ if (!TEXT_EXTENSIONS.has(extension)) {
94
+ continue;
95
+ }
96
+ const content = await readFile(absPath, "utf8").catch(() => undefined);
97
+ if (!content || content.length > options.maxFileBytes) {
98
+ continue;
99
+ }
100
+ const relPath = relative(repoRoot, absPath).replace(/\\/gu, "/");
101
+ nodes.push(createContextNode(relPath, content));
102
+ state.count += 1;
103
+ }
104
+ }
105
+ function createContextNode(path, content) {
106
+ const kind = classifyContextNodeKind(path);
107
+ return {
108
+ nodeId: path,
109
+ path,
110
+ kind,
111
+ ...(inferLanguage(path) ? { language: inferLanguage(path) } : {}),
112
+ sizeBytes: Buffer.byteLength(content, "utf8"),
113
+ headings: extractHeadings(path, content),
114
+ symbols: extractSymbols(content),
115
+ keywords: extractKeywords(path, content),
116
+ imports: extractImports(path, content)
117
+ };
118
+ }
119
+ function buildContextGraphEdges(nodes) {
120
+ const paths = new Set(nodes.map((node) => node.path));
121
+ const edges = [];
122
+ for (const node of nodes) {
123
+ for (const importTarget of node.imports) {
124
+ const resolvedTarget = resolveContextImport(node.path, importTarget, paths);
125
+ if (resolvedTarget) {
126
+ edges.push({
127
+ fromNodeId: node.nodeId,
128
+ toNodeId: resolvedTarget,
129
+ kind: "imports"
130
+ });
131
+ }
132
+ }
133
+ if (node.kind === "document") {
134
+ const documentTargets = node.keywords
135
+ .map((keyword) => nodes.find((candidate) => candidate.path !== node.path && candidate.path.includes(keyword)))
136
+ .filter((candidate) => candidate !== undefined)
137
+ .slice(0, 3);
138
+ for (const target of documentTargets) {
139
+ edges.push({
140
+ fromNodeId: node.nodeId,
141
+ toNodeId: target.nodeId,
142
+ kind: "documents"
143
+ });
144
+ }
145
+ }
146
+ }
147
+ return dedupeEdges(edges);
148
+ }
149
+ function scoreContextNode(node, terms) {
150
+ if (terms.length === 0) {
151
+ return {
152
+ nodeId: node.nodeId,
153
+ path: node.path,
154
+ kind: node.kind,
155
+ score: 1,
156
+ matchedTerms: [],
157
+ reasons: ["default_match"]
158
+ };
159
+ }
160
+ let score = 0;
161
+ const matchedTerms = new Set();
162
+ const reasons = new Set();
163
+ for (const term of terms) {
164
+ if (node.path.toLowerCase().includes(term)) {
165
+ score += 6;
166
+ matchedTerms.add(term);
167
+ reasons.add("path");
168
+ }
169
+ if (node.keywords.includes(term)) {
170
+ score += 3;
171
+ matchedTerms.add(term);
172
+ reasons.add("keyword");
173
+ }
174
+ if (node.symbols.some((symbol) => symbol.toLowerCase().includes(term))) {
175
+ score += 5;
176
+ matchedTerms.add(term);
177
+ reasons.add("symbol");
178
+ }
179
+ if (node.headings.some((heading) => heading.toLowerCase().includes(term))) {
180
+ score += 4;
181
+ matchedTerms.add(term);
182
+ reasons.add("heading");
183
+ }
184
+ if (node.imports.some((importPath) => importPath.toLowerCase().includes(term))) {
185
+ score += 2;
186
+ matchedTerms.add(term);
187
+ reasons.add("import");
188
+ }
189
+ }
190
+ if (score === 0) {
191
+ return undefined;
192
+ }
193
+ return {
194
+ nodeId: node.nodeId,
195
+ path: node.path,
196
+ kind: node.kind,
197
+ score,
198
+ matchedTerms: [...matchedTerms],
199
+ reasons: [...reasons]
200
+ };
201
+ }
202
+ function normalizeQueryTerms(query) {
203
+ const rawTerms = [
204
+ ...(query.text ? tokenize(query.text) : []),
205
+ ...((query.terms ?? []).flatMap((term) => tokenize(term)))
206
+ ];
207
+ return [...new Set(rawTerms)];
208
+ }
209
+ function classifyContextNodeKind(path) {
210
+ const extension = extname(path).toLowerCase();
211
+ if (path.endsWith("package.json") || path.endsWith("tsconfig.json")) {
212
+ return "manifest";
213
+ }
214
+ if (extension === ".md" || extension === ".txt") {
215
+ return "document";
216
+ }
217
+ if (extension === ".sh") {
218
+ return "script";
219
+ }
220
+ if (extension === ".json" || extension === ".yaml" || extension === ".yml") {
221
+ return "config";
222
+ }
223
+ return "source_file";
224
+ }
225
+ function inferLanguage(path) {
226
+ const extension = extname(path).toLowerCase();
227
+ switch (extension) {
228
+ case ".ts":
229
+ case ".tsx":
230
+ return "typescript";
231
+ case ".js":
232
+ case ".jsx":
233
+ case ".mjs":
234
+ case ".cjs":
235
+ return "javascript";
236
+ case ".md":
237
+ return "markdown";
238
+ case ".json":
239
+ return "json";
240
+ case ".yaml":
241
+ case ".yml":
242
+ return "yaml";
243
+ case ".py":
244
+ return "python";
245
+ case ".sh":
246
+ return "shell";
247
+ default:
248
+ return undefined;
249
+ }
250
+ }
251
+ function extractHeadings(path, content) {
252
+ if (extname(path).toLowerCase() !== ".md") {
253
+ return [];
254
+ }
255
+ return content
256
+ .split(/\r?\n/gu)
257
+ .map((line) => line.trim())
258
+ .filter((line) => line.startsWith("#"))
259
+ .map((line) => line.replace(/^#+\s*/u, "").trim())
260
+ .filter(Boolean)
261
+ .slice(0, 12);
262
+ }
263
+ function extractSymbols(content) {
264
+ const out = new Set();
265
+ const patterns = [
266
+ /export\s+(?:async\s+)?function\s+([A-Za-z0-9_]+)/gu,
267
+ /export\s+class\s+([A-Za-z0-9_]+)/gu,
268
+ /export\s+const\s+([A-Za-z0-9_]+)/gu,
269
+ /function\s+([A-Za-z0-9_]+)/gu,
270
+ /class\s+([A-Za-z0-9_]+)/gu,
271
+ /interface\s+([A-Za-z0-9_]+)/gu,
272
+ /type\s+([A-Za-z0-9_]+)/gu
273
+ ];
274
+ for (const pattern of patterns) {
275
+ for (const match of content.matchAll(pattern)) {
276
+ if (match[1]) {
277
+ out.add(match[1]);
278
+ }
279
+ }
280
+ }
281
+ return [...out].slice(0, 16);
282
+ }
283
+ function extractKeywords(path, content) {
284
+ const out = new Set();
285
+ for (const part of path.split(/[\/._-]+/u)) {
286
+ if (part.length >= 3) {
287
+ out.add(part.toLowerCase());
288
+ }
289
+ }
290
+ for (const token of tokenize(content.split(/\r?\n/gu).slice(0, 16).join(" "))) {
291
+ out.add(token);
292
+ }
293
+ return [...out].slice(0, 24);
294
+ }
295
+ function extractImports(path, content) {
296
+ if (![".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(extname(path).toLowerCase())) {
297
+ return [];
298
+ }
299
+ const imports = new Set();
300
+ const patterns = [
301
+ /from\s+["']([^"']+)["']/gu,
302
+ /require\(\s*["']([^"']+)["']\s*\)/gu,
303
+ /import\(\s*["']([^"']+)["']\s*\)/gu
304
+ ];
305
+ for (const pattern of patterns) {
306
+ for (const match of content.matchAll(pattern)) {
307
+ const candidate = match[1]?.trim();
308
+ if (candidate) {
309
+ imports.add(candidate);
310
+ }
311
+ }
312
+ }
313
+ return [...imports].slice(0, 24);
314
+ }
315
+ function resolveContextImport(fromPath, importPath, paths) {
316
+ if (!importPath.startsWith(".")) {
317
+ return undefined;
318
+ }
319
+ const fromDirectory = fromPath.includes("/") ? fromPath.slice(0, fromPath.lastIndexOf("/")) : "";
320
+ const base = posix.normalize(posix.join(fromDirectory, importPath)).replace(/^\.\//u, "");
321
+ const extensionlessBase = extname(base) ? base.slice(0, -extname(base).length) : base;
322
+ const candidates = [
323
+ base,
324
+ extensionlessBase,
325
+ `${extensionlessBase}.ts`,
326
+ `${extensionlessBase}.tsx`,
327
+ `${extensionlessBase}.js`,
328
+ `${extensionlessBase}.jsx`,
329
+ `${extensionlessBase}.md`,
330
+ `${base}.ts`,
331
+ `${base}.tsx`,
332
+ `${base}.js`,
333
+ `${base}.jsx`,
334
+ `${base}.md`,
335
+ `${base}/index.ts`,
336
+ `${base}/index.tsx`,
337
+ `${base}/index.js`
338
+ ];
339
+ return candidates.find((candidate) => paths.has(candidate));
340
+ }
341
+ function dedupeEdges(edges) {
342
+ const seen = new Set();
343
+ return edges.filter((edge) => {
344
+ const key = `${edge.kind}:${edge.fromNodeId}:${edge.toNodeId}`;
345
+ if (seen.has(key)) {
346
+ return false;
347
+ }
348
+ seen.add(key);
349
+ return true;
350
+ });
351
+ }
352
+ function tokenize(input) {
353
+ const normalized = input.replace(/([a-z0-9])([A-Z])/gu, "$1 $2").toLowerCase();
354
+ const stopWords = new Set([
355
+ "the",
356
+ "and",
357
+ "for",
358
+ "with",
359
+ "from",
360
+ "that",
361
+ "this",
362
+ "into",
363
+ "only",
364
+ "keep",
365
+ "make",
366
+ "loop",
367
+ "then",
368
+ "when"
369
+ ]);
370
+ return [...new Set(normalized.match(/[a-z0-9_]{3,}/gu) ?? [])].filter((term) => !stopWords.has(term));
371
+ }
@@ -0,0 +1,20 @@
1
+ import { type IdentityAttestation, type IdentityClaims, type IdentityToken } from "../contracts/index.js";
2
+ export interface LocalIdentityAuthority {
3
+ keyId: string;
4
+ algorithm: "ed25519";
5
+ privateKeyPem: string;
6
+ publicKeyPem: string;
7
+ }
8
+ export declare function createLocalIdentityAuthority(input?: {
9
+ keyId?: string;
10
+ }): LocalIdentityAuthority;
11
+ export declare function issueIdentityToken(input: {
12
+ authority: Pick<LocalIdentityAuthority, "keyId" | "algorithm" | "privateKeyPem">;
13
+ claims: IdentityClaims;
14
+ }): IdentityToken;
15
+ export declare function verifyIdentityToken(input: {
16
+ token: IdentityToken;
17
+ publicKeyPem: string;
18
+ now?: string;
19
+ }): IdentityAttestation;
20
+ export declare function hasIdentityScope(token: IdentityToken, requiredScope: string): boolean;
@@ -0,0 +1,86 @@
1
+ import { createPrivateKey, createPublicKey, generateKeyPairSync, sign, verify } from "node:crypto";
2
+ import { cloneIdentityAttestation, cloneIdentityClaims, cloneIdentityToken } from "../contracts/index.js";
3
+ export function createLocalIdentityAuthority(input = {}) {
4
+ const { privateKey, publicKey } = generateKeyPairSync("ed25519");
5
+ return {
6
+ keyId: input.keyId ?? `martin-local-${Date.now().toString(36)}`,
7
+ algorithm: "ed25519",
8
+ privateKeyPem: privateKey.export({ format: "pem", type: "pkcs8" }).toString(),
9
+ publicKeyPem: publicKey.export({ format: "pem", type: "spki" }).toString()
10
+ };
11
+ }
12
+ export function issueIdentityToken(input) {
13
+ const claims = cloneIdentityClaims(input.claims);
14
+ const signer = createPrivateKey(input.authority.privateKeyPem);
15
+ const payload = serializeIdentityClaims(claims);
16
+ const signature = sign(null, payload, signer).toString("base64");
17
+ return cloneIdentityToken({
18
+ schemaVersion: "martin.identity.v1",
19
+ algorithm: input.authority.algorithm,
20
+ keyId: input.authority.keyId,
21
+ claims,
22
+ signature
23
+ });
24
+ }
25
+ export function verifyIdentityToken(input) {
26
+ const token = cloneIdentityToken(input.token);
27
+ const verifier = createPublicKey(input.publicKeyPem);
28
+ const payload = serializeIdentityClaims(token.claims);
29
+ const verifiedAt = input.now ?? new Date().toISOString();
30
+ if (token.schemaVersion !== "martin.identity.v1") {
31
+ return cloneIdentityAttestation({
32
+ valid: false,
33
+ verifiedAt,
34
+ reason: `Unsupported identity schema version '${token.schemaVersion}'.`,
35
+ token
36
+ });
37
+ }
38
+ const signatureValid = verify(null, payload, verifier, Buffer.from(token.signature, "base64"));
39
+ if (!signatureValid) {
40
+ return cloneIdentityAttestation({
41
+ valid: false,
42
+ verifiedAt,
43
+ reason: "Identity signature verification failed.",
44
+ token
45
+ });
46
+ }
47
+ const expiresAt = token.claims.expiresAt ? Date.parse(token.claims.expiresAt) : undefined;
48
+ if (expiresAt !== undefined && Number.isFinite(expiresAt) && expiresAt <= Date.parse(verifiedAt)) {
49
+ return cloneIdentityAttestation({
50
+ valid: false,
51
+ verifiedAt,
52
+ reason: "Identity token is expired.",
53
+ token
54
+ });
55
+ }
56
+ return cloneIdentityAttestation({
57
+ valid: true,
58
+ verifiedAt,
59
+ reason: `Identity token for role '${token.claims.role}' verified successfully.`,
60
+ token
61
+ });
62
+ }
63
+ export function hasIdentityScope(token, requiredScope) {
64
+ const required = requiredScope.trim().toLowerCase();
65
+ if (required.length === 0) {
66
+ return false;
67
+ }
68
+ return token.claims.scopes.some((scope) => scope.trim().toLowerCase() === required);
69
+ }
70
+ function serializeIdentityClaims(claims) {
71
+ return Buffer.from(JSON.stringify(claims, sortKeys), "utf8");
72
+ }
73
+ function sortKeys(_, value) {
74
+ if (Array.isArray(value)) {
75
+ return value;
76
+ }
77
+ if (value && typeof value === "object") {
78
+ return Object.keys(value)
79
+ .sort()
80
+ .reduce((sorted, key) => {
81
+ sorted[key] = value[key];
82
+ return sorted;
83
+ }, {});
84
+ }
85
+ return value;
86
+ }
@@ -2,13 +2,18 @@ import { type ApprovalPolicy, type CostProvenance, type ExecutionProfile, type F
2
2
  import { classifyFailure, computeEvidenceVector, evaluatePatchDecision, evaluateCostGovernor, evaluateBudgetPreflight, inferExit, nextPolicyPhase, policyPhaseToLifecycleState, scorePatchDecision, selectRecoveryRecipe, type ExitDecision } from "./policy.js";
3
3
  import { evaluateChangeApprovalLeash, evaluateFilesystemLeash, evaluateSecretLeash, redactSecretsFromText, resolveExecutionProfile, evaluateVerificationLeash } from "./leash.js";
4
4
  import { buildRepoGroundingIndex, loadOrBuildRepoGroundingIndex, queryRepoGroundingIndex, scanPatchForGroundingViolations } from "./grounding.js";
5
- import { captureRollbackBoundary, listAttemptChangedFilesSinceBoundary, restoreRollbackBoundary } from "./rollback.js";
5
+ import { captureRollbackBoundary, restoreRollbackBoundary } from "./rollback.js";
6
6
  import { type RunStore } from "./persistence/index.js";
7
7
  export type { ApprovalPolicy, BudgetPreflightEstimate, BudgetSettlement, CostProvenance, EvidenceVector, ExecutionProfile, FailureClass, InterventionType, PatchDecision, PatchDecisionArtifact, PatchDecisionReasonCode, PatchScore, MutationMode, RollbackBoundaryArtifact, RollbackBoundaryStrategy, RollbackFileSnapshot, RollbackOutcomeArtifact, RollbackOutcomeStatus, PolicyPhase } from "../contracts/index.js";
8
- export { classifyFailure, computeEvidenceVector, evaluatePatchDecision, evaluateCostGovernor, evaluateBudgetPreflight, inferExit, nextPolicyPhase, policyPhaseToLifecycleState, scorePatchDecision, selectRecoveryRecipe, evaluateVerificationLeash, evaluateFilesystemLeash, evaluateChangeApprovalLeash, evaluateSecretLeash, resolveExecutionProfile, redactSecretsFromText, buildRepoGroundingIndex, loadOrBuildRepoGroundingIndex, queryRepoGroundingIndex, scanPatchForGroundingViolations, captureRollbackBoundary, listAttemptChangedFilesSinceBoundary, restoreRollbackBoundary };
8
+ export { classifyFailure, computeEvidenceVector, evaluatePatchDecision, evaluateCostGovernor, evaluateBudgetPreflight, inferExit, nextPolicyPhase, policyPhaseToLifecycleState, scorePatchDecision, selectRecoveryRecipe, evaluateVerificationLeash, evaluateFilesystemLeash, evaluateChangeApprovalLeash, evaluateSecretLeash, resolveExecutionProfile, redactSecretsFromText, buildRepoGroundingIndex, loadOrBuildRepoGroundingIndex, queryRepoGroundingIndex, scanPatchForGroundingViolations, captureRollbackBoundary, restoreRollbackBoundary };
9
9
  export type { BudgetPreflightDecision, BudgetPreflightInput, CostGovernorState, EvidenceVectorInput, EvaluatedPatchDecision, ExitDecision, FailureAssessment, PatchDecisionInput, RecoveryDecision, RecoveryRecipe } from "./policy.js";
10
10
  export type { ResolvedExecutionProfile, SafetyLeashDecision, SafetyViolation } from "./leash.js";
11
11
  export type { GroundingScanResult, GroundingViolation, GroundingViolationKind, RepoGroundingHit, RepoGroundingIndex } from "./grounding.js";
12
+ export { buildContextGraphSnapshot, queryContextGraph } from "./context-graph.js";
13
+ export { createLocalIdentityAuthority, hasIdentityScope, issueIdentityToken, verifyIdentityToken } from "./identity.js";
14
+ export type { LocalIdentityAuthority } from "./identity.js";
15
+ export { compileExecutionPolicy } from "./policy-compiler.js";
16
+ export { assessTrajectory, decideCircuitBreak } from "./trajectory.js";
12
17
  export { runContextIntegrityPrecheck } from "./context-integrity.js";
13
18
  export type { ContextIntegrityPrecheck, ContextIntegrityVerdict } from "./context-integrity.js";
14
19
  export { compilePromptPacket } from "./compiler.js";
@@ -132,6 +137,8 @@ export interface AttemptPolicyDecision {
132
137
  allowed: boolean;
133
138
  reason: string;
134
139
  recommendedIntervention?: InterventionType;
140
+ trajectoryAssessment?: import("../contracts/index.js").TrajectoryAssessment;
141
+ circuitBreakDecision?: import("../contracts/index.js").CircuitBreakDecision;
135
142
  }
136
143
  /**
137
144
  * Admission gate — must pass before any attempt is executed.