@martinloop/mcp 0.3.6 → 0.3.7

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 (102) hide show
  1. package/README.md +137 -145
  2. package/dist/discovery-metadata.d.ts +1 -1
  3. package/dist/discovery-metadata.js +1 -1
  4. package/dist/package-version.d.ts +1 -1
  5. package/dist/package-version.js +1 -1
  6. package/dist/resources.d.ts +2 -1
  7. package/dist/resources.js +251 -197
  8. package/dist/server-validation.d.ts +1 -1
  9. package/dist/server-validation.js +11 -16
  10. package/dist/server.d.ts +0 -23
  11. package/dist/server.js +7 -152
  12. package/dist/tools/run-loop.d.ts +2 -1
  13. package/dist/tools/run-loop.js +5 -1
  14. package/dist/tools/tool-support.js +1 -0
  15. package/dist/vendor/adapters/adapters/src/claude-cli.d.ts +146 -0
  16. package/dist/vendor/adapters/adapters/src/claude-cli.js +1100 -0
  17. package/dist/vendor/adapters/adapters/src/cli-bridge.d.ts +103 -0
  18. package/dist/vendor/adapters/adapters/src/cli-bridge.js +569 -0
  19. package/dist/vendor/adapters/adapters/src/codex-launcher.d.ts +78 -0
  20. package/dist/vendor/adapters/adapters/src/codex-launcher.js +663 -0
  21. package/dist/vendor/adapters/adapters/src/direct-provider.d.ts +10 -0
  22. package/dist/vendor/adapters/adapters/src/direct-provider.js +40 -0
  23. package/dist/vendor/adapters/adapters/src/index.d.ts +8 -0
  24. package/dist/vendor/adapters/adapters/src/index.js +8 -0
  25. package/dist/vendor/adapters/adapters/src/openai-compatible.d.ts +62 -0
  26. package/dist/vendor/adapters/adapters/src/openai-compatible.js +306 -0
  27. package/dist/vendor/adapters/adapters/src/runtime-support.d.ts +17 -0
  28. package/dist/vendor/adapters/adapters/src/runtime-support.js +59 -0
  29. package/dist/vendor/adapters/adapters/src/stub-agent-cli.d.ts +8 -0
  30. package/dist/vendor/adapters/adapters/src/stub-agent-cli.js +40 -0
  31. package/dist/vendor/adapters/adapters/src/stub-direct-provider.d.ts +8 -0
  32. package/dist/vendor/adapters/adapters/src/stub-direct-provider.js +12 -0
  33. package/dist/vendor/adapters/adapters/src/verifier-only.d.ts +9 -0
  34. package/dist/vendor/adapters/adapters/src/verifier-only.js +63 -0
  35. package/dist/vendor/adapters/claude-cli.d.ts +2 -2
  36. package/dist/vendor/adapters/claude-cli.js +28 -42
  37. package/dist/vendor/adapters/contracts/src/context-graph.d.ts +48 -0
  38. package/dist/vendor/adapters/contracts/src/context-graph.js +26 -0
  39. package/dist/vendor/adapters/contracts/src/execution-policy.d.ts +78 -0
  40. package/dist/vendor/adapters/contracts/src/execution-policy.js +43 -0
  41. package/dist/vendor/adapters/contracts/src/governance.d.ts +24 -0
  42. package/dist/vendor/adapters/contracts/src/governance.js +11 -0
  43. package/dist/vendor/adapters/contracts/src/identity.d.ts +29 -0
  44. package/dist/vendor/adapters/contracts/src/identity.js +30 -0
  45. package/dist/vendor/adapters/contracts/src/index.d.ts +412 -0
  46. package/dist/vendor/adapters/contracts/src/index.js +225 -0
  47. package/dist/vendor/adapters/contracts/src/operator.d.ts +19 -0
  48. package/dist/vendor/adapters/contracts/src/operator.js +11 -0
  49. package/dist/vendor/adapters/contracts/src/trajectory.d.ts +26 -0
  50. package/dist/vendor/adapters/contracts/src/trajectory.js +27 -0
  51. package/dist/vendor/adapters/core/src/compiler.d.ts +52 -0
  52. package/dist/vendor/adapters/core/src/compiler.js +52 -0
  53. package/dist/vendor/adapters/core/src/context-graph.d.ts +3 -0
  54. package/dist/vendor/adapters/core/src/context-graph.js +371 -0
  55. package/dist/vendor/adapters/core/src/context-integrity.d.ts +26 -0
  56. package/dist/vendor/adapters/core/src/context-integrity.js +80 -0
  57. package/dist/vendor/adapters/core/src/grounding.d.ts +38 -0
  58. package/dist/vendor/adapters/core/src/grounding.js +273 -0
  59. package/dist/vendor/adapters/core/src/identity.d.ts +20 -0
  60. package/dist/vendor/adapters/core/src/identity.js +86 -0
  61. package/dist/vendor/adapters/core/src/index.d.ts +186 -0
  62. package/dist/vendor/adapters/core/src/index.js +1495 -0
  63. package/dist/vendor/adapters/core/src/leash.d.ts +48 -0
  64. package/dist/vendor/adapters/core/src/leash.js +497 -0
  65. package/dist/vendor/adapters/core/src/persistence/compiler.d.ts +18 -0
  66. package/dist/vendor/adapters/core/src/persistence/compiler.js +34 -0
  67. package/dist/vendor/adapters/core/src/persistence/index.d.ts +10 -0
  68. package/dist/vendor/adapters/core/src/persistence/index.js +5 -0
  69. package/dist/vendor/adapters/core/src/persistence/integrity.d.ts +39 -0
  70. package/dist/vendor/adapters/core/src/persistence/integrity.js +252 -0
  71. package/dist/vendor/adapters/core/src/persistence/ledger.d.ts +23 -0
  72. package/dist/vendor/adapters/core/src/persistence/ledger.js +9 -0
  73. package/dist/vendor/adapters/core/src/persistence/memory-store.d.ts +63 -0
  74. package/dist/vendor/adapters/core/src/persistence/memory-store.js +115 -0
  75. package/dist/vendor/adapters/core/src/persistence/runs-reader.d.ts +66 -0
  76. package/dist/vendor/adapters/core/src/persistence/runs-reader.js +140 -0
  77. package/dist/vendor/adapters/core/src/persistence/store.d.ts +89 -0
  78. package/dist/vendor/adapters/core/src/persistence/store.js +125 -0
  79. package/dist/vendor/adapters/core/src/persistence/trace-store.d.ts +85 -0
  80. package/dist/vendor/adapters/core/src/persistence/trace-store.js +125 -0
  81. package/dist/vendor/adapters/core/src/policy-compiler.d.ts +2 -0
  82. package/dist/vendor/adapters/core/src/policy-compiler.js +195 -0
  83. package/dist/vendor/adapters/core/src/policy.d.ts +156 -0
  84. package/dist/vendor/adapters/core/src/policy.js +704 -0
  85. package/dist/vendor/adapters/core/src/repo-analyzer.d.ts +53 -0
  86. package/dist/vendor/adapters/core/src/repo-analyzer.js +263 -0
  87. package/dist/vendor/adapters/core/src/rollback.d.ts +15 -0
  88. package/dist/vendor/adapters/core/src/rollback.js +253 -0
  89. package/dist/vendor/adapters/core/src/routing.d.ts +82 -0
  90. package/dist/vendor/adapters/core/src/routing.js +336 -0
  91. package/dist/vendor/adapters/core/src/test-integrity.d.ts +64 -0
  92. package/dist/vendor/adapters/core/src/test-integrity.js +197 -0
  93. package/dist/vendor/adapters/core/src/trajectory.d.ts +18 -0
  94. package/dist/vendor/adapters/core/src/trajectory.js +295 -0
  95. package/dist/vendor/adapters/openai-compatible.js +6 -6
  96. package/dist/vendor/adapters/verifier-only.js +2 -2
  97. package/dist/vendor/contracts/index.d.ts +1 -1
  98. package/dist/vendor/core/compiler.js +4 -9
  99. package/dist/vendor/core/index.js +1 -88
  100. package/dist/vendor/core/rollback.js +2 -3
  101. package/package.json +76 -76
  102. package/server.json +21 -21
