@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.
Files changed (76) hide show
  1. package/README.md +131 -158
  2. package/dist/discovery-metadata.d.ts +16 -0
  3. package/dist/discovery-metadata.js +62 -0
  4. package/dist/discovery-support.d.ts +62 -0
  5. package/dist/discovery-support.js +224 -0
  6. package/dist/package-version.d.ts +1 -0
  7. package/dist/package-version.js +3 -0
  8. package/dist/prompts.d.ts +13 -3
  9. package/dist/prompts.js +445 -74
  10. package/dist/resources.d.ts +27 -5
  11. package/dist/resources.js +557 -71
  12. package/dist/server-validation.d.ts +2 -3
  13. package/dist/server-validation.js +262 -122
  14. package/dist/server.d.ts +76 -7
  15. package/dist/server.js +1126 -400
  16. package/dist/tools/doctor.js +14 -6
  17. package/dist/tools/get-attempt.d.ts +13 -6
  18. package/dist/tools/get-attempt.js +14 -5
  19. package/dist/tools/get-run.d.ts +19 -12
  20. package/dist/tools/get-run.js +20 -11
  21. package/dist/tools/get-status.d.ts +11 -0
  22. package/dist/tools/get-status.js +12 -2
  23. package/dist/tools/get-verification-results.d.ts +10 -7
  24. package/dist/tools/get-verification-results.js +11 -6
  25. package/dist/tools/inspect-loop.d.ts +9 -0
  26. package/dist/tools/inspect-loop.js +11 -2
  27. package/dist/tools/list-runs.d.ts +25 -5
  28. package/dist/tools/list-runs.js +21 -4
  29. package/dist/tools/preflight.js +7 -2
  30. package/dist/tools/run-dossier.d.ts +37 -4
  31. package/dist/tools/run-dossier.js +40 -5
  32. package/dist/tools/run-loop.d.ts +19 -0
  33. package/dist/tools/run-loop.js +41 -3
  34. package/dist/tools/run-store.d.ts +57 -3
  35. package/dist/tools/run-store.js +404 -53
  36. package/dist/tools/tool-errors.d.ts +37 -0
  37. package/dist/tools/tool-errors.js +170 -0
  38. package/dist/tools/tool-response.d.ts +16 -0
  39. package/dist/tools/tool-response.js +34 -0
  40. package/dist/tools/tool-support.d.ts +92 -2
  41. package/dist/tools/tool-support.js +358 -63
  42. package/dist/tools/triage-runs.d.ts +33 -0
  43. package/dist/tools/triage-runs.js +138 -0
  44. package/dist/vendor/adapters/claude-cli.js +0 -1
  45. package/dist/vendor/adapters/cli-bridge.js +0 -1
  46. package/dist/vendor/adapters/direct-provider.js +0 -1
  47. package/dist/vendor/adapters/index.js +0 -1
  48. package/dist/vendor/adapters/runtime-support.js +0 -1
  49. package/dist/vendor/adapters/stub-agent-cli.js +0 -1
  50. package/dist/vendor/adapters/stub-direct-provider.js +0 -1
  51. package/dist/vendor/adapters/verifier-only.js +0 -1
  52. package/dist/vendor/contracts/governance.js +0 -1
  53. package/dist/vendor/contracts/index.d.ts +2 -0
  54. package/dist/vendor/contracts/index.js +1 -1
  55. package/dist/vendor/contracts/operator.d.ts +19 -0
  56. package/dist/vendor/contracts/operator.js +11 -0
  57. package/dist/vendor/core/compiler.js +0 -1
  58. package/dist/vendor/core/context-integrity.js +0 -1
  59. package/dist/vendor/core/grounding.js +0 -1
  60. package/dist/vendor/core/index.js +1 -2
  61. package/dist/vendor/core/leash.js +19 -12
  62. package/dist/vendor/core/persistence/compiler.js +0 -1
  63. package/dist/vendor/core/persistence/index.js +0 -1
  64. package/dist/vendor/core/persistence/ledger.js +0 -1
  65. package/dist/vendor/core/persistence/runs-reader.js +0 -1
  66. package/dist/vendor/core/persistence/store.js +0 -1
  67. package/dist/vendor/core/policy.js +0 -1
  68. package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
  69. package/dist/vendor/core/red-blue/red-phase.js +135 -0
  70. package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
  71. package/dist/vendor/core/red-blue/risk-tiers.js +32 -0
  72. package/dist/vendor/core/rollback.js +2 -3
  73. package/package.json +10 -5
  74. package/server.json +2 -2
  75. package/dist/tools/cockpit-support.d.ts +0 -69
  76. 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[];