@martinloop/mcp 0.2.7 → 0.3.0
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 +49 -104
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/prompts.d.ts +1 -1
- package/dist/resources.d.ts +1 -1
- package/dist/resources.js +2 -2
- package/dist/server-validation.d.ts +1 -0
- package/dist/server-validation.js +8 -0
- package/dist/server.js +18 -2
- package/dist/tools/doctor.d.ts +12 -1
- package/dist/tools/doctor.js +37 -6
- package/dist/tools/eval.js +3 -2
- package/dist/tools/get-run.d.ts +2 -0
- package/dist/tools/get-run.js +2 -1
- package/dist/tools/get-verification-results.d.ts +2 -0
- package/dist/tools/get-verification-results.js +2 -1
- package/dist/tools/pr-tools.js +2 -1
- package/dist/tools/preflight.d.ts +14 -1
- package/dist/tools/preflight.js +36 -5
- package/dist/tools/run-dossier.d.ts +2 -0
- package/dist/tools/run-dossier.js +4 -2
- package/dist/tools/run-loop.d.ts +3 -2
- package/dist/tools/run-loop.js +48 -28
- package/dist/tools/tool-errors.js +1 -1
- package/dist/tools/tool-support.d.ts +6 -3
- package/dist/tools/tool-support.js +12 -5
- package/dist/vendor/adapters/claude-cli.d.ts +25 -0
- package/dist/vendor/adapters/claude-cli.js +279 -19
- package/dist/vendor/adapters/cli-bridge.d.ts +1 -0
- package/dist/vendor/adapters/cli-bridge.js +44 -3
- package/dist/vendor/adapters/codex-launcher.d.ts +44 -0
- package/dist/vendor/adapters/codex-launcher.js +247 -0
- package/dist/vendor/adapters/index.d.ts +3 -2
- package/dist/vendor/adapters/index.js +3 -2
- package/dist/vendor/adapters/openai-compatible.d.ts +19 -4
- package/dist/vendor/adapters/openai-compatible.js +44 -19
- package/dist/vendor/adapters/runtime-support.d.ts +3 -0
- package/dist/vendor/adapters/runtime-support.js +8 -1
- package/dist/vendor/adapters/verifier-only.js +4 -3
- package/dist/vendor/contracts/index.d.ts +39 -0
- package/dist/vendor/contracts/index.js +2 -0
- package/dist/vendor/core/index.d.ts +23 -3
- package/dist/vendor/core/index.js +88 -15
- package/dist/vendor/core/persistence/index.d.ts +2 -0
- package/dist/vendor/core/persistence/index.js +1 -0
- package/dist/vendor/core/persistence/integrity.d.ts +38 -0
- package/dist/vendor/core/persistence/integrity.js +239 -0
- package/dist/vendor/core/persistence/store.d.ts +7 -0
- package/dist/vendor/core/persistence/store.js +25 -1
- package/dist/vendor/core/policy.d.ts +9 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -2,6 +2,7 @@ import { buildArtifactSummary, buildBudgetSnapshot, buildCostSnapshot, buildEven
|
|
|
2
2
|
import { readRunControlState } from "./run-controls.js";
|
|
3
3
|
import { martinEvalTool } from "./eval.js";
|
|
4
4
|
import { assessRunRisk } from "./workflow-governance.js";
|
|
5
|
+
import type { ReceiptIntegritySummary } from "../vendor/contracts/index.js";
|
|
5
6
|
export interface MartinRunDossierInput {
|
|
6
7
|
file?: string;
|
|
7
8
|
loopId?: string;
|
|
@@ -15,6 +16,7 @@ export interface MartinRunDossierOutput {
|
|
|
15
16
|
loop: ReturnType<typeof buildLoopPreview>;
|
|
16
17
|
budget: ReturnType<typeof buildBudgetSnapshot>;
|
|
17
18
|
cost: ReturnType<typeof buildCostSnapshot>;
|
|
19
|
+
receiptIntegrity: ReceiptIntegritySummary;
|
|
18
20
|
attempts: Array<{
|
|
19
21
|
index: number;
|
|
20
22
|
attemptId?: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { buildArtifactSummary, buildBudgetSnapshot, buildCostSnapshot, buildEventSummaries, buildLoopPreview, buildSuggestedPromptNames, buildSuggestedResourceUris, buildVerificationSummary } from "./tool-support.js";
|
|
1
|
+
import { buildArtifactSummary, buildBudgetSnapshot, buildCostSnapshot, buildEventSummaries, buildLoopPreview, resolveReceiptIntegrity, buildSuggestedPromptNames, buildSuggestedResourceUris, buildVerificationSummary } from "./tool-support.js";
|
|
2
|
+
import { resolveTrustedLoopRepoRoot } from "../server-validation.js";
|
|
2
3
|
import { loadDetailedLoopRecord, readAttemptArtifactFiles, readLedgerEvents } from "./run-store.js";
|
|
3
4
|
import { readRunControlState } from "./run-controls.js";
|
|
4
5
|
import { martinEvalTool } from "./eval.js";
|
|
@@ -9,7 +10,7 @@ export async function martinRunDossierTool(input) {
|
|
|
9
10
|
const verification = buildVerificationSummary(detail.loop, ledgerEvents);
|
|
10
11
|
const control = await readRunControlState(detail);
|
|
11
12
|
const evaluation = await martinEvalTool(input);
|
|
12
|
-
const repoRoot = detail.loop.task?.repoRoot
|
|
13
|
+
const repoRoot = resolveTrustedLoopRepoRoot(detail.loop.task?.repoRoot);
|
|
13
14
|
const risk = assessRunRisk({
|
|
14
15
|
objective: detail.loop.task?.objective ?? detail.loop.loopId,
|
|
15
16
|
allowedPaths: detail.loop.task?.allowedPaths ?? [],
|
|
@@ -51,6 +52,7 @@ export async function martinRunDossierTool(input) {
|
|
|
51
52
|
loop: buildLoopPreview(detail.loop),
|
|
52
53
|
budget: buildBudgetSnapshot(detail.loop.budget),
|
|
53
54
|
cost: buildCostSnapshot(detail.loop.cost),
|
|
55
|
+
receiptIntegrity: resolveReceiptIntegrity(detail.loop),
|
|
54
56
|
attempts,
|
|
55
57
|
verification,
|
|
56
58
|
artifacts: buildArtifactSummary(detail.loop),
|
package/dist/tools/run-loop.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { type LoopBudget } from "../vendor/contracts/index.js";
|
|
1
|
+
import { type LoopBudget, type ReceiptScope } from "../vendor/contracts/index.js";
|
|
2
2
|
import { buildArtifactSummary, buildVerificationSummary, buildLoopPreview, type MartinEngine } from "./tool-support.js";
|
|
3
3
|
export interface RunLoopInput {
|
|
4
4
|
objective: string;
|
|
5
5
|
workingDirectory?: string;
|
|
6
|
-
engine?: "claude" | "codex";
|
|
6
|
+
engine?: "claude" | "codex" | "gemini";
|
|
7
7
|
model?: string;
|
|
8
8
|
maxUsd?: number;
|
|
9
9
|
maxIterations?: number;
|
|
@@ -35,6 +35,7 @@ export interface RunLoopOutput {
|
|
|
35
35
|
runDirectory: string;
|
|
36
36
|
loopRecordPath: string;
|
|
37
37
|
ledgerPath: string;
|
|
38
|
+
receiptScope: ReceiptScope;
|
|
38
39
|
loop: ReturnType<typeof buildLoopPreview>;
|
|
39
40
|
verification: ReturnType<typeof buildVerificationSummary>;
|
|
40
41
|
artifacts: ReturnType<typeof buildArtifactSummary>;
|
package/dist/tools/run-loop.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { createClaudeCliAdapter, createCodexCliAdapter,
|
|
1
|
+
import { createClaudeCliAdapter, createCodexCliAdapter, createGeminiCliAdapter, probeCodexLaunch, resolveCliCommandAvailability, createVerifierOnlyAdapter } from "../vendor/adapters/index.js";
|
|
2
2
|
import { createFileRunStore, evaluateCostGovernor, resolveRunsRoot, runMartin } from "../vendor/core/index.js";
|
|
3
3
|
import { DEFAULT_BUDGET } from "../vendor/contracts/index.js";
|
|
4
4
|
import { normalizeSafePathPatterns, resolveSafeRepoRoot } from "../server-validation.js";
|
|
5
|
-
import { evaluateMcpRunGate } from "../workflow-state.js";
|
|
6
5
|
import { MartinToolError } from "./tool-errors.js";
|
|
7
6
|
import { buildArtifactSummary, buildVerificationSummary, buildLoopPreview, buildRunRecordPaths, getEngineAvailability, resolveExecutionMode } from "./tool-support.js";
|
|
8
7
|
export async function runLoopTool(input) {
|
|
@@ -12,38 +11,57 @@ export async function runLoopTool(input) {
|
|
|
12
11
|
const allowedPaths = normalizeSafePathPatterns(input.allowedPaths, "allowedPaths");
|
|
13
12
|
const deniedPaths = normalizeSafePathPatterns(input.deniedPaths, "deniedPaths");
|
|
14
13
|
const executionMode = resolveExecutionMode();
|
|
15
|
-
const
|
|
14
|
+
const workspaceRoot = resolveSafeRepoRoot();
|
|
16
15
|
const runsRoot = resolveRunsRoot(process.env);
|
|
17
|
-
const
|
|
18
|
-
|
|
16
|
+
const receiptScope = {
|
|
17
|
+
invocationRoot: workspaceRoot,
|
|
19
18
|
workingDirectory,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
repoRoot: workingDirectory,
|
|
20
|
+
runsRoot
|
|
21
|
+
};
|
|
22
|
+
if (executionMode.liveMode) {
|
|
23
|
+
if (engine === "codex") {
|
|
24
|
+
const engineAvailability = resolveCliCommandAvailability("codex");
|
|
25
|
+
if (!engineAvailability.available) {
|
|
26
|
+
throw new MartinToolError("engine_unavailable", `Engine '${engine}' is not available on PATH.`, {
|
|
27
|
+
category: "environment",
|
|
28
|
+
suggestion: "Install the requested CLI or set MARTIN_LIVE=false for a no-spend proof run.",
|
|
29
|
+
retryable: false
|
|
30
|
+
});
|
|
32
31
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
const codexProbe = probeCodexLaunch({
|
|
33
|
+
workingDirectory,
|
|
34
|
+
availability: engineAvailability
|
|
35
|
+
});
|
|
36
|
+
if (!codexProbe.ok) {
|
|
37
|
+
throw new MartinToolError("engine_unavailable", codexProbe.summary, {
|
|
38
|
+
category: "environment",
|
|
39
|
+
suggestion: "Run martin_doctor or martin_preflight with engine='codex' before retrying live governed work.",
|
|
40
|
+
retryable: false
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const engineAvailability = getEngineAvailability(engine);
|
|
46
|
+
if (!engineAvailability.available) {
|
|
47
|
+
throw new MartinToolError("engine_unavailable", `Engine '${engine}' is not available on PATH.`, {
|
|
48
|
+
category: "environment",
|
|
49
|
+
suggestion: "Install the requested CLI or set MARTIN_LIVE=false for a no-spend proof run.",
|
|
50
|
+
retryable: false
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
41
54
|
}
|
|
42
|
-
const adapter =
|
|
43
|
-
?
|
|
55
|
+
const adapter = !executionMode.liveMode
|
|
56
|
+
? createVerifierOnlyAdapter({
|
|
57
|
+
workingDirectory,
|
|
58
|
+
label: "Proof mode adapter (MARTIN_LIVE=false)"
|
|
59
|
+
})
|
|
44
60
|
: engine === "codex"
|
|
45
61
|
? createCodexCliAdapter({ workingDirectory, ...(model ? { model } : {}) })
|
|
46
|
-
:
|
|
62
|
+
: engine === "gemini"
|
|
63
|
+
? createGeminiCliAdapter({ workingDirectory, ...(model ? { model } : {}) })
|
|
64
|
+
: createClaudeCliAdapter({ workingDirectory, ...(model ? { model } : {}) });
|
|
47
65
|
const partialBudget = {};
|
|
48
66
|
if (input.maxUsd !== undefined) {
|
|
49
67
|
partialBudget.maxUsd = input.maxUsd;
|
|
@@ -62,6 +80,7 @@ export async function runLoopTool(input) {
|
|
|
62
80
|
workspaceId: input.workspaceId ?? "ws_mcp",
|
|
63
81
|
projectId: input.projectId ?? "proj_mcp",
|
|
64
82
|
store: createFileRunStore({ runsRoot }),
|
|
83
|
+
receiptScope,
|
|
65
84
|
task: {
|
|
66
85
|
title: input.objective.slice(0, 100),
|
|
67
86
|
objective: input.objective,
|
|
@@ -106,6 +125,7 @@ export async function runLoopTool(input) {
|
|
|
106
125
|
budget,
|
|
107
126
|
inspection: {
|
|
108
127
|
...recordPaths,
|
|
128
|
+
receiptScope: result.loop.receiptScope ?? receiptScope,
|
|
109
129
|
loop: buildLoopPreview(result.loop),
|
|
110
130
|
verification,
|
|
111
131
|
artifacts
|
|
@@ -92,7 +92,7 @@ export function toToolFailure(error) {
|
|
|
92
92
|
code: "engine_unavailable",
|
|
93
93
|
category: "environment",
|
|
94
94
|
message,
|
|
95
|
-
suggestion: "Install the requested CLI or set MARTIN_LIVE=false for
|
|
95
|
+
suggestion: "Install the requested CLI or set MARTIN_LIVE=false for a no-spend proof run.",
|
|
96
96
|
retryable: false
|
|
97
97
|
};
|
|
98
98
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { LoopArtifact, LoopBudget, LoopCost, LoopEvent, LoopTask } from "../vendor/contracts/index.js";
|
|
1
|
+
import type { LoopArtifact, LoopBudget, LoopCost, LoopEvent, LoopTask, ReceiptIntegritySummary, ReceiptScope } from "../vendor/contracts/index.js";
|
|
2
2
|
import { type LedgerEvent, type LoopAttemptRecord, type LoopRunRecord } from "../vendor/core/index.js";
|
|
3
|
-
export type MartinEngine = "claude" | "codex";
|
|
3
|
+
export type MartinEngine = "claude" | "codex" | "gemini";
|
|
4
4
|
export interface InspectableLoopAttempt extends LoopAttemptRecord {
|
|
5
5
|
attemptId?: string;
|
|
6
6
|
summary?: string;
|
|
@@ -11,6 +11,8 @@ export interface InspectableLoopRecord extends Omit<LoopRunRecord, "attempts" |
|
|
|
11
11
|
artifacts?: LoopArtifact[];
|
|
12
12
|
events?: LoopEvent[];
|
|
13
13
|
metadata?: Record<string, string>;
|
|
14
|
+
receiptIntegrity?: ReceiptIntegritySummary;
|
|
15
|
+
receiptScope?: ReceiptScope;
|
|
14
16
|
}
|
|
15
17
|
export interface LoopPreview {
|
|
16
18
|
loopId: string;
|
|
@@ -90,7 +92,7 @@ export interface CliAvailability {
|
|
|
90
92
|
}
|
|
91
93
|
export interface ExecutionMode {
|
|
92
94
|
liveMode: boolean;
|
|
93
|
-
mode: "live" | "
|
|
95
|
+
mode: "live" | "proof";
|
|
94
96
|
detail: string;
|
|
95
97
|
}
|
|
96
98
|
export interface RunStoreInspection extends LoopCollectionSummary {
|
|
@@ -113,6 +115,7 @@ export declare function buildLoopPreview(loop: InspectableLoopRecord): LoopPrevi
|
|
|
113
115
|
export declare function buildAttemptSummary(attempt: InspectableLoopAttempt, artifacts?: AttemptArtifactFiles): AttemptSummary;
|
|
114
116
|
export declare function buildArtifactSummary(loop: InspectableLoopRecord): ArtifactSummary;
|
|
115
117
|
export declare function buildVerificationSummary(loop: InspectableLoopRecord, ledgerEvents?: LedgerEvent[]): VerificationSummary;
|
|
118
|
+
export declare function resolveReceiptIntegrity(loop: InspectableLoopRecord): ReceiptIntegritySummary;
|
|
116
119
|
export declare function buildEventSummaries(loop: InspectableLoopRecord, limit?: number): EventSummary[];
|
|
117
120
|
export declare function buildLoopCollectionSummary(loops: Array<LoopRunRecord | InspectableLoopRecord>): LoopCollectionSummary;
|
|
118
121
|
export declare function inspectRunsRoot(runsRoot?: string): Promise<RunStoreInspection>;
|
|
@@ -11,10 +11,10 @@ export function resolveExecutionMode() {
|
|
|
11
11
|
const liveMode = process.env.MARTIN_LIVE !== "false";
|
|
12
12
|
return {
|
|
13
13
|
liveMode,
|
|
14
|
-
mode: liveMode ? "live" : "
|
|
14
|
+
mode: liveMode ? "live" : "proof",
|
|
15
15
|
detail: liveMode
|
|
16
16
|
? "Live CLI execution is enabled."
|
|
17
|
-
: "
|
|
17
|
+
: "Proof mode is active because MARTIN_LIVE=false."
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
export function detectCliAvailability(command) {
|
|
@@ -126,7 +126,11 @@ export function buildVerificationSummary(loop, ledgerEvents = []) {
|
|
|
126
126
|
const verificationEvents = (loop.events ?? []).filter((event) => event.type === "verification.completed");
|
|
127
127
|
const verificationLedgerEvents = ledgerEvents.filter((event) => event.kind === "verification.completed");
|
|
128
128
|
const warnings = [];
|
|
129
|
+
const integrity = resolveReceiptIntegrity(loop);
|
|
129
130
|
const ledgerWarnings = getLedgerWarnings(ledgerEvents);
|
|
131
|
+
if (integrity.state !== "verified") {
|
|
132
|
+
warnings.push(`Receipt integrity is ${integrity.state}; persisted verifier evidence is not trustworthy yet.`);
|
|
133
|
+
}
|
|
130
134
|
warnings.push(...ledgerWarnings);
|
|
131
135
|
if (verificationEvents.length === 0) {
|
|
132
136
|
warnings.push(verificationLedgerEvents.length > 0
|
|
@@ -163,6 +167,12 @@ export function buildVerificationSummary(loop, ledgerEvents = []) {
|
|
|
163
167
|
warnings
|
|
164
168
|
};
|
|
165
169
|
}
|
|
170
|
+
export function resolveReceiptIntegrity(loop) {
|
|
171
|
+
return (loop.receiptIntegrity ?? {
|
|
172
|
+
state: "unsigned",
|
|
173
|
+
reason: "Receipt integrity metadata was not available on the loop record."
|
|
174
|
+
});
|
|
175
|
+
}
|
|
166
176
|
export function buildEventSummaries(loop, limit = 5) {
|
|
167
177
|
return (loop.events ?? [])
|
|
168
178
|
.slice(-limit)
|
|
@@ -287,9 +297,6 @@ export function buildSuggestedResourceUris(loopId) {
|
|
|
287
297
|
`martin://runs/${loopId}/verification`,
|
|
288
298
|
"martin://guides/mcp-usage",
|
|
289
299
|
"martin://guides/agent-start",
|
|
290
|
-
"martin://guides/command-map",
|
|
291
|
-
"martin://guides/ide-onboarding",
|
|
292
|
-
"martin://guides/operating-rules",
|
|
293
300
|
"martin://guides/publish-readiness"
|
|
294
301
|
];
|
|
295
302
|
}
|
|
@@ -80,6 +80,21 @@ export interface CodexCliAdapterOptions {
|
|
|
80
80
|
extraArgs?: string[];
|
|
81
81
|
spawnImpl?: SpawnLike;
|
|
82
82
|
}
|
|
83
|
+
export interface GeminiCliAdapterOptions {
|
|
84
|
+
workingDirectory?: string;
|
|
85
|
+
timeoutMs?: number;
|
|
86
|
+
verifyTimeoutMs?: number;
|
|
87
|
+
label?: string;
|
|
88
|
+
/** Override the model passed via --model flag. Defaults to the Gemini `flash` alias. */
|
|
89
|
+
model?: string;
|
|
90
|
+
/** Approval mode for headless Gemini runs. Defaults to yolo for autonomous execution. */
|
|
91
|
+
approvalMode?: "default" | "auto_edit" | "yolo" | "plan";
|
|
92
|
+
/** Enable Gemini sandbox mode when the host is configured for it. Disabled by default. */
|
|
93
|
+
sandbox?: boolean;
|
|
94
|
+
/** Extra args appended after core args. */
|
|
95
|
+
extraArgs?: string[];
|
|
96
|
+
spawnImpl?: SpawnLike;
|
|
97
|
+
}
|
|
83
98
|
export declare function createAgentCliAdapter(options: AgentCliAdapterOptions): MartinAdapter;
|
|
84
99
|
/**
|
|
85
100
|
* Spawns `claude --output-format json --print "<prompt>" --dangerously-skip-permissions [extraArgs]`.
|
|
@@ -102,3 +117,13 @@ export declare function createClaudeCliAdapter(options?: ClaudeCliAdapterOptions
|
|
|
102
117
|
* npm install -g @openai/codex
|
|
103
118
|
*/
|
|
104
119
|
export declare function createCodexCliAdapter(options?: CodexCliAdapterOptions): MartinAdapter;
|
|
120
|
+
/**
|
|
121
|
+
* Spawns `gemini --model <model> --prompt "" --approval-mode <mode> --output-format json [...]`.
|
|
122
|
+
*
|
|
123
|
+
* The prompt is delivered via stdin while forcing headless mode with `--prompt ""`,
|
|
124
|
+
* which keeps large MartinLoop prompts off the command line on Windows.
|
|
125
|
+
*
|
|
126
|
+
* Requires the Gemini CLI to be installed and authenticated:
|
|
127
|
+
* npm install -g @google/gemini-cli
|
|
128
|
+
*/
|
|
129
|
+
export declare function createGeminiCliAdapter(options?: GeminiCliAdapterOptions): MartinAdapter;
|