@martinloop/mcp 0.2.0 → 0.2.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 +131 -158
- package/dist/discovery-metadata.d.ts +16 -0
- package/dist/discovery-metadata.js +62 -0
- package/dist/discovery-support.d.ts +62 -0
- package/dist/discovery-support.js +224 -0
- package/dist/package-version.d.ts +1 -0
- package/dist/package-version.js +3 -0
- package/dist/prompts.d.ts +13 -3
- package/dist/prompts.js +445 -74
- package/dist/resources.d.ts +27 -5
- package/dist/resources.js +557 -71
- package/dist/server-validation.d.ts +2 -3
- package/dist/server-validation.js +262 -122
- package/dist/server.d.ts +76 -7
- package/dist/server.js +1126 -400
- package/dist/tools/doctor.js +14 -6
- package/dist/tools/get-attempt.d.ts +13 -6
- package/dist/tools/get-attempt.js +14 -5
- package/dist/tools/get-run.d.ts +19 -12
- package/dist/tools/get-run.js +20 -11
- package/dist/tools/get-status.d.ts +11 -0
- package/dist/tools/get-status.js +12 -2
- package/dist/tools/get-verification-results.d.ts +10 -7
- package/dist/tools/get-verification-results.js +11 -6
- package/dist/tools/inspect-loop.d.ts +9 -0
- package/dist/tools/inspect-loop.js +11 -2
- package/dist/tools/list-runs.d.ts +25 -5
- package/dist/tools/list-runs.js +21 -4
- package/dist/tools/preflight.js +7 -2
- package/dist/tools/run-dossier.d.ts +37 -4
- package/dist/tools/run-dossier.js +40 -5
- package/dist/tools/run-loop.d.ts +19 -0
- package/dist/tools/run-loop.js +41 -3
- package/dist/tools/run-store.d.ts +57 -3
- package/dist/tools/run-store.js +404 -53
- package/dist/tools/tool-errors.d.ts +37 -0
- package/dist/tools/tool-errors.js +170 -0
- package/dist/tools/tool-response.d.ts +16 -0
- package/dist/tools/tool-response.js +34 -0
- package/dist/tools/tool-support.d.ts +92 -2
- package/dist/tools/tool-support.js +358 -63
- package/dist/tools/triage-runs.d.ts +33 -0
- package/dist/tools/triage-runs.js +138 -0
- package/dist/vendor/adapters/claude-cli.js +0 -1
- package/dist/vendor/adapters/cli-bridge.js +0 -1
- package/dist/vendor/adapters/direct-provider.js +0 -1
- package/dist/vendor/adapters/index.js +0 -1
- package/dist/vendor/adapters/runtime-support.js +0 -1
- package/dist/vendor/adapters/stub-agent-cli.js +0 -1
- package/dist/vendor/adapters/stub-direct-provider.js +0 -1
- package/dist/vendor/adapters/verifier-only.js +0 -1
- package/dist/vendor/contracts/governance.js +0 -1
- package/dist/vendor/contracts/index.d.ts +2 -0
- package/dist/vendor/contracts/index.js +1 -1
- package/dist/vendor/contracts/operator.d.ts +19 -0
- package/dist/vendor/contracts/operator.js +11 -0
- package/dist/vendor/core/compiler.js +0 -1
- package/dist/vendor/core/context-integrity.js +0 -1
- package/dist/vendor/core/grounding.js +0 -1
- package/dist/vendor/core/index.js +1 -2
- package/dist/vendor/core/leash.js +19 -12
- package/dist/vendor/core/persistence/compiler.js +0 -1
- package/dist/vendor/core/persistence/index.js +0 -1
- package/dist/vendor/core/persistence/ledger.js +0 -1
- package/dist/vendor/core/persistence/runs-reader.js +0 -1
- package/dist/vendor/core/persistence/store.js +0 -1
- package/dist/vendor/core/policy.js +0 -1
- package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
- package/dist/vendor/core/red-blue/red-phase.js +135 -0
- package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
- package/dist/vendor/core/red-blue/risk-tiers.js +32 -0
- package/dist/vendor/core/rollback.js +2 -3
- package/package.json +10 -5
- package/server.json +2 -2
- package/dist/tools/cockpit-support.d.ts +0 -69
- package/dist/tools/cockpit-support.js +0 -108
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
export class MartinToolError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
category;
|
|
4
|
+
suggestion;
|
|
5
|
+
retryable;
|
|
6
|
+
exposeMessage;
|
|
7
|
+
details;
|
|
8
|
+
constructor(code, message, options = {}) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "MartinToolError";
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.category = options.category ?? "transient";
|
|
13
|
+
this.suggestion = options.suggestion;
|
|
14
|
+
this.retryable = options.retryable ?? false;
|
|
15
|
+
this.exposeMessage = options.exposeMessage ?? true;
|
|
16
|
+
this.details = options.details;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const SENSITIVE_MESSAGE_PATTERN = /([A-Za-z]:\\|\/|policy\.rego|policy\.wasm|\.pem|\.env)/u;
|
|
20
|
+
export function sanitizePotentiallySensitiveMessage(message) {
|
|
21
|
+
return SENSITIVE_MESSAGE_PATTERN.test(message) ? "Tool execution failed." : message;
|
|
22
|
+
}
|
|
23
|
+
export function sanitizeToolErrorMessage(error) {
|
|
24
|
+
if (error instanceof MartinToolError) {
|
|
25
|
+
return error.exposeMessage
|
|
26
|
+
? sanitizePotentiallySensitiveMessage(error.message)
|
|
27
|
+
: "Tool execution failed.";
|
|
28
|
+
}
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
return sanitizePotentiallySensitiveMessage(message);
|
|
31
|
+
}
|
|
32
|
+
export function toToolFailure(error) {
|
|
33
|
+
if (error instanceof MartinToolError) {
|
|
34
|
+
return {
|
|
35
|
+
code: error.code,
|
|
36
|
+
category: error.category,
|
|
37
|
+
message: sanitizeToolErrorMessage(error),
|
|
38
|
+
...(error.suggestion ? { suggestion: error.suggestion } : {}),
|
|
39
|
+
retryable: error.retryable,
|
|
40
|
+
...(error.details ? { details: error.details } : {})
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
44
|
+
const message = sanitizeToolErrorMessage(error);
|
|
45
|
+
if (error instanceof SyntaxError || /JSON/u.test(rawMessage)) {
|
|
46
|
+
return {
|
|
47
|
+
code: "invalid_json",
|
|
48
|
+
category: "invalid_input",
|
|
49
|
+
message,
|
|
50
|
+
suggestion: "Provide a valid JSON-serialized LoopRecord.",
|
|
51
|
+
retryable: false
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (/No loop records found\./u.test(rawMessage)) {
|
|
55
|
+
return {
|
|
56
|
+
code: "no_loop_records",
|
|
57
|
+
category: "not_found",
|
|
58
|
+
message: "No loop records found.",
|
|
59
|
+
suggestion: "Run martin_run first or point file, loopId, or runsDir at a populated Martin runs location.",
|
|
60
|
+
retryable: false
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (/Attempt .* not found\./u.test(rawMessage)) {
|
|
64
|
+
return {
|
|
65
|
+
code: "attempt_not_found",
|
|
66
|
+
category: "not_found",
|
|
67
|
+
message,
|
|
68
|
+
suggestion: "Choose a valid attemptIndex for the selected Martin run.",
|
|
69
|
+
retryable: false
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (/Provide exactly one/u.test(rawMessage)) {
|
|
73
|
+
return {
|
|
74
|
+
code: "invalid_selector",
|
|
75
|
+
category: "invalid_input",
|
|
76
|
+
message,
|
|
77
|
+
suggestion: "Choose exactly one selector: loopJson, file, loopId, or latest.",
|
|
78
|
+
retryable: false
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (/Unknown tool/u.test(rawMessage)) {
|
|
82
|
+
return {
|
|
83
|
+
code: "unknown_tool",
|
|
84
|
+
category: "invalid_input",
|
|
85
|
+
message,
|
|
86
|
+
suggestion: "Refresh the tool list and call one of the advertised Martin tools.",
|
|
87
|
+
retryable: false
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (/is not available on PATH/u.test(rawMessage)) {
|
|
91
|
+
return {
|
|
92
|
+
code: "engine_unavailable",
|
|
93
|
+
category: "environment",
|
|
94
|
+
message,
|
|
95
|
+
suggestion: "Install the requested CLI or set MARTIN_LIVE=false for stub execution.",
|
|
96
|
+
retryable: false
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (/Unknown arguments/u.test(rawMessage) ||
|
|
100
|
+
/Tool arguments must be an object\./u.test(rawMessage) ||
|
|
101
|
+
/^Invalid /u.test(rawMessage)) {
|
|
102
|
+
return {
|
|
103
|
+
code: /Invalid (allowedPaths|deniedPaths|file|loopId|runsDir|workingDirectory)\./u.test(rawMessage)
|
|
104
|
+
? "invalid_path"
|
|
105
|
+
: "invalid_arguments",
|
|
106
|
+
category: "invalid_input",
|
|
107
|
+
message,
|
|
108
|
+
suggestion: "Check the tool schema and resend only supported, in-scope values.",
|
|
109
|
+
retryable: false
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (/Unable to read Martin runs store\./u.test(rawMessage)) {
|
|
113
|
+
return {
|
|
114
|
+
code: "store_unreadable",
|
|
115
|
+
category: "store_unreadable",
|
|
116
|
+
message,
|
|
117
|
+
suggestion: "Check runsDir permissions and confirm the selected Martin run store is readable.",
|
|
118
|
+
retryable: false
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
code: "tool_execution_failed",
|
|
123
|
+
category: "transient",
|
|
124
|
+
message,
|
|
125
|
+
suggestion: "Review the tool inputs and environment, then retry when the underlying issue is fixed.",
|
|
126
|
+
retryable: true
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
export function invalidArgumentsError(message, suggestion) {
|
|
130
|
+
return new MartinToolError("invalid_arguments", message, {
|
|
131
|
+
category: "invalid_input",
|
|
132
|
+
suggestion
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
export function invalidPathError(message, suggestion) {
|
|
136
|
+
return new MartinToolError("invalid_path", message, {
|
|
137
|
+
category: "invalid_input",
|
|
138
|
+
suggestion
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
export function invalidSelectorError(message, suggestion) {
|
|
142
|
+
return new MartinToolError("invalid_selector", message, {
|
|
143
|
+
category: "invalid_input",
|
|
144
|
+
suggestion
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
export function noLoopRecordsError(message = "No loop records found.") {
|
|
148
|
+
return new MartinToolError("no_loop_records", message, {
|
|
149
|
+
category: "not_found",
|
|
150
|
+
suggestion: "Run martin_run first or point file, loopId, or runsDir at a populated Martin runs location."
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
export function attemptNotFoundError(attemptIndex) {
|
|
154
|
+
return new MartinToolError("attempt_not_found", `Attempt ${attemptIndex} not found.`, {
|
|
155
|
+
category: "not_found",
|
|
156
|
+
suggestion: "Choose an attemptIndex that exists in the selected Martin run."
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
export function storeUnreadableError(message = "Unable to read Martin runs store.") {
|
|
160
|
+
return new MartinToolError("store_unreadable", message, {
|
|
161
|
+
category: "store_unreadable",
|
|
162
|
+
suggestion: "Check runsDir permissions and confirm the selected Martin run store is readable."
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
export function unsupportedOperationError(message, suggestion) {
|
|
166
|
+
return new MartinToolError("unsupported_operation", message, {
|
|
167
|
+
category: "invalid_input",
|
|
168
|
+
suggestion
|
|
169
|
+
});
|
|
170
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ToolFailure } from "./tool-errors.js";
|
|
2
|
+
interface TextContentBlock {
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function createToolSuccessResult<T extends object>(output: T, summary: string): {
|
|
7
|
+
content: TextContentBlock[];
|
|
8
|
+
structuredContent: T;
|
|
9
|
+
_meta: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
export declare function createToolErrorResult(failure: ToolFailure): {
|
|
12
|
+
content: TextContentBlock[];
|
|
13
|
+
isError: true;
|
|
14
|
+
_meta: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
function createJsonBlock(output) {
|
|
2
|
+
return {
|
|
3
|
+
type: "text",
|
|
4
|
+
text: JSON.stringify(output, null, 2)
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export function createToolSuccessResult(output, summary) {
|
|
8
|
+
return {
|
|
9
|
+
content: [createJsonBlock(output), { type: "text", text: summary }],
|
|
10
|
+
structuredContent: output,
|
|
11
|
+
_meta: {
|
|
12
|
+
"martinloop/summary": summary,
|
|
13
|
+
"martinloop/contentVersion": "2026-05-15"
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function createToolErrorResult(failure) {
|
|
18
|
+
const content = [
|
|
19
|
+
{ type: "text", text: `Tool error: ${failure.message}` }
|
|
20
|
+
];
|
|
21
|
+
if (failure.suggestion) {
|
|
22
|
+
content.push({ type: "text", text: `Suggestion: ${failure.suggestion}` });
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
content,
|
|
26
|
+
isError: true,
|
|
27
|
+
_meta: {
|
|
28
|
+
"martinloop/error": failure,
|
|
29
|
+
"martinloop/errorCode": failure.code,
|
|
30
|
+
"martinloop/errorCategory": failure.category,
|
|
31
|
+
"martinloop/retryable": failure.retryable
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
+
import type { LoopArtifact, LoopBudget, LoopCost, LoopEvent, LoopTask } from "../vendor/contracts/index.js";
|
|
2
|
+
import { type LedgerEvent, type LoopAttemptRecord, type LoopRunRecord } from "../vendor/core/index.js";
|
|
1
3
|
export type MartinEngine = "claude" | "codex";
|
|
4
|
+
export interface InspectableLoopAttempt extends LoopAttemptRecord {
|
|
5
|
+
attemptId?: string;
|
|
6
|
+
summary?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface InspectableLoopRecord extends Omit<LoopRunRecord, "attempts" | "task"> {
|
|
9
|
+
attempts: InspectableLoopAttempt[];
|
|
10
|
+
task?: LoopTask;
|
|
11
|
+
artifacts?: LoopArtifact[];
|
|
12
|
+
events?: LoopEvent[];
|
|
13
|
+
metadata?: Record<string, string>;
|
|
14
|
+
}
|
|
2
15
|
export interface LoopPreview {
|
|
3
16
|
loopId: string;
|
|
4
17
|
title: string;
|
|
@@ -15,23 +28,100 @@ export interface LoopPreview {
|
|
|
15
28
|
remainingBudgetUsd: number;
|
|
16
29
|
remainingIterations: number;
|
|
17
30
|
remainingTokens: number;
|
|
31
|
+
lastAttempt?: AttemptSummary;
|
|
32
|
+
}
|
|
33
|
+
export interface AttemptArtifactFiles {
|
|
34
|
+
directory: string;
|
|
35
|
+
available: boolean;
|
|
36
|
+
files: string[];
|
|
37
|
+
}
|
|
38
|
+
export interface AttemptSummary {
|
|
39
|
+
index: number;
|
|
40
|
+
attemptId?: string;
|
|
41
|
+
adapterId?: string;
|
|
42
|
+
model?: string;
|
|
43
|
+
failureClass?: string;
|
|
44
|
+
intervention?: string;
|
|
45
|
+
startedAt?: string;
|
|
46
|
+
completedAt?: string;
|
|
47
|
+
summary?: string;
|
|
48
|
+
artifacts?: AttemptArtifactFiles;
|
|
49
|
+
}
|
|
50
|
+
export interface ArtifactSummary {
|
|
51
|
+
totalCount: number;
|
|
52
|
+
kinds: Record<string, number>;
|
|
53
|
+
highlights: Array<{
|
|
54
|
+
artifactId: string;
|
|
55
|
+
kind: string;
|
|
56
|
+
label: string;
|
|
57
|
+
uri: string;
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
export interface VerificationSummary {
|
|
61
|
+
status: "passed" | "failed" | "unavailable";
|
|
62
|
+
eventCount: number;
|
|
63
|
+
ledgerEventCount: number;
|
|
64
|
+
latestAttemptIndex?: number;
|
|
65
|
+
completedAt?: string;
|
|
66
|
+
summary?: string;
|
|
67
|
+
warnings: string[];
|
|
68
|
+
}
|
|
69
|
+
export interface RunWarningEnvelope {
|
|
70
|
+
warnings: string[];
|
|
71
|
+
}
|
|
72
|
+
export interface EventSummary {
|
|
73
|
+
type: string;
|
|
74
|
+
timestamp?: string;
|
|
75
|
+
lifecycleState?: string;
|
|
76
|
+
payload: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
export interface LoopCollectionSummary {
|
|
79
|
+
latestRun?: LoopPreview;
|
|
80
|
+
recentRuns: LoopPreview[];
|
|
81
|
+
statusBreakdown: Record<string, number>;
|
|
82
|
+
lifecycleBreakdown: Record<string, number>;
|
|
18
83
|
}
|
|
19
84
|
export interface CliAvailability {
|
|
85
|
+
command: string;
|
|
20
86
|
available: boolean;
|
|
87
|
+
locator: string;
|
|
21
88
|
detail: string;
|
|
22
89
|
resolvedPath?: string;
|
|
23
90
|
}
|
|
24
91
|
export interface ExecutionMode {
|
|
25
92
|
liveMode: boolean;
|
|
26
93
|
mode: "live" | "stub";
|
|
94
|
+
detail: string;
|
|
27
95
|
}
|
|
28
|
-
export interface RunStoreInspection {
|
|
96
|
+
export interface RunStoreInspection extends LoopCollectionSummary {
|
|
97
|
+
runsRoot: string;
|
|
29
98
|
exists: boolean;
|
|
30
99
|
loopCount: number;
|
|
31
|
-
latestRun?: LoopPreview;
|
|
32
100
|
warnings: string[];
|
|
33
101
|
}
|
|
102
|
+
export interface CanonicalRunPaths {
|
|
103
|
+
runsRoot: string;
|
|
104
|
+
runDirectory: string;
|
|
105
|
+
loopRecordPath: string;
|
|
106
|
+
ledgerPath: string;
|
|
107
|
+
}
|
|
34
108
|
export declare function resolveExecutionMode(): ExecutionMode;
|
|
109
|
+
export declare function detectCliAvailability(command: string): CliAvailability;
|
|
35
110
|
export declare function getEngineAvailability(engine: MartinEngine): CliAvailability;
|
|
36
111
|
export declare function formatUsd(value: number): string;
|
|
112
|
+
export declare function buildLoopPreview(loop: InspectableLoopRecord): LoopPreview;
|
|
113
|
+
export declare function buildAttemptSummary(attempt: InspectableLoopAttempt, artifacts?: AttemptArtifactFiles): AttemptSummary;
|
|
114
|
+
export declare function buildArtifactSummary(loop: InspectableLoopRecord): ArtifactSummary;
|
|
115
|
+
export declare function buildVerificationSummary(loop: InspectableLoopRecord, ledgerEvents?: LedgerEvent[]): VerificationSummary;
|
|
116
|
+
export declare function buildEventSummaries(loop: InspectableLoopRecord, limit?: number): EventSummary[];
|
|
117
|
+
export declare function buildLoopCollectionSummary(loops: Array<LoopRunRecord | InspectableLoopRecord>): LoopCollectionSummary;
|
|
37
118
|
export declare function inspectRunsRoot(runsRoot?: string): Promise<RunStoreInspection>;
|
|
119
|
+
export declare function buildRunRecordPaths(runsRoot: string, loopId: string): CanonicalRunPaths;
|
|
120
|
+
export declare function buildAttemptArtifactDirectory(runsRoot: string, loopId: string, attemptIndex: number): string;
|
|
121
|
+
export declare function buildAttemptArtifactsReference(runsRoot: string, loopId: string, attemptIndex: number): Promise<AttemptArtifactFiles>;
|
|
122
|
+
export declare function buildCostSnapshot(cost: Pick<LoopCost, "actualUsd" | "tokensIn" | "tokensOut"> & {
|
|
123
|
+
avoidedUsd?: number;
|
|
124
|
+
}): LoopCost;
|
|
125
|
+
export declare function buildBudgetSnapshot(budget: LoopBudget): LoopBudget;
|
|
126
|
+
export declare function buildSuggestedResourceUris(loopId: string): string[];
|
|
127
|
+
export declare function buildSuggestedPromptNames(): string[];
|