@martinloop/mcp 0.5.3 → 0.5.5
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 +6 -6
- package/dist/server-validation.js +2 -0
- package/dist/server.js +30 -3
- package/dist/tools/run-loop.d.ts +1 -0
- package/dist/tools/run-loop.js +25 -4
- package/dist/tools/tool-response.d.ts +9 -1
- package/dist/tools/tool-response.js +7 -5
- package/dist/tools/tool-support.js +62 -271
- package/dist/vendor/adapters/claude-cli.d.ts +9 -0
- package/dist/vendor/adapters/claude-cli.js +19 -2
- package/dist/vendor/adapters/codex-capabilities.d.ts +12 -3
- package/dist/vendor/adapters/codex-capabilities.js +46 -18
- package/dist/vendor/adapters/codex-cli.d.ts +2 -1
- package/dist/vendor/adapters/codex-cli.js +12 -2
- package/dist/vendor/adapters/codex-host.d.ts +4 -1
- package/dist/vendor/adapters/codex-host.js +34 -16
- package/dist/vendor/adapters/codex-launcher.d.ts +1 -1
- package/dist/vendor/adapters/codex-launcher.js +1 -1
- package/dist/vendor/adapters/index.d.ts +2 -1
- package/dist/vendor/adapters/index.js +1 -0
- package/dist/vendor/contracts/agent-execution.d.ts +9 -0
- package/dist/vendor/contracts/agent-execution.js +14 -0
- package/dist/vendor/contracts/index.d.ts +9 -0
- package/dist/vendor/contracts/index.js +1 -0
- package/dist/vendor/core/grounding.js +42 -7
- package/dist/vendor/core/index.d.ts +5 -2
- package/dist/vendor/core/index.js +12 -3
- package/dist/vendor/presentation/governed-plan.d.ts +33 -0
- package/dist/vendor/presentation/governed-plan.js +146 -0
- package/dist/vendor/presentation/index.d.ts +7 -0
- package/dist/vendor/presentation/index.js +7 -0
- package/dist/vendor/presentation/motion.d.ts +12 -0
- package/dist/vendor/presentation/motion.js +123 -0
- package/dist/vendor/presentation/status.d.ts +8 -0
- package/dist/vendor/presentation/status.js +11 -0
- package/dist/vendor/presentation/table.d.ts +11 -0
- package/dist/vendor/presentation/table.js +47 -0
- package/dist/vendor/presentation/text.d.ts +6 -0
- package/dist/vendor/presentation/text.js +30 -0
- package/dist/vendor/presentation/theme.d.ts +31 -0
- package/dist/vendor/presentation/theme.js +82 -0
- package/dist/vendor/presentation/verified-handoff.d.ts +15 -0
- package/dist/vendor/presentation/verified-handoff.js +151 -0
- package/package.json +3 -2
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -57,27 +57,27 @@ These aren't hypotheticals. The $28 overshoot happened in production testing. We
|
|
|
57
57
|
|
|
58
58
|
### Claude Code
|
|
59
59
|
```sh
|
|
60
|
-
claude mcp add martin-loop -- npx -y @martinloop/mcp@0.5.
|
|
60
|
+
claude mcp add martin-loop -- npx -y @martinloop/mcp@0.5.5
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
Windows:
|
|
64
64
|
```sh
|
|
65
|
-
claude mcp add --transport stdio --scope user martin-loop -- cmd /c npx -y @martinloop/mcp@0.5.
|
|
65
|
+
claude mcp add --transport stdio --scope user martin-loop -- cmd /c npx -y @martinloop/mcp@0.5.5
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
### Codex
|
|
69
69
|
```sh
|
|
70
|
-
codex mcp add martin-loop -- npx -y @martinloop/mcp@0.5.
|
|
70
|
+
codex mcp add martin-loop -- npx -y @martinloop/mcp@0.5.5
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
### Gemini CLI
|
|
74
74
|
```sh
|
|
75
|
-
gemini mcp add martin-loop -- npx -y @martinloop/mcp@0.5.
|
|
75
|
+
gemini mcp add martin-loop -- npx -y @martinloop/mcp@0.5.5
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
### Any MCP Host
|
|
79
79
|
```sh
|
|
80
|
-
npx -y @martinloop/mcp@0.5.
|
|
80
|
+
npx -y @martinloop/mcp@0.5.5
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
## How a Governed Run Works
|
|
@@ -139,7 +139,7 @@ MartinLoop does not round failure into success. It preserves the evidence and fo
|
|
|
139
139
|
| `git restore` fails mid-rollback | Throws, leaves dirty state | Retries once, falls back to `git checkout`, cleans up |
|
|
140
140
|
| Invalid `--profile` flag | Crashes | Warns, falls back to `minimal`, keeps running |
|
|
141
141
|
|
|
142
|
-
## Codex compatibility in 0.5.
|
|
142
|
+
## Codex compatibility in 0.5.5
|
|
143
143
|
|
|
144
144
|
MartinLoop no longer assumes one Codex host or one fixed Codex flag set. The CLI resolves the exact Codex executable, reads its advertised capabilities, negotiates a supported write strategy, proves that strategy before reporting launch readiness, and reuses the same contract for the governed run.
|
|
145
145
|
|
|
@@ -151,6 +151,7 @@ function validateRunInput(args) {
|
|
|
151
151
|
"maxIterations",
|
|
152
152
|
"maxTokens",
|
|
153
153
|
"verifyTimeoutMs",
|
|
154
|
+
"providerExecutionTimeoutMs",
|
|
154
155
|
"maxMinutes",
|
|
155
156
|
"maxFilesChanged",
|
|
156
157
|
"maxCommands",
|
|
@@ -180,6 +181,7 @@ function validateRunInput(args) {
|
|
|
180
181
|
...optionalPositiveInteger(record.maxIterations, "maxIterations"),
|
|
181
182
|
...optionalPositiveInteger(record.maxTokens, "maxTokens"),
|
|
182
183
|
...optionalPositiveInteger(record.verifyTimeoutMs, "verifyTimeoutMs"),
|
|
184
|
+
...optionalPositiveInteger(record.providerExecutionTimeoutMs, "providerExecutionTimeoutMs"),
|
|
183
185
|
...optionalPositiveInteger(record.maxMinutes, "maxMinutes"),
|
|
184
186
|
...optionalPositiveInteger(record.maxFilesChanged, "maxFilesChanged"),
|
|
185
187
|
...optionalPositiveInteger(record.maxCommands, "maxCommands"),
|
package/dist/server.js
CHANGED
|
@@ -47,6 +47,7 @@ import { runLoopTool } from "./tools/run-loop.js";
|
|
|
47
47
|
import { MARTIN_ENGINE_VALUES } from "./tools/tool-support.js";
|
|
48
48
|
import { classifyRoute } from "./vendor/core/index.js";
|
|
49
49
|
import { createToolErrorResult, createToolSuccessResult } from "./tools/tool-response.js";
|
|
50
|
+
import { buildGovernedPlanStages, renderGovernedRunPlanMarkdown, renderVerifiedHandoffMarkdown } from "./vendor/presentation/index.js";
|
|
50
51
|
import { MartinToolError, toToolFailure } from "./tools/tool-errors.js";
|
|
51
52
|
import { normalizeLoopBudget } from "./tools/workflow-governance.js";
|
|
52
53
|
import { resolveSafeRepoRoot, sanitizeToolErrorMessage, validateToolInput } from "./server-validation.js";
|
|
@@ -793,6 +794,16 @@ export function createMartinMcpServer(serverInfo) {
|
|
|
793
794
|
exclusiveMinimum: 0,
|
|
794
795
|
description: "Maximum total tokens across all attempts."
|
|
795
796
|
},
|
|
797
|
+
verifyTimeoutMs: {
|
|
798
|
+
type: "integer",
|
|
799
|
+
exclusiveMinimum: 0,
|
|
800
|
+
description: "Hard timeout for each verifier command in milliseconds."
|
|
801
|
+
},
|
|
802
|
+
providerExecutionTimeoutMs: {
|
|
803
|
+
type: "integer",
|
|
804
|
+
exclusiveMinimum: 0,
|
|
805
|
+
description: "Hard timeout for each provider coding process in milliseconds."
|
|
806
|
+
},
|
|
796
807
|
verificationPlan: {
|
|
797
808
|
type: "array",
|
|
798
809
|
items: { type: "string" },
|
|
@@ -1594,7 +1605,23 @@ export function createMartinMcpServer(serverInfo) {
|
|
|
1594
1605
|
budget: output.normalized.budget
|
|
1595
1606
|
}).catch(() => { });
|
|
1596
1607
|
}
|
|
1597
|
-
|
|
1608
|
+
const prefPlanView = {
|
|
1609
|
+
ready: output.ok,
|
|
1610
|
+
task: output.normalized.objective,
|
|
1611
|
+
engine: output.normalized.engine,
|
|
1612
|
+
mode: output.readiness.liveMode ? "live" : "proof",
|
|
1613
|
+
budget: output.normalized.budget,
|
|
1614
|
+
verifier: output.normalized.verificationPlan,
|
|
1615
|
+
receiptScope: output.receiptScope,
|
|
1616
|
+
policyProfile: output.policy.name,
|
|
1617
|
+
blockingIssues: output.ok ? [] : [output.summary],
|
|
1618
|
+
warnings: output.warnings,
|
|
1619
|
+
stages: []
|
|
1620
|
+
};
|
|
1621
|
+
prefPlanView.stages = buildGovernedPlanStages(prefPlanView);
|
|
1622
|
+
return createToolSuccessResult(output, output.summary, {
|
|
1623
|
+
human: renderGovernedRunPlanMarkdown(prefPlanView)
|
|
1624
|
+
});
|
|
1598
1625
|
}
|
|
1599
1626
|
if (name === "martin_logs") {
|
|
1600
1627
|
const input = validateToolInput("martin_logs", args);
|
|
@@ -1644,12 +1671,12 @@ export function createMartinMcpServer(serverInfo) {
|
|
|
1644
1671
|
if (name === "martin_run_dossier") {
|
|
1645
1672
|
const input = validateToolInput("martin_run_dossier", args);
|
|
1646
1673
|
const output = await martinRunDossierTool(input);
|
|
1647
|
-
return createToolSuccessResult(output, `Dossier ready for Martin run ${output.loop.loopId} with ${output.attempts.length} attempt(s)
|
|
1674
|
+
return createToolSuccessResult(output, `Dossier ready for Martin run ${output.loop.loopId} with ${output.attempts.length} attempt(s).`, { human: renderVerifiedHandoffMarkdown(output.verifiedHandoff) });
|
|
1648
1675
|
}
|
|
1649
1676
|
if (name === "martin_dossier") {
|
|
1650
1677
|
const input = validateToolInput("martin_dossier", args);
|
|
1651
1678
|
const output = await martinRunDossierTool(input);
|
|
1652
|
-
return createToolSuccessResult(output, `Dossier ready for Martin run ${output.loop.loopId} in ${output.format} format
|
|
1679
|
+
return createToolSuccessResult(output, `Dossier ready for Martin run ${output.loop.loopId} in ${output.format} format.`, { human: renderVerifiedHandoffMarkdown(output.verifiedHandoff) });
|
|
1653
1680
|
}
|
|
1654
1681
|
if (name === "martin_eval") {
|
|
1655
1682
|
const input = validateToolInput("martin_eval", args);
|
package/dist/tools/run-loop.d.ts
CHANGED
package/dist/tools/run-loop.js
CHANGED
|
@@ -30,7 +30,7 @@ export async function runLoopTool(input) {
|
|
|
30
30
|
repoRoot: workingDirectory,
|
|
31
31
|
runsRoot
|
|
32
32
|
};
|
|
33
|
-
let
|
|
33
|
+
let codexProbeOverride;
|
|
34
34
|
if (executionMode.liveMode) {
|
|
35
35
|
if (engine === "codex") {
|
|
36
36
|
const engineAvailability = resolveCliCommandAvailability("codex");
|
|
@@ -43,7 +43,10 @@ export async function runLoopTool(input) {
|
|
|
43
43
|
}
|
|
44
44
|
const codexProbe = probeCodexLaunch({
|
|
45
45
|
workingDirectory,
|
|
46
|
-
availability: engineAvailability
|
|
46
|
+
availability: engineAvailability,
|
|
47
|
+
...(input.providerExecutionTimeoutMs !== undefined
|
|
48
|
+
? { providerExecutionTimeoutMs: input.providerExecutionTimeoutMs }
|
|
49
|
+
: {})
|
|
47
50
|
});
|
|
48
51
|
if (!codexProbe.ok) {
|
|
49
52
|
throw new MartinToolError("engine_unavailable", codexProbe.summary, {
|
|
@@ -52,7 +55,7 @@ export async function runLoopTool(input) {
|
|
|
52
55
|
retryable: false
|
|
53
56
|
});
|
|
54
57
|
}
|
|
55
|
-
|
|
58
|
+
codexProbeOverride = codexProbe;
|
|
56
59
|
}
|
|
57
60
|
else {
|
|
58
61
|
const engineAvailability = getEngineAvailability(engine);
|
|
@@ -76,18 +79,33 @@ export async function runLoopTool(input) {
|
|
|
76
79
|
? createCodexCliAdapter({
|
|
77
80
|
workingDirectory,
|
|
78
81
|
...(input.verifyTimeoutMs !== undefined ? { verifyTimeoutMs: input.verifyTimeoutMs } : {}),
|
|
82
|
+
...(input.providerExecutionTimeoutMs !== undefined
|
|
83
|
+
? { providerExecutionTimeoutMs: input.providerExecutionTimeoutMs }
|
|
84
|
+
: {}),
|
|
79
85
|
...(model ? { model } : {}),
|
|
80
|
-
...(
|
|
86
|
+
...(codexProbeOverride
|
|
87
|
+
? {
|
|
88
|
+
command: codexProbeOverride.command,
|
|
89
|
+
capabilityProfile: codexProbeOverride.capabilityProfile,
|
|
90
|
+
autonomyResolution: codexProbeOverride.autonomyResolution
|
|
91
|
+
}
|
|
92
|
+
: {})
|
|
81
93
|
})
|
|
82
94
|
: engine === "gemini"
|
|
83
95
|
? createGeminiCliAdapter({
|
|
84
96
|
workingDirectory,
|
|
85
97
|
...(input.verifyTimeoutMs !== undefined ? { verifyTimeoutMs: input.verifyTimeoutMs } : {}),
|
|
98
|
+
...(input.providerExecutionTimeoutMs !== undefined
|
|
99
|
+
? { providerExecutionTimeoutMs: input.providerExecutionTimeoutMs }
|
|
100
|
+
: {}),
|
|
86
101
|
...(model ? { model } : {})
|
|
87
102
|
})
|
|
88
103
|
: createClaudeCliAdapter({
|
|
89
104
|
workingDirectory,
|
|
90
105
|
...(input.verifyTimeoutMs !== undefined ? { verifyTimeoutMs: input.verifyTimeoutMs } : {}),
|
|
106
|
+
...(input.providerExecutionTimeoutMs !== undefined
|
|
107
|
+
? { providerExecutionTimeoutMs: input.providerExecutionTimeoutMs }
|
|
108
|
+
: {}),
|
|
91
109
|
...(model ? { model } : {})
|
|
92
110
|
});
|
|
93
111
|
const partialBudget = {};
|
|
@@ -113,6 +131,9 @@ export async function runLoopTool(input) {
|
|
|
113
131
|
...(input.verifyTimeoutMs !== undefined
|
|
114
132
|
? { verificationTimeoutMs: input.verifyTimeoutMs }
|
|
115
133
|
: {}),
|
|
134
|
+
...(input.providerExecutionTimeoutMs !== undefined
|
|
135
|
+
? { providerExecutionTimeoutMs: input.providerExecutionTimeoutMs }
|
|
136
|
+
: {}),
|
|
116
137
|
repoRoot: workingDirectory,
|
|
117
138
|
...(allowedPaths ? { allowedPaths } : {}),
|
|
118
139
|
...(deniedPaths ? { deniedPaths } : {})
|
|
@@ -3,7 +3,15 @@ interface TextContentBlock {
|
|
|
3
3
|
type: "text";
|
|
4
4
|
text: string;
|
|
5
5
|
}
|
|
6
|
-
export
|
|
6
|
+
export interface ToolSuccessRenderOptions {
|
|
7
|
+
/** Explicit human-readable Markdown for content[0].
|
|
8
|
+
* Overrides resolveHumanArtifact fallback when provided. */
|
|
9
|
+
human?: string;
|
|
10
|
+
/** Include compatibility JSON block in content[]. Default: true.
|
|
11
|
+
* Set false only after real-host testing proves structuredContent alone suffices. */
|
|
12
|
+
includeCompatibilityJson?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function createToolSuccessResult<T extends object>(output: T, summary: string, options?: ToolSuccessRenderOptions): {
|
|
7
15
|
content: TextContentBlock[];
|
|
8
16
|
structuredContent: T;
|
|
9
17
|
_meta: Record<string, unknown>;
|
|
@@ -8,12 +8,14 @@ function resolveHumanArtifact(output, summary) {
|
|
|
8
8
|
const rendered = "rendered" in output ? output.rendered : undefined;
|
|
9
9
|
return typeof rendered === "string" && rendered.trim().length > 0 ? rendered : summary;
|
|
10
10
|
}
|
|
11
|
-
export function createToolSuccessResult(output, summary) {
|
|
11
|
+
export function createToolSuccessResult(output, summary, options = {}) {
|
|
12
|
+
const humanText = options.human ?? resolveHumanArtifact(output, summary);
|
|
13
|
+
const content = [{ type: "text", text: humanText }];
|
|
14
|
+
if (options.includeCompatibilityJson !== false) {
|
|
15
|
+
content.push(createJsonBlock(output));
|
|
16
|
+
}
|
|
12
17
|
return {
|
|
13
|
-
content
|
|
14
|
-
{ type: "text", text: resolveHumanArtifact(output, summary) },
|
|
15
|
-
createJsonBlock(output)
|
|
16
|
-
],
|
|
18
|
+
content,
|
|
17
19
|
structuredContent: output,
|
|
18
20
|
_meta: {
|
|
19
21
|
"martinloop/summary": summary,
|