@martinloop/mcp 0.3.8 → 0.3.9

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 (103) hide show
  1. package/README.md +148 -105
  2. package/dist/resources.js +148 -148
  3. package/dist/server.js +0 -0
  4. package/dist/tools/preflight.d.ts +0 -2
  5. package/dist/tools/preflight.js +2 -42
  6. package/dist/vendor/adapters/openai-compatible.js +6 -6
  7. package/dist/vendor/contracts/index.d.ts +0 -2
  8. package/dist/vendor/contracts/index.js +0 -2
  9. package/dist/vendor/core/index.d.ts +0 -2
  10. package/dist/vendor/core/index.js +0 -2
  11. package/package.json +86 -83
  12. package/server.json +21 -21
  13. package/LICENSE +0 -216
  14. package/dist/vendor/adapters/adapters/src/claude-cli.d.ts +0 -146
  15. package/dist/vendor/adapters/adapters/src/claude-cli.js +0 -1100
  16. package/dist/vendor/adapters/adapters/src/cli-bridge.d.ts +0 -103
  17. package/dist/vendor/adapters/adapters/src/cli-bridge.js +0 -569
  18. package/dist/vendor/adapters/adapters/src/codex-launcher.d.ts +0 -78
  19. package/dist/vendor/adapters/adapters/src/codex-launcher.js +0 -663
  20. package/dist/vendor/adapters/adapters/src/direct-provider.d.ts +0 -10
  21. package/dist/vendor/adapters/adapters/src/direct-provider.js +0 -40
  22. package/dist/vendor/adapters/adapters/src/index.d.ts +0 -8
  23. package/dist/vendor/adapters/adapters/src/index.js +0 -8
  24. package/dist/vendor/adapters/adapters/src/openai-compatible.d.ts +0 -62
  25. package/dist/vendor/adapters/adapters/src/openai-compatible.js +0 -306
  26. package/dist/vendor/adapters/adapters/src/runtime-support.d.ts +0 -17
  27. package/dist/vendor/adapters/adapters/src/runtime-support.js +0 -59
  28. package/dist/vendor/adapters/adapters/src/stub-agent-cli.d.ts +0 -8
  29. package/dist/vendor/adapters/adapters/src/stub-agent-cli.js +0 -40
  30. package/dist/vendor/adapters/adapters/src/stub-direct-provider.d.ts +0 -8
  31. package/dist/vendor/adapters/adapters/src/stub-direct-provider.js +0 -12
  32. package/dist/vendor/adapters/adapters/src/verifier-only.d.ts +0 -9
  33. package/dist/vendor/adapters/adapters/src/verifier-only.js +0 -63
  34. package/dist/vendor/adapters/contracts/src/context-graph.d.ts +0 -48
  35. package/dist/vendor/adapters/contracts/src/context-graph.js +0 -26
  36. package/dist/vendor/adapters/contracts/src/execution-policy.d.ts +0 -78
  37. package/dist/vendor/adapters/contracts/src/execution-policy.js +0 -43
  38. package/dist/vendor/adapters/contracts/src/governance.d.ts +0 -24
  39. package/dist/vendor/adapters/contracts/src/governance.js +0 -11
  40. package/dist/vendor/adapters/contracts/src/identity.d.ts +0 -29
  41. package/dist/vendor/adapters/contracts/src/identity.js +0 -30
  42. package/dist/vendor/adapters/contracts/src/index.d.ts +0 -412
  43. package/dist/vendor/adapters/contracts/src/index.js +0 -225
  44. package/dist/vendor/adapters/contracts/src/operator.d.ts +0 -19
  45. package/dist/vendor/adapters/contracts/src/operator.js +0 -11
  46. package/dist/vendor/adapters/contracts/src/trajectory.d.ts +0 -26
  47. package/dist/vendor/adapters/contracts/src/trajectory.js +0 -27
  48. package/dist/vendor/adapters/core/src/compiler.d.ts +0 -52
  49. package/dist/vendor/adapters/core/src/compiler.js +0 -52
  50. package/dist/vendor/adapters/core/src/context-graph.d.ts +0 -3
  51. package/dist/vendor/adapters/core/src/context-graph.js +0 -371
  52. package/dist/vendor/adapters/core/src/context-integrity.d.ts +0 -26
  53. package/dist/vendor/adapters/core/src/context-integrity.js +0 -80
  54. package/dist/vendor/adapters/core/src/grounding.d.ts +0 -38
  55. package/dist/vendor/adapters/core/src/grounding.js +0 -273
  56. package/dist/vendor/adapters/core/src/identity.d.ts +0 -20
  57. package/dist/vendor/adapters/core/src/identity.js +0 -86
  58. package/dist/vendor/adapters/core/src/index.d.ts +0 -186
  59. package/dist/vendor/adapters/core/src/index.js +0 -1495
  60. package/dist/vendor/adapters/core/src/leash.d.ts +0 -48
  61. package/dist/vendor/adapters/core/src/leash.js +0 -497
  62. package/dist/vendor/adapters/core/src/persistence/compiler.d.ts +0 -18
  63. package/dist/vendor/adapters/core/src/persistence/compiler.js +0 -34
  64. package/dist/vendor/adapters/core/src/persistence/index.d.ts +0 -10
  65. package/dist/vendor/adapters/core/src/persistence/index.js +0 -5
  66. package/dist/vendor/adapters/core/src/persistence/integrity.d.ts +0 -39
  67. package/dist/vendor/adapters/core/src/persistence/integrity.js +0 -252
  68. package/dist/vendor/adapters/core/src/persistence/ledger.d.ts +0 -23
  69. package/dist/vendor/adapters/core/src/persistence/ledger.js +0 -9
  70. package/dist/vendor/adapters/core/src/persistence/memory-store.d.ts +0 -63
  71. package/dist/vendor/adapters/core/src/persistence/memory-store.js +0 -115
  72. package/dist/vendor/adapters/core/src/persistence/runs-reader.d.ts +0 -66
  73. package/dist/vendor/adapters/core/src/persistence/runs-reader.js +0 -140
  74. package/dist/vendor/adapters/core/src/persistence/store.d.ts +0 -89
  75. package/dist/vendor/adapters/core/src/persistence/store.js +0 -125
  76. package/dist/vendor/adapters/core/src/persistence/trace-store.d.ts +0 -85
  77. package/dist/vendor/adapters/core/src/persistence/trace-store.js +0 -125
  78. package/dist/vendor/adapters/core/src/policy-compiler.d.ts +0 -2
  79. package/dist/vendor/adapters/core/src/policy-compiler.js +0 -195
  80. package/dist/vendor/adapters/core/src/policy.d.ts +0 -156
  81. package/dist/vendor/adapters/core/src/policy.js +0 -704
  82. package/dist/vendor/adapters/core/src/repo-analyzer.d.ts +0 -53
  83. package/dist/vendor/adapters/core/src/repo-analyzer.js +0 -263
  84. package/dist/vendor/adapters/core/src/rollback.d.ts +0 -15
  85. package/dist/vendor/adapters/core/src/rollback.js +0 -253
  86. package/dist/vendor/adapters/core/src/routing.d.ts +0 -82
  87. package/dist/vendor/adapters/core/src/routing.js +0 -336
  88. package/dist/vendor/adapters/core/src/test-integrity.d.ts +0 -64
  89. package/dist/vendor/adapters/core/src/test-integrity.js +0 -197
  90. package/dist/vendor/adapters/core/src/trajectory.d.ts +0 -18
  91. package/dist/vendor/adapters/core/src/trajectory.js +0 -295
  92. package/dist/vendor/contracts/delivery.d.ts +0 -47
  93. package/dist/vendor/contracts/delivery.js +0 -18
  94. package/dist/vendor/core/delivery/index.d.ts +0 -6
  95. package/dist/vendor/core/delivery/index.js +0 -4
  96. package/dist/vendor/core/delivery/message-client.d.ts +0 -18
  97. package/dist/vendor/core/delivery/message-client.js +0 -38
  98. package/dist/vendor/core/delivery/message-ledger.d.ts +0 -35
  99. package/dist/vendor/core/delivery/message-ledger.js +0 -97
  100. package/dist/vendor/core/delivery/message-schema.d.ts +0 -16
  101. package/dist/vendor/core/delivery/message-schema.js +0 -111
  102. package/dist/vendor/core/delivery/update-check.d.ts +0 -19
  103. package/dist/vendor/core/delivery/update-check.js +0 -107
@@ -1,48 +0,0 @@
1
- import type { ApprovalPolicy, ExecutionProfile, LoopTask } from "../../../contracts/index.js";
2
- export type SafetySurface = "command" | "filesystem" | "secret" | "spend" | "network" | "dependency";
3
- export type SafetyViolationKind = "command_blocked" | "path_not_allowed" | "path_denied" | "path_outside_repo" | "network_blocked" | "dependency_approval_required" | "migration_approval_required" | "config_change_approval_required" | "secret_value" | "protected_path";
4
- export interface SafetyViolation {
5
- kind: SafetyViolationKind;
6
- message: string;
7
- command?: string;
8
- file?: string;
9
- match?: string;
10
- }
11
- export interface SafetyLeashDecision {
12
- allowed: boolean;
13
- blocked: boolean;
14
- riskLevel: "safe" | "blocked";
15
- surface: SafetySurface;
16
- profile?: ExecutionProfile;
17
- blockedCommands: string[];
18
- violations: SafetyViolation[];
19
- reason?: string;
20
- }
21
- export interface ResolvedExecutionProfile {
22
- name: ExecutionProfile;
23
- networkMode: "off" | "allowlisted" | "open";
24
- allowedNetworkDomains: string[];
25
- requireDependencyApproval: boolean;
26
- requireMigrationApproval: boolean;
27
- requireConfigApproval: boolean;
28
- }
29
- export declare function evaluateVerificationLeash(task: Pick<LoopTask, "verificationPlan" | "verificationStack" | "executionProfile" | "allowedNetworkDomains">): SafetyLeashDecision;
30
- export declare function evaluateFilesystemLeash(input: {
31
- repoRoot?: string;
32
- changedFiles: string[];
33
- allowedPaths?: string[];
34
- deniedPaths?: string[];
35
- }): SafetyLeashDecision;
36
- export declare function evaluateSecretLeash(input: {
37
- values: string[];
38
- }): SafetyLeashDecision;
39
- export declare function resolveExecutionProfile(input: {
40
- executionProfile?: ExecutionProfile;
41
- allowedNetworkDomains?: string[];
42
- }): ResolvedExecutionProfile;
43
- export declare function evaluateChangeApprovalLeash(input: {
44
- changedFiles: string[];
45
- executionProfile?: ExecutionProfile;
46
- approvalPolicy?: ApprovalPolicy;
47
- }): SafetyLeashDecision;
48
- export declare function redactSecretsFromText(input: string): string;
@@ -1,497 +0,0 @@
1
- import { isAbsolute, relative, resolve } from "node:path";
2
- const BLOCKED_PATTERNS = [
3
- /(^|[\s;&|`(])rm\s+-rf(\s|$)/iu,
4
- /git\s+reset\s+--hard/iu,
5
- /git\s+clean\s+-fd/iu,
6
- /curl\b[^\n|]*\|\s*(sh|bash)/iu,
7
- /wget\b[^\n|]*\|\s*(sh|bash)/iu,
8
- /(^|[\s;&|`(])sudo(\s|$)/iu,
9
- /(^|[\s;&|`(])mkfs(\.|\s|$)/iu,
10
- /(^|[\s;&|`(])dd\s+if=/iu,
11
- /(shutdown|reboot)(\s|$)/iu,
12
- /:\(\)\s*\{\s*:\|:&\s*\}\s*;\s*:/iu,
13
- /chmod\s+-R\s+777\s+\//iu,
14
- /(kubectl|docker)\s+.*\b(delete|prune|rm)\b/iu,
15
- /ssh\s+/iu,
16
- /scp\s+/iu,
17
- // bash/sh -c "<destructive command>" wrappers — flags the wrapper shape directly,
18
- // since a naive regex on the outer command misses the destructive inner command.
19
- /\b(?:bash|sh|zsh)\s+-c\s+["'`]/iu,
20
- // recursive directory deletion via `find ... -delete` / `find ... -exec rm`
21
- /\bfind\s+\S+(?:\s+-[a-z-]+(?:\s+\S+)?)*\s+-delete\b/iu,
22
- /\bfind\s+\S+(?:\s+-[a-z-]+(?:\s+\S+)?)*\s+-exec\s+rm\b/iu,
23
- // scripting-language recursive deletion one-liners
24
- /\bshutil\.rmtree\s*\(/iu,
25
- /\bos\.(?:remove|rmdir|removedirs|unlink)\s*\(/iu,
26
- /\.(?:rm|rmdir|unlink)(?:Sync)?\s*\(/iu,
27
- /\brimraf\s*\(/iu,
28
- // Windows destructive deletion / formatting patterns
29
- /\b(?:cmd(?:\.exe)?\s+\/c\s+)?del(?:\.exe)?\s+\/[^\n]*(?:\bs\b|\bq\b|\bf\b)/iu,
30
- /\b(?:cmd(?:\.exe)?\s+\/c\s+)?rmdir(?:\.exe)?\s+\/[^\n]*\bs\b/iu,
31
- /\bremove-item\b[^\n]*(?:-recurse|-r)\b[^\n]*(?:-force|-fo)\b/iu,
32
- /\b(?:format-volume|diskpart)\b/iu
33
- ];
34
- /**
35
- * Detects `rm` invocations that combine recursive + force flags regardless of
36
- * flag ordering/grouping (`-rf`, `-fr`, `-r -f`, `--recursive --force`),
37
- * absolute-path invocation (`/bin/rm`, `/usr/bin/rm`), case, or `${IFS}`-style
38
- * shell obfuscation — all of which slip past the literal `rm\s+-rf` pattern.
39
- */
40
- function commandContainsDestructiveRemoval(command) {
41
- const normalized = command.replace(/\$\{?IFS\}?/giu, " ").toLowerCase();
42
- const rmInvocation = /(?:^|[\s;&|`(])(?:[^\s;&|`(]+\/)?rm\s+([^\n;|`]+)/giu;
43
- let match;
44
- while ((match = rmInvocation.exec(normalized)) !== null) {
45
- const args = match[1] ?? "";
46
- const hasRecursive = /(?:^|\s)-[a-z]*r[a-z]*(?:\s|$)|--recursive\b/u.test(args);
47
- const hasForce = /(?:^|\s)-[a-z]*f[a-z]*(?:\s|$)|--force\b/u.test(args);
48
- if (hasRecursive && hasForce) {
49
- return true;
50
- }
51
- }
52
- return false;
53
- }
54
- const SECRET_PATTERNS = [
55
- {
56
- kind: "secret_value",
57
- pattern: /\bOPENAI_API_KEY\s*=\s*[^\s"'`]+/giu,
58
- replacement: "OPENAI_API_KEY=[REDACTED_SECRET]"
59
- },
60
- {
61
- kind: "secret_value",
62
- pattern: /\bsk-[A-Za-z0-9_-]{8,}\b/gu,
63
- replacement: "[REDACTED_SECRET]"
64
- },
65
- {
66
- kind: "secret_value",
67
- pattern: /\bghp_[A-Za-z0-9_]{16,}\b/gu,
68
- replacement: "[REDACTED_SECRET]"
69
- },
70
- {
71
- kind: "secret_value",
72
- pattern: /\bgithub_pat_[A-Za-z0-9_]{20,}\b/gu,
73
- replacement: "[REDACTED_SECRET]"
74
- },
75
- {
76
- kind: "secret_value",
77
- pattern: /\b(?:gho|ghu|ghs|ghr)_[A-Za-z0-9_]{16,}\b/gu,
78
- replacement: "[REDACTED_SECRET]"
79
- },
80
- {
81
- kind: "secret_value",
82
- pattern: /\bAKIA[0-9A-Z]{16}\b/gu,
83
- replacement: "[REDACTED_SECRET]"
84
- },
85
- {
86
- kind: "secret_value",
87
- pattern: /\b(?:aws_secret_access_key|AWS_SECRET_ACCESS_KEY)\s*[:=]\s*[^\s"'`]+/giu,
88
- replacement: "AWS_SECRET_ACCESS_KEY=[REDACTED_SECRET]"
89
- },
90
- {
91
- kind: "secret_value",
92
- pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/giu,
93
- replacement: "[REDACTED_SECRET]"
94
- },
95
- {
96
- kind: "secret_value",
97
- pattern: /\bAIza[0-9A-Za-z_-]{30,}\b/gu,
98
- replacement: "[REDACTED_SECRET]"
99
- },
100
- {
101
- kind: "secret_value",
102
- pattern: /-----BEGIN(?:\s+[A-Z0-9]+)*\s+PRIVATE KEY-----[\s\S]*?-----END(?:\s+[A-Z0-9]+)*\s+PRIVATE KEY-----/gu,
103
- replacement: "[REDACTED_SECRET]"
104
- },
105
- {
106
- kind: "secret_value",
107
- pattern: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/gu,
108
- replacement: "[REDACTED_SECRET]"
109
- },
110
- {
111
- kind: "secret_value",
112
- pattern: /\b(?:api[_-]?key|secret|password|passwd|token)\s*[:=]\s*["']?[A-Za-z0-9_\-/+=]{12,}["']?/giu,
113
- replacement: "[REDACTED_SECRET]"
114
- }
115
- ];
116
- const PROTECTED_PATH_PATTERNS = [
117
- {
118
- kind: "protected_path",
119
- pattern: /\B\.env(?!\.example\b)(?:\.[A-Za-z0-9._-]+)?\b/giu,
120
- replacement: "[REDACTED_PATH]"
121
- },
122
- {
123
- kind: "protected_path",
124
- pattern: /\bid_rsa\b/giu,
125
- replacement: "[REDACTED_PATH]"
126
- },
127
- {
128
- kind: "protected_path",
129
- pattern: /\b[A-Za-z0-9._/-]+\.(pem|p12|key)\b/giu,
130
- replacement: "[REDACTED_PATH]"
131
- }
132
- ];
133
- export function evaluateVerificationLeash(task) {
134
- const commands = [
135
- ...(task.verificationPlan ?? []),
136
- ...((task.verificationStack ?? []).map((step) => step.command))
137
- ].filter(Boolean);
138
- const profile = resolveExecutionProfile(task);
139
- const blockedCommands = commands.filter((command) => BLOCKED_PATTERNS.some((pattern) => pattern.test(command)) ||
140
- commandContainsDestructiveRemoval(command));
141
- const violations = blockedCommands.map((command) => ({
142
- kind: "command_blocked",
143
- command,
144
- message: `Blocked destructive verifier command: ${command}`
145
- }));
146
- if (blockedCommands.length > 0) {
147
- return {
148
- allowed: false,
149
- blocked: true,
150
- riskLevel: "blocked",
151
- surface: "command",
152
- profile: profile.name,
153
- blockedCommands,
154
- violations,
155
- reason: "Safety leash blocked destructive or unbounded verifier commands."
156
- };
157
- }
158
- const networkViolations = commands
159
- .map((command) => buildNetworkViolation(command, profile))
160
- .filter((violation) => Boolean(violation));
161
- if (networkViolations.length > 0) {
162
- return {
163
- allowed: false,
164
- blocked: true,
165
- riskLevel: "blocked",
166
- surface: "network",
167
- profile: profile.name,
168
- blockedCommands: commands.filter((command) => buildNetworkViolation(command, profile)),
169
- violations: networkViolations,
170
- reason: `Safety leash blocked outbound network access for the ${profile.name} profile.`
171
- };
172
- }
173
- return {
174
- allowed: true,
175
- blocked: false,
176
- riskLevel: "safe",
177
- surface: "command",
178
- profile: profile.name,
179
- blockedCommands: [],
180
- violations: []
181
- };
182
- }
183
- export function evaluateFilesystemLeash(input) {
184
- const violations = [];
185
- for (const rawFile of input.changedFiles) {
186
- const normalized = normalizeChangedFile(rawFile, input.repoRoot);
187
- if (normalized.outsideRepo) {
188
- violations.push({
189
- kind: "path_outside_repo",
190
- file: rawFile,
191
- message: `Changed file is outside the configured repo root: ${rawFile}`
192
- });
193
- continue;
194
- }
195
- const file = normalized.file;
196
- if (!file) {
197
- continue;
198
- }
199
- if ((input.deniedPaths ?? []).some((pattern) => matchesPathPattern(file, pattern))) {
200
- violations.push({
201
- kind: "path_denied",
202
- file,
203
- message: `Changed file matches a denylisted path: ${file}`
204
- });
205
- continue;
206
- }
207
- const allowedPaths = input.allowedPaths ?? [];
208
- if (allowedPaths.length > 0 && !allowedPaths.some((pattern) => matchesPathPattern(file, pattern))) {
209
- violations.push({
210
- kind: "path_not_allowed",
211
- file,
212
- message: `Changed file is outside the allowed paths: ${file}`
213
- });
214
- }
215
- }
216
- if (violations.length > 0) {
217
- return {
218
- allowed: false,
219
- blocked: true,
220
- riskLevel: "blocked",
221
- surface: "filesystem",
222
- blockedCommands: [],
223
- violations,
224
- reason: "Safety leash blocked file changes outside the allowed repo contract."
225
- };
226
- }
227
- return {
228
- allowed: true,
229
- blocked: false,
230
- riskLevel: "safe",
231
- surface: "filesystem",
232
- blockedCommands: [],
233
- violations: []
234
- };
235
- }
236
- export function evaluateSecretLeash(input) {
237
- const violations = [];
238
- for (const value of input.values) {
239
- if (!value)
240
- continue;
241
- for (const rule of SECRET_PATTERNS) {
242
- for (const match of value.matchAll(rule.pattern)) {
243
- const matched = match[0];
244
- if (!matched)
245
- continue;
246
- violations.push({
247
- kind: rule.kind,
248
- match: matched,
249
- message: "Secret-like credential value detected in the runtime context."
250
- });
251
- }
252
- }
253
- }
254
- if (violations.length > 0) {
255
- return {
256
- allowed: false,
257
- blocked: true,
258
- riskLevel: "blocked",
259
- surface: "secret",
260
- blockedCommands: [],
261
- violations,
262
- reason: "Safety leash blocked secret-like credential values from entering the runtime context."
263
- };
264
- }
265
- return {
266
- allowed: true,
267
- blocked: false,
268
- riskLevel: "safe",
269
- surface: "secret",
270
- blockedCommands: [],
271
- violations: []
272
- };
273
- }
274
- export function resolveExecutionProfile(input) {
275
- const name = input.executionProfile ?? "strict_local";
276
- const allowedNetworkDomains = [...(input.allowedNetworkDomains ?? [])];
277
- switch (name) {
278
- case "ci_safe":
279
- return {
280
- name,
281
- networkMode: "off",
282
- allowedNetworkDomains,
283
- requireDependencyApproval: true,
284
- requireMigrationApproval: true,
285
- requireConfigApproval: true
286
- };
287
- case "staging_controlled":
288
- return {
289
- name,
290
- networkMode: allowedNetworkDomains.length > 0 ? "allowlisted" : "off",
291
- allowedNetworkDomains,
292
- requireDependencyApproval: true,
293
- requireMigrationApproval: true,
294
- requireConfigApproval: true
295
- };
296
- case "research_untrusted":
297
- return {
298
- name,
299
- networkMode: allowedNetworkDomains.length > 0 ? "allowlisted" : "open",
300
- allowedNetworkDomains,
301
- requireDependencyApproval: true,
302
- requireMigrationApproval: true,
303
- requireConfigApproval: true
304
- };
305
- case "strict_local":
306
- default:
307
- return {
308
- name: "strict_local",
309
- networkMode: "off",
310
- allowedNetworkDomains,
311
- requireDependencyApproval: true,
312
- requireMigrationApproval: true,
313
- requireConfigApproval: true
314
- };
315
- }
316
- }
317
- export function evaluateChangeApprovalLeash(input) {
318
- const profile = resolveExecutionProfile({
319
- executionProfile: input.executionProfile
320
- });
321
- const violations = [];
322
- for (const file of input.changedFiles.map((entry) => entry.replace(/\\/gu, "/"))) {
323
- if (isDependencyFile(file) && profile.requireDependencyApproval && !input.approvalPolicy?.dependencyAdds) {
324
- violations.push({
325
- kind: "dependency_approval_required",
326
- file,
327
- message: `Dependency-related file change requires approval in the ${profile.name} profile: ${file}`
328
- });
329
- continue;
330
- }
331
- if (isMigrationFile(file) && profile.requireMigrationApproval && !input.approvalPolicy?.migrations) {
332
- violations.push({
333
- kind: "migration_approval_required",
334
- file,
335
- message: `Migration change requires approval in the ${profile.name} profile: ${file}`
336
- });
337
- continue;
338
- }
339
- if (isConfigChangeFile(file) && profile.requireConfigApproval && !input.approvalPolicy?.configChanges) {
340
- violations.push({
341
- kind: "config_change_approval_required",
342
- file,
343
- message: `Deployment or configuration change requires approval in the ${profile.name} profile: ${file}`
344
- });
345
- }
346
- }
347
- if (violations.length > 0) {
348
- return {
349
- allowed: false,
350
- blocked: true,
351
- riskLevel: "blocked",
352
- surface: "dependency",
353
- profile: profile.name,
354
- blockedCommands: [],
355
- violations,
356
- reason: "Safety leash blocked dependency, migration, or configuration changes that require approval."
357
- };
358
- }
359
- return {
360
- allowed: true,
361
- blocked: false,
362
- riskLevel: "safe",
363
- surface: "dependency",
364
- profile: profile.name,
365
- blockedCommands: [],
366
- violations: []
367
- };
368
- }
369
- export function redactSecretsFromText(input) {
370
- let output = input;
371
- for (const rule of [...SECRET_PATTERNS, ...PROTECTED_PATH_PATTERNS]) {
372
- output = output.replace(rule.pattern, rule.replacement);
373
- }
374
- return output;
375
- }
376
- function normalizeChangedFile(file, repoRoot) {
377
- const normalizedInput = file.replace(/\\/gu, "/");
378
- if (!repoRoot) {
379
- return {
380
- file: normalizedInput,
381
- outsideRepo: normalizedInput.startsWith("../") || normalizedInput.includes("/../")
382
- };
383
- }
384
- const absoluteRoot = resolve(repoRoot);
385
- const absoluteFile = isAbsolute(file) ? resolve(file) : resolve(absoluteRoot, file);
386
- const repoRelative = relative(absoluteRoot, absoluteFile).replace(/\\/gu, "/");
387
- if (repoRelative.length === 0 ||
388
- repoRelative === ".." ||
389
- repoRelative.startsWith("../") ||
390
- isAbsolute(repoRelative)) {
391
- return { outsideRepo: true };
392
- }
393
- return {
394
- file: repoRelative,
395
- outsideRepo: false
396
- };
397
- }
398
- function matchesPathPattern(file, pattern) {
399
- const normalizedFile = normalizePathForMatching(file);
400
- const normalizedPattern = normalizePathForMatching(pattern);
401
- if (!normalizedPattern.includes("*")) {
402
- return (normalizedFile === normalizedPattern ||
403
- normalizedFile.startsWith(`${normalizedPattern.replace(/\/$/u, "")}/`));
404
- }
405
- const regexStr = normalizedPattern
406
- .replace(/[.+^${}()|[\]\\]/gu, "\\$&")
407
- .replace(/\*\*/gu, "__DOUBLESTAR__")
408
- .replace(/\*/gu, "[^/]*")
409
- .replace(/__DOUBLESTAR__/gu, ".*");
410
- return new RegExp(`^${regexStr}$`, "u").test(normalizedFile);
411
- }
412
- function normalizePathForMatching(value) {
413
- return value
414
- .replace(/\\/gu, "/")
415
- .replace(/^\.\//u, "")
416
- .replace(/\/{2,}/gu, "/")
417
- .replace(/\/$/u, "");
418
- }
419
- function buildNetworkViolation(command, profile) {
420
- const targets = extractNetworkTargets(command);
421
- if (targets.length === 0) {
422
- return undefined;
423
- }
424
- if (profile.networkMode === "open") {
425
- return undefined;
426
- }
427
- if (profile.networkMode === "allowlisted") {
428
- const blockedTarget = targets.find((target) => !profile.allowedNetworkDomains.some((domain) => target === domain || target.endsWith(`.${domain}`)));
429
- if (!blockedTarget) {
430
- return undefined;
431
- }
432
- return {
433
- kind: "network_blocked",
434
- command,
435
- match: blockedTarget,
436
- message: `Network target is not allowlisted for the ${profile.name} profile: ${blockedTarget}`
437
- };
438
- }
439
- return {
440
- kind: "network_blocked",
441
- command,
442
- match: targets[0],
443
- message: `Outbound network access is blocked for the ${profile.name} profile.`
444
- };
445
- }
446
- function extractNetworkTargets(command) {
447
- if (!/\b(curl|wget|invoke-webrequest|iwr|httpie|http)\b/iu.test(command)) {
448
- return [];
449
- }
450
- return [...command.matchAll(/https?:\/\/([^/\s"'`]+)/giu)]
451
- .map((match) => match[1]?.toLowerCase())
452
- .filter((value) => Boolean(value));
453
- }
454
- function isDependencyFile(file) {
455
- const normalized = file.replace(/\\/gu, "/");
456
- return [
457
- "package.json",
458
- "package-lock.json",
459
- "pnpm-lock.yaml",
460
- "yarn.lock",
461
- "bun.lock",
462
- "bun.lockb",
463
- "pyproject.toml",
464
- "requirements.txt",
465
- "Cargo.toml",
466
- "Cargo.lock"
467
- ].includes(normalized.split("/").at(-1) ?? normalized);
468
- }
469
- function isMigrationFile(file) {
470
- const normalized = file.replace(/\\/gu, "/");
471
- return (normalized.includes("/migrations/") ||
472
- normalized.startsWith("migrations/") ||
473
- normalized.includes("prisma/migrations/"));
474
- }
475
- function isConfigChangeFile(file) {
476
- const normalized = file.replace(/\\/gu, "/");
477
- const leaf = normalized.split("/").at(-1) ?? normalized;
478
- if ([
479
- "vercel.json",
480
- "netlify.toml",
481
- "wrangler.toml",
482
- "docker-compose.yml",
483
- "docker-compose.yaml",
484
- "compose.yml",
485
- "compose.yaml",
486
- "fly.toml",
487
- "railway.json"
488
- ].includes(leaf)) {
489
- return true;
490
- }
491
- return (normalized.startsWith(".github/workflows/") ||
492
- normalized.startsWith("deploy/") ||
493
- normalized.startsWith("deployment/") ||
494
- normalized.startsWith("infra/") ||
495
- normalized.startsWith("infrastructure/") ||
496
- normalized.startsWith("ops/"));
497
- }
@@ -1,18 +0,0 @@
1
- import { type CompilerAdapterRequest, type PromptPacket } from "../compiler.js";
2
- import type { RunStore } from "./store.js";
3
- export interface CompileResult {
4
- packet: PromptPacket;
5
- }
6
- /**
7
- * Compile a deterministic PromptPacket from the request state and, when a
8
- * store is provided, persist it as compiled-context.json in the attempt
9
- * artifact directory.
10
- *
11
- * R3.7: Context compiler produces deterministic compiled-context.json.
12
- * R3.8: Any attempt prompt can be reconstructed from disk artifacts alone.
13
- */
14
- export declare function compileAndPersistContext(request: CompilerAdapterRequest, options: {
15
- attemptIndex: number;
16
- store?: RunStore;
17
- now?: string;
18
- }): Promise<CompileResult>;
@@ -1,34 +0,0 @@
1
- import { compilePromptPacket } from "../compiler.js";
2
- import { makeLedgerEvent } from "./ledger.js";
3
- /**
4
- * Compile a deterministic PromptPacket from the request state and, when a
5
- * store is provided, persist it as compiled-context.json in the attempt
6
- * artifact directory.
7
- *
8
- * R3.7: Context compiler produces deterministic compiled-context.json.
9
- * R3.8: Any attempt prompt can be reconstructed from disk artifacts alone.
10
- */
11
- export async function compileAndPersistContext(request, options) {
12
- const packet = compilePromptPacket(request);
13
- const ts = options.now ?? new Date().toISOString();
14
- if (options.store) {
15
- // Write compiled-context.json to attempt artifact directory
16
- await options.store.writeAttemptArtifacts(request.loopId, options.attemptIndex, {
17
- compiledContext: packet
18
- });
19
- // Append prompt.compiled ledger event
20
- await options.store.appendLedger(request.loopId, makeLedgerEvent({
21
- kind: "prompt.compiled",
22
- runId: request.loopId,
23
- attemptIndex: options.attemptIndex,
24
- payload: {
25
- attemptId: request.attemptId,
26
- attemptNumber: packet.attemptNumber,
27
- priorFailurePatterns: packet.priorFailurePatterns,
28
- budgetEnvelope: packet.budgetEnvelope
29
- },
30
- timestamp: ts
31
- }));
32
- }
33
- return { packet };
34
- }
@@ -1,10 +0,0 @@
1
- export { makeLedgerEvent } from "./ledger.js";
2
- export type { LedgerEvent, LedgerEventDraft, LedgerEventKind } from "./ledger.js";
3
- export { resolveReceiptIntegrityPath, verifyReceiptIntegrityFromFiles, writeReceiptIntegrityMaterial } from "./integrity.js";
4
- export type { ReceiptIntegrityChainEntry, StoredReceiptIntegrityMaterial } from "./integrity.js";
5
- export { artifactDir, createFileRunStore, resolveRunsRoot, runDir } from "./store.js";
6
- export type { AttemptArtifacts, RunContract, RunStore } from "./store.js";
7
- export { readAllLoopRecords, readLatestLoopRecord, readLatestLoopRecordFromFile, readLoopRecordsFromFile } from "./runs-reader.js";
8
- export type { LoopAttemptRecord, LoopRunRecord } from "./runs-reader.js";
9
- export { compileAndPersistContext } from "./compiler.js";
10
- export type { CompileResult } from "./compiler.js";
@@ -1,5 +0,0 @@
1
- export { makeLedgerEvent } from "./ledger.js";
2
- export { resolveReceiptIntegrityPath, verifyReceiptIntegrityFromFiles, writeReceiptIntegrityMaterial } from "./integrity.js";
3
- export { artifactDir, createFileRunStore, resolveRunsRoot, runDir } from "./store.js";
4
- export { readAllLoopRecords, readLatestLoopRecord, readLatestLoopRecordFromFile, readLoopRecordsFromFile } from "./runs-reader.js";
5
- export { compileAndPersistContext } from "./compiler.js";
@@ -1,39 +0,0 @@
1
- import type { LoopRecord, ReceiptIntegritySummary, ReceiptScope } from "../../../../contracts/index.js";
2
- export interface ReceiptIntegrityChainEntry {
3
- index: number;
4
- eventId?: string;
5
- type?: string;
6
- kind?: string;
7
- timestamp?: string;
8
- prevHash: string;
9
- entryHash: string;
10
- }
11
- export interface StoredReceiptIntegrityMaterial {
12
- schemaVersion: "martin.receipt-integrity.v1";
13
- runId: string;
14
- keyId: string;
15
- signedAt: string;
16
- scope?: ReceiptScope;
17
- loopRecordSha256: string;
18
- ledgerSha256: string;
19
- ledgerHeadHash: string;
20
- entryCount: number;
21
- chain: ReceiptIntegrityChainEntry[];
22
- signatureHmacSha256: string;
23
- }
24
- export declare function resolveReceiptIntegrityRoot(env?: NodeJS.ProcessEnv): string;
25
- export declare function writeReceiptIntegrityMaterial(input: {
26
- runId: string;
27
- runsRoot: string;
28
- loopRecord: LoopRecord;
29
- ledgerEntries: unknown[];
30
- scope?: ReceiptScope;
31
- signedAt?: string;
32
- }): Promise<StoredReceiptIntegrityMaterial | undefined>;
33
- export declare function verifyReceiptIntegrityFromFiles(input: {
34
- runId: string;
35
- runsRoot: string;
36
- loopRecordPath: string;
37
- ledgerPath: string;
38
- }): Promise<ReceiptIntegritySummary>;
39
- export declare function resolveReceiptIntegrityPath(runsRoot: string, runId: string): string;