@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.
- package/README.md +137 -145
- package/dist/discovery-metadata.d.ts +1 -1
- package/dist/discovery-metadata.js +1 -1
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/resources.d.ts +2 -1
- package/dist/resources.js +251 -197
- package/dist/server-validation.d.ts +1 -1
- package/dist/server-validation.js +11 -16
- package/dist/server.d.ts +0 -23
- package/dist/server.js +7 -152
- package/dist/tools/run-loop.d.ts +2 -1
- package/dist/tools/run-loop.js +5 -1
- package/dist/tools/tool-support.js +1 -0
- package/dist/vendor/adapters/adapters/src/claude-cli.d.ts +146 -0
- package/dist/vendor/adapters/adapters/src/claude-cli.js +1100 -0
- package/dist/vendor/adapters/adapters/src/cli-bridge.d.ts +103 -0
- package/dist/vendor/adapters/adapters/src/cli-bridge.js +569 -0
- package/dist/vendor/adapters/adapters/src/codex-launcher.d.ts +78 -0
- package/dist/vendor/adapters/adapters/src/codex-launcher.js +663 -0
- package/dist/vendor/adapters/adapters/src/direct-provider.d.ts +10 -0
- package/dist/vendor/adapters/adapters/src/direct-provider.js +40 -0
- package/dist/vendor/adapters/adapters/src/index.d.ts +8 -0
- package/dist/vendor/adapters/adapters/src/index.js +8 -0
- package/dist/vendor/adapters/adapters/src/openai-compatible.d.ts +62 -0
- package/dist/vendor/adapters/adapters/src/openai-compatible.js +306 -0
- package/dist/vendor/adapters/adapters/src/runtime-support.d.ts +17 -0
- package/dist/vendor/adapters/adapters/src/runtime-support.js +59 -0
- package/dist/vendor/adapters/adapters/src/stub-agent-cli.d.ts +8 -0
- package/dist/vendor/adapters/adapters/src/stub-agent-cli.js +40 -0
- package/dist/vendor/adapters/adapters/src/stub-direct-provider.d.ts +8 -0
- package/dist/vendor/adapters/adapters/src/stub-direct-provider.js +12 -0
- package/dist/vendor/adapters/adapters/src/verifier-only.d.ts +9 -0
- package/dist/vendor/adapters/adapters/src/verifier-only.js +63 -0
- package/dist/vendor/adapters/claude-cli.d.ts +2 -2
- package/dist/vendor/adapters/claude-cli.js +28 -42
- package/dist/vendor/adapters/contracts/src/context-graph.d.ts +48 -0
- package/dist/vendor/adapters/contracts/src/context-graph.js +26 -0
- package/dist/vendor/adapters/contracts/src/execution-policy.d.ts +78 -0
- package/dist/vendor/adapters/contracts/src/execution-policy.js +43 -0
- package/dist/vendor/adapters/contracts/src/governance.d.ts +24 -0
- package/dist/vendor/adapters/contracts/src/governance.js +11 -0
- package/dist/vendor/adapters/contracts/src/identity.d.ts +29 -0
- package/dist/vendor/adapters/contracts/src/identity.js +30 -0
- package/dist/vendor/adapters/contracts/src/index.d.ts +412 -0
- package/dist/vendor/adapters/contracts/src/index.js +225 -0
- package/dist/vendor/adapters/contracts/src/operator.d.ts +19 -0
- package/dist/vendor/adapters/contracts/src/operator.js +11 -0
- package/dist/vendor/adapters/contracts/src/trajectory.d.ts +26 -0
- package/dist/vendor/adapters/contracts/src/trajectory.js +27 -0
- package/dist/vendor/adapters/core/src/compiler.d.ts +52 -0
- package/dist/vendor/adapters/core/src/compiler.js +52 -0
- package/dist/vendor/adapters/core/src/context-graph.d.ts +3 -0
- package/dist/vendor/adapters/core/src/context-graph.js +371 -0
- package/dist/vendor/adapters/core/src/context-integrity.d.ts +26 -0
- package/dist/vendor/adapters/core/src/context-integrity.js +80 -0
- package/dist/vendor/adapters/core/src/grounding.d.ts +38 -0
- package/dist/vendor/adapters/core/src/grounding.js +273 -0
- package/dist/vendor/adapters/core/src/identity.d.ts +20 -0
- package/dist/vendor/adapters/core/src/identity.js +86 -0
- package/dist/vendor/adapters/core/src/index.d.ts +186 -0
- package/dist/vendor/adapters/core/src/index.js +1495 -0
- package/dist/vendor/adapters/core/src/leash.d.ts +48 -0
- package/dist/vendor/adapters/core/src/leash.js +497 -0
- package/dist/vendor/adapters/core/src/persistence/compiler.d.ts +18 -0
- package/dist/vendor/adapters/core/src/persistence/compiler.js +34 -0
- package/dist/vendor/adapters/core/src/persistence/index.d.ts +10 -0
- package/dist/vendor/adapters/core/src/persistence/index.js +5 -0
- package/dist/vendor/adapters/core/src/persistence/integrity.d.ts +39 -0
- package/dist/vendor/adapters/core/src/persistence/integrity.js +252 -0
- package/dist/vendor/adapters/core/src/persistence/ledger.d.ts +23 -0
- package/dist/vendor/adapters/core/src/persistence/ledger.js +9 -0
- package/dist/vendor/adapters/core/src/persistence/memory-store.d.ts +63 -0
- package/dist/vendor/adapters/core/src/persistence/memory-store.js +115 -0
- package/dist/vendor/adapters/core/src/persistence/runs-reader.d.ts +66 -0
- package/dist/vendor/adapters/core/src/persistence/runs-reader.js +140 -0
- package/dist/vendor/adapters/core/src/persistence/store.d.ts +89 -0
- package/dist/vendor/adapters/core/src/persistence/store.js +125 -0
- package/dist/vendor/adapters/core/src/persistence/trace-store.d.ts +85 -0
- package/dist/vendor/adapters/core/src/persistence/trace-store.js +125 -0
- package/dist/vendor/adapters/core/src/policy-compiler.d.ts +2 -0
- package/dist/vendor/adapters/core/src/policy-compiler.js +195 -0
- package/dist/vendor/adapters/core/src/policy.d.ts +156 -0
- package/dist/vendor/adapters/core/src/policy.js +704 -0
- package/dist/vendor/adapters/core/src/repo-analyzer.d.ts +53 -0
- package/dist/vendor/adapters/core/src/repo-analyzer.js +263 -0
- package/dist/vendor/adapters/core/src/rollback.d.ts +15 -0
- package/dist/vendor/adapters/core/src/rollback.js +253 -0
- package/dist/vendor/adapters/core/src/routing.d.ts +82 -0
- package/dist/vendor/adapters/core/src/routing.js +336 -0
- package/dist/vendor/adapters/core/src/test-integrity.d.ts +64 -0
- package/dist/vendor/adapters/core/src/test-integrity.js +197 -0
- package/dist/vendor/adapters/core/src/trajectory.d.ts +18 -0
- package/dist/vendor/adapters/core/src/trajectory.js +295 -0
- package/dist/vendor/adapters/openai-compatible.js +6 -6
- package/dist/vendor/adapters/verifier-only.js +2 -2
- package/dist/vendor/contracts/index.d.ts +1 -1
- package/dist/vendor/core/compiler.js +4 -9
- package/dist/vendor/core/index.js +1 -88
- package/dist/vendor/core/rollback.js +2 -3
- package/package.json +76 -76
- 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
|
|
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
|
|
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
|
|
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
|
|
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)} (
|
|
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 +=
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
800
|
+
argsBuilder: (_prompt) => [
|
|
808
801
|
"--output-format",
|
|
809
802
|
"stream-json",
|
|
810
803
|
"--verbose",
|
|
811
804
|
"--print",
|
|
812
805
|
"--dangerously-skip-permissions",
|
|
813
|
-
//
|
|
814
|
-
//
|
|
815
|
-
//
|
|
816
|
-
//
|
|
817
|
-
|
|
818
|
-
|
|
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
|
-
|
|
919
|
-
|
|
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(
|
|
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(
|
|
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
|
+
}
|