martin-loop 0.1.5 → 1.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/CODE_OF_CONDUCT.md +32 -0
- package/LICENSE +21 -21
- package/README.md +307 -398
- package/demo/seeded-workspace/README.md +35 -35
- package/demo/seeded-workspace/TASKS.md +29 -29
- package/demo/seeded-workspace/martin.config.yaml +11 -11
- package/demo/seeded-workspace/package.json +8 -8
- package/demo/seeded-workspace/src/invoice-summary.js +11 -11
- package/demo/seeded-workspace/test/invoice-summary.test.js +20 -20
- package/dist/bin/martin-loop.js +0 -0
- package/dist/vendor/adapters/counter.d.ts +1 -0
- package/dist/vendor/adapters/counter.js +4 -0
- package/dist/vendor/adapters/git-baseline.d.ts +50 -0
- package/dist/vendor/adapters/git-baseline.js +233 -0
- package/dist/vendor/adapters/openrouter-adapter.d.ts +15 -0
- package/dist/vendor/adapters/openrouter-adapter.js +302 -0
- package/dist/vendor/adapters/usage.d.ts +48 -0
- package/dist/vendor/adapters/usage.js +66 -0
- package/dist/vendor/cli/bin/exit.d.ts +12 -0
- package/dist/vendor/cli/bin/exit.js +28 -0
- package/dist/vendor/cli/commands/analyze.d.ts +5 -0
- package/dist/vendor/cli/commands/analyze.js +58 -0
- package/dist/vendor/cli/commands/audit-log-verify.d.ts +34 -0
- package/dist/vendor/cli/commands/audit-log-verify.js +99 -0
- package/dist/vendor/cli/commands/audit.d.ts +8 -0
- package/dist/vendor/cli/commands/audit.js +199 -0
- package/dist/vendor/cli/commands/corpus.d.ts +5 -0
- package/dist/vendor/cli/commands/corpus.js +60 -0
- package/dist/vendor/cli/commands/doctor.d.ts +8 -0
- package/dist/vendor/cli/commands/doctor.js +219 -0
- package/dist/vendor/cli/commands/explain.d.ts +17 -0
- package/dist/vendor/cli/commands/explain.js +176 -0
- package/dist/vendor/cli/commands/export.d.ts +5 -0
- package/dist/vendor/cli/commands/export.js +60 -0
- package/dist/vendor/cli/commands/governance.d.ts +8 -0
- package/dist/vendor/cli/commands/governance.js +95 -0
- package/dist/vendor/cli/commands/improve.d.ts +18 -0
- package/dist/vendor/cli/commands/improve.js +396 -0
- package/dist/vendor/cli/commands/init.d.ts +8 -0
- package/dist/vendor/cli/commands/init.js +281 -0
- package/dist/vendor/cli/commands/migration.d.ts +8 -0
- package/dist/vendor/cli/commands/migration.js +67 -0
- package/dist/vendor/cli/commands/prior.d.ts +23 -0
- package/dist/vendor/cli/commands/prior.js +145 -0
- package/dist/vendor/cli/commands/resume.d.ts +21 -0
- package/dist/vendor/cli/commands/resume.js +73 -0
- package/dist/vendor/cli/commands/verify.d.ts +6 -0
- package/dist/vendor/cli/commands/verify.js +43 -0
- package/dist/vendor/cli/research/public-corpus.d.ts +43 -0
- package/dist/vendor/cli/research/public-corpus.js +151 -0
- package/dist/vendor/cli/ui/error-card.d.ts +38 -0
- package/dist/vendor/cli/ui/error-card.js +103 -0
- package/dist/vendor/cli/ui/mission-brief.d.ts +41 -0
- package/dist/vendor/cli/ui/mission-brief.js +173 -0
- package/dist/vendor/cli/ui/summary-card.d.ts +34 -0
- package/dist/vendor/cli/ui/summary-card.js +102 -0
- package/dist/vendor/contracts/audit.d.ts +46 -0
- package/dist/vendor/contracts/audit.js +360 -0
- package/dist/vendor/contracts/post-phase15.d.ts +240 -0
- package/dist/vendor/contracts/post-phase15.js +166 -0
- package/dist/vendor/core/agent/mandates.d.ts +46 -0
- package/dist/vendor/core/agent/mandates.js +178 -0
- package/dist/vendor/core/agent/receipts.d.ts +38 -0
- package/dist/vendor/core/agent/receipts.js +131 -0
- package/dist/vendor/core/agent/signing.d.ts +17 -0
- package/dist/vendor/core/agent/signing.js +91 -0
- package/dist/vendor/core/attestation/sign.d.ts +25 -0
- package/dist/vendor/core/attestation/sign.js +216 -0
- package/dist/vendor/core/autonomy/autonomous-promotion.d.ts +120 -0
- package/dist/vendor/core/autonomy/autonomous-promotion.js +346 -0
- package/dist/vendor/core/autonomy/envelope-v2.d.ts +29 -0
- package/dist/vendor/core/autonomy/envelope-v2.js +60 -0
- package/dist/vendor/core/autonomy/envelope.d.ts +17 -0
- package/dist/vendor/core/autonomy/envelope.js +27 -0
- package/dist/vendor/core/autonomy/escalation-ledger.d.ts +20 -0
- package/dist/vendor/core/autonomy/escalation-ledger.js +18 -0
- package/dist/vendor/core/autonomy/resume.d.ts +15 -0
- package/dist/vendor/core/autonomy/resume.js +23 -0
- package/dist/vendor/core/circuit/circuit-breaker.d.ts +60 -0
- package/dist/vendor/core/circuit/circuit-breaker.js +143 -0
- package/dist/vendor/core/context-distillation.d.ts +3 -0
- package/dist/vendor/core/context-distillation.js +44 -0
- package/dist/vendor/core/context-flow/compile-context.d.ts +8 -0
- package/dist/vendor/core/context-flow/compile-context.js +111 -0
- package/dist/vendor/core/context-flow/entities.d.ts +2 -0
- package/dist/vendor/core/context-flow/entities.js +44 -0
- package/dist/vendor/core/context-flow/evaluate-policy.d.ts +2 -0
- package/dist/vendor/core/context-flow/evaluate-policy.js +42 -0
- package/dist/vendor/core/context-flow/index.d.ts +11 -0
- package/dist/vendor/core/context-flow/index.js +24 -0
- package/dist/vendor/core/context-flow/labels.d.ts +3 -0
- package/dist/vendor/core/context-flow/labels.js +17 -0
- package/dist/vendor/core/context-flow/normalizer.d.ts +9 -0
- package/dist/vendor/core/context-flow/normalizer.js +69 -0
- package/dist/vendor/core/context-flow/profiles.d.ts +33 -0
- package/dist/vendor/core/context-flow/profiles.js +36 -0
- package/dist/vendor/core/context-flow/redaction.d.ts +1 -0
- package/dist/vendor/core/context-flow/redaction.js +6 -0
- package/dist/vendor/core/context-flow/sensitivity.d.ts +2 -0
- package/dist/vendor/core/context-flow/sensitivity.js +27 -0
- package/dist/vendor/core/context-flow/sync-preview.d.ts +2 -0
- package/dist/vendor/core/context-flow/sync-preview.js +22 -0
- package/dist/vendor/core/context-flow/token-estimator.d.ts +3 -0
- package/dist/vendor/core/context-flow/token-estimator.js +13 -0
- package/dist/vendor/core/context-flow/types.d.ts +91 -0
- package/dist/vendor/core/context-flow/types.js +2 -0
- package/dist/vendor/core/context-utility.d.ts +47 -0
- package/dist/vendor/core/context-utility.js +405 -0
- package/dist/vendor/core/cost/pipeline.d.ts +92 -0
- package/dist/vendor/core/cost/pipeline.js +141 -0
- package/dist/vendor/core/cost/tagged-cost.d.ts +27 -0
- package/dist/vendor/core/cost/tagged-cost.js +55 -0
- package/dist/vendor/core/cost-governor.d.ts +2 -0
- package/dist/vendor/core/cost-governor.js +50 -0
- package/dist/vendor/core/cve/cve-check.d.ts +80 -0
- package/dist/vendor/core/cve/cve-check.js +172 -0
- package/dist/vendor/core/digital-twin/index.d.ts +27 -0
- package/dist/vendor/core/digital-twin/index.js +90 -0
- package/dist/vendor/core/drift/drift-graph.d.ts +47 -0
- package/dist/vendor/core/drift/drift-graph.js +100 -0
- package/dist/vendor/core/drift/objective-lock.d.ts +69 -0
- package/dist/vendor/core/drift/objective-lock.js +88 -0
- package/dist/vendor/core/drift/scope.d.ts +46 -0
- package/dist/vendor/core/drift/scope.js +102 -0
- package/dist/vendor/core/drift/signature-lock.d.ts +48 -0
- package/dist/vendor/core/drift/signature-lock.js +202 -0
- package/dist/vendor/core/drift/stale-proof-gate.d.ts +21 -0
- package/dist/vendor/core/drift/stale-proof-gate.js +19 -0
- package/dist/vendor/core/eval/known-bad-world-runner.d.ts +24 -0
- package/dist/vendor/core/eval/known-bad-world-runner.js +256 -0
- package/dist/vendor/core/evidence/claim-audit.d.ts +18 -0
- package/dist/vendor/core/evidence/claim-audit.js +89 -0
- package/dist/vendor/core/exit-intelligence.d.ts +2 -0
- package/dist/vendor/core/exit-intelligence.js +58 -0
- package/dist/vendor/core/explain/formatter.d.ts +42 -0
- package/dist/vendor/core/explain/formatter.js +171 -0
- package/dist/vendor/core/explain/timeline.d.ts +29 -0
- package/dist/vendor/core/explain/timeline.js +213 -0
- package/dist/vendor/core/failure-taxonomy.d.ts +2 -0
- package/dist/vendor/core/failure-taxonomy.js +76 -0
- package/dist/vendor/core/gateway/index.d.ts +10 -0
- package/dist/vendor/core/gateway/index.js +12 -0
- package/dist/vendor/core/gateway/registry.d.ts +40 -0
- package/dist/vendor/core/gateway/registry.js +97 -0
- package/dist/vendor/core/gateway/transport.d.ts +31 -0
- package/dist/vendor/core/gateway/transport.js +82 -0
- package/dist/vendor/core/gateway/vault.d.ts +19 -0
- package/dist/vendor/core/gateway/vault.js +29 -0
- package/dist/vendor/core/graph/adapters.d.ts +43 -0
- package/dist/vendor/core/graph/adapters.js +91 -0
- package/dist/vendor/core/graph/hotspots.d.ts +22 -0
- package/dist/vendor/core/graph/hotspots.js +30 -0
- package/dist/vendor/core/graph/index.d.ts +1 -0
- package/dist/vendor/core/graph/index.js +2 -0
- package/dist/vendor/core/honey/honey-tokens.d.ts +32 -0
- package/dist/vendor/core/honey/honey-tokens.js +44 -0
- package/dist/vendor/core/index.d.ts +2 -2
- package/dist/vendor/core/index.js +38 -12
- package/dist/vendor/core/learning/bayesian-update.d.ts +31 -0
- package/dist/vendor/core/learning/bayesian-update.js +60 -0
- package/dist/vendor/core/learning/prior-sets.d.ts +42 -0
- package/dist/vendor/core/learning/prior-sets.js +111 -0
- package/dist/vendor/core/learning/promotion-gate.d.ts +17 -0
- package/dist/vendor/core/learning/promotion-gate.js +23 -0
- package/dist/vendor/core/leash/blast-radius.d.ts +42 -0
- package/dist/vendor/core/leash/blast-radius.js +156 -0
- package/dist/vendor/core/leash/policy-leash.d.ts +31 -0
- package/dist/vendor/core/leash/policy-leash.js +117 -0
- package/dist/vendor/core/memo/memo.d.ts +63 -0
- package/dist/vendor/core/memo/memo.js +97 -0
- package/dist/vendor/core/memory/learning-pipeline.d.ts +154 -0
- package/dist/vendor/core/memory/learning-pipeline.js +391 -0
- package/dist/vendor/core/memory/palace.d.ts +84 -0
- package/dist/vendor/core/memory/palace.js +379 -0
- package/dist/vendor/core/merge/ast-merge.d.ts +22 -0
- package/dist/vendor/core/merge/ast-merge.js +350 -0
- package/dist/vendor/core/merge/text-merge.d.ts +12 -0
- package/dist/vendor/core/merge/text-merge.js +182 -0
- package/dist/vendor/core/otel/tracer.d.ts +45 -0
- package/dist/vendor/core/otel/tracer.js +116 -0
- package/dist/vendor/core/parallel/parallel-attempts.d.ts +28 -0
- package/dist/vendor/core/parallel/parallel-attempts.js +41 -0
- package/dist/vendor/core/parallel/scorer.d.ts +24 -0
- package/dist/vendor/core/parallel/scorer.js +65 -0
- package/dist/vendor/core/pattern-detection.d.ts +64 -0
- package/dist/vendor/core/pattern-detection.js +108 -0
- package/dist/vendor/core/persistence/checkpoint.d.ts +44 -0
- package/dist/vendor/core/persistence/checkpoint.js +156 -0
- package/dist/vendor/core/persistence/cleanup.d.ts +22 -0
- package/dist/vendor/core/persistence/cleanup.js +131 -0
- package/dist/vendor/core/persistence/index.d.ts +2 -0
- package/dist/vendor/core/persistence/index.js +1 -0
- package/dist/vendor/core/persistence/runs-reader.d.ts +52 -0
- package/dist/vendor/core/persistence/runs-reader.js +84 -0
- package/dist/vendor/core/persistence/store.d.ts +6 -1
- package/dist/vendor/core/persistence/store.js +5 -0
- package/dist/vendor/core/policy/file-touch-quota.d.ts +60 -0
- package/dist/vendor/core/policy/file-touch-quota.js +105 -0
- package/dist/vendor/core/policy/policy-loader.d.ts +30 -0
- package/dist/vendor/core/policy/policy-loader.js +170 -0
- package/dist/vendor/core/policy/policy-schema.d.ts +55 -0
- package/dist/vendor/core/policy/policy-schema.js +78 -0
- package/dist/vendor/core/probe/probe.d.ts +49 -0
- package/dist/vendor/core/probe/probe.js +115 -0
- package/dist/vendor/core/proof/patch-proof.d.ts +58 -0
- package/dist/vendor/core/proof/patch-proof.js +84 -0
- package/dist/vendor/core/proof/semantic-probe.d.ts +25 -0
- package/dist/vendor/core/proof/semantic-probe.js +82 -0
- package/dist/vendor/core/recovery/failure-mode-runner.d.ts +29 -0
- package/dist/vendor/core/recovery/failure-mode-runner.js +39 -0
- package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
- package/dist/vendor/core/red-blue/red-phase.js +141 -0
- package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
- package/dist/vendor/core/red-blue/risk-tiers.js +33 -0
- package/dist/vendor/core/replay/replay.d.ts +85 -0
- package/dist/vendor/core/replay/replay.js +109 -0
- package/dist/vendor/core/router/engine.d.ts +54 -0
- package/dist/vendor/core/router/engine.js +131 -0
- package/dist/vendor/core/router/index.d.ts +1 -0
- package/dist/vendor/core/router/index.js +2 -0
- package/dist/vendor/core/router/trust-calibration.d.ts +57 -0
- package/dist/vendor/core/router/trust-calibration.js +127 -0
- package/dist/vendor/core/run-martin.d.ts +2 -0
- package/dist/vendor/core/run-martin.js +287 -0
- package/dist/vendor/core/security/cve-scanner.d.ts +62 -0
- package/dist/vendor/core/security/cve-scanner.js +178 -0
- package/dist/vendor/core/sentinel/efficiency-sentinel.d.ts +29 -0
- package/dist/vendor/core/sentinel/efficiency-sentinel.js +30 -0
- package/dist/vendor/core/sentinel/progress-guard.d.ts +35 -0
- package/dist/vendor/core/sentinel/progress-guard.js +46 -0
- package/dist/vendor/core/siem/siem-emitter.d.ts +49 -0
- package/dist/vendor/core/siem/siem-emitter.js +157 -0
- package/dist/vendor/core/strategy/attempt-brief.d.ts +22 -0
- package/dist/vendor/core/strategy/attempt-brief.js +89 -0
- package/dist/vendor/core/summarize/diff-summary.d.ts +35 -0
- package/dist/vendor/core/summarize/diff-summary.js +204 -0
- package/dist/vendor/core/surface-signals.d.ts +21 -0
- package/dist/vendor/core/surface-signals.js +139 -0
- package/dist/vendor/core/truth/truth-wall.d.ts +51 -0
- package/dist/vendor/core/truth/truth-wall.js +69 -0
- package/dist/vendor/core/truth-spine.d.ts +26 -0
- package/dist/vendor/core/truth-spine.js +62 -0
- package/dist/vendor/core/types.d.ts +115 -0
- package/dist/vendor/core/types.js +2 -0
- package/dist/vendor/core/verification/tiered-verify.d.ts +17 -0
- package/dist/vendor/core/verification/tiered-verify.js +29 -0
- package/dist/vendor/core/verifier-pyramid.d.ts +32 -0
- package/dist/vendor/core/verifier-pyramid.js +111 -0
- package/dist/vendor/core/workflow-artifacts.d.ts +99 -0
- package/dist/vendor/core/workflow-artifacts.js +668 -0
- package/dist/vendor/core/wrap/supervised-run.d.ts +96 -0
- package/dist/vendor/core/wrap/supervised-run.js +178 -0
- package/docs/assets/cli-animated.svg +139 -0
- package/docs/assets/cli-static.svg +34 -0
- package/docs/assets/github-hero-v2.svg +23 -0
- package/docs/assets/martin-raplph.png.jpg +0 -0
- package/docs/assets/martinloop-logo.png +0 -0
- package/docs/assets/nvidia-inception-program-light.png +0 -0
- package/docs/assets/nvidia-inception-program.png +0 -0
- package/docs/assets/phase3c-sidesidebyside-demo.html +228 -0
- package/docs/assets/side-by-side.svg +134 -0
- package/docs/oss/CLAUDE-CODE-WALKTHROUGH.md +142 -142
- package/docs/oss/EXAMPLES.md +134 -134
- package/docs/oss/OSS-BOUNDARY-REPORT.json +1 -1
- package/docs/oss/OSS-BOUNDARY-REPORT.md +1 -1
- package/docs/oss/QUICKSTART.md +170 -165
- package/docs/oss/RALPH-LOOP-SAFETY.md +113 -113
- package/docs/oss/README.md +96 -96
- package/docs/oss/RELEASE-SURFACE-REPORT.json +2 -1
- package/docs/oss/RELEASE-SURFACE-REPORT.md +2 -1
- package/package.json +130 -58
- package/docs/distribution/DIRECTORY-SUBMISSIONS.md +0 -89
- package/docs/distribution/INTEGRATION-OUTREACH.md +0 -61
- package/docs/distribution/UNDER-3-CHALLENGE.md +0 -65
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { getTracer } from "../otel/tracer.js";
|
|
2
|
+
export class McpServerRegistry {
|
|
3
|
+
servers = new Map();
|
|
4
|
+
constructor(initialServers = []) {
|
|
5
|
+
for (const server of initialServers) {
|
|
6
|
+
this.register(server);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
register(server) {
|
|
10
|
+
if (!server.id || !server.url) {
|
|
11
|
+
throw new Error(`Invalid MCP server configuration for: ${server.name}`);
|
|
12
|
+
}
|
|
13
|
+
this.servers.set(server.id, server);
|
|
14
|
+
}
|
|
15
|
+
unregister(serverId) {
|
|
16
|
+
return this.servers.delete(serverId);
|
|
17
|
+
}
|
|
18
|
+
getServer(serverId) {
|
|
19
|
+
return this.servers.get(serverId);
|
|
20
|
+
}
|
|
21
|
+
listServers() {
|
|
22
|
+
return Array.from(this.servers.values());
|
|
23
|
+
}
|
|
24
|
+
evaluateToolPolicy(attempt) {
|
|
25
|
+
const tracer = getTracer();
|
|
26
|
+
const span = tracer.startSpan("martin.gateway_policy", {
|
|
27
|
+
"tool.name": attempt.toolName,
|
|
28
|
+
"server.id": attempt.serverId,
|
|
29
|
+
"context.loop": attempt.context.loopId
|
|
30
|
+
});
|
|
31
|
+
const finish = (decision) => {
|
|
32
|
+
tracer.endSpan(span, decision.action === "deny" ? "ERROR" : "OK");
|
|
33
|
+
return decision;
|
|
34
|
+
};
|
|
35
|
+
const server = this.getServer(attempt.serverId);
|
|
36
|
+
if (!server) {
|
|
37
|
+
return finish({
|
|
38
|
+
action: "deny",
|
|
39
|
+
reason: `Server ID '${attempt.serverId}' not registered.`
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (server.trustTier === "untrusted" &&
|
|
43
|
+
attempt.context.executionProfile === "ci_safe") {
|
|
44
|
+
return finish({
|
|
45
|
+
action: "deny",
|
|
46
|
+
reason: "Untrusted MCP servers are disabled under ci_safe profile."
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Direct blocklist
|
|
50
|
+
if (this.matchesPattern(attempt.toolName, server.blockedTools)) {
|
|
51
|
+
return finish({
|
|
52
|
+
action: "deny",
|
|
53
|
+
reason: `Tool '${attempt.toolName}' is blocked by server policy.`
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
// Allowlist
|
|
57
|
+
if (server.allowedTools.length > 0 &&
|
|
58
|
+
!this.matchesPattern(attempt.toolName, server.allowedTools)) {
|
|
59
|
+
return finish({
|
|
60
|
+
action: "deny",
|
|
61
|
+
reason: `Tool '${attempt.toolName}' is not in the server allowlist.`
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Dangerous patterns require dry-run ("simulate") if not strongly verified
|
|
65
|
+
if (server.trustTier !== "system") {
|
|
66
|
+
const stringifiedArgs = JSON.stringify(attempt.args);
|
|
67
|
+
if (stringifiedArgs.includes("rm -rf") ||
|
|
68
|
+
stringifiedArgs.includes("drop table")) {
|
|
69
|
+
return finish({
|
|
70
|
+
action: "simulate",
|
|
71
|
+
mockResponse: {
|
|
72
|
+
success: true,
|
|
73
|
+
stdout: "",
|
|
74
|
+
stderr: "DRY-RUN: Command intercepted and skipped."
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return finish({ action: "allow" });
|
|
80
|
+
}
|
|
81
|
+
matchesPattern(tool, patterns) {
|
|
82
|
+
for (const p of patterns) {
|
|
83
|
+
if (p === "*")
|
|
84
|
+
return true;
|
|
85
|
+
if (p.endsWith("*")) {
|
|
86
|
+
const prefix = p.slice(0, -1);
|
|
87
|
+
if (tool.startsWith(prefix))
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
else if (p === tool) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { McpServerConfig } from "./registry.js";
|
|
2
|
+
import type { McpTokenVault } from "./vault.js";
|
|
3
|
+
export interface JsonRpcRequest {
|
|
4
|
+
jsonrpc: "2.0";
|
|
5
|
+
id: string | number;
|
|
6
|
+
method: string;
|
|
7
|
+
params?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface JsonRpcResponse<T = unknown> {
|
|
10
|
+
jsonrpc: "2.0";
|
|
11
|
+
id: string | number;
|
|
12
|
+
result?: T;
|
|
13
|
+
error?: {
|
|
14
|
+
code: number;
|
|
15
|
+
message: string;
|
|
16
|
+
data?: unknown;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export declare class McpTransportError extends Error {
|
|
20
|
+
readonly status?: number | undefined;
|
|
21
|
+
readonly data?: unknown | undefined;
|
|
22
|
+
constructor(message: string, status?: number | undefined, data?: unknown | undefined);
|
|
23
|
+
}
|
|
24
|
+
export declare class McpHttpTransport {
|
|
25
|
+
private readonly vault?;
|
|
26
|
+
constructor(vault?: McpTokenVault | undefined);
|
|
27
|
+
/**
|
|
28
|
+
* Dispatches a raw JSON-RPC 2.0 request to an external MCP HTTP server.
|
|
29
|
+
*/
|
|
30
|
+
executeCommand<T = unknown>(server: McpServerConfig, method: string, params: Record<string, unknown>, requestId: string): Promise<T>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export class McpTransportError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
data;
|
|
4
|
+
constructor(message, status, data) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.status = status;
|
|
7
|
+
this.data = data;
|
|
8
|
+
this.name = "McpTransportError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class McpHttpTransport {
|
|
12
|
+
vault;
|
|
13
|
+
constructor(vault) {
|
|
14
|
+
this.vault = vault;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Dispatches a raw JSON-RPC 2.0 request to an external MCP HTTP server.
|
|
18
|
+
*/
|
|
19
|
+
async executeCommand(server, method, params, requestId) {
|
|
20
|
+
const payload = {
|
|
21
|
+
jsonrpc: "2.0",
|
|
22
|
+
id: requestId,
|
|
23
|
+
method,
|
|
24
|
+
params
|
|
25
|
+
};
|
|
26
|
+
const headers = new Headers({
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
"User-Agent": "Martin-Loop-Gateway/0.1.0"
|
|
29
|
+
});
|
|
30
|
+
if (server.headers) {
|
|
31
|
+
for (const [key, value] of Object.entries(server.headers)) {
|
|
32
|
+
headers.set(key, value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (this.vault) {
|
|
36
|
+
const dynamicHeaders = await this.vault.resolveHeaders(server.id);
|
|
37
|
+
for (const [key, value] of Object.entries(dynamicHeaders)) {
|
|
38
|
+
headers.set(key, value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
// 30s timeout so the loop doesn't hang indefinitely on a bad server
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
const timeout = setTimeout(() => controller.abort(), 30000);
|
|
45
|
+
const response = await fetch(server.url, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers,
|
|
48
|
+
body: JSON.stringify(payload),
|
|
49
|
+
signal: controller.signal
|
|
50
|
+
});
|
|
51
|
+
clearTimeout(timeout);
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
throw new McpTransportError(`HTTP Error ${response.status}: Failed to reach MCP Server '${server.id}'`, response.status);
|
|
54
|
+
}
|
|
55
|
+
const rawJson = await response.text();
|
|
56
|
+
let rpcResponse;
|
|
57
|
+
try {
|
|
58
|
+
rpcResponse = JSON.parse(rawJson);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
throw new McpTransportError(`Invalid JSON received from MCP Server '${server.id}'`);
|
|
62
|
+
}
|
|
63
|
+
if (rpcResponse.error) {
|
|
64
|
+
throw new McpTransportError(`MCP Server Internal Error: ${rpcResponse.error.message}`, undefined, rpcResponse.error.data);
|
|
65
|
+
}
|
|
66
|
+
// JSON-RPC 2.0 requires `result` to exist on success
|
|
67
|
+
if (rpcResponse.result === undefined) {
|
|
68
|
+
throw new McpTransportError(`Malformed JSON-RPC response from '${server.id}': Missing result.`);
|
|
69
|
+
}
|
|
70
|
+
return rpcResponse.result;
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
if (e instanceof McpTransportError) {
|
|
74
|
+
throw e;
|
|
75
|
+
}
|
|
76
|
+
const err = e;
|
|
77
|
+
const errMessage = err.name === "AbortError" ? "Request Timeout" : err.message;
|
|
78
|
+
throw new McpTransportError(`Network error dispatching to MCP Server '${server.id}': ${errMessage}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface McpTokenVault {
|
|
2
|
+
/**
|
|
3
|
+
* Resolves authentication headers for a given server dynamically.
|
|
4
|
+
* Can be implemented via OAuth, Secret Managers, or static config.
|
|
5
|
+
*/
|
|
6
|
+
resolveHeaders(serverId: string): Promise<Record<string, string>>;
|
|
7
|
+
}
|
|
8
|
+
export declare class StaticTokenVault implements McpTokenVault {
|
|
9
|
+
private readonly staticHeaders;
|
|
10
|
+
constructor(staticHeaders: Map<string, Record<string, string>>);
|
|
11
|
+
resolveHeaders(serverId: string): Promise<Record<string, string>>;
|
|
12
|
+
}
|
|
13
|
+
export declare class OAuthProxyVault implements McpTokenVault {
|
|
14
|
+
private readonly oauthTokenEndpoint;
|
|
15
|
+
private readonly clientId;
|
|
16
|
+
private readonly clientSecret;
|
|
17
|
+
constructor(oauthTokenEndpoint: string, clientId: string, clientSecret: string);
|
|
18
|
+
resolveHeaders(serverId: string): Promise<Record<string, string>>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export class StaticTokenVault {
|
|
2
|
+
staticHeaders;
|
|
3
|
+
constructor(staticHeaders) {
|
|
4
|
+
this.staticHeaders = staticHeaders;
|
|
5
|
+
}
|
|
6
|
+
async resolveHeaders(serverId) {
|
|
7
|
+
return this.staticHeaders.get(serverId) ?? {};
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class OAuthProxyVault {
|
|
11
|
+
oauthTokenEndpoint;
|
|
12
|
+
clientId;
|
|
13
|
+
clientSecret;
|
|
14
|
+
constructor(oauthTokenEndpoint, clientId, clientSecret) {
|
|
15
|
+
this.oauthTokenEndpoint = oauthTokenEndpoint;
|
|
16
|
+
this.clientId = clientId;
|
|
17
|
+
this.clientSecret = clientSecret;
|
|
18
|
+
}
|
|
19
|
+
async resolveHeaders(serverId) {
|
|
20
|
+
// Basic dynamic OAuth token fetch simulation for multi-tenant isolation
|
|
21
|
+
// Without actually making real un-mocked requests that could crash tests
|
|
22
|
+
const token = Buffer.from(`${this.clientId}:${this.clientSecret}-${serverId}`).toString("base64");
|
|
23
|
+
return {
|
|
24
|
+
Authorization: `Bearer ${token}`,
|
|
25
|
+
"X-Martin-Scope": "dynamic-vault"
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=vault.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { RepoHotspot } from "./hotspots.js";
|
|
2
|
+
export interface MartinGraphAdapter {
|
|
3
|
+
queryRegressions(targetFiles: string[], objective: string): Promise<RepoHotspot[]>;
|
|
4
|
+
ingestRun(record: unknown): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Abstract interface to ensure the system can hot-swap external graph engines
|
|
8
|
+
* (like Neo4j) without rewriting the core calculation logic when workspace scale grows.
|
|
9
|
+
*/
|
|
10
|
+
export declare abstract class AbstractGraphStore implements MartinGraphAdapter {
|
|
11
|
+
abstract queryRegressions(targetFiles: string[], objective: string): Promise<RepoHotspot[]>;
|
|
12
|
+
abstract ingestRun(record: unknown): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare class JsonAdjacencyGraphAdapter extends AbstractGraphStore {
|
|
15
|
+
private readonly adjacencyFilePath;
|
|
16
|
+
constructor(adjacencyFilePath: string);
|
|
17
|
+
queryRegressions(targetFiles: string[], _objective: string): Promise<RepoHotspot[]>;
|
|
18
|
+
ingestRun(_record: unknown): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* GitBlameGraphAdapter
|
|
22
|
+
*
|
|
23
|
+
* Derives repository hotspots from live git history — no static JSON file required.
|
|
24
|
+
*
|
|
25
|
+
* For each target file, runs `git log --oneline --follow -- <file>` to count
|
|
26
|
+
* how many commits have touched it. Files with a commit count >= the configured
|
|
27
|
+
* threshold are returned as hotspots. The regression count is the git commit count,
|
|
28
|
+
* which is a reliable, repo-native signal of churn / instability.
|
|
29
|
+
*
|
|
30
|
+
* Fail-open: any git error (not a repo, file not tracked, git not installed) returns
|
|
31
|
+
* an empty result for that file — never throws.
|
|
32
|
+
*/
|
|
33
|
+
export declare class GitBlameGraphAdapter extends AbstractGraphStore {
|
|
34
|
+
private readonly repoRoot;
|
|
35
|
+
/** Files with >= this many commits are classified as hotspots. Default: 5 */
|
|
36
|
+
private readonly commitThreshold;
|
|
37
|
+
constructor(repoRoot: string,
|
|
38
|
+
/** Files with >= this many commits are classified as hotspots. Default: 5 */
|
|
39
|
+
commitThreshold?: number);
|
|
40
|
+
queryRegressions(targetFiles: string[], _objective: string): Promise<RepoHotspot[]>;
|
|
41
|
+
ingestRun(_record: unknown): Promise<void>;
|
|
42
|
+
private countCommits;
|
|
43
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
/**
|
|
6
|
+
* Abstract interface to ensure the system can hot-swap external graph engines
|
|
7
|
+
* (like Neo4j) without rewriting the core calculation logic when workspace scale grows.
|
|
8
|
+
*/
|
|
9
|
+
export class AbstractGraphStore {
|
|
10
|
+
}
|
|
11
|
+
export class JsonAdjacencyGraphAdapter extends AbstractGraphStore {
|
|
12
|
+
adjacencyFilePath;
|
|
13
|
+
constructor(adjacencyFilePath) {
|
|
14
|
+
super();
|
|
15
|
+
this.adjacencyFilePath = adjacencyFilePath;
|
|
16
|
+
}
|
|
17
|
+
async queryRegressions(targetFiles, _objective) {
|
|
18
|
+
try {
|
|
19
|
+
const data = await fs.readFile(this.adjacencyFilePath, "utf8");
|
|
20
|
+
const adjacencyList = JSON.parse(data);
|
|
21
|
+
const hotspots = [];
|
|
22
|
+
for (const file of targetFiles) {
|
|
23
|
+
if (adjacencyList[file] && adjacencyList[file].regressionCount > 0) {
|
|
24
|
+
hotspots.push(adjacencyList[file]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return hotspots;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// If the adjacency file does not exist yet, or parsing fails, return empty context natively
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async ingestRun(_record) {
|
|
35
|
+
// In a real execution, we parse the record for "verification_failed" events
|
|
36
|
+
// and upsert the files into the JSON map.
|
|
37
|
+
// Stubbed for standard interface completion.
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* GitBlameGraphAdapter
|
|
42
|
+
*
|
|
43
|
+
* Derives repository hotspots from live git history — no static JSON file required.
|
|
44
|
+
*
|
|
45
|
+
* For each target file, runs `git log --oneline --follow -- <file>` to count
|
|
46
|
+
* how many commits have touched it. Files with a commit count >= the configured
|
|
47
|
+
* threshold are returned as hotspots. The regression count is the git commit count,
|
|
48
|
+
* which is a reliable, repo-native signal of churn / instability.
|
|
49
|
+
*
|
|
50
|
+
* Fail-open: any git error (not a repo, file not tracked, git not installed) returns
|
|
51
|
+
* an empty result for that file — never throws.
|
|
52
|
+
*/
|
|
53
|
+
export class GitBlameGraphAdapter extends AbstractGraphStore {
|
|
54
|
+
repoRoot;
|
|
55
|
+
commitThreshold;
|
|
56
|
+
constructor(repoRoot,
|
|
57
|
+
/** Files with >= this many commits are classified as hotspots. Default: 5 */
|
|
58
|
+
commitThreshold = 5) {
|
|
59
|
+
super();
|
|
60
|
+
this.repoRoot = repoRoot;
|
|
61
|
+
this.commitThreshold = commitThreshold;
|
|
62
|
+
}
|
|
63
|
+
async queryRegressions(targetFiles, _objective) {
|
|
64
|
+
const hotspots = [];
|
|
65
|
+
for (const file of targetFiles) {
|
|
66
|
+
const count = await this.countCommits(file);
|
|
67
|
+
if (count >= this.commitThreshold) {
|
|
68
|
+
hotspots.push({
|
|
69
|
+
file,
|
|
70
|
+
regressionCount: count,
|
|
71
|
+
associatedTaskTypes: ["churn", "high-frequency-change"]
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return hotspots;
|
|
76
|
+
}
|
|
77
|
+
async ingestRun(_record) {
|
|
78
|
+
// Live adapter — reads directly from git history, no ingest needed.
|
|
79
|
+
}
|
|
80
|
+
async countCommits(file) {
|
|
81
|
+
try {
|
|
82
|
+
const { stdout } = await execFileAsync("git", ["log", "--oneline", "--follow", "--", file], { cwd: this.repoRoot });
|
|
83
|
+
return stdout.trim().split("\n").filter(Boolean).length;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// git not available, file not tracked, or not inside a git repo — safe fallback
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LoopMemoryStore } from "../memory/palace.js";
|
|
2
|
+
import type { MartinGraphAdapter } from "./adapters.js";
|
|
3
|
+
export interface RepoHotspot {
|
|
4
|
+
file: string;
|
|
5
|
+
regressionCount: number;
|
|
6
|
+
lastFailureClass?: string;
|
|
7
|
+
associatedTaskTypes: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface GraphContextAssembly {
|
|
10
|
+
hotspotsDetected: RepoHotspot[];
|
|
11
|
+
suggestedContextAdditions: string[];
|
|
12
|
+
}
|
|
13
|
+
export declare class MartinGraph {
|
|
14
|
+
private readonly memoryStore?;
|
|
15
|
+
private readonly graphAdapter?;
|
|
16
|
+
constructor(memoryStore?: LoopMemoryStore | undefined, graphAdapter?: MartinGraphAdapter | undefined);
|
|
17
|
+
/**
|
|
18
|
+
* Translates a raw array of memory briefs into a structural hotspot map identifying
|
|
19
|
+
* files that frequently fail verification or cause rollbacks.
|
|
20
|
+
*/
|
|
21
|
+
assembleHotspotContext(targetFiles: string[], objective: string): Promise<GraphContextAssembly>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class MartinGraph {
|
|
2
|
+
memoryStore;
|
|
3
|
+
graphAdapter;
|
|
4
|
+
constructor(memoryStore, graphAdapter) {
|
|
5
|
+
this.memoryStore = memoryStore;
|
|
6
|
+
this.graphAdapter = graphAdapter;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Translates a raw array of memory briefs into a structural hotspot map identifying
|
|
10
|
+
* files that frequently fail verification or cause rollbacks.
|
|
11
|
+
*/
|
|
12
|
+
async assembleHotspotContext(targetFiles, objective) {
|
|
13
|
+
if (!this.memoryStore && !this.graphAdapter) {
|
|
14
|
+
return { hotspotsDetected: [], suggestedContextAdditions: [] };
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
// Pull real statistics from the underlying database / persistence layer
|
|
18
|
+
const hotspots = this.graphAdapter
|
|
19
|
+
? await this.graphAdapter.queryRegressions(targetFiles, objective)
|
|
20
|
+
: [];
|
|
21
|
+
const riskyFiles = hotspots.filter((h) => h.regressionCount > 2);
|
|
22
|
+
const suggestedContextAdditions = riskyFiles.map((h) => `CRITICAL: The file '${h.file}' has regressed ${h.regressionCount} times in similar past tasks. Double-check types and imports before patching.`);
|
|
23
|
+
return { hotspotsDetected: hotspots, suggestedContextAdditions };
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return { hotspotsDetected: [], suggestedContextAdditions: [] };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=hotspots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./hotspots.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface HoneyTokenSet {
|
|
2
|
+
runId: string;
|
|
3
|
+
tokens: string[];
|
|
4
|
+
}
|
|
5
|
+
export interface Patch {
|
|
6
|
+
patchId: string;
|
|
7
|
+
diff: string;
|
|
8
|
+
changedFiles: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface HoneyTokenViolation {
|
|
11
|
+
trapId: "T13";
|
|
12
|
+
severity: "block";
|
|
13
|
+
description: string;
|
|
14
|
+
matchedToken: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generates 3 HMAC-derived canary symbols per run.
|
|
18
|
+
*
|
|
19
|
+
* Properties:
|
|
20
|
+
* - Deterministic: same runId + secret always produces same tokens
|
|
21
|
+
* - Isolated: different runIds produce different tokens (no cross-run reuse)
|
|
22
|
+
* - Format: __martin_canary_{hmac_prefix}__
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateHoneyTokenSet(runId: string, secret: string): HoneyTokenSet;
|
|
25
|
+
/**
|
|
26
|
+
* Scans a patch diff for any honey token references.
|
|
27
|
+
* Pure string grep — zero model calls, zero API cost.
|
|
28
|
+
*
|
|
29
|
+
* Returns T13 GroundingViolation if a canary token appears in the patch,
|
|
30
|
+
* null if the patch is clean.
|
|
31
|
+
*/
|
|
32
|
+
export declare function scanPatchForHoneyTokens(patch: Patch, tokens: HoneyTokenSet): HoneyTokenViolation | null;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createHmac } from "node:crypto";
|
|
2
|
+
// ─── Token Generation ─────────────────────────────────────────────────────────
|
|
3
|
+
/**
|
|
4
|
+
* Generates 3 HMAC-derived canary symbols per run.
|
|
5
|
+
*
|
|
6
|
+
* Properties:
|
|
7
|
+
* - Deterministic: same runId + secret always produces same tokens
|
|
8
|
+
* - Isolated: different runIds produce different tokens (no cross-run reuse)
|
|
9
|
+
* - Format: __martin_canary_{hmac_prefix}__
|
|
10
|
+
*/
|
|
11
|
+
export function generateHoneyTokenSet(runId, secret) {
|
|
12
|
+
const tokens = [];
|
|
13
|
+
for (let i = 0; i < 3; i++) {
|
|
14
|
+
const hmac = createHmac("sha256", secret)
|
|
15
|
+
.update(`${runId}:canary:${i}`)
|
|
16
|
+
.digest("hex");
|
|
17
|
+
// Use a deterministic 16-char prefix per slot to keep tokens distinct
|
|
18
|
+
const prefix = hmac.slice(i * 8, i * 8 + 16);
|
|
19
|
+
tokens.push(`__martin_canary_${prefix}__`);
|
|
20
|
+
}
|
|
21
|
+
return { runId, tokens };
|
|
22
|
+
}
|
|
23
|
+
// ─── Scan ─────────────────────────────────────────────────────────────────────
|
|
24
|
+
/**
|
|
25
|
+
* Scans a patch diff for any honey token references.
|
|
26
|
+
* Pure string grep — zero model calls, zero API cost.
|
|
27
|
+
*
|
|
28
|
+
* Returns T13 GroundingViolation if a canary token appears in the patch,
|
|
29
|
+
* null if the patch is clean.
|
|
30
|
+
*/
|
|
31
|
+
export function scanPatchForHoneyTokens(patch, tokens) {
|
|
32
|
+
for (const token of tokens.tokens) {
|
|
33
|
+
if (patch.diff.includes(token)) {
|
|
34
|
+
return {
|
|
35
|
+
trapId: "T13",
|
|
36
|
+
severity: "block",
|
|
37
|
+
description: `Honey token reference detected in patch ${patch.patchId} — instant rejection.`,
|
|
38
|
+
matchedToken: token
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=honey-tokens.js.map
|
|
@@ -13,8 +13,8 @@ export { runContextIntegrityPrecheck } from "./context-integrity.js";
|
|
|
13
13
|
export type { ContextIntegrityPrecheck, ContextIntegrityVerdict } from "./context-integrity.js";
|
|
14
14
|
export { compilePromptPacket } from "./compiler.js";
|
|
15
15
|
export type { PromptPacket, CompilerAdapterRequest } from "./compiler.js";
|
|
16
|
-
export { createFileRunStore, makeLedgerEvent, resolveRunsRoot } from "./persistence/index.js";
|
|
17
|
-
export type { AttemptArtifacts, LedgerEvent, LedgerEventKind, RunContract, RunStore } from "./persistence/index.js";
|
|
16
|
+
export { createFileRunStore, makeLedgerEvent, readAllLoopRecords, readLatestLoopRecord, readLatestLoopRecordFromFile, readLoopRecordsFromFile, resolveRunsRoot } from "./persistence/index.js";
|
|
17
|
+
export type { AttemptArtifacts, LedgerEvent, LedgerEventKind, LoopAttemptRecord, LoopRunRecord, RunContract, RunStore } from "./persistence/index.js";
|
|
18
18
|
export { compileAndPersistContext } from "./persistence/index.js";
|
|
19
19
|
export type { CompileResult } from "./persistence/index.js";
|
|
20
20
|
export interface MartinAdapterRequest {
|