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,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* summary-card.ts
|
|
3
|
+
*
|
|
4
|
+
* Renders a human-readable run summary card to stdout after every martin run.
|
|
5
|
+
* Respects --json flag and MARTIN_NO_SUMMARY env var.
|
|
6
|
+
* Width: 56 chars to fit any terminal >= 60 cols.
|
|
7
|
+
*/
|
|
8
|
+
const CARD_WIDTH = 56;
|
|
9
|
+
const INNER_WIDTH = CARD_WIDTH - 4; // 2 border chars + 2 padding spaces
|
|
10
|
+
export function shouldRenderSummaryCard(args) {
|
|
11
|
+
if (process.env.MARTIN_NO_SUMMARY === "1")
|
|
12
|
+
return false;
|
|
13
|
+
if (args.includes("--json"))
|
|
14
|
+
return false;
|
|
15
|
+
// Only render when stdout is a TTY or when explicitly forced
|
|
16
|
+
if (!process.stdout.isTTY && process.env.MARTIN_FORCE_SUMMARY !== "1")
|
|
17
|
+
return false;
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
export function renderSummaryCard(input) {
|
|
21
|
+
const lines = [];
|
|
22
|
+
const top = `╔${"═".repeat(CARD_WIDTH - 2)}╗`;
|
|
23
|
+
const bottom = `╚${"═".repeat(CARD_WIDTH - 2)}╝`;
|
|
24
|
+
const divider = `╠${"═".repeat(CARD_WIDTH - 2)}╣`;
|
|
25
|
+
const title = input.succeeded
|
|
26
|
+
? "Martin Loop — Run Complete"
|
|
27
|
+
: "Martin Loop — Run Failed";
|
|
28
|
+
lines.push(top);
|
|
29
|
+
lines.push(row(title));
|
|
30
|
+
lines.push(divider);
|
|
31
|
+
if (input.succeeded) {
|
|
32
|
+
const attemptLabel = input.attemptCount === 1
|
|
33
|
+
? "1 attempt"
|
|
34
|
+
: `attempt ${input.attemptCount} of ${input.maxAttempts}`;
|
|
35
|
+
lines.push(row(`Outcome SUCCEEDED (${attemptLabel})`));
|
|
36
|
+
lines.push(row(`Objective ${truncate(input.objective, INNER_WIDTH - 12)}`));
|
|
37
|
+
if (input.grade) {
|
|
38
|
+
const grounding = input.groundingScore !== undefined
|
|
39
|
+
? ` (grounding: ${input.groundingScore.toFixed(2)})`
|
|
40
|
+
: "";
|
|
41
|
+
lines.push(row(`Patch grade ${input.grade}${grounding}`));
|
|
42
|
+
}
|
|
43
|
+
if (input.modelName) {
|
|
44
|
+
const probe = input.probeTier ? ` (probe: ${input.probeTier})` : "";
|
|
45
|
+
lines.push(row(`Model ${truncate(input.modelName + probe, INNER_WIDTH - 12)}`));
|
|
46
|
+
}
|
|
47
|
+
const probeNote = input.probeCostUsd !== undefined
|
|
48
|
+
? ` (probe $${input.probeCostUsd.toFixed(2)} + attempts $${(input.costUsd - input.probeCostUsd).toFixed(2)})`
|
|
49
|
+
: "";
|
|
50
|
+
lines.push(row(`Cost $${input.costUsd.toFixed(2)}${probeNote}`));
|
|
51
|
+
if (input.routerSelectedModel !== undefined) {
|
|
52
|
+
const routerCostStr = input.routerCostPer1kTcs !== undefined
|
|
53
|
+
? ` · $${input.routerCostPer1kTcs.toFixed(4)}/1kTcs`
|
|
54
|
+
: "";
|
|
55
|
+
const tierStr = input.routerTrustTier ? ` [${input.routerTrustTier}]` : "";
|
|
56
|
+
lines.push(row(`Route ${truncate(input.routerSelectedModel + routerCostStr + tierStr, INNER_WIDTH - 12)}`));
|
|
57
|
+
}
|
|
58
|
+
if (input.blastRadius !== undefined) {
|
|
59
|
+
lines.push(row(`Blast radius ${input.blastRadius}/100`));
|
|
60
|
+
}
|
|
61
|
+
lines.push(row(`Duration ${formatDuration(input.durationMs)}`));
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
lines.push(row(`Outcome FAILED after ${input.attemptCount} attempt${input.attemptCount !== 1 ? "s" : ""}`));
|
|
65
|
+
lines.push(row(`Objective ${truncate(input.objective, INNER_WIDTH - 12)}`));
|
|
66
|
+
if (input.lastBlockReason) {
|
|
67
|
+
lines.push(row(`Last block ${truncate(input.lastBlockReason, INNER_WIDTH - 12)}`));
|
|
68
|
+
}
|
|
69
|
+
lines.push(row(`Cost $${input.costUsd.toFixed(2)} (all attempts charged)`));
|
|
70
|
+
const rollbackStr = input.rollbackComplete === false
|
|
71
|
+
? "incomplete — check workspace"
|
|
72
|
+
: "complete — workspace restored";
|
|
73
|
+
lines.push(row(`Rollback ${rollbackStr}`));
|
|
74
|
+
}
|
|
75
|
+
lines.push(divider);
|
|
76
|
+
lines.push(row(`Audit trail → ~/.martin/runs/${truncate(input.loopId, INNER_WIDTH - 22)}`));
|
|
77
|
+
if (!input.succeeded) {
|
|
78
|
+
lines.push(row(`Tip: martin explain ${truncate(input.loopId, INNER_WIDTH - 22)}`));
|
|
79
|
+
}
|
|
80
|
+
lines.push(bottom);
|
|
81
|
+
return lines.join("\n");
|
|
82
|
+
}
|
|
83
|
+
function row(content) {
|
|
84
|
+
const remaining = CARD_WIDTH - 4 - content.length;
|
|
85
|
+
const padding = remaining > 0 ? " ".repeat(remaining) : "";
|
|
86
|
+
return `║ ${content}${padding} ║`;
|
|
87
|
+
}
|
|
88
|
+
function truncate(str, maxLen) {
|
|
89
|
+
if (str.length <= maxLen)
|
|
90
|
+
return str;
|
|
91
|
+
return `${str.slice(0, maxLen - 3)}...`;
|
|
92
|
+
}
|
|
93
|
+
function formatDuration(ms) {
|
|
94
|
+
if (ms < 1000)
|
|
95
|
+
return `${ms}ms`;
|
|
96
|
+
if (ms < 60_000)
|
|
97
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
98
|
+
const mins = Math.floor(ms / 60_000);
|
|
99
|
+
const secs = Math.round((ms % 60_000) / 1000);
|
|
100
|
+
return `${mins}m ${secs}s`;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=summary-card.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface AuditManifestEntry {
|
|
2
|
+
path: string;
|
|
3
|
+
sha256: string;
|
|
4
|
+
sizeBytes: number;
|
|
5
|
+
}
|
|
6
|
+
export interface AuditManifest {
|
|
7
|
+
runId: string;
|
|
8
|
+
generatedAt: string;
|
|
9
|
+
generatedBy: string;
|
|
10
|
+
files: AuditManifestEntry[];
|
|
11
|
+
manifestVersion: "h3.v1";
|
|
12
|
+
tamperEvident: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface AuditPackFile {
|
|
15
|
+
path: string;
|
|
16
|
+
content: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AuditPackInput {
|
|
19
|
+
runId: string;
|
|
20
|
+
generatedBy: string;
|
|
21
|
+
generatedAt: string;
|
|
22
|
+
files: AuditPackFile[];
|
|
23
|
+
}
|
|
24
|
+
export interface GenerateAuditPackFromRunDirectoryOptions {
|
|
25
|
+
runId: string;
|
|
26
|
+
runDir: string;
|
|
27
|
+
outputDir: string;
|
|
28
|
+
generatedBy?: string;
|
|
29
|
+
generatedAt?: string;
|
|
30
|
+
truthFacts?: unknown[];
|
|
31
|
+
treatyTimeline?: unknown[];
|
|
32
|
+
}
|
|
33
|
+
export interface AuditPackGenerationResult {
|
|
34
|
+
packPath: string;
|
|
35
|
+
manifest: AuditManifest;
|
|
36
|
+
}
|
|
37
|
+
export interface AuditPackVerificationResult {
|
|
38
|
+
ok: boolean;
|
|
39
|
+
manifest: AuditManifest;
|
|
40
|
+
checkedFiles: AuditManifestEntry[];
|
|
41
|
+
failures: string[];
|
|
42
|
+
}
|
|
43
|
+
export declare function generateAuditPackFromRunDirectory(options: GenerateAuditPackFromRunDirectoryOptions): Promise<AuditPackGenerationResult>;
|
|
44
|
+
export declare function writeAuditPack(packPath: string, input: AuditPackInput): Promise<AuditPackGenerationResult>;
|
|
45
|
+
export declare function verifyAuditPack(packPath: string): Promise<AuditPackVerificationResult>;
|
|
46
|
+
export declare function stableStringify(value: unknown): string;
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, join, relative, resolve } from "node:path";
|
|
4
|
+
const AUDIT_DIRECTORIES = [
|
|
5
|
+
"patch-proofs",
|
|
6
|
+
"drift-reports",
|
|
7
|
+
"truth-facts",
|
|
8
|
+
"treaty-timeline",
|
|
9
|
+
"red-findings",
|
|
10
|
+
"hypothesis-ledger"
|
|
11
|
+
];
|
|
12
|
+
export async function generateAuditPackFromRunDirectory(options) {
|
|
13
|
+
const runSource = await readRunAuditSource(options.runDir);
|
|
14
|
+
const generatedAt = options.generatedAt ??
|
|
15
|
+
(typeof runSource.state?.updatedAt === "string" ? runSource.state.updatedAt : undefined) ??
|
|
16
|
+
(typeof runSource.contract.createdAt === "string" ? runSource.contract.createdAt : undefined) ??
|
|
17
|
+
new Date().toISOString();
|
|
18
|
+
const files = buildAuditPackFiles({
|
|
19
|
+
runId: options.runId,
|
|
20
|
+
runSource,
|
|
21
|
+
truthFacts: options.truthFacts ?? [],
|
|
22
|
+
treatyTimeline: options.treatyTimeline ?? []
|
|
23
|
+
});
|
|
24
|
+
const packPath = join(resolve(options.outputDir), `audit-pack-${options.runId}`);
|
|
25
|
+
return writeAuditPack(packPath, {
|
|
26
|
+
runId: options.runId,
|
|
27
|
+
generatedAt,
|
|
28
|
+
generatedBy: options.generatedBy ?? "martin",
|
|
29
|
+
files
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export async function writeAuditPack(packPath, input) {
|
|
33
|
+
const normalizedFiles = [...input.files].sort((left, right) => left.path.localeCompare(right.path));
|
|
34
|
+
const manifest = createAuditManifest(input.runId, input.generatedAt, input.generatedBy, normalizedFiles);
|
|
35
|
+
await mkdir(packPath, { recursive: true });
|
|
36
|
+
for (const directory of AUDIT_DIRECTORIES) {
|
|
37
|
+
await mkdir(join(packPath, directory), { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
for (const file of normalizedFiles) {
|
|
40
|
+
await mkdir(join(packPath, relative(".", file.path).split(/[\\/]/u).slice(0, -1).join("/")), {
|
|
41
|
+
recursive: true
|
|
42
|
+
});
|
|
43
|
+
await writeFile(join(packPath, file.path), file.content, "utf8");
|
|
44
|
+
}
|
|
45
|
+
await writeFile(join(packPath, "MANIFEST.json"), `${stableStringify(manifest)}\n`, "utf8");
|
|
46
|
+
return {
|
|
47
|
+
packPath,
|
|
48
|
+
manifest
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export async function verifyAuditPack(packPath) {
|
|
52
|
+
const resolvedPackPath = resolve(packPath);
|
|
53
|
+
const manifest = JSON.parse(await readFile(join(resolvedPackPath, "MANIFEST.json"), "utf8"));
|
|
54
|
+
const actualFiles = await collectAuditManifestEntries(resolvedPackPath);
|
|
55
|
+
const manifestFiles = [...manifest.files].sort((left, right) => left.path.localeCompare(right.path));
|
|
56
|
+
const failures = [];
|
|
57
|
+
const actualPaths = new Set(actualFiles.map((entry) => entry.path));
|
|
58
|
+
const manifestPaths = new Set(manifestFiles.map((entry) => entry.path));
|
|
59
|
+
for (const entry of manifestFiles) {
|
|
60
|
+
if (!actualPaths.has(entry.path)) {
|
|
61
|
+
failures.push(`Missing file: ${entry.path}`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const actual = actualFiles.find((candidate) => candidate.path === entry.path);
|
|
65
|
+
if (!actual) {
|
|
66
|
+
failures.push(`Missing file: ${entry.path}`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (actual.sha256 !== entry.sha256) {
|
|
70
|
+
failures.push(`Checksum mismatch: ${entry.path}`);
|
|
71
|
+
}
|
|
72
|
+
if (actual.sizeBytes !== entry.sizeBytes) {
|
|
73
|
+
failures.push(`Size mismatch: ${entry.path}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (const actual of actualFiles) {
|
|
77
|
+
if (!manifestPaths.has(actual.path)) {
|
|
78
|
+
failures.push(`Unexpected file not covered by manifest: ${actual.path}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
ok: failures.length === 0,
|
|
83
|
+
manifest,
|
|
84
|
+
checkedFiles: actualFiles,
|
|
85
|
+
failures
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function stableStringify(value) {
|
|
89
|
+
return JSON.stringify(sortValue(value), null, 2);
|
|
90
|
+
}
|
|
91
|
+
function createAuditManifest(runId, generatedAt, generatedBy, files) {
|
|
92
|
+
const entries = files.map((file) => ({
|
|
93
|
+
path: normalizeAuditPath(file.path),
|
|
94
|
+
sha256: hashContent(file.content),
|
|
95
|
+
sizeBytes: Buffer.byteLength(file.content, "utf8")
|
|
96
|
+
}));
|
|
97
|
+
return {
|
|
98
|
+
runId,
|
|
99
|
+
generatedAt,
|
|
100
|
+
generatedBy,
|
|
101
|
+
files: entries,
|
|
102
|
+
manifestVersion: "h3.v1",
|
|
103
|
+
tamperEvident: true
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function buildAuditPackFiles(input) {
|
|
107
|
+
const { runId, runSource, truthFacts, treatyTimeline } = input;
|
|
108
|
+
const patchProofs = buildPatchProofs(runSource);
|
|
109
|
+
const driftReports = buildDriftReports(runSource);
|
|
110
|
+
const redFindings = buildRedFindings(runSource);
|
|
111
|
+
const hypothesisLedger = buildHypothesisLedger(runId, runSource);
|
|
112
|
+
return [
|
|
113
|
+
{
|
|
114
|
+
path: "patch-proofs/contract.json",
|
|
115
|
+
content: `${stableStringify(runSource.contract)}\n`
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
path: "patch-proofs/ledger.jsonl",
|
|
119
|
+
content: runSource.ledgerLines.length > 0 ? `${runSource.ledgerLines.join("\n")}\n` : ""
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
path: "patch-proofs/attempts.json",
|
|
123
|
+
content: `${stableStringify(patchProofs)}\n`
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
path: "drift-reports/drift-summary.json",
|
|
127
|
+
content: `${stableStringify(driftReports)}\n`
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
path: "truth-facts/truth-facts.json",
|
|
131
|
+
content: `${stableStringify({ runId, facts: truthFacts })}\n`
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
path: "treaty-timeline/treaty-timeline.json",
|
|
135
|
+
content: `${stableStringify({ runId, transitions: treatyTimeline })}\n`
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
path: "red-findings/red-findings.json",
|
|
139
|
+
content: `${stableStringify({ runId, findings: redFindings })}\n`
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
path: "hypothesis-ledger/hypothesis-ledger.json",
|
|
143
|
+
content: `${stableStringify(hypothesisLedger)}\n`
|
|
144
|
+
},
|
|
145
|
+
...collectAttemptFiles(runSource.attempts, "patch-proofs", [
|
|
146
|
+
"diff.patch",
|
|
147
|
+
"patch-decision.json",
|
|
148
|
+
"patch-score.json",
|
|
149
|
+
"final-semantic-verification.json",
|
|
150
|
+
"attempt-semantic-check.json"
|
|
151
|
+
]),
|
|
152
|
+
...collectAttemptFiles(runSource.attempts, "drift-reports", [
|
|
153
|
+
"grounding-scan.json",
|
|
154
|
+
"scope-surface.json",
|
|
155
|
+
"leash.json",
|
|
156
|
+
"rollback-outcome.json",
|
|
157
|
+
"rollback-boundary.json"
|
|
158
|
+
])
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
function buildPatchProofs(runSource) {
|
|
162
|
+
return {
|
|
163
|
+
attemptCount: runSource.attempts.length,
|
|
164
|
+
attempts: runSource.attempts.map((attempt) => ({
|
|
165
|
+
attempt: attempt.attemptLabel,
|
|
166
|
+
files: Object.keys(attempt.files).filter((file) => [
|
|
167
|
+
"diff.patch",
|
|
168
|
+
"patch-decision.json",
|
|
169
|
+
"patch-score.json",
|
|
170
|
+
"final-semantic-verification.json",
|
|
171
|
+
"attempt-semantic-check.json"
|
|
172
|
+
].includes(file))
|
|
173
|
+
}))
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function buildDriftReports(runSource) {
|
|
177
|
+
return {
|
|
178
|
+
state: runSource.state,
|
|
179
|
+
attemptCount: runSource.attempts.length,
|
|
180
|
+
attempts: runSource.attempts.map((attempt) => {
|
|
181
|
+
const grounding = parseOptionalJson(attempt.files["grounding-scan.json"]);
|
|
182
|
+
const leash = parseOptionalJson(attempt.files["leash.json"]);
|
|
183
|
+
return {
|
|
184
|
+
attempt: attempt.attemptLabel,
|
|
185
|
+
hasGroundingScan: attempt.files["grounding-scan.json"] !== undefined,
|
|
186
|
+
hasScopeSurface: attempt.files["scope-surface.json"] !== undefined,
|
|
187
|
+
hasLeash: attempt.files["leash.json"] !== undefined,
|
|
188
|
+
groundingViolations: Array.isArray(grounding?.violations) ? grounding.violations.length : 0,
|
|
189
|
+
safetyBlocked: typeof leash?.blocked === "boolean" ? leash.blocked : false
|
|
190
|
+
};
|
|
191
|
+
})
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function buildRedFindings(runSource) {
|
|
195
|
+
const findings = [];
|
|
196
|
+
for (const event of runSource.ledgerEvents) {
|
|
197
|
+
const kind = typeof event.kind === "string" ? event.kind : "";
|
|
198
|
+
if (kind.includes("violation") ||
|
|
199
|
+
kind.includes("discard") ||
|
|
200
|
+
kind.includes("escalat") ||
|
|
201
|
+
kind.includes("blocked")) {
|
|
202
|
+
findings.push({
|
|
203
|
+
source: "ledger",
|
|
204
|
+
kind,
|
|
205
|
+
payload: typeof event.payload === "object" && event.payload !== null ? event.payload : {}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
for (const attempt of runSource.attempts) {
|
|
210
|
+
const grounding = parseOptionalJson(attempt.files["grounding-scan.json"]);
|
|
211
|
+
if (Array.isArray(grounding?.violations) && grounding.violations.length > 0) {
|
|
212
|
+
findings.push({
|
|
213
|
+
source: attempt.attemptLabel,
|
|
214
|
+
kind: "grounding.violations_found",
|
|
215
|
+
violations: grounding.violations
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return findings;
|
|
220
|
+
}
|
|
221
|
+
function buildHypothesisLedger(runId, runSource) {
|
|
222
|
+
const task = typeof runSource.contract.task === "object" && runSource.contract.task !== null
|
|
223
|
+
? runSource.contract.task
|
|
224
|
+
: null;
|
|
225
|
+
return {
|
|
226
|
+
runId,
|
|
227
|
+
objective: (typeof runSource.contract.objective === "string" ? runSource.contract.objective : undefined) ??
|
|
228
|
+
(typeof task?.objective === "string" ? task.objective : undefined) ??
|
|
229
|
+
null,
|
|
230
|
+
verificationPlan: task?.verificationPlan ?? [],
|
|
231
|
+
eventKinds: runSource.ledgerEvents
|
|
232
|
+
.map((event) => (typeof event.kind === "string" ? event.kind : null))
|
|
233
|
+
.filter((value) => value !== null),
|
|
234
|
+
attempts: runSource.attempts.map((attempt) => ({
|
|
235
|
+
attempt: attempt.attemptLabel,
|
|
236
|
+
hasPatchDecision: attempt.files["patch-decision.json"] !== undefined,
|
|
237
|
+
hasPatchScore: attempt.files["patch-score.json"] !== undefined,
|
|
238
|
+
hasGroundingScan: attempt.files["grounding-scan.json"] !== undefined
|
|
239
|
+
}))
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function collectAttemptFiles(attempts, section, names) {
|
|
243
|
+
const files = [];
|
|
244
|
+
for (const attempt of attempts) {
|
|
245
|
+
for (const name of names) {
|
|
246
|
+
const content = attempt.files[name];
|
|
247
|
+
if (content === undefined) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
files.push({
|
|
251
|
+
path: `${section}/${attempt.attemptLabel}/${name}`,
|
|
252
|
+
content: ensureTrailingNewline(content)
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return files;
|
|
257
|
+
}
|
|
258
|
+
async function readRunAuditSource(runDir) {
|
|
259
|
+
const resolvedRunDir = resolve(runDir);
|
|
260
|
+
const contract = JSON.parse(await readFile(join(resolvedRunDir, "contract.json"), "utf8"));
|
|
261
|
+
const state = await readJsonIfExists(join(resolvedRunDir, "state.json"));
|
|
262
|
+
const ledgerPath = join(resolvedRunDir, "ledger.jsonl");
|
|
263
|
+
const ledgerRaw = await readFile(ledgerPath, "utf8").catch(() => "");
|
|
264
|
+
const ledgerLines = ledgerRaw.split(/\r?\n/u).filter((line) => line.length > 0);
|
|
265
|
+
const ledgerEvents = ledgerLines.map((line) => JSON.parse(line));
|
|
266
|
+
const artifactsRoot = join(resolvedRunDir, "artifacts");
|
|
267
|
+
const attemptEntries = await readdir(artifactsRoot, { withFileTypes: true }).catch(() => []);
|
|
268
|
+
const attempts = [];
|
|
269
|
+
for (const entry of attemptEntries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
270
|
+
if (!entry.isDirectory()) {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const attemptDir = join(artifactsRoot, entry.name);
|
|
274
|
+
const fileEntries = await readdir(attemptDir, { withFileTypes: true });
|
|
275
|
+
const files = {};
|
|
276
|
+
for (const fileEntry of fileEntries) {
|
|
277
|
+
if (!fileEntry.isFile()) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
const fileName = fileEntry.name;
|
|
281
|
+
files[fileName] = await readFile(join(attemptDir, fileName), "utf8");
|
|
282
|
+
}
|
|
283
|
+
attempts.push({
|
|
284
|
+
attemptLabel: entry.name,
|
|
285
|
+
files
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
contract,
|
|
290
|
+
state,
|
|
291
|
+
ledgerLines,
|
|
292
|
+
ledgerEvents,
|
|
293
|
+
attempts
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
async function collectAuditManifestEntries(packPath) {
|
|
297
|
+
const entries = [];
|
|
298
|
+
await collectFilesRecursive(packPath, packPath, entries);
|
|
299
|
+
return entries.sort((left, right) => left.path.localeCompare(right.path));
|
|
300
|
+
}
|
|
301
|
+
async function collectFilesRecursive(root, current, entries) {
|
|
302
|
+
const fileEntries = await readdir(current, { withFileTypes: true });
|
|
303
|
+
for (const entry of fileEntries) {
|
|
304
|
+
const fullPath = join(current, entry.name);
|
|
305
|
+
if (entry.isDirectory()) {
|
|
306
|
+
await collectFilesRecursive(root, fullPath, entries);
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (basename(fullPath) === "MANIFEST.json") {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
const content = await readFile(fullPath, "utf8");
|
|
313
|
+
const fileStat = await stat(fullPath);
|
|
314
|
+
entries.push({
|
|
315
|
+
path: normalizeAuditPath(relative(root, fullPath)),
|
|
316
|
+
sha256: hashContent(content),
|
|
317
|
+
sizeBytes: fileStat.size
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async function readJsonIfExists(pathname) {
|
|
322
|
+
try {
|
|
323
|
+
return JSON.parse(await readFile(pathname, "utf8"));
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function parseOptionalJson(content) {
|
|
330
|
+
if (!content) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
return JSON.parse(content);
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function hashContent(content) {
|
|
341
|
+
return crypto.createHash("sha256").update(content).digest("hex");
|
|
342
|
+
}
|
|
343
|
+
function normalizeAuditPath(pathname) {
|
|
344
|
+
return pathname.replace(/\\/gu, "/");
|
|
345
|
+
}
|
|
346
|
+
function ensureTrailingNewline(content) {
|
|
347
|
+
return content.endsWith("\n") ? content : `${content}\n`;
|
|
348
|
+
}
|
|
349
|
+
function sortValue(value) {
|
|
350
|
+
if (Array.isArray(value)) {
|
|
351
|
+
return value.map((entry) => sortValue(entry));
|
|
352
|
+
}
|
|
353
|
+
if (value && typeof value === "object") {
|
|
354
|
+
return Object.fromEntries(Object.entries(value)
|
|
355
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
356
|
+
.map(([key, entry]) => [key, sortValue(entry)]));
|
|
357
|
+
}
|
|
358
|
+
return value;
|
|
359
|
+
}
|
|
360
|
+
//# sourceMappingURL=audit.js.map
|