@@ -11,14 +11,14 @@
11
11
  *
12
12
  * MCP tools and integration tests use the same factories.
13
13
  */
14
- import type { MartinAdapter, MartinAdapterRequest } from "../core/index.js";
14
+ import type { MartinAdapter } from "../core/index.js";
15
15
  import { type SpawnLike } from "./cli-bridge.js";
16
16
  /**
17
17
  * Given a prompt string, returns the full argv array to pass to spawn().
18
18
  * Example for Claude: () => ["--output-format", "json", "--print"]
19
19
  * Example for Codex: () => ["exec", "--sandbox", "workspace-write", "-"]
20
20
  */
21
- export type CliArgsBuilder = (prompt: string, request: MartinAdapterRequest) => string[];
21
+ export type CliArgsBuilder = (prompt: string) => string[];
22
22
  export type CliStdinBuilder = (prompt: string) => string | undefined;
23
23
  export interface AgentCliAdapterOptions {
24
24
  /** The executable to spawn (e.g. "claude", "codex"). */
@@ -239,15 +239,13 @@ function extractGeminiJsonResult(stdout, modelLabel) {
239
239
  })
240
240
  };
241
241
  }
242
- function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate) {
242
+ function createStreamingUsageInspector(capUsd, modelLabel) {
243
243
  const pricing = (modelLabel ? MODEL_PRICING[modelLabel] : undefined) ??
244
244
  { inputPer1K: BLENDED_INPUT_COST_PER_1K, outputPer1K: BLENDED_OUTPUT_COST_PER_1K };
245
245
  // Safety margin: terminate at 80% of cap to bound one-turn overshoot.
246
246
  // Without this, a single expensive turn can blow past the cap before the
247
247
  // next check fires (proven live: $1.50 cap → $28.42 actual).
248
- const largeContext = promptTokenEstimate > 10_000;
249
- const effectiveCapRatio = largeContext ? 0.7 : 0.8;
250
- const effectiveCapUsd = capUsd * effectiveCapRatio;
248
+ const effectiveCapUsd = capUsd * 0.8;
251
249
  // Token-count ceiling fallback: if no usage events are ever parsed (e.g.
252
250
  // Claude changes its stream-json event format), use raw byte volume as a
253
251
  // last-resort circuit breaker. Derived from budget / blended cost per char.
@@ -271,7 +269,7 @@ function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate)
271
269
  const checkBudgetExceeded = (terminate) => {
272
270
  if (capUsd > 0 && cumulativeUsd > effectiveCapUsd) {
273
271
  terminate(`Streaming usage cap exceeded after ${String(turns)} turn(s): cumulative cost ~$${cumulativeUsd.toFixed(4)} ` +
274
- `surpassed the per-attempt cap $${capUsd.toFixed(4)} (${String(Math.round(effectiveCapRatio * 100))}% threshold: $${effectiveCapUsd.toFixed(4)}). ` +
272
+ `surpassed the per-attempt cap $${capUsd.toFixed(4)} (80% threshold: $${effectiveCapUsd.toFixed(4)}). ` +
275
273
  `Subprocess terminated to bound runaway overspend.`);
276
274
  }
277
275
  };
@@ -302,23 +300,11 @@ function createStreamingUsageInspector(capUsd, modelLabel, promptTokenEstimate)
302
300
  if (turnTokensIn === 0 && turnTokensOut === 0) {
303
301
  return;
304
302
  }
305
- const turnUsd = (turnTokensIn / 1000) * pricing.inputPer1K + (turnTokensOut / 1000) * pricing.outputPer1K;
306
- const remainingBudgetBeforeTurn = Math.max(capUsd - cumulativeUsd, 0);
307
- if (capUsd > 0 && remainingBudgetBeforeTurn > 0 && turnUsd > remainingBudgetBeforeTurn * 0.5) {
308
- cumulativeUsd += turnUsd;
309
- tokensIn += turnTokensIn;
310
- tokensOut += turnTokensOut;
311
- turns += 1;
312
- usageEventSeen = true;
313
- terminate(`Single turn spend ~$${turnUsd.toFixed(4)} consumed more than 50% of the remaining per-attempt budget ` +
314
- `($${remainingBudgetBeforeTurn.toFixed(4)} before the turn). Subprocess terminated to prevent a one-turn overshoot.`);
315
- return;
316
- }
317
303
  tokensIn += turnTokensIn;
318
304
  tokensOut += turnTokensOut;
319
305
  turns += 1;
320
306
  usageEventSeen = true;
321
- cumulativeUsd += turnUsd;
307
+ cumulativeUsd += (turnTokensIn / 1000) * pricing.inputPer1K + (turnTokensOut / 1000) * pricing.outputPer1K;
322
308
  checkBudgetExceeded(terminate);
323
309
  };
324
310
  const ingestLine = (line, terminate) => {
@@ -477,7 +463,7 @@ export function createAgentCliAdapter(options) {
477
463
  };
478
464
  }
479
465
  }
480
- const args = options.argsBuilder(prompt, request);
466
+ const args = options.argsBuilder(prompt);
481
467
  const stdinData = options.stdinBuilder?.(prompt);
482
468
  // Live cumulative-cost circuit breaker: a single attempt should never be
483
469
  // allowed to spend more than the loop has left. `--output-format json`
@@ -486,7 +472,7 @@ export function createAgentCliAdapter(options) {
486
472
  // instant projected spend crosses what remains — bounding the worst case
487
473
  // to roughly one turn's overshoot rather than the entire runaway session.
488
474
  const streamingUsage = options.streamingUsageCap && request.context.remainingBudgetUsd > 0
489
- ? createStreamingUsageInspector(request.context.remainingBudgetUsd, options.model ?? options.command, estimatedUsage.tokensIn)
475
+ ? createStreamingUsageInspector(request.context.remainingBudgetUsd, options.model ?? options.command)
490
476
  : undefined;
491
477
  const agentResult = await runSubprocess(options.command, args, {
492
478
  cwd: workingDirectory,
@@ -536,10 +522,14 @@ export function createAgentCliAdapter(options) {
536
522
  };
537
523
  }
538
524
  if (agentResult.exitCode !== 0 && agentResult.stdout.trim().length === 0) {
525
+ const fullStderr = agentResult.stderr.trim();
526
+ const stderrSnippet = fullStderr ? fullStderr.slice(0, 2000) : "(no stderr)";
527
+ const stdoutLen = agentResult.stdout.length;
528
+ const diagnosticSummary = `${options.command} exited (code ${String(agentResult.exitCode)}) with empty stdout (${String(stdoutLen)} bytes). stderr: ${stderrSnippet}`;
539
529
  const failureMessage = formatPreVerifierSubprocessFailure(options.command, agentResult.stderr, agentResult.exitCode);
540
530
  return {
541
531
  status: "failed",
542
- summary: `${options.command} subprocess exited before verifier execution.`,
532
+ summary: diagnosticSummary,
543
533
  usage: normalizeUsage({
544
534
  actualUsd: 0,
545
535
  tokensIn: 0,
@@ -548,6 +538,9 @@ export function createAgentCliAdapter(options) {
548
538
  }),
549
539
  verification: { passed: false, summary: `Verifier not run: ${failureMessage}` },
550
540
  failure: {
541
+ // Raw stderr is preserved in diagnosticSummary above; use the
542
+ // normalized/classified message here so downstream consumers and
543
+ // tests get a consistent, parseable failure signal.
551
544
  message: failureMessage
552
545
  }
553
546
  };
@@ -804,18 +797,21 @@ export function createClaudeCliAdapter(options = {}) {
804
797
  supportsJsonOutput: true,
805
798
  streamingUsageCap: true,
806
799
  spawnImpl: options.spawnImpl,
807
- argsBuilder: (_prompt, request) => [
800
+ argsBuilder: (_prompt) => [
808
801
  "--output-format",
809
802
  "stream-json",
810
803
  "--verbose",
811
804
  "--print",
812
805
  "--dangerously-skip-permissions",
813
- // Prevent the child Claude process from loading the parent's MCP servers.
814
- // Without this, a MartinLoop MCP server in the user's config gets spawned
815
- // inside the governed subprocess, causing conflicts and "MCP server being
816
- // overwritten" errors.
817
- "--strict-mcp-config",
818
- ...(request.context.remainingTokens > 0 ? ["--max-tokens", String(request.context.remainingTokens)] : []),
806
+ // Subprocess isolation strategy:
807
+ // --bare: skips hooks (prevents SessionEnd/hook failures causing non-zero exits),
808
+ // MCP server loading, LSP, CLAUDE.md discovery, and background prefetches.
809
+ // Requires ANTHROPIC_API_KEY (OAuth/keychain auth not available in bare mode).
810
+ // --strict-mcp-config: fallback when ANTHROPIC_API_KEY is not set — still
811
+ // prevents parent MCP servers from being inherited by the subprocess.
812
+ ...(process.env["ANTHROPIC_API_KEY"] ? ["--bare"] : ["--strict-mcp-config"]),
813
+ // NOTE: --max-tokens does not exist in the claude CLI. Token cap enforcement
814
+ // is handled at the MartinLoop layer via streamingUsageCap, not via subprocess flags.
819
815
  ...modelArgs,
820
816
  ...extraArgs
821
817
  ],
@@ -915,21 +911,13 @@ function buildPrompt(request) {
915
911
  const lines = [];
916
912
  const mutationMode = request.context.mutationMode ?? "edit";
917
913
  lines.push("You are running in autonomous agentic mode.");
918
- if (mutationMode === "verify_only") {
919
- lines.push("DO NOT EDIT FILES. Run the verifier only and report whether it passes.");
920
- lines.push("Do not ask for confirmation. Do not ask clarifying questions.");
921
- }
922
- else {
923
- lines.push("MAKE ALL REQUIRED FILE EDITS NOW. Do not ask for confirmation. Do not ask clarifying questions.");
924
- lines.push("Do not explain what you found without also making the changes. Edit the files and complete the task.");
925
- }
914
+ lines.push("MAKE ALL REQUIRED FILE EDITS NOW. Do not ask for confirmation. Do not ask clarifying questions.");
915
+ lines.push("Do not explain what you found without also making the changes. Edit the files and complete the task.");
926
916
  lines.push("");
927
917
  lines.push("If PROGRESS.md exists in your working directory, read it first for context from prior attempts.");
928
918
  lines.push("If it does not exist, proceed with the objective below.");
929
919
  lines.push("");
930
- lines.push(mutationMode === "verify_only"
931
- ? "Complete the following verification-only task without making file changes."
932
- : "Complete the following coding task. Make all necessary file changes.");
920
+ lines.push("Complete the following coding task. Make all necessary file changes.");
933
921
  lines.push("When you are done, the verification commands listed below must pass.");
934
922
  lines.push("");
935
923
  lines.push("OBJECTIVE:");
@@ -967,9 +955,7 @@ function buildPrompt(request) {
967
955
  lines.push(` Attempt ${String(attemptNumber)}`);
968
956
  lines.push(` Remaining budget: $${String(request.context.remainingBudgetUsd)} USD`);
969
957
  lines.push(` Remaining iterations: ${String(request.context.remainingIterations)}`);
970
- lines.push(mutationMode === "verify_only"
971
- ? " Do not modify files; only run verification."
972
- : " Do not expand scope beyond what is needed to pass verification.");
958
+ lines.push(" Do not expand scope beyond what is needed to pass verification.");
973
959
  lines.push("");
974
960
  if (request.previousAttempts.length > 0) {
975
961
  lines.push("PRIOR FAILED ATTEMPTS (learn from these — do not repeat the same mistakes):");
@@ -0,0 +1,48 @@
1
+ export type ContextGraphNodeKind = "source_file" | "document" | "manifest" | "script" | "config";
2
+ export type ContextGraphEdgeKind = "imports" | "documents";
3
+ export interface ContextGraphNode {
4
+ nodeId: string;
5
+ path: string;
6
+ kind: ContextGraphNodeKind;
7
+ language?: string;
8
+ sizeBytes: number;
9
+ headings: string[];
10
+ symbols: string[];
11
+ keywords: string[];
12
+ imports: string[];
13
+ }
14
+ export interface ContextGraphEdge {
15
+ fromNodeId: string;
16
+ toNodeId: string;
17
+ kind: ContextGraphEdgeKind;
18
+ }
19
+ export interface ContextGraphSnapshot {
20
+ schemaVersion: "martin.context-graph.v1";
21
+ repoRoot: string;
22
+ createdAt: string;
23
+ nodeCount: number;
24
+ edgeCount: number;
25
+ truncated: boolean;
26
+ nodes: ContextGraphNode[];
27
+ edges: ContextGraphEdge[];
28
+ }
29
+ export interface ContextQuery {
30
+ text?: string;
31
+ terms?: string[];
32
+ pathPrefix?: string;
33
+ kinds?: ContextGraphNodeKind[];
34
+ limit?: number;
35
+ }
36
+ export interface ContextGraphBuildOptions {
37
+ maxFiles?: number;
38
+ maxFileBytes?: number;
39
+ }
40
+ export interface ContextGraphHit {
41
+ nodeId: string;
42
+ path: string;
43
+ kind: ContextGraphNodeKind;
44
+ score: number;
45
+ matchedTerms: string[];
46
+ reasons: string[];
47
+ }
48
+ export declare function cloneContextGraphSnapshot(snapshot: ContextGraphSnapshot): ContextGraphSnapshot;
@@ -0,0 +1,26 @@
1
+ export function cloneContextGraphSnapshot(snapshot) {
2
+ return {
3
+ schemaVersion: snapshot.schemaVersion,
4
+ repoRoot: snapshot.repoRoot,
5
+ createdAt: snapshot.createdAt,
6
+ nodeCount: snapshot.nodeCount,
7
+ edgeCount: snapshot.edgeCount,
8
+ truncated: snapshot.truncated,
9
+ nodes: snapshot.nodes.map((node) => ({
10
+ nodeId: node.nodeId,
11
+ path: node.path,
12
+ kind: node.kind,
13
+ ...(node.language ? { language: node.language } : {}),
14
+ sizeBytes: node.sizeBytes,
15
+ headings: [...node.headings],
16
+ symbols: [...node.symbols],
17
+ keywords: [...node.keywords],
18
+ imports: [...node.imports]
19
+ })),
20
+ edges: snapshot.edges.map((edge) => ({
21
+ fromNodeId: edge.fromNodeId,
22
+ toNodeId: edge.toNodeId,
23
+ kind: edge.kind
24
+ }))
25
+ };
26
+ }
@@ -0,0 +1,78 @@
1
+ import type { ApprovalPolicy, LoopBudget, LoopTask, MutationMode } from "./index.js";
2
+ import type { DestructiveActionPolicy, PolicyProfile, TelemetryDestination } from "./governance.js";
3
+ export interface ExecutionPolicy {
4
+ configPath: string;
5
+ budget: LoopBudget;
6
+ governance: {
7
+ policyProfile: PolicyProfile;
8
+ telemetryDestination: TelemetryDestination;
9
+ destructiveActionPolicy: DestructiveActionPolicy;
10
+ };
11
+ task: {
12
+ verificationPlan: string[];
13
+ mutationMode?: MutationMode;
14
+ repoRoot?: string;
15
+ allowedPaths?: string[];
16
+ deniedPaths?: string[];
17
+ acceptanceCriteria?: string[];
18
+ approvalPolicy?: ApprovalPolicy;
19
+ };
20
+ provenance: ExecutionPolicyProvenanceEntry[];
21
+ }
22
+ export interface ExecutionPolicyProvenanceEntry {
23
+ field: string;
24
+ source: "default" | "config" | "request";
25
+ value: string;
26
+ }
27
+ export interface ExecutionPolicyDefaults {
28
+ budget: LoopBudget;
29
+ policyProfile: PolicyProfile;
30
+ telemetryDestination: TelemetryDestination;
31
+ destructiveActionPolicy: DestructiveActionPolicy;
32
+ verifierRules: string[];
33
+ }
34
+ export interface ExecutionPolicyConfigInput {
35
+ policyProfile?: string;
36
+ budget?: Partial<LoopBudget>;
37
+ governance?: {
38
+ destructiveActionPolicy?: string;
39
+ telemetryDestination?: string;
40
+ verifierRules?: string[];
41
+ };
42
+ }
43
+ export interface ExecutionPolicyRequestInput {
44
+ budget: LoopBudget;
45
+ budgetOverrides?: Partial<Record<keyof LoopBudget, true>>;
46
+ policyProfile?: string;
47
+ telemetryDestination?: string;
48
+ verificationPlan?: string[];
49
+ mutationMode?: LoopTask["mutationMode"];
50
+ repoRoot?: string;
51
+ allowedPaths?: string[];
52
+ deniedPaths?: string[];
53
+ acceptanceCriteria?: string[];
54
+ approvalPolicy?: ApprovalPolicy;
55
+ }
56
+ export interface ExecutionPolicyCompileInput {
57
+ configPath: string;
58
+ defaults: ExecutionPolicyDefaults;
59
+ config?: ExecutionPolicyConfigInput;
60
+ request: ExecutionPolicyRequestInput;
61
+ }
62
+ export type RoutingMode = "direct" | "manager" | "adaptive" | "consensus";
63
+ export interface RoutingPolicy {
64
+ enabled: boolean;
65
+ mode: RoutingMode;
66
+ /** Max percentage of total budget that can be spent before first code change. */
67
+ maxPreworkBudgetPct: number;
68
+ /** Hard dollar cap on pre-work spend. */
69
+ maxPreworkCostUsd: number;
70
+ /** Max model calls allowed for manager/router/planner before worker starts. */
71
+ maxManagerCalls: number;
72
+ /** Skip orchestration entirely if task confidence is above this threshold (0-1). */
73
+ skipOrchestrationIfConfidenceAbove: number;
74
+ /** Force direct execution for tasks classified as simple. */
75
+ requireDirectForSimpleTasks: boolean;
76
+ }
77
+ export declare const DEFAULT_ROUTING_POLICY: RoutingPolicy;
78
+ export declare function cloneExecutionPolicy(policy: ExecutionPolicy): ExecutionPolicy;
@@ -0,0 +1,43 @@
1
+ export const DEFAULT_ROUTING_POLICY = {
2
+ enabled: true,
3
+ mode: "adaptive",
4
+ maxPreworkBudgetPct: 25,
5
+ maxPreworkCostUsd: 2.0,
6
+ maxManagerCalls: 2,
7
+ skipOrchestrationIfConfidenceAbove: 0.85,
8
+ requireDirectForSimpleTasks: true
9
+ };
10
+ export function cloneExecutionPolicy(policy) {
11
+ return {
12
+ configPath: policy.configPath,
13
+ budget: {
14
+ maxUsd: policy.budget.maxUsd,
15
+ softLimitUsd: policy.budget.softLimitUsd,
16
+ maxIterations: policy.budget.maxIterations,
17
+ maxTokens: policy.budget.maxTokens
18
+ },
19
+ governance: {
20
+ policyProfile: policy.governance.policyProfile,
21
+ telemetryDestination: policy.governance.telemetryDestination,
22
+ destructiveActionPolicy: policy.governance.destructiveActionPolicy
23
+ },
24
+ task: {
25
+ verificationPlan: [...policy.task.verificationPlan],
26
+ ...(policy.task.mutationMode ? { mutationMode: policy.task.mutationMode } : {}),
27
+ ...(policy.task.repoRoot ? { repoRoot: policy.task.repoRoot } : {}),
28
+ ...(policy.task.allowedPaths ? { allowedPaths: [...policy.task.allowedPaths] } : {}),
29
+ ...(policy.task.deniedPaths ? { deniedPaths: [...policy.task.deniedPaths] } : {}),
30
+ ...(policy.task.acceptanceCriteria
31
+ ? { acceptanceCriteria: [...policy.task.acceptanceCriteria] }
32
+ : {}),
33
+ ...(policy.task.approvalPolicy
34
+ ? {
35
+ approvalPolicy: {
36
+ ...policy.task.approvalPolicy
37
+ }
38
+ }
39
+ : {})
40
+ },
41
+ provenance: policy.provenance.map((entry) => ({ ...entry }))
42
+ };
43
+ }
@@ -0,0 +1,24 @@
1
+ export type PolicyProfile = "strict" | "balanced" | "overnight" | "debug";
2
+ export type DestructiveActionPolicy = "never" | "approval" | "allowed";
3
+ export type TelemetryDestination = "local-only" | "control-plane";
4
+ export type GovernanceSnapshot = {
5
+ policyProfile: PolicyProfile;
6
+ maxUsd: number;
7
+ softLimitUsd: number;
8
+ maxTokens: number;
9
+ maxIterations: number;
10
+ allowedAdapters: string[];
11
+ allowedModels: string[];
12
+ destructiveActionPolicy: DestructiveActionPolicy;
13
+ approvalRequired: boolean;
14
+ verifierRules: string[];
15
+ escalationRoute: string;
16
+ telemetryDestination: TelemetryDestination;
17
+ retentionPolicy: string;
18
+ provenance: Array<{
19
+ field: string;
20
+ value: string;
21
+ source: string;
22
+ }>;
23
+ };
24
+ export declare function createGovernanceSnapshot(snapshot: GovernanceSnapshot): GovernanceSnapshot;
@@ -0,0 +1,11 @@
1
+ export function createGovernanceSnapshot(snapshot) {
2
+ return {
3
+ ...snapshot,
4
+ allowedAdapters: [...snapshot.allowedAdapters],
5
+ allowedModels: [...snapshot.allowedModels],
6
+ verifierRules: [...snapshot.verifierRules],
7
+ provenance: snapshot.provenance.map((entry) => ({
8
+ ...entry
9
+ }))
10
+ };
11
+ }
@@ -0,0 +1,29 @@
1
+ export type IdentityAlgorithm = "ed25519";
2
+ export type IdentityRole = "governor" | "verifier" | "worker" | "reviewer" | "observer";
3
+ export interface IdentityClaims {
4
+ subject: string;
5
+ issuer: string;
6
+ role: IdentityRole;
7
+ scopes: string[];
8
+ issuedAt: string;
9
+ expiresAt?: string;
10
+ workspaceId?: string;
11
+ sessionId?: string;
12
+ metadata?: Record<string, string>;
13
+ }
14
+ export interface IdentityToken {
15
+ schemaVersion: "martin.identity.v1";
16
+ algorithm: IdentityAlgorithm;
17
+ keyId: string;
18
+ claims: IdentityClaims;
19
+ signature: string;
20
+ }
21
+ export interface IdentityAttestation {
22
+ valid: boolean;
23
+ verifiedAt: string;
24
+ reason: string;
25
+ token: IdentityToken;
26
+ }
27
+ export declare function cloneIdentityClaims(claims: IdentityClaims): IdentityClaims;
28
+ export declare function cloneIdentityToken(token: IdentityToken): IdentityToken;
29
+ export declare function cloneIdentityAttestation(attestation: IdentityAttestation): IdentityAttestation;
@@ -0,0 +1,30 @@
1
+ export function cloneIdentityClaims(claims) {
2
+ return {
3
+ subject: claims.subject,
4
+ issuer: claims.issuer,
5
+ role: claims.role,
6
+ scopes: [...claims.scopes],
7
+ issuedAt: claims.issuedAt,
8
+ ...(claims.expiresAt ? { expiresAt: claims.expiresAt } : {}),
9
+ ...(claims.workspaceId ? { workspaceId: claims.workspaceId } : {}),
10
+ ...(claims.sessionId ? { sessionId: claims.sessionId } : {}),
11
+ ...(claims.metadata ? { metadata: { ...claims.metadata } } : {})
12
+ };
13
+ }
14
+ export function cloneIdentityToken(token) {
15
+ return {
16
+ schemaVersion: token.schemaVersion,
17
+ algorithm: token.algorithm,
18
+ keyId: token.keyId,
19
+ claims: cloneIdentityClaims(token.claims),
20
+ signature: token.signature
21
+ };
22
+ }
23
+ export function cloneIdentityAttestation(attestation) {
24
+ return {
25
+ valid: attestation.valid,
26
+ verifiedAt: attestation.verifiedAt,
27
+ reason: attestation.reason,
28
+ token: cloneIdentityToken(attestation.token)
29
+ };
30
+ }