@martinloop/mcp 0.5.6 → 0.5.7
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 +137 -175
- package/dist/arcade/resource.js +20 -20
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/resources.js +148 -160
- package/dist/server.js +192 -43
- package/dist/tools/execution-policy.js +1 -1
- package/dist/tools/get-status.d.ts +2 -4
- package/dist/tools/get-status.js +6 -3
- package/dist/tools/preflight.d.ts +1 -1
- package/dist/tools/run-loop.d.ts +1 -1
- package/dist/tools/run-loop.js +3 -1
- package/dist/tools/run-store.js +1 -1
- package/dist/tools/tool-support.d.ts +3 -2
- package/dist/tools/tool-support.js +9 -2
- package/dist/tools/workflow-governance.d.ts +1 -1
- package/dist/tools/workflow-governance.js +1 -1
- package/dist/vendor/adapters/openai-compatible.js +6 -6
- package/dist/vendor/adapters/verifier-only.js +1 -1
- package/dist/vendor/contracts/execution-policy.js +1 -1
- package/dist/vendor/contracts/exits.d.ts +1 -1
- package/dist/vendor/contracts/governance.d.ts +1 -1
- package/dist/vendor/contracts/index.d.ts +1 -1
- package/dist/vendor/contracts/index.js +1 -2
- package/dist/vendor/contracts/operator.d.ts +1 -1
- package/dist/vendor/contracts/operator.js +1 -2
- package/dist/vendor/core/compiler.d.ts +2 -2
- package/dist/vendor/core/compiler.js +3 -1
- package/dist/vendor/core/exits.js +9 -4
- package/dist/vendor/core/grounding.d.ts +1 -0
- package/dist/vendor/core/grounding.js +28 -1
- package/dist/vendor/core/index.d.ts +2 -2
- package/dist/vendor/core/index.js +3 -1
- package/dist/vendor/core/policy-compiler.js +17 -1
- package/dist/vendor/core/policy.d.ts +1 -1
- package/dist/vendor/core/policy.js +7 -5
- package/dist/vendor/presentation/motion.js +0 -4
- package/dist/workflow-state.js +1 -1
- package/package.json +90 -81
- package/server.json +21 -21
package/dist/server.js
CHANGED
|
@@ -95,8 +95,7 @@ const loopPreviewSchema = {
|
|
|
95
95
|
"pressure",
|
|
96
96
|
"shouldStop",
|
|
97
97
|
"remainingBudgetUsd",
|
|
98
|
-
"remainingIterations"
|
|
99
|
-
"remainingTokens"
|
|
98
|
+
"remainingIterations"
|
|
100
99
|
]
|
|
101
100
|
};
|
|
102
101
|
const budgetSchema = {
|
|
@@ -108,7 +107,7 @@ const budgetSchema = {
|
|
|
108
107
|
maxIterations: { type: "integer" },
|
|
109
108
|
maxTokens: { type: "integer" }
|
|
110
109
|
},
|
|
111
|
-
required: ["maxUsd", "softLimitUsd", "maxIterations"
|
|
110
|
+
required: ["maxUsd", "softLimitUsd", "maxIterations"]
|
|
112
111
|
};
|
|
113
112
|
const costSchema = {
|
|
114
113
|
type: "object",
|
|
@@ -293,7 +292,6 @@ const runOutputSchema = {
|
|
|
293
292
|
"shouldStop",
|
|
294
293
|
"remainingBudgetUsd",
|
|
295
294
|
"remainingIterations",
|
|
296
|
-
"remainingTokens",
|
|
297
295
|
"engine",
|
|
298
296
|
"workingDirectory",
|
|
299
297
|
"budget",
|
|
@@ -382,7 +380,6 @@ const statusOutputSchema = {
|
|
|
382
380
|
"shouldStop",
|
|
383
381
|
"remainingBudgetUsd",
|
|
384
382
|
"remainingIterations",
|
|
385
|
-
"remainingTokens",
|
|
386
383
|
"budget",
|
|
387
384
|
"inspection"
|
|
388
385
|
]
|
|
@@ -704,23 +701,142 @@ const planOutputSchema = {
|
|
|
704
701
|
};
|
|
705
702
|
const logsOutputSchema = {
|
|
706
703
|
type: "object",
|
|
707
|
-
additionalProperties:
|
|
704
|
+
additionalProperties: false,
|
|
705
|
+
properties: {
|
|
706
|
+
source: { type: "string", description: "Resolved path to the loop-record source file." },
|
|
707
|
+
sourceKind: {
|
|
708
|
+
type: "string",
|
|
709
|
+
enum: ["file", "loop_id", "latest", "runs_root"],
|
|
710
|
+
description: "How the run was identified: by file path, loop ID, latest flag, or runs directory."
|
|
711
|
+
},
|
|
712
|
+
loopId: { type: "string", description: "Unique MartinLoop run identifier." },
|
|
713
|
+
logCount: { type: "integer", description: "Number of log entries returned after applying the limit." },
|
|
714
|
+
live: {
|
|
715
|
+
type: "object",
|
|
716
|
+
additionalProperties: false,
|
|
717
|
+
properties: {
|
|
718
|
+
lifecycleState: { type: "string", description: "Current run lifecycle state (e.g. running, completed, cancelled)." },
|
|
719
|
+
pauseState: {
|
|
720
|
+
type: "string",
|
|
721
|
+
enum: ["active", "paused", "cancellation_requested"],
|
|
722
|
+
description: "Whether the run is active, paused, or has a pending cancellation."
|
|
723
|
+
},
|
|
724
|
+
approvalState: {
|
|
725
|
+
type: "string",
|
|
726
|
+
enum: ["not_required", "resume_requested"],
|
|
727
|
+
description: "Whether the run is waiting at a human-approval checkpoint."
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
required: ["lifecycleState", "pauseState", "approvalState"]
|
|
731
|
+
},
|
|
732
|
+
entries: {
|
|
733
|
+
type: "array",
|
|
734
|
+
description: "Log entries sorted by timestamp descending, capped at limit.",
|
|
735
|
+
items: {
|
|
736
|
+
type: "object",
|
|
737
|
+
additionalProperties: false,
|
|
738
|
+
properties: {
|
|
739
|
+
timestamp: { type: "string", description: "ISO 8601 timestamp of the event, if present." },
|
|
740
|
+
source: {
|
|
741
|
+
type: "string",
|
|
742
|
+
enum: ["event", "ledger", "control"],
|
|
743
|
+
description: "Origin stream: loop event bus, governance ledger, or operator control receipts."
|
|
744
|
+
},
|
|
745
|
+
kind: { type: "string", description: "Event type or control action name." },
|
|
746
|
+
payload: { type: "object", additionalProperties: true, description: "Event-specific payload data." }
|
|
747
|
+
},
|
|
748
|
+
required: ["source", "kind", "payload"]
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
},
|
|
752
|
+
required: ["source", "sourceKind", "loopId", "logCount", "live", "entries"]
|
|
708
753
|
};
|
|
709
754
|
const controlOutputSchema = {
|
|
710
755
|
type: "object",
|
|
711
|
-
additionalProperties:
|
|
756
|
+
additionalProperties: false,
|
|
757
|
+
properties: {
|
|
758
|
+
loopId: { type: "string", description: "MartinLoop run identifier the control was applied to." },
|
|
759
|
+
action: {
|
|
760
|
+
type: "string",
|
|
761
|
+
enum: ["pause", "cancel", "continue"],
|
|
762
|
+
description: "The control action that was recorded."
|
|
763
|
+
},
|
|
764
|
+
controlId: { type: "string", description: "Unique receipt ID for this control action." },
|
|
765
|
+
requestedAt: { type: "string", description: "ISO 8601 timestamp when the control was recorded." },
|
|
766
|
+
requestedBy: { type: "string", description: "Identity that requested the control, if provided." },
|
|
767
|
+
reason: { type: "string", description: "Human-readable reason for the control, if provided." }
|
|
768
|
+
},
|
|
769
|
+
required: ["loopId", "action", "controlId", "requestedAt"]
|
|
712
770
|
};
|
|
713
771
|
const evalOutputSchema = {
|
|
714
772
|
type: "object",
|
|
715
|
-
additionalProperties:
|
|
773
|
+
additionalProperties: false,
|
|
774
|
+
properties: {
|
|
775
|
+
source: { type: "string", description: "Resolved path to the loop-record source file." },
|
|
776
|
+
sourceKind: {
|
|
777
|
+
type: "string",
|
|
778
|
+
enum: ["file", "loop_id", "latest", "runs_root"],
|
|
779
|
+
description: "How the run was identified."
|
|
780
|
+
},
|
|
781
|
+
loopId: { type: "string", description: "Unique MartinLoop run identifier." },
|
|
782
|
+
score: { type: "number", description: "Numeric evaluation score from 0–100." },
|
|
783
|
+
grade: {
|
|
784
|
+
type: "string",
|
|
785
|
+
enum: ["mergeable", "mergeable_with_review", "needs_review", "blocked", "insufficient_evidence"],
|
|
786
|
+
description: "Overall merge readiness grade derived from the six check dimensions."
|
|
787
|
+
},
|
|
788
|
+
checks: {
|
|
789
|
+
type: "object",
|
|
790
|
+
additionalProperties: false,
|
|
791
|
+
properties: {
|
|
792
|
+
taskCompletion: { type: "string", enum: ["passed", "warning", "failed"], description: "Whether the run reached a completed status." },
|
|
793
|
+
verifier: { type: "string", enum: ["passed", "warning", "failed"], description: "Whether automated verifiers passed." },
|
|
794
|
+
diffDiscipline: { type: "string", enum: ["passed", "warning", "failed"], description: "Whether file-scope discipline was maintained." },
|
|
795
|
+
regressionRisk: { type: "string", enum: ["passed", "warning", "failed"], description: "Whether regression risk signals were detected." },
|
|
796
|
+
securityRisk: { type: "string", enum: ["passed", "warning", "failed"], description: "Whether security risk signals were detected." },
|
|
797
|
+
reviewability: { type: "string", enum: ["passed", "warning", "failed"], description: "Whether the PR body and dossier are reviewer-ready." }
|
|
798
|
+
},
|
|
799
|
+
required: ["taskCompletion", "verifier", "diffDiscipline", "regressionRisk", "securityRisk", "reviewability"]
|
|
800
|
+
},
|
|
801
|
+
warnings: { type: "array", items: { type: "string" }, description: "Non-blocking advisory warnings from the evaluation." },
|
|
802
|
+
summary: { type: "string", description: "One-paragraph plain-English evaluation summary." }
|
|
803
|
+
},
|
|
804
|
+
required: ["source", "sourceKind", "loopId", "score", "grade", "checks", "warnings", "summary"]
|
|
716
805
|
};
|
|
717
806
|
const prSummaryOutputSchema = {
|
|
718
807
|
type: "object",
|
|
719
|
-
additionalProperties:
|
|
808
|
+
additionalProperties: false,
|
|
809
|
+
properties: {
|
|
810
|
+
loopId: { type: "string", description: "MartinLoop run identifier used to generate the summary." },
|
|
811
|
+
title: { type: "string", description: "Suggested GitHub pull-request title." },
|
|
812
|
+
body: { type: "string", description: "GitHub-flavoured Markdown PR body containing the run dossier." },
|
|
813
|
+
grade: {
|
|
814
|
+
type: "string",
|
|
815
|
+
enum: ["mergeable", "mergeable_with_review", "needs_review", "blocked", "insufficient_evidence"],
|
|
816
|
+
description: "Verification grade assigned to the run."
|
|
817
|
+
},
|
|
818
|
+
score: { type: "number", description: "Numeric verification score from 0–100." }
|
|
819
|
+
},
|
|
820
|
+
required: ["loopId", "title", "body", "grade", "score"]
|
|
720
821
|
};
|
|
721
822
|
const prReviewOutputSchema = {
|
|
722
823
|
type: "object",
|
|
723
|
-
additionalProperties:
|
|
824
|
+
additionalProperties: false,
|
|
825
|
+
properties: {
|
|
826
|
+
loopId: { type: "string", description: "MartinLoop run identifier the review was performed against." },
|
|
827
|
+
verdict: {
|
|
828
|
+
type: "string",
|
|
829
|
+
enum: ["approve_with_review", "needs_changes", "blocked"],
|
|
830
|
+
description: "Merge verdict: approve_with_review means safe to merge with human review; needs_changes requires fixes; blocked means do not merge."
|
|
831
|
+
},
|
|
832
|
+
findings: {
|
|
833
|
+
type: "array",
|
|
834
|
+
items: { type: "string" },
|
|
835
|
+
description: "Specific findings that informed the verdict."
|
|
836
|
+
},
|
|
837
|
+
summary: { type: "string", description: "Plain-English review summary." }
|
|
838
|
+
},
|
|
839
|
+
required: ["loopId", "verdict", "findings", "summary"]
|
|
724
840
|
};
|
|
725
841
|
export function createMartinMcpServer(serverInfo) {
|
|
726
842
|
const server = new Server({
|
|
@@ -1034,20 +1150,26 @@ export function createMartinMcpServer(serverInfo) {
|
|
|
1034
1150
|
},
|
|
1035
1151
|
{
|
|
1036
1152
|
name: "martin_logs",
|
|
1037
|
-
description: "Read recent
|
|
1153
|
+
description: "Read recent MartinLoop events, ledger entries, and operator control receipts for a single run. " +
|
|
1154
|
+
"Use to observe live or completed run activity, diagnose stuck or failed runs, or audit operator actions. " +
|
|
1155
|
+
"Do not use to check run completion status — use martin_get_status instead. " +
|
|
1156
|
+
"Do not use to retrieve verification evidence — use martin_get_verification_results instead. " +
|
|
1157
|
+
"This tool only reads persisted run files and does not execute commands, modify state, or contact GitHub.",
|
|
1038
1158
|
annotations: {
|
|
1039
1159
|
readOnlyHint: true,
|
|
1040
|
-
|
|
1160
|
+
destructiveHint: false,
|
|
1161
|
+
idempotentHint: true,
|
|
1162
|
+
openWorldHint: false
|
|
1041
1163
|
},
|
|
1042
1164
|
inputSchema: {
|
|
1043
1165
|
type: "object",
|
|
1044
1166
|
additionalProperties: false,
|
|
1045
1167
|
properties: {
|
|
1046
|
-
file: { type: "string" },
|
|
1047
|
-
loopId: { type: "string" },
|
|
1048
|
-
runsDir: { type: "string" },
|
|
1049
|
-
latest: { const: true },
|
|
1050
|
-
limit: { type: "integer", minimum: 1 }
|
|
1168
|
+
file: { type: "string", description: "Absolute or relative path to a loop-record.json file or run directory. Mutually exclusive with loopId and latest." },
|
|
1169
|
+
loopId: { type: "string", description: "MartinLoop run identifier from the run store. Mutually exclusive with file and latest." },
|
|
1170
|
+
runsDir: { type: "string", description: "Override the default run-store root directory. Optional; defaults to the MartinLoop runs directory." },
|
|
1171
|
+
latest: { const: true, description: "When true, loads the most recently updated run in the run store. Mutually exclusive with file and loopId." },
|
|
1172
|
+
limit: { type: "integer", minimum: 1, description: "Maximum number of log entries to return, sorted by timestamp descending. Defaults to 20." }
|
|
1051
1173
|
},
|
|
1052
1174
|
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
1053
1175
|
},
|
|
@@ -1243,10 +1365,16 @@ export function createMartinMcpServer(serverInfo) {
|
|
|
1243
1365
|
},
|
|
1244
1366
|
{
|
|
1245
1367
|
name: "martin_get_verification_results",
|
|
1246
|
-
description: "Load verification evidence for a
|
|
1368
|
+
description: "Load structured verification evidence for a MartinLoop run — verifier commands, pass/fail outcomes, and contradiction signals — from stored loop events and ledger entries. " +
|
|
1369
|
+
"Use after a run completes to confirm whether automated verifiers passed before merging or promoting the result. " +
|
|
1370
|
+
"Do not use to get a merge-readiness grade — use martin_eval for a scored grade with six check dimensions. " +
|
|
1371
|
+
"Do not use for live run status — use martin_get_status instead. " +
|
|
1372
|
+
"This tool only reads persisted run files and does not execute commands, modify state, or contact GitHub.",
|
|
1247
1373
|
annotations: {
|
|
1248
1374
|
readOnlyHint: true,
|
|
1249
|
-
|
|
1375
|
+
destructiveHint: false,
|
|
1376
|
+
idempotentHint: true,
|
|
1377
|
+
openWorldHint: false
|
|
1250
1378
|
},
|
|
1251
1379
|
inputSchema: {
|
|
1252
1380
|
type: "object",
|
|
@@ -1254,10 +1382,10 @@ export function createMartinMcpServer(serverInfo) {
|
|
|
1254
1382
|
properties: {
|
|
1255
1383
|
file: {
|
|
1256
1384
|
type: "string",
|
|
1257
|
-
description: "
|
|
1385
|
+
description: "Absolute or relative path to a loop-record.json file or run directory. Mutually exclusive with loopId."
|
|
1258
1386
|
},
|
|
1259
|
-
loopId: { type: "string", description: "
|
|
1260
|
-
runsDir: { type: "string", description: "
|
|
1387
|
+
loopId: { type: "string", description: "MartinLoop run identifier from the run store. Mutually exclusive with file." },
|
|
1388
|
+
runsDir: { type: "string", description: "Override the default run-store root directory. Optional." }
|
|
1261
1389
|
},
|
|
1262
1390
|
oneOf: [{ required: ["file"] }, { required: ["loopId"] }]
|
|
1263
1391
|
},
|
|
@@ -1316,19 +1444,26 @@ export function createMartinMcpServer(serverInfo) {
|
|
|
1316
1444
|
},
|
|
1317
1445
|
{
|
|
1318
1446
|
name: "martin_eval",
|
|
1319
|
-
description: "Grade a
|
|
1447
|
+
description: "Grade a MartinLoop run across six dimensions — task completion, verifier health, diff discipline, regression risk, security risk, and reviewability — and return a scored merge-readiness verdict. " +
|
|
1448
|
+
"Use after a governed run completes to decide whether the result is safe to merge or promote. " +
|
|
1449
|
+
"Use before martin_pr_summary or martin_create_pr to confirm the run is merge-ready. " +
|
|
1450
|
+
"Do not use to retrieve raw verification command output — use martin_get_verification_results for that. " +
|
|
1451
|
+
"Do not use to review an existing PR body — use martin_review_pr instead. " +
|
|
1452
|
+
"This tool reads saved run evidence and inspects local git signals; it does not modify state or contact GitHub.",
|
|
1320
1453
|
annotations: {
|
|
1321
1454
|
readOnlyHint: true,
|
|
1322
|
-
|
|
1455
|
+
destructiveHint: false,
|
|
1456
|
+
idempotentHint: true,
|
|
1457
|
+
openWorldHint: false
|
|
1323
1458
|
},
|
|
1324
1459
|
inputSchema: {
|
|
1325
1460
|
type: "object",
|
|
1326
1461
|
additionalProperties: false,
|
|
1327
1462
|
properties: {
|
|
1328
|
-
file: { type: "string" },
|
|
1329
|
-
loopId: { type: "string" },
|
|
1330
|
-
runsDir: { type: "string" },
|
|
1331
|
-
latest: { const: true }
|
|
1463
|
+
file: { type: "string", description: "Absolute or relative path to a loop-record.json file or run directory. Mutually exclusive with loopId and latest." },
|
|
1464
|
+
loopId: { type: "string", description: "MartinLoop run identifier from the run store. Mutually exclusive with file and latest." },
|
|
1465
|
+
runsDir: { type: "string", description: "Override the default run-store root directory. Optional." },
|
|
1466
|
+
latest: { const: true, description: "When true, evaluates the most recently updated run in the run store. Mutually exclusive with file and loopId." }
|
|
1332
1467
|
},
|
|
1333
1468
|
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
1334
1469
|
},
|
|
@@ -1336,20 +1471,27 @@ export function createMartinMcpServer(serverInfo) {
|
|
|
1336
1471
|
},
|
|
1337
1472
|
{
|
|
1338
1473
|
name: "martin_pr_summary",
|
|
1339
|
-
description: "Generate a
|
|
1474
|
+
description: "Generate a GitHub-ready pull-request title and Markdown body from a completed MartinLoop run dossier, including its verification grade and score. " +
|
|
1475
|
+
"Use after a governed run completes when you need PR copy without creating the PR. " +
|
|
1476
|
+
"Use martin_create_pr instead to actually open the PR on GitHub. " +
|
|
1477
|
+
"Use martin_review_pr to evaluate an existing PR body against run evidence. " +
|
|
1478
|
+
"Use martin_eval first if you need a merge-readiness grade before generating the PR body. " +
|
|
1479
|
+
"This tool only reads saved run evidence and does not modify the repository or contact GitHub.",
|
|
1340
1480
|
annotations: {
|
|
1341
1481
|
readOnlyHint: true,
|
|
1342
|
-
|
|
1482
|
+
destructiveHint: false,
|
|
1483
|
+
idempotentHint: true,
|
|
1484
|
+
openWorldHint: false
|
|
1343
1485
|
},
|
|
1344
1486
|
inputSchema: {
|
|
1345
1487
|
type: "object",
|
|
1346
1488
|
additionalProperties: false,
|
|
1347
1489
|
properties: {
|
|
1348
|
-
file: { type: "string" },
|
|
1349
|
-
loopId: { type: "string" },
|
|
1350
|
-
runsDir: { type: "string" },
|
|
1351
|
-
latest: { const: true },
|
|
1352
|
-
format: { type: "string", enum: ["json", "md", "github-pr"] }
|
|
1490
|
+
file: { type: "string", description: "Absolute or relative path to a loop-record.json file or run directory. Mutually exclusive with loopId and latest." },
|
|
1491
|
+
loopId: { type: "string", description: "MartinLoop run identifier from the run store. Mutually exclusive with file and latest." },
|
|
1492
|
+
runsDir: { type: "string", description: "Override the default run-store root directory. Optional." },
|
|
1493
|
+
latest: { const: true, description: "When true, generates the summary for the most recently updated run. Mutually exclusive with file and loopId." },
|
|
1494
|
+
format: { type: "string", enum: ["json", "md", "github-pr"], description: "Dossier rendering format. Defaults to github-pr for PR body generation. Use md for plain Markdown or json for structured output." }
|
|
1353
1495
|
},
|
|
1354
1496
|
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
1355
1497
|
},
|
|
@@ -1381,21 +1523,28 @@ export function createMartinMcpServer(serverInfo) {
|
|
|
1381
1523
|
},
|
|
1382
1524
|
{
|
|
1383
1525
|
name: "martin_review_pr",
|
|
1384
|
-
description: "Review a PR or
|
|
1526
|
+
description: "Review a PR body or draft against the MartinLoop run dossier and evaluation evidence, and return a verdict with specific findings. " +
|
|
1527
|
+
"Use when you have an existing PR body and want to check whether it accurately represents the governed run evidence. " +
|
|
1528
|
+
"Supply prBody to review a specific body string; omit it to evaluate the auto-generated dossier body. " +
|
|
1529
|
+
"Do not use to generate a PR body from scratch — use martin_pr_summary instead. " +
|
|
1530
|
+
"Do not use to open or create a PR — use martin_create_pr instead. " +
|
|
1531
|
+
"This tool only reads saved run evidence and does not modify the repository or contact GitHub.",
|
|
1385
1532
|
annotations: {
|
|
1386
1533
|
readOnlyHint: true,
|
|
1387
|
-
|
|
1534
|
+
destructiveHint: false,
|
|
1535
|
+
idempotentHint: true,
|
|
1536
|
+
openWorldHint: false
|
|
1388
1537
|
},
|
|
1389
1538
|
inputSchema: {
|
|
1390
1539
|
type: "object",
|
|
1391
1540
|
additionalProperties: false,
|
|
1392
1541
|
properties: {
|
|
1393
|
-
file: { type: "string" },
|
|
1394
|
-
loopId: { type: "string" },
|
|
1395
|
-
runsDir: { type: "string" },
|
|
1396
|
-
latest: { const: true },
|
|
1397
|
-
format: { type: "string", enum: ["json", "md", "github-pr"] },
|
|
1398
|
-
prBody: { type: "string" }
|
|
1542
|
+
file: { type: "string", description: "Absolute or relative path to a loop-record.json file or run directory. Mutually exclusive with loopId and latest." },
|
|
1543
|
+
loopId: { type: "string", description: "MartinLoop run identifier from the run store. Mutually exclusive with file and latest." },
|
|
1544
|
+
runsDir: { type: "string", description: "Override the default run-store root directory. Optional." },
|
|
1545
|
+
latest: { const: true, description: "When true, reviews against the most recently updated run. Mutually exclusive with file and loopId." },
|
|
1546
|
+
format: { type: "string", enum: ["json", "md", "github-pr"], description: "Dossier format used when generating the reference body for comparison. Defaults to github-pr." },
|
|
1547
|
+
prBody: { type: "string", description: "The PR body text to review. If omitted, the auto-generated dossier body is evaluated instead." }
|
|
1399
1548
|
},
|
|
1400
1549
|
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
1401
1550
|
},
|
|
@@ -5,7 +5,7 @@ export function compileMcpExecutionPolicy(input) {
|
|
|
5
5
|
maxUsd: input.maxUsd ?? DEFAULT_BUDGET.maxUsd,
|
|
6
6
|
softLimitUsd: Math.min(DEFAULT_BUDGET.softLimitUsd, input.maxUsd ?? DEFAULT_BUDGET.maxUsd),
|
|
7
7
|
maxIterations: input.maxIterations ?? DEFAULT_BUDGET.maxIterations,
|
|
8
|
-
maxTokens: input.maxTokens
|
|
8
|
+
...(input.maxTokens !== undefined ? { maxTokens: input.maxTokens } : {})
|
|
9
9
|
};
|
|
10
10
|
const policy = compileExecutionPolicy({
|
|
11
11
|
configPath: "mcp://inline",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { CostProvenance } from "../vendor/contracts/index.js";
|
|
2
1
|
import { type LoopPreview } from "./tool-support.js";
|
|
3
2
|
export interface GetStatusInput {
|
|
4
3
|
/** JSON-serialized LoopRecord. */
|
|
@@ -19,18 +18,17 @@ export interface GetStatusOutput {
|
|
|
19
18
|
lifecycleState: string;
|
|
20
19
|
attempts: number;
|
|
21
20
|
costUsd: number;
|
|
22
|
-
costProvenance: CostProvenance;
|
|
23
21
|
avoidedUsd: number;
|
|
24
22
|
pressure: string;
|
|
25
23
|
shouldStop: boolean;
|
|
26
24
|
remainingBudgetUsd: number;
|
|
27
25
|
remainingIterations: number;
|
|
28
|
-
remainingTokens
|
|
26
|
+
remainingTokens?: number;
|
|
29
27
|
budget: {
|
|
30
28
|
maxUsd: number;
|
|
31
29
|
softLimitUsd: number;
|
|
32
30
|
maxIterations: number;
|
|
33
|
-
maxTokens
|
|
31
|
+
maxTokens?: number;
|
|
34
32
|
};
|
|
35
33
|
inspection: {
|
|
36
34
|
loop: LoopPreview;
|
package/dist/tools/get-status.js
CHANGED
|
@@ -31,18 +31,21 @@ export async function getStatusTool(input) {
|
|
|
31
31
|
lifecycleState: loop.lifecycleState,
|
|
32
32
|
attempts: loop.attempts.length,
|
|
33
33
|
costUsd: loop.cost.actualUsd,
|
|
34
|
-
costProvenance: loop.cost.provenance ?? "unavailable",
|
|
35
34
|
avoidedUsd: loop.cost.avoidedUsd ?? 0,
|
|
36
35
|
pressure: costState.pressure,
|
|
37
36
|
shouldStop: costState.shouldStop,
|
|
38
37
|
remainingBudgetUsd: costState.remainingBudgetUsd,
|
|
39
38
|
remainingIterations: costState.remainingIterations,
|
|
40
|
-
|
|
39
|
+
...(costState.remainingTokens !== undefined
|
|
40
|
+
? { remainingTokens: costState.remainingTokens }
|
|
41
|
+
: {}),
|
|
41
42
|
budget: {
|
|
42
43
|
maxUsd: loop.budget.maxUsd,
|
|
43
44
|
softLimitUsd: loop.budget.softLimitUsd,
|
|
44
45
|
maxIterations: loop.budget.maxIterations,
|
|
45
|
-
|
|
46
|
+
...(loop.budget.maxTokens !== undefined
|
|
47
|
+
? { maxTokens: loop.budget.maxTokens }
|
|
48
|
+
: {})
|
|
46
49
|
},
|
|
47
50
|
inspection: {
|
|
48
51
|
loop: buildLoopPreview(loop)
|
package/dist/tools/run-loop.d.ts
CHANGED
package/dist/tools/run-loop.js
CHANGED
|
@@ -174,7 +174,9 @@ export async function runLoopTool(input) {
|
|
|
174
174
|
shouldStop: costState.shouldStop,
|
|
175
175
|
remainingBudgetUsd: costState.remainingBudgetUsd,
|
|
176
176
|
remainingIterations: costState.remainingIterations,
|
|
177
|
-
|
|
177
|
+
...(costState.remainingTokens !== undefined
|
|
178
|
+
? { remainingTokens: costState.remainingTokens }
|
|
179
|
+
: {}),
|
|
178
180
|
engine,
|
|
179
181
|
workingDirectory,
|
|
180
182
|
budget,
|
package/dist/tools/run-store.js
CHANGED
|
@@ -641,7 +641,7 @@ function validateInspectableLoopRecord(value) {
|
|
|
641
641
|
!isFiniteNumber(budget["maxUsd"]) ||
|
|
642
642
|
!isFiniteNumber(budget["softLimitUsd"]) ||
|
|
643
643
|
!Number.isInteger(budget["maxIterations"]) ||
|
|
644
|
-
!Number.isInteger(budget["maxTokens"]) ||
|
|
644
|
+
(budget["maxTokens"] !== undefined && !Number.isInteger(budget["maxTokens"])) ||
|
|
645
645
|
!isRecord(cost) ||
|
|
646
646
|
!isFiniteNumber(cost["actualUsd"]) ||
|
|
647
647
|
!isFiniteNumber(cost["tokensIn"]) ||
|
|
@@ -6,7 +6,8 @@ export interface InspectableLoopAttempt extends LoopAttemptRecord {
|
|
|
6
6
|
attemptId?: string;
|
|
7
7
|
summary?: string;
|
|
8
8
|
}
|
|
9
|
-
export interface InspectableLoopRecord extends Omit<LoopRunRecord, "attempts" | "task"> {
|
|
9
|
+
export interface InspectableLoopRecord extends Omit<LoopRunRecord, "attempts" | "task" | "budget"> {
|
|
10
|
+
budget: LoopBudget;
|
|
10
11
|
attempts: InspectableLoopAttempt[];
|
|
11
12
|
task?: LoopTask;
|
|
12
13
|
artifacts?: LoopArtifact[];
|
|
@@ -33,7 +34,7 @@ export interface LoopPreview {
|
|
|
33
34
|
shouldStop: boolean;
|
|
34
35
|
remainingBudgetUsd: number;
|
|
35
36
|
remainingIterations: number;
|
|
36
|
-
remainingTokens
|
|
37
|
+
remainingTokens?: number;
|
|
37
38
|
lastAttempt?: AttemptSummary;
|
|
38
39
|
routingEconomics?: Record<string, unknown>;
|
|
39
40
|
}
|
|
@@ -157,7 +157,9 @@ export function buildLoopPreview(loop) {
|
|
|
157
157
|
shouldStop: costState.shouldStop,
|
|
158
158
|
remainingBudgetUsd: costState.remainingBudgetUsd,
|
|
159
159
|
remainingIterations: costState.remainingIterations,
|
|
160
|
-
|
|
160
|
+
...(costState.remainingTokens !== undefined
|
|
161
|
+
? { remainingTokens: costState.remainingTokens }
|
|
162
|
+
: {}),
|
|
161
163
|
...(lastAttempt ? { lastAttempt: buildAttemptSummary(lastAttempt) } : {}),
|
|
162
164
|
...(loop.routingEconomics ? { routingEconomics: buildRoutingEconomicsSummary(loop.routingEconomics) } : {})
|
|
163
165
|
};
|
|
@@ -291,7 +293,12 @@ export function buildCostSnapshot(cost) {
|
|
|
291
293
|
};
|
|
292
294
|
}
|
|
293
295
|
export function buildBudgetSnapshot(budget) {
|
|
294
|
-
return {
|
|
296
|
+
return {
|
|
297
|
+
maxUsd: budget.maxUsd,
|
|
298
|
+
softLimitUsd: budget.softLimitUsd,
|
|
299
|
+
maxIterations: budget.maxIterations,
|
|
300
|
+
...(budget.maxTokens !== undefined ? { maxTokens: budget.maxTokens } : {})
|
|
301
|
+
};
|
|
295
302
|
}
|
|
296
303
|
export function buildSuggestedResourceUris(loopId) {
|
|
297
304
|
return ["martin://server/health", "martin://runs/recent", "martin://runs/triage", "martin://runs/latest", "martin://runs/latest/summary", "martin://runs/latest/proof-card", "martin://runs/latest/budget-status", "martin://runs/latest/verifier-evidence", "martin://runs/latest/rollback-evidence", "martin://policies/current", "martin://repo/risk-map", "martin://verifiers/results", "martin://agent/next-step", `martin://runs/${loopId}`, `martin://runs/${loopId}/dossier`, `martin://runs/${loopId}/verification`, "martin://guides/mcp-usage", "martin://guides/agent-start", "martin://guides/publish-readiness"];
|
|
@@ -271,7 +271,7 @@ export function normalizeLoopBudget(overrides = {}) {
|
|
|
271
271
|
maxUsd,
|
|
272
272
|
softLimitUsd,
|
|
273
273
|
maxIterations: overrides.maxIterations ?? DEFAULT_BUDGET.maxIterations,
|
|
274
|
-
maxTokens: overrides.maxTokens
|
|
274
|
+
...(overrides.maxTokens !== undefined ? { maxTokens: overrides.maxTokens } : {})
|
|
275
275
|
};
|
|
276
276
|
}
|
|
277
277
|
export function assessRunRisk(input) {
|
|
@@ -103,12 +103,12 @@ function normalizeOpenAiCompatibleUsage(input) {
|
|
|
103
103
|
// ---------------------------------------------------------------------------
|
|
104
104
|
// Prompt builder
|
|
105
105
|
// ---------------------------------------------------------------------------
|
|
106
|
-
const DEFAULT_SYSTEM_PROMPT = `You are an expert software engineer executing a governed coding task.
|
|
107
|
-
Follow these rules exactly:
|
|
108
|
-
- Read the task description carefully and implement only what is asked.
|
|
109
|
-
- Do not add features, refactors, or improvements beyond the stated task.
|
|
110
|
-
- If the task asks you to write or modify code, output the complete file content with changes applied.
|
|
111
|
-
- Be precise, minimal, and test-backed in all changes.
|
|
106
|
+
const DEFAULT_SYSTEM_PROMPT = `You are an expert software engineer executing a governed coding task.
|
|
107
|
+
Follow these rules exactly:
|
|
108
|
+
- Read the task description carefully and implement only what is asked.
|
|
109
|
+
- Do not add features, refactors, or improvements beyond the stated task.
|
|
110
|
+
- If the task asks you to write or modify code, output the complete file content with changes applied.
|
|
111
|
+
- Be precise, minimal, and test-backed in all changes.
|
|
112
112
|
- State what you changed and why at the end of your response.`;
|
|
113
113
|
export const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com";
|
|
114
114
|
export function resolveOpenAiCompatibleRuntimeConfig(env = process.env) {
|
|
@@ -26,7 +26,7 @@ export function createVerifierOnlyAdapter(options = {}) {
|
|
|
26
26
|
const verification = await runVerification(request.context.verificationPlan, workingDirectory, verifyTimeoutMs, request.context.verificationStack, options.spawnImpl, {
|
|
27
27
|
runId: request.loopId,
|
|
28
28
|
workspaceId: request.workspaceId,
|
|
29
|
-
cwd: workingDirectory
|
|
29
|
+
cwd: workingDirectory,
|
|
30
30
|
});
|
|
31
31
|
const changedFiles = shouldTrackVerifierWrites
|
|
32
32
|
? (await readGitChangedFiles(workingDirectory, 5_000)).filter((file) => !baselineChangedFiles.has(file))
|
|
@@ -14,7 +14,7 @@ export function cloneExecutionPolicy(policy) {
|
|
|
14
14
|
maxUsd: policy.budget.maxUsd,
|
|
15
15
|
softLimitUsd: policy.budget.softLimitUsd,
|
|
16
16
|
maxIterations: policy.budget.maxIterations,
|
|
17
|
-
maxTokens: policy.budget.maxTokens
|
|
17
|
+
...(policy.budget.maxTokens !== undefined ? { maxTokens: policy.budget.maxTokens } : {})
|
|
18
18
|
},
|
|
19
19
|
governance: {
|
|
20
20
|
policyProfile: policy.governance.policyProfile,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const MARTIN_ERROR_CATEGORIES: readonly ["invalid_input", "environment", "auth", "not_found", "store_unreadable", "verification_failed", "policy_blocked", "budget_exit", "transient"
|
|
1
|
+
export declare const MARTIN_ERROR_CATEGORIES: readonly ["invalid_input", "environment", "auth", "not_found", "store_unreadable", "verification_failed", "policy_blocked", "budget_exit", "transient"];
|
|
2
2
|
export type MartinErrorCategory = (typeof MARTIN_ERROR_CATEGORIES)[number];
|
|
3
3
|
export type MartinOutputMode = "human" | "json" | "quiet";
|
|
4
4
|
export interface MartinRunSelector {
|