@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.
- package/README.md +148 -105
- package/dist/resources.js +148 -148
- package/dist/server.js +0 -0
- package/dist/tools/preflight.d.ts +0 -2
- package/dist/tools/preflight.js +2 -42
- package/dist/vendor/adapters/openai-compatible.js +6 -6
- package/dist/vendor/contracts/index.d.ts +0 -2
- package/dist/vendor/contracts/index.js +0 -2
- package/dist/vendor/core/index.d.ts +0 -2
- package/dist/vendor/core/index.js +0 -2
- package/package.json +86 -83
- package/server.json +21 -21
- package/LICENSE +0 -216
- package/dist/vendor/adapters/adapters/src/claude-cli.d.ts +0 -146
- package/dist/vendor/adapters/adapters/src/claude-cli.js +0 -1100
- package/dist/vendor/adapters/adapters/src/cli-bridge.d.ts +0 -103
- package/dist/vendor/adapters/adapters/src/cli-bridge.js +0 -569
- package/dist/vendor/adapters/adapters/src/codex-launcher.d.ts +0 -78
- package/dist/vendor/adapters/adapters/src/codex-launcher.js +0 -663
- package/dist/vendor/adapters/adapters/src/direct-provider.d.ts +0 -10
- package/dist/vendor/adapters/adapters/src/direct-provider.js +0 -40
- package/dist/vendor/adapters/adapters/src/index.d.ts +0 -8
- package/dist/vendor/adapters/adapters/src/index.js +0 -8
- package/dist/vendor/adapters/adapters/src/openai-compatible.d.ts +0 -62
- package/dist/vendor/adapters/adapters/src/openai-compatible.js +0 -306
- package/dist/vendor/adapters/adapters/src/runtime-support.d.ts +0 -17
- package/dist/vendor/adapters/adapters/src/runtime-support.js +0 -59
- package/dist/vendor/adapters/adapters/src/stub-agent-cli.d.ts +0 -8
- package/dist/vendor/adapters/adapters/src/stub-agent-cli.js +0 -40
- package/dist/vendor/adapters/adapters/src/stub-direct-provider.d.ts +0 -8
- package/dist/vendor/adapters/adapters/src/stub-direct-provider.js +0 -12
- package/dist/vendor/adapters/adapters/src/verifier-only.d.ts +0 -9
- package/dist/vendor/adapters/adapters/src/verifier-only.js +0 -63
- package/dist/vendor/adapters/contracts/src/context-graph.d.ts +0 -48
- package/dist/vendor/adapters/contracts/src/context-graph.js +0 -26
- package/dist/vendor/adapters/contracts/src/execution-policy.d.ts +0 -78
- package/dist/vendor/adapters/contracts/src/execution-policy.js +0 -43
- package/dist/vendor/adapters/contracts/src/governance.d.ts +0 -24
- package/dist/vendor/adapters/contracts/src/governance.js +0 -11
- package/dist/vendor/adapters/contracts/src/identity.d.ts +0 -29
- package/dist/vendor/adapters/contracts/src/identity.js +0 -30
- package/dist/vendor/adapters/contracts/src/index.d.ts +0 -412
- package/dist/vendor/adapters/contracts/src/index.js +0 -225
- package/dist/vendor/adapters/contracts/src/operator.d.ts +0 -19
- package/dist/vendor/adapters/contracts/src/operator.js +0 -11
- package/dist/vendor/adapters/contracts/src/trajectory.d.ts +0 -26
- package/dist/vendor/adapters/contracts/src/trajectory.js +0 -27
- package/dist/vendor/adapters/core/src/compiler.d.ts +0 -52
- package/dist/vendor/adapters/core/src/compiler.js +0 -52
- package/dist/vendor/adapters/core/src/context-graph.d.ts +0 -3
- package/dist/vendor/adapters/core/src/context-graph.js +0 -371
- package/dist/vendor/adapters/core/src/context-integrity.d.ts +0 -26
- package/dist/vendor/adapters/core/src/context-integrity.js +0 -80
- package/dist/vendor/adapters/core/src/grounding.d.ts +0 -38
- package/dist/vendor/adapters/core/src/grounding.js +0 -273
- package/dist/vendor/adapters/core/src/identity.d.ts +0 -20
- package/dist/vendor/adapters/core/src/identity.js +0 -86
- package/dist/vendor/adapters/core/src/index.d.ts +0 -186
- package/dist/vendor/adapters/core/src/index.js +0 -1495
- package/dist/vendor/adapters/core/src/leash.d.ts +0 -48
- package/dist/vendor/adapters/core/src/leash.js +0 -497
- package/dist/vendor/adapters/core/src/persistence/compiler.d.ts +0 -18
- package/dist/vendor/adapters/core/src/persistence/compiler.js +0 -34
- package/dist/vendor/adapters/core/src/persistence/index.d.ts +0 -10
- package/dist/vendor/adapters/core/src/persistence/index.js +0 -5
- package/dist/vendor/adapters/core/src/persistence/integrity.d.ts +0 -39
- package/dist/vendor/adapters/core/src/persistence/integrity.js +0 -252
- package/dist/vendor/adapters/core/src/persistence/ledger.d.ts +0 -23
- package/dist/vendor/adapters/core/src/persistence/ledger.js +0 -9
- package/dist/vendor/adapters/core/src/persistence/memory-store.d.ts +0 -63
- package/dist/vendor/adapters/core/src/persistence/memory-store.js +0 -115
- package/dist/vendor/adapters/core/src/persistence/runs-reader.d.ts +0 -66
- package/dist/vendor/adapters/core/src/persistence/runs-reader.js +0 -140
- package/dist/vendor/adapters/core/src/persistence/store.d.ts +0 -89
- package/dist/vendor/adapters/core/src/persistence/store.js +0 -125
- package/dist/vendor/adapters/core/src/persistence/trace-store.d.ts +0 -85
- package/dist/vendor/adapters/core/src/persistence/trace-store.js +0 -125
- package/dist/vendor/adapters/core/src/policy-compiler.d.ts +0 -2
- package/dist/vendor/adapters/core/src/policy-compiler.js +0 -195
- package/dist/vendor/adapters/core/src/policy.d.ts +0 -156
- package/dist/vendor/adapters/core/src/policy.js +0 -704
- package/dist/vendor/adapters/core/src/repo-analyzer.d.ts +0 -53
- package/dist/vendor/adapters/core/src/repo-analyzer.js +0 -263
- package/dist/vendor/adapters/core/src/rollback.d.ts +0 -15
- package/dist/vendor/adapters/core/src/rollback.js +0 -253
- package/dist/vendor/adapters/core/src/routing.d.ts +0 -82
- package/dist/vendor/adapters/core/src/routing.js +0 -336
- package/dist/vendor/adapters/core/src/test-integrity.d.ts +0 -64
- package/dist/vendor/adapters/core/src/test-integrity.js +0 -197
- package/dist/vendor/adapters/core/src/trajectory.d.ts +0 -18
- package/dist/vendor/adapters/core/src/trajectory.js +0 -295
- package/dist/vendor/contracts/delivery.d.ts +0 -47
- package/dist/vendor/contracts/delivery.js +0 -18
- package/dist/vendor/core/delivery/index.d.ts +0 -6
- package/dist/vendor/core/delivery/index.js +0 -4
- package/dist/vendor/core/delivery/message-client.d.ts +0 -18
- package/dist/vendor/core/delivery/message-client.js +0 -38
- package/dist/vendor/core/delivery/message-ledger.d.ts +0 -35
- package/dist/vendor/core/delivery/message-ledger.js +0 -97
- package/dist/vendor/core/delivery/message-schema.d.ts +0 -16
- package/dist/vendor/core/delivery/message-schema.js +0 -111
- package/dist/vendor/core/delivery/update-check.d.ts +0 -19
- package/dist/vendor/core/delivery/update-check.js +0 -107
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import type { LoopBudget, LoopRecord, LoopTask, MachineState } from "../../../../contracts/index.js";
|
|
2
|
-
import { type LedgerEvent } from "./ledger.js";
|
|
3
|
-
export interface RunContract {
|
|
4
|
-
runId: string;
|
|
5
|
-
workspaceId: string;
|
|
6
|
-
projectId: string;
|
|
7
|
-
task: LoopTask;
|
|
8
|
-
budget: LoopBudget;
|
|
9
|
-
createdAt: string;
|
|
10
|
-
metadata?: Record<string, string>;
|
|
11
|
-
}
|
|
12
|
-
export interface AttemptArtifacts {
|
|
13
|
-
/** Compiled PromptPacket written as compiled-context.json */
|
|
14
|
-
compiledContext: unknown;
|
|
15
|
-
/** Structured verification evidence captured from the authoritative MartinLoop verifier (optional) */
|
|
16
|
-
verification?: unknown;
|
|
17
|
-
/** Unified diff string from the patch (optional) */
|
|
18
|
-
diff?: string;
|
|
19
|
-
/** Raw verifier command output (optional) */
|
|
20
|
-
verifierOutput?: string;
|
|
21
|
-
/** Grounding scan result (optional) */
|
|
22
|
-
groundingScan?: unknown;
|
|
23
|
-
/** Safety leash artifact captured for a blocked or escalated attempt (optional) */
|
|
24
|
-
leash?: unknown;
|
|
25
|
-
/** Patch score artifact captured for Phase 10 patch-truth decisions (optional) */
|
|
26
|
-
patchScore?: unknown;
|
|
27
|
-
/** Patch keep/discard/escalate decision artifact (optional) */
|
|
28
|
-
patchDecision?: unknown;
|
|
29
|
-
/** Rollback boundary captured before an attempt mutates the repo (optional) */
|
|
30
|
-
rollbackBoundary?: unknown;
|
|
31
|
-
/** Rollback restore outcome captured after discard/escalation/failure (optional) */
|
|
32
|
-
rollbackOutcome?: unknown;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* RunStore isolates all filesystem persistence from orchestration logic.
|
|
36
|
-
* runMartin accepts an optional store; when provided, every lifecycle event
|
|
37
|
-
* is durably written before the run proceeds to the next step.
|
|
38
|
-
*/
|
|
39
|
-
export interface RunStore {
|
|
40
|
-
/**
|
|
41
|
-
* Optional runs root hint for filesystem-backed stores.
|
|
42
|
-
* Orchestration should prefer this over recomputing the default home store.
|
|
43
|
-
*/
|
|
44
|
-
runsRoot?: string;
|
|
45
|
-
/**
|
|
46
|
-
* Write contract.json for a new run. Called once at run start.
|
|
47
|
-
* The contract is immutable after this point.
|
|
48
|
-
*/
|
|
49
|
-
initRun(contract: RunContract): Promise<void>;
|
|
50
|
-
/**
|
|
51
|
-
* Overwrite state.json with the current MachineState.
|
|
52
|
-
* Called on every phase transition.
|
|
53
|
-
*/
|
|
54
|
-
updateState(runId: string, state: MachineState): Promise<void>;
|
|
55
|
-
/**
|
|
56
|
-
* Append one event line to ledger.jsonl. Append-only — never rewrites.
|
|
57
|
-
*/
|
|
58
|
-
appendLedger(runId: string, event: LedgerEvent): Promise<void>;
|
|
59
|
-
/**
|
|
60
|
-
* Write artifacts for a completed attempt to artifacts/attempt-<n>/.
|
|
61
|
-
*/
|
|
62
|
-
writeAttemptArtifacts(runId: string, attemptIndex: number, artifacts: AttemptArtifacts): Promise<void>;
|
|
63
|
-
/**
|
|
64
|
-
* Persist the latest canonical loop record snapshot when the caller has one.
|
|
65
|
-
* Optional to avoid breaking custom RunStore implementations.
|
|
66
|
-
*/
|
|
67
|
-
writeLoopRecord?(runId: string, loop: LoopRecord): Promise<void>;
|
|
68
|
-
}
|
|
69
|
-
export declare function resolveRunsRoot(env?: NodeJS.ProcessEnv): string;
|
|
70
|
-
export declare function runDir(runsRoot: string, runId: string): string;
|
|
71
|
-
export declare function artifactDir(runsRoot: string, runId: string, attemptIndex: number): string;
|
|
72
|
-
/**
|
|
73
|
-
* Filesystem-backed RunStore. Writes to:
|
|
74
|
-
* <runsRoot>/<runId>/contract.json
|
|
75
|
-
* <runsRoot>/<runId>/state.json
|
|
76
|
-
* <runsRoot>/<runId>/ledger.jsonl
|
|
77
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/compiled-context.json
|
|
78
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/diff.patch (if diff provided)
|
|
79
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/verifier-output.txt (if provided)
|
|
80
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/grounding-scan.json (if provided)
|
|
81
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/leash.json (if leash provided)
|
|
82
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/patch-score.json (if patchScore provided)
|
|
83
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/patch-decision.json (if patchDecision provided)
|
|
84
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/rollback-boundary.json (if rollbackBoundary provided)
|
|
85
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/rollback-outcome.json (if rollbackOutcome provided)
|
|
86
|
-
*/
|
|
87
|
-
export declare function createFileRunStore(options?: {
|
|
88
|
-
runsRoot?: string;
|
|
89
|
-
}): RunStore;
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import { writeReceiptIntegrityMaterial } from "./integrity.js";
|
|
6
|
-
// ─── FileRunStore implementation ─────────────────────────────────────────────
|
|
7
|
-
const RUN_INDEX_FILENAME = "run-index.ndjson";
|
|
8
|
-
export function resolveRunsRoot(env = process.env) {
|
|
9
|
-
return env["MARTIN_RUNS_DIR"]?.trim() ??
|
|
10
|
-
join(homedir(), ".martin", "runs");
|
|
11
|
-
}
|
|
12
|
-
export function runDir(runsRoot, runId) {
|
|
13
|
-
return join(runsRoot, runId);
|
|
14
|
-
}
|
|
15
|
-
export function artifactDir(runsRoot, runId, attemptIndex) {
|
|
16
|
-
return join(runsRoot, runId, "artifacts", `attempt-${String(attemptIndex).padStart(3, "0")}`);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Filesystem-backed RunStore. Writes to:
|
|
20
|
-
* <runsRoot>/<runId>/contract.json
|
|
21
|
-
* <runsRoot>/<runId>/state.json
|
|
22
|
-
* <runsRoot>/<runId>/ledger.jsonl
|
|
23
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/compiled-context.json
|
|
24
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/diff.patch (if diff provided)
|
|
25
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/verifier-output.txt (if provided)
|
|
26
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/grounding-scan.json (if provided)
|
|
27
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/leash.json (if leash provided)
|
|
28
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/patch-score.json (if patchScore provided)
|
|
29
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/patch-decision.json (if patchDecision provided)
|
|
30
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/rollback-boundary.json (if rollbackBoundary provided)
|
|
31
|
-
* <runsRoot>/<runId>/artifacts/attempt-<n>/rollback-outcome.json (if rollbackOutcome provided)
|
|
32
|
-
*/
|
|
33
|
-
export function createFileRunStore(options = {}) {
|
|
34
|
-
const runsRoot = options.runsRoot ?? resolveRunsRoot();
|
|
35
|
-
return {
|
|
36
|
-
runsRoot,
|
|
37
|
-
async initRun(contract) {
|
|
38
|
-
const dir = runDir(runsRoot, contract.runId);
|
|
39
|
-
await mkdir(dir, { recursive: true });
|
|
40
|
-
await writeJsonFile(join(dir, "contract.json"), contract);
|
|
41
|
-
},
|
|
42
|
-
async updateState(runId, state) {
|
|
43
|
-
const dir = runDir(runsRoot, runId);
|
|
44
|
-
await mkdir(dir, { recursive: true });
|
|
45
|
-
await writeJsonFile(join(dir, "state.json"), state);
|
|
46
|
-
},
|
|
47
|
-
async appendLedger(runId, event) {
|
|
48
|
-
const dir = runDir(runsRoot, runId);
|
|
49
|
-
await mkdir(dir, { recursive: true });
|
|
50
|
-
await appendFile(join(dir, "ledger.jsonl"), `${JSON.stringify(event)}\n`, "utf8");
|
|
51
|
-
},
|
|
52
|
-
async writeAttemptArtifacts(runId, attemptIndex, artifacts) {
|
|
53
|
-
const dir = artifactDir(runsRoot, runId, attemptIndex);
|
|
54
|
-
await mkdir(dir, { recursive: true });
|
|
55
|
-
await writeJsonFile(join(dir, "compiled-context.json"), artifacts.compiledContext);
|
|
56
|
-
if (artifacts.verification !== undefined) {
|
|
57
|
-
await writeJsonFile(join(dir, "verification.json"), artifacts.verification);
|
|
58
|
-
}
|
|
59
|
-
if (artifacts.diff !== undefined) {
|
|
60
|
-
await writeFile(join(dir, "diff.patch"), artifacts.diff, "utf8");
|
|
61
|
-
}
|
|
62
|
-
if (artifacts.verifierOutput !== undefined) {
|
|
63
|
-
await writeFile(join(dir, "verifier-output.txt"), artifacts.verifierOutput, "utf8");
|
|
64
|
-
}
|
|
65
|
-
if (artifacts.groundingScan !== undefined) {
|
|
66
|
-
await writeJsonFile(join(dir, "grounding-scan.json"), artifacts.groundingScan);
|
|
67
|
-
}
|
|
68
|
-
if (artifacts.leash !== undefined) {
|
|
69
|
-
await writeJsonFile(join(dir, "leash.json"), artifacts.leash);
|
|
70
|
-
}
|
|
71
|
-
if (artifacts.patchScore !== undefined) {
|
|
72
|
-
await writeJsonFile(join(dir, "patch-score.json"), artifacts.patchScore);
|
|
73
|
-
}
|
|
74
|
-
if (artifacts.patchDecision !== undefined) {
|
|
75
|
-
await writeJsonFile(join(dir, "patch-decision.json"), artifacts.patchDecision);
|
|
76
|
-
}
|
|
77
|
-
if (artifacts.rollbackBoundary !== undefined) {
|
|
78
|
-
await writeJsonFile(join(dir, "rollback-boundary.json"), artifacts.rollbackBoundary);
|
|
79
|
-
}
|
|
80
|
-
if (artifacts.rollbackOutcome !== undefined) {
|
|
81
|
-
await writeJsonFile(join(dir, "rollback-outcome.json"), artifacts.rollbackOutcome);
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
async writeLoopRecord(runId, loop) {
|
|
85
|
-
const dir = runDir(runsRoot, runId);
|
|
86
|
-
await mkdir(dir, { recursive: true });
|
|
87
|
-
await writeJsonFile(join(dir, "loop-record.json"), loop);
|
|
88
|
-
await appendRunIndexRecord(runsRoot, loop);
|
|
89
|
-
const ledgerRaw = await readFile(join(dir, "ledger.jsonl"), "utf8").catch(() => "");
|
|
90
|
-
const ledgerEntries = ledgerRaw
|
|
91
|
-
.split(/\r?\n/u)
|
|
92
|
-
.map((line) => line.trim())
|
|
93
|
-
.filter(Boolean)
|
|
94
|
-
.map((line) => JSON.parse(line));
|
|
95
|
-
await writeReceiptIntegrityMaterial({
|
|
96
|
-
runId,
|
|
97
|
-
runsRoot,
|
|
98
|
-
loopRecord: loop,
|
|
99
|
-
ledgerEntries,
|
|
100
|
-
scope: loop.receiptScope ??
|
|
101
|
-
{
|
|
102
|
-
...(loop.task.repoRoot ? { repoRoot: loop.task.repoRoot } : {}),
|
|
103
|
-
...(loop.task.repoRoot ? { workingDirectory: loop.task.repoRoot } : {}),
|
|
104
|
-
runsRoot
|
|
105
|
-
},
|
|
106
|
-
signedAt: loop.updatedAt
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
112
|
-
async function writeJsonFile(path, value) {
|
|
113
|
-
await writeFile(path, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
114
|
-
}
|
|
115
|
-
async function appendRunIndexRecord(runsRoot, loop) {
|
|
116
|
-
const line = JSON.stringify({
|
|
117
|
-
loopId: loop.loopId,
|
|
118
|
-
workspaceId: loop.workspaceId,
|
|
119
|
-
projectId: loop.projectId,
|
|
120
|
-
status: loop.status,
|
|
121
|
-
lifecycleState: loop.lifecycleState,
|
|
122
|
-
updatedAt: loop.updatedAt
|
|
123
|
-
});
|
|
124
|
-
await appendFile(join(runsRoot, RUN_INDEX_FILENAME), `${line}\n`, "utf8");
|
|
125
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Append-Only Trace Store
|
|
3
|
-
*
|
|
4
|
-
* Aggregates run data over time to build institutional memory. Every governed
|
|
5
|
-
* run's routing decision, cost, failure class, and outcome is appended to a
|
|
6
|
-
* local JSONL trace file. Data is NEVER overwritten — only appended.
|
|
7
|
-
*
|
|
8
|
-
* The trace store feeds:
|
|
9
|
-
* - classifyRoute() with historicalDirectSuccessRate from real past runs
|
|
10
|
-
* - Cost prediction models with actual spend data
|
|
11
|
-
* - Failure pattern detection across runs
|
|
12
|
-
* - Team analytics and optimization recommendations
|
|
13
|
-
*
|
|
14
|
-
* Storage: `<runsRoot>/_martin/trace-log.jsonl` (one JSON object per line)
|
|
15
|
-
*/
|
|
16
|
-
export interface TraceEntry {
|
|
17
|
-
/** ISO-8601 timestamp */
|
|
18
|
-
timestamp: string;
|
|
19
|
-
/** Unique loop identifier */
|
|
20
|
-
loopId: string;
|
|
21
|
-
/** The objective that was governed */
|
|
22
|
-
objective: string;
|
|
23
|
-
/** Which engine executed the run */
|
|
24
|
-
engine: string;
|
|
25
|
-
/** Route selected by classifyRoute */
|
|
26
|
-
selectedRoute: "direct" | "manager" | "consensus";
|
|
27
|
-
/** Route classifier confidence (0-1) */
|
|
28
|
-
routeConfidence: number;
|
|
29
|
-
/** Budget allocated (USD) */
|
|
30
|
-
budgetUsd: number;
|
|
31
|
-
/** Actual spend (USD) */
|
|
32
|
-
actualCostUsd: number;
|
|
33
|
-
/** Pre-work burn percentage */
|
|
34
|
-
preWorkBurnPct: number;
|
|
35
|
-
/** Number of attempts */
|
|
36
|
-
attempts: number;
|
|
37
|
-
/** Final loop status */
|
|
38
|
-
status: string;
|
|
39
|
-
/** Final lifecycle state */
|
|
40
|
-
lifecycleState: string;
|
|
41
|
-
/** Failure class of last attempt (if failed) */
|
|
42
|
-
failureClass?: string;
|
|
43
|
-
/** Whether verification passed */
|
|
44
|
-
verificationPassed: boolean;
|
|
45
|
-
/** Number of files changed */
|
|
46
|
-
filesChanged: number;
|
|
47
|
-
/** Working directory (hashed for privacy) */
|
|
48
|
-
workspaceHash: string;
|
|
49
|
-
}
|
|
50
|
-
export interface TraceAggregation {
|
|
51
|
-
totalRuns: number;
|
|
52
|
-
directRuns: number;
|
|
53
|
-
managerRuns: number;
|
|
54
|
-
consensusRuns: number;
|
|
55
|
-
directSuccessRate: number;
|
|
56
|
-
managerSuccessRate: number;
|
|
57
|
-
averageCostUsd: number;
|
|
58
|
-
averagePreWorkBurnPct: number;
|
|
59
|
-
totalSpendUsd: number;
|
|
60
|
-
totalSavedUsd: number;
|
|
61
|
-
topFailureClasses: Array<{
|
|
62
|
-
failureClass: string;
|
|
63
|
-
count: number;
|
|
64
|
-
}>;
|
|
65
|
-
averageAttemptsPerRun: number;
|
|
66
|
-
lastUpdated: string;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Append a trace entry to the local trace store. Never overwrites.
|
|
70
|
-
*/
|
|
71
|
-
export declare function appendTraceEntry(runsRoot: string, entry: TraceEntry): Promise<void>;
|
|
72
|
-
/**
|
|
73
|
-
* Read all trace entries from the local trace store.
|
|
74
|
-
*/
|
|
75
|
-
export declare function readTraceEntries(runsRoot: string): Promise<TraceEntry[]>;
|
|
76
|
-
/**
|
|
77
|
-
* Aggregate trace entries into summary statistics.
|
|
78
|
-
* Used by classifyRoute() to get historicalDirectSuccessRate.
|
|
79
|
-
*/
|
|
80
|
-
export declare function aggregateTraces(entries: TraceEntry[]): TraceAggregation;
|
|
81
|
-
/**
|
|
82
|
-
* Get the historical direct success rate for use in route classification.
|
|
83
|
-
* Returns undefined if insufficient data (< 5 runs).
|
|
84
|
-
*/
|
|
85
|
-
export declare function getHistoricalDirectSuccessRate(runsRoot: string): Promise<number | undefined>;
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Append-Only Trace Store
|
|
3
|
-
*
|
|
4
|
-
* Aggregates run data over time to build institutional memory. Every governed
|
|
5
|
-
* run's routing decision, cost, failure class, and outcome is appended to a
|
|
6
|
-
* local JSONL trace file. Data is NEVER overwritten — only appended.
|
|
7
|
-
*
|
|
8
|
-
* The trace store feeds:
|
|
9
|
-
* - classifyRoute() with historicalDirectSuccessRate from real past runs
|
|
10
|
-
* - Cost prediction models with actual spend data
|
|
11
|
-
* - Failure pattern detection across runs
|
|
12
|
-
* - Team analytics and optimization recommendations
|
|
13
|
-
*
|
|
14
|
-
* Storage: `<runsRoot>/_martin/trace-log.jsonl` (one JSON object per line)
|
|
15
|
-
*/
|
|
16
|
-
import { appendFile, mkdir, readFile } from "node:fs/promises";
|
|
17
|
-
import { join, resolve } from "node:path";
|
|
18
|
-
const TRACE_DIRECTORY = "_martin";
|
|
19
|
-
const TRACE_FILENAME = "trace-log.jsonl";
|
|
20
|
-
function resolveTracePath(runsRoot) {
|
|
21
|
-
return join(resolve(runsRoot), TRACE_DIRECTORY, TRACE_FILENAME);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Append a trace entry to the local trace store. Never overwrites.
|
|
25
|
-
*/
|
|
26
|
-
export async function appendTraceEntry(runsRoot, entry) {
|
|
27
|
-
const tracePath = resolveTracePath(runsRoot);
|
|
28
|
-
await mkdir(join(resolve(runsRoot), TRACE_DIRECTORY), { recursive: true });
|
|
29
|
-
const line = JSON.stringify(entry) + "\n";
|
|
30
|
-
await appendFile(tracePath, line, "utf8");
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Read all trace entries from the local trace store.
|
|
34
|
-
*/
|
|
35
|
-
export async function readTraceEntries(runsRoot) {
|
|
36
|
-
const tracePath = resolveTracePath(runsRoot);
|
|
37
|
-
try {
|
|
38
|
-
const raw = await readFile(tracePath, "utf8");
|
|
39
|
-
return raw
|
|
40
|
-
.split("\n")
|
|
41
|
-
.filter((line) => line.trim().length > 0)
|
|
42
|
-
.map((line) => {
|
|
43
|
-
try {
|
|
44
|
-
return JSON.parse(line);
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
})
|
|
50
|
-
.filter((entry) => entry !== null);
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Aggregate trace entries into summary statistics.
|
|
58
|
-
* Used by classifyRoute() to get historicalDirectSuccessRate.
|
|
59
|
-
*/
|
|
60
|
-
export function aggregateTraces(entries) {
|
|
61
|
-
if (entries.length === 0) {
|
|
62
|
-
return {
|
|
63
|
-
totalRuns: 0,
|
|
64
|
-
directRuns: 0,
|
|
65
|
-
managerRuns: 0,
|
|
66
|
-
consensusRuns: 0,
|
|
67
|
-
directSuccessRate: 0,
|
|
68
|
-
managerSuccessRate: 0,
|
|
69
|
-
averageCostUsd: 0,
|
|
70
|
-
averagePreWorkBurnPct: 0,
|
|
71
|
-
totalSpendUsd: 0,
|
|
72
|
-
totalSavedUsd: 0,
|
|
73
|
-
topFailureClasses: [],
|
|
74
|
-
averageAttemptsPerRun: 0,
|
|
75
|
-
lastUpdated: new Date().toISOString()
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
const direct = entries.filter((e) => e.selectedRoute === "direct");
|
|
79
|
-
const manager = entries.filter((e) => e.selectedRoute === "manager");
|
|
80
|
-
const consensus = entries.filter((e) => e.selectedRoute === "consensus");
|
|
81
|
-
const directSuccesses = direct.filter((e) => e.status === "completed" && e.verificationPassed);
|
|
82
|
-
const managerSuccesses = manager.filter((e) => e.status === "completed" && e.verificationPassed);
|
|
83
|
-
const totalCost = entries.reduce((sum, e) => sum + e.actualCostUsd, 0);
|
|
84
|
-
const totalBudget = entries.reduce((sum, e) => sum + e.budgetUsd, 0);
|
|
85
|
-
const totalAttempts = entries.reduce((sum, e) => sum + e.attempts, 0);
|
|
86
|
-
const totalBurnPct = entries.reduce((sum, e) => sum + e.preWorkBurnPct, 0);
|
|
87
|
-
// Count failure classes
|
|
88
|
-
const failureCounts = new Map();
|
|
89
|
-
for (const entry of entries) {
|
|
90
|
-
if (entry.failureClass) {
|
|
91
|
-
failureCounts.set(entry.failureClass, (failureCounts.get(entry.failureClass) ?? 0) + 1);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
const topFailureClasses = [...failureCounts.entries()]
|
|
95
|
-
.map(([failureClass, count]) => ({ failureClass, count }))
|
|
96
|
-
.sort((a, b) => b.count - a.count)
|
|
97
|
-
.slice(0, 10);
|
|
98
|
-
return {
|
|
99
|
-
totalRuns: entries.length,
|
|
100
|
-
directRuns: direct.length,
|
|
101
|
-
managerRuns: manager.length,
|
|
102
|
-
consensusRuns: consensus.length,
|
|
103
|
-
directSuccessRate: direct.length > 0 ? directSuccesses.length / direct.length : 0,
|
|
104
|
-
managerSuccessRate: manager.length > 0 ? managerSuccesses.length / manager.length : 0,
|
|
105
|
-
averageCostUsd: Math.round((totalCost / entries.length) * 100) / 100,
|
|
106
|
-
averagePreWorkBurnPct: Math.round(totalBurnPct / entries.length),
|
|
107
|
-
totalSpendUsd: Math.round(totalCost * 100) / 100,
|
|
108
|
-
totalSavedUsd: Math.round((totalBudget - totalCost) * 100) / 100,
|
|
109
|
-
topFailureClasses,
|
|
110
|
-
averageAttemptsPerRun: Math.round((totalAttempts / entries.length) * 10) / 10,
|
|
111
|
-
lastUpdated: entries[entries.length - 1]?.timestamp ?? new Date().toISOString()
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Get the historical direct success rate for use in route classification.
|
|
116
|
-
* Returns undefined if insufficient data (< 5 runs).
|
|
117
|
-
*/
|
|
118
|
-
export async function getHistoricalDirectSuccessRate(runsRoot) {
|
|
119
|
-
const entries = await readTraceEntries(runsRoot);
|
|
120
|
-
const directRuns = entries.filter((e) => e.selectedRoute === "direct");
|
|
121
|
-
if (directRuns.length < 5)
|
|
122
|
-
return undefined;
|
|
123
|
-
const successes = directRuns.filter((e) => e.status === "completed" && e.verificationPassed);
|
|
124
|
-
return successes.length / directRuns.length;
|
|
125
|
-
}
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { cloneExecutionPolicy } from "../../../contracts/index.js";
|
|
2
|
-
export function compileExecutionPolicy(input) {
|
|
3
|
-
const provenance = [];
|
|
4
|
-
const budget = {
|
|
5
|
-
maxUsd: resolveBudgetField("maxUsd", input, provenance),
|
|
6
|
-
softLimitUsd: resolveBudgetField("softLimitUsd", input, provenance),
|
|
7
|
-
maxIterations: resolveBudgetField("maxIterations", input, provenance),
|
|
8
|
-
maxTokens: resolveBudgetField("maxTokens", input, provenance)
|
|
9
|
-
};
|
|
10
|
-
if (budget.softLimitUsd >= budget.maxUsd) {
|
|
11
|
-
budget.softLimitUsd = Math.round(budget.maxUsd * 0.75 * 100) / 100;
|
|
12
|
-
provenance.push({
|
|
13
|
-
field: "budget.softLimitUsd",
|
|
14
|
-
source: "config",
|
|
15
|
-
value: String(budget.softLimitUsd)
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
const governance = {
|
|
19
|
-
policyProfile: resolveEnumField({
|
|
20
|
-
field: "governance.policyProfile",
|
|
21
|
-
defaultsTo: input.defaults.policyProfile,
|
|
22
|
-
configValue: input.config?.policyProfile,
|
|
23
|
-
requestValue: input.request.policyProfile,
|
|
24
|
-
allowed: ["strict", "balanced", "overnight", "debug"],
|
|
25
|
-
provenance
|
|
26
|
-
}),
|
|
27
|
-
telemetryDestination: resolveEnumField({
|
|
28
|
-
field: "governance.telemetryDestination",
|
|
29
|
-
defaultsTo: input.defaults.telemetryDestination,
|
|
30
|
-
configValue: input.config?.governance?.telemetryDestination,
|
|
31
|
-
requestValue: input.request.telemetryDestination,
|
|
32
|
-
allowed: ["local-only", "control-plane"],
|
|
33
|
-
provenance
|
|
34
|
-
}),
|
|
35
|
-
destructiveActionPolicy: resolveEnumField({
|
|
36
|
-
field: "governance.destructiveActionPolicy",
|
|
37
|
-
defaultsTo: input.defaults.destructiveActionPolicy,
|
|
38
|
-
configValue: input.config?.governance?.destructiveActionPolicy,
|
|
39
|
-
allowed: ["never", "approval", "allowed"],
|
|
40
|
-
provenance
|
|
41
|
-
})
|
|
42
|
-
};
|
|
43
|
-
const verificationPlan = resolveVerificationPlan(input, provenance);
|
|
44
|
-
const task = {
|
|
45
|
-
verificationPlan
|
|
46
|
-
};
|
|
47
|
-
if (input.request.mutationMode) {
|
|
48
|
-
task.mutationMode = input.request.mutationMode;
|
|
49
|
-
provenance.push({
|
|
50
|
-
field: "task.mutationMode",
|
|
51
|
-
source: "request",
|
|
52
|
-
value: input.request.mutationMode
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
if (input.request.repoRoot) {
|
|
56
|
-
task.repoRoot = input.request.repoRoot;
|
|
57
|
-
provenance.push({
|
|
58
|
-
field: "task.repoRoot",
|
|
59
|
-
source: "request",
|
|
60
|
-
value: input.request.repoRoot
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
if ((input.request.allowedPaths?.length ?? 0) > 0) {
|
|
64
|
-
const allowedPaths = input.request.allowedPaths ?? [];
|
|
65
|
-
task.allowedPaths = [...allowedPaths];
|
|
66
|
-
provenance.push({
|
|
67
|
-
field: "task.allowedPaths",
|
|
68
|
-
source: "request",
|
|
69
|
-
value: allowedPaths.join(", ")
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
if ((input.request.deniedPaths?.length ?? 0) > 0) {
|
|
73
|
-
const deniedPaths = input.request.deniedPaths ?? [];
|
|
74
|
-
task.deniedPaths = [...deniedPaths];
|
|
75
|
-
provenance.push({
|
|
76
|
-
field: "task.deniedPaths",
|
|
77
|
-
source: "request",
|
|
78
|
-
value: deniedPaths.join(", ")
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
if ((input.request.acceptanceCriteria?.length ?? 0) > 0) {
|
|
82
|
-
const acceptanceCriteria = input.request.acceptanceCriteria ?? [];
|
|
83
|
-
task.acceptanceCriteria = [...acceptanceCriteria];
|
|
84
|
-
provenance.push({
|
|
85
|
-
field: "task.acceptanceCriteria",
|
|
86
|
-
source: "request",
|
|
87
|
-
value: acceptanceCriteria.join(", ")
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
if (input.request.approvalPolicy) {
|
|
91
|
-
task.approvalPolicy = { ...input.request.approvalPolicy };
|
|
92
|
-
provenance.push({
|
|
93
|
-
field: "task.approvalPolicy",
|
|
94
|
-
source: "request",
|
|
95
|
-
value: JSON.stringify(input.request.approvalPolicy)
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
return cloneExecutionPolicy({
|
|
99
|
-
configPath: input.configPath,
|
|
100
|
-
budget,
|
|
101
|
-
governance,
|
|
102
|
-
task,
|
|
103
|
-
provenance
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
function resolveBudgetField(field, input, provenance) {
|
|
107
|
-
if (input.request.budgetOverrides?.[field]) {
|
|
108
|
-
const value = input.request.budget[field];
|
|
109
|
-
provenance.push({
|
|
110
|
-
field: `budget.${String(field)}`,
|
|
111
|
-
source: "request",
|
|
112
|
-
value: String(value)
|
|
113
|
-
});
|
|
114
|
-
return value;
|
|
115
|
-
}
|
|
116
|
-
const configValue = input.config?.budget?.[field];
|
|
117
|
-
if (typeof configValue === "number" && Number.isFinite(configValue)) {
|
|
118
|
-
provenance.push({
|
|
119
|
-
field: `budget.${String(field)}`,
|
|
120
|
-
source: "config",
|
|
121
|
-
value: String(configValue)
|
|
122
|
-
});
|
|
123
|
-
return configValue;
|
|
124
|
-
}
|
|
125
|
-
const value = input.defaults.budget[field];
|
|
126
|
-
provenance.push({
|
|
127
|
-
field: `budget.${String(field)}`,
|
|
128
|
-
source: "default",
|
|
129
|
-
value: String(value)
|
|
130
|
-
});
|
|
131
|
-
return value;
|
|
132
|
-
}
|
|
133
|
-
function resolveVerificationPlan(input, provenance) {
|
|
134
|
-
const requestVerificationPlan = normalizeStringList(input.request.verificationPlan);
|
|
135
|
-
if (requestVerificationPlan.length > 0) {
|
|
136
|
-
provenance.push({
|
|
137
|
-
field: "task.verificationPlan",
|
|
138
|
-
source: "request",
|
|
139
|
-
value: requestVerificationPlan.join(", ")
|
|
140
|
-
});
|
|
141
|
-
return requestVerificationPlan;
|
|
142
|
-
}
|
|
143
|
-
const configVerificationPlan = normalizeStringList(input.config?.governance?.verifierRules);
|
|
144
|
-
if (configVerificationPlan.length > 0) {
|
|
145
|
-
provenance.push({
|
|
146
|
-
field: "task.verificationPlan",
|
|
147
|
-
source: "config",
|
|
148
|
-
value: configVerificationPlan.join(", ")
|
|
149
|
-
});
|
|
150
|
-
return configVerificationPlan;
|
|
151
|
-
}
|
|
152
|
-
const defaultVerificationPlan = normalizeStringList(input.defaults.verifierRules);
|
|
153
|
-
provenance.push({
|
|
154
|
-
field: "task.verificationPlan",
|
|
155
|
-
source: "default",
|
|
156
|
-
value: defaultVerificationPlan.join(", ")
|
|
157
|
-
});
|
|
158
|
-
return defaultVerificationPlan;
|
|
159
|
-
}
|
|
160
|
-
function resolveEnumField(input) {
|
|
161
|
-
const normalizedRequest = normalizeEnumCandidate(input.requestValue, input.allowed);
|
|
162
|
-
if (normalizedRequest) {
|
|
163
|
-
input.provenance.push({
|
|
164
|
-
field: input.field,
|
|
165
|
-
source: "request",
|
|
166
|
-
value: normalizedRequest
|
|
167
|
-
});
|
|
168
|
-
return normalizedRequest;
|
|
169
|
-
}
|
|
170
|
-
const normalizedConfig = normalizeEnumCandidate(input.configValue, input.allowed);
|
|
171
|
-
if (normalizedConfig) {
|
|
172
|
-
input.provenance.push({
|
|
173
|
-
field: input.field,
|
|
174
|
-
source: "config",
|
|
175
|
-
value: normalizedConfig
|
|
176
|
-
});
|
|
177
|
-
return normalizedConfig;
|
|
178
|
-
}
|
|
179
|
-
input.provenance.push({
|
|
180
|
-
field: input.field,
|
|
181
|
-
source: "default",
|
|
182
|
-
value: input.defaultsTo
|
|
183
|
-
});
|
|
184
|
-
return input.defaultsTo;
|
|
185
|
-
}
|
|
186
|
-
function normalizeEnumCandidate(value, allowed) {
|
|
187
|
-
if (typeof value !== "string") {
|
|
188
|
-
return undefined;
|
|
189
|
-
}
|
|
190
|
-
const trimmed = value.trim();
|
|
191
|
-
return allowed.find((candidate) => candidate === trimmed);
|
|
192
|
-
}
|
|
193
|
-
function normalizeStringList(values) {
|
|
194
|
-
return (values ?? []).map((value) => value.trim()).filter(Boolean);
|
|
195
|
-
}
|