projscan 4.12.0 → 4.13.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/README.md +69 -11
- package/dist/cli/commands/prove.d.ts +3 -0
- package/dist/cli/commands/prove.js +298 -0
- package/dist/cli/commands/prove.js.map +1 -0
- package/dist/cli/commands/startMissionBundle.js +38 -0
- package/dist/cli/commands/startMissionBundle.js.map +1 -1
- package/dist/cli/registerCommands.js +2 -0
- package/dist/cli/registerCommands.js.map +1 -1
- package/dist/core/evidenceComment.js +31 -0
- package/dist/core/evidenceComment.js.map +1 -1
- package/dist/core/feedback.js +18 -0
- package/dist/core/feedback.js.map +1 -1
- package/dist/core/proofLedger.d.ts +8 -0
- package/dist/core/proofLedger.js +134 -0
- package/dist/core/proofLedger.js.map +1 -0
- package/dist/core/prove.d.ts +18 -0
- package/dist/core/prove.js +821 -0
- package/dist/core/prove.js.map +1 -0
- package/dist/core/releaseEvidence.js +48 -0
- package/dist/core/releaseEvidence.js.map +1 -1
- package/dist/core/simulate.js +109 -2
- package/dist/core/simulate.js.map +1 -1
- package/dist/mcp/toolCatalog.js +2 -0
- package/dist/mcp/toolCatalog.js.map +1 -1
- package/dist/mcp/tools/prove.d.ts +2 -0
- package/dist/mcp/tools/prove.js +93 -0
- package/dist/mcp/tools/prove.js.map +1 -0
- package/dist/projscan-sbom.cdx.json +6 -6
- package/dist/publicCore.d.ts +1 -0
- package/dist/publicCore.js +1 -0
- package/dist/publicCore.js.map +1 -1
- package/dist/tool-manifest.json +68 -3
- package/dist/types/dogfood.d.ts +4 -0
- package/dist/types/evidencePack.d.ts +13 -0
- package/dist/types/proofLedger.d.ts +30 -0
- package/dist/types/proofLedger.js +2 -0
- package/dist/types/proofLedger.js.map +1 -0
- package/dist/types/prove.d.ts +107 -0
- package/dist/types/prove.js +2 -0
- package/dist/types/prove.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/utils/formatSupport.d.ts +1 -0
- package/dist/utils/formatSupport.js +1 -0
- package/dist/utils/formatSupport.js.map +1 -1
- package/docs/GUIDE.md +35 -1
- package/docs/demos/projscan-4-1-demo.html +24 -24
- package/docs/projscan-mission-control.gif +0 -0
- package/docs/projscan-mission-control.png +0 -0
- package/docs/projscan-mission-proof.gif +0 -0
- package/docs/projscan-proof-router.png +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,9 +24,9 @@ Use projscan when an agent asks one of these questions:
|
|
|
24
24
|
- Which files should I read before changing this feature?
|
|
25
25
|
- Which proof commands should I run before handoff?
|
|
26
26
|
- Which risks need fixes, reviewer attention, or release sign-off?
|
|
27
|
-
-
|
|
27
|
+
- Which risk should I fix first?
|
|
28
28
|
|
|
29
|
-
projscan runs core scans on your machine. It respects `.gitignore`, keeps `.env` values out of scans unless you opt in, and exposes the same evidence through a CLI and a
|
|
29
|
+
projscan runs core scans on your machine. It respects `.gitignore`, keeps `.env` values out of scans unless you opt in, and exposes the same evidence through a CLI and a 48-tool MCP server. The language layer uses 11 AST adapters covering 12 named languages.
|
|
30
30
|
|
|
31
31
|
```text
|
|
32
32
|
Your agent / engineer
|
|
@@ -36,11 +36,14 @@ Your agent / engineer
|
|
|
36
36
|
+----------------------------------------------------------------+
|
|
37
37
|
| projscan (runs locally, source stays on this machine) |
|
|
38
38
|
| ------------------------------------------------------------ |
|
|
39
|
-
| Mission Control
|
|
40
|
-
| |
|
|
41
|
-
| |
|
|
42
|
-
| |
|
|
43
|
-
| |
|
|
39
|
+
| Mission Control -> assess Cards -> simulate risk -> prove |
|
|
40
|
+
| | | | |
|
|
41
|
+
| | | +- allowed files
|
|
42
|
+
| | | +- forbidden files
|
|
43
|
+
| | | +- proof receipt
|
|
44
|
+
| | +- bounded extraction |
|
|
45
|
+
| | +- regression test first |
|
|
46
|
+
| | +- leave unchanged |
|
|
44
47
|
| +- evidence strength |
|
|
45
48
|
| +- trust memory |
|
|
46
49
|
| +- AgentLoopKit handoff |
|
|
@@ -84,12 +87,27 @@ Use these three workflows before scanning the full command catalog.
|
|
|
84
87
|
projscan start --intent "what files do I need to change for auth?"
|
|
85
88
|
projscan start --intent "what should we build next?" # Routes to a before-edit implementation workplan
|
|
86
89
|
projscan understand --view change --intent "add auth token refresh" --format json
|
|
90
|
+
projscan prove --intent "is my agent allowed to change billing retry logic?"
|
|
87
91
|
projscan preflight --mode before_edit --format json
|
|
88
92
|
```
|
|
89
93
|
|
|
90
|
-
You get a cited change map, read-first files, likely touched files, blocked inputs, and a before-edit proof gate.
|
|
94
|
+
You get a cited change map, read-first files, likely touched files, blocked inputs, an executable Proof Contract, and a before-edit proof gate.
|
|
91
95
|
|
|
92
|
-
Success criteria: the agent can name the files to read first, the likely files to touch, and the proof
|
|
96
|
+
Success criteria: the agent can name the files to read first, the likely files to touch, the forbidden files to avoid, and the proof commands to run before editing.
|
|
97
|
+
|
|
98
|
+
### Before handing work to an agent
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
projscan prove --intent "is my agent allowed to change billing retry logic?" --save-contract .projscan/proof-contract.json
|
|
102
|
+
projscan prove --record-command "npm test -- tests/billing/retry.test.ts" --exit-code 0 --duration-ms 1842 --summary "billing retry tests passed"
|
|
103
|
+
projscan prove --changed --contract .projscan/proof-contract.json --format markdown
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
You get a Proof Contract before edits and a Proof Receipt after edits. The contract names allowed files, forbidden files, risky contracts, likely tests, missing regression-test evidence, proof commands, safe change shape, rollback, confidence, and reviewer guidance. The receipt checks the real working tree against that contract and classifies changed files as allowed production, expected tests, documentation, generated proof artifacts, config/security drift, forbidden touches, or unexpected production. It also reports proof replay status, risk delta, commit readiness, and a reviewer checklist.
|
|
107
|
+
|
|
108
|
+
Proof Replay records command, exit code, duration, changed-file fingerprint, redacted summary, and optional log path in `.projscan/proof-ledger.jsonl`. `prove --changed` marks proof as passed, missing, failed, partial, or stale. If the agent edits new files after proof ran, the receipt says the proof is stale before a reviewer reads the diff.
|
|
109
|
+
|
|
110
|
+
Success criteria: the reviewer sees whether the agent stayed inside the contract, whether the right proof ran, and whether that proof is still fresh.
|
|
93
111
|
|
|
94
112
|
### Before handoff or commit
|
|
95
113
|
|
|
@@ -173,6 +191,43 @@ npm run docs:screenshots
|
|
|
173
191
|
npm run docs:demos
|
|
174
192
|
```
|
|
175
193
|
|
|
194
|
+
## 4.13.0 Notes
|
|
195
|
+
|
|
196
|
+
4.13.0 ships Proof Replay for Executable Proof Contracts:
|
|
197
|
+
|
|
198
|
+
- `projscan prove --intent "<change>"` creates a local Proof Contract before
|
|
199
|
+
editing. It names allowed files, forbidden files, risky contracts, likely
|
|
200
|
+
tests, missing regression-test evidence, proof commands, rollback, confidence,
|
|
201
|
+
Trust Memory signals, evidence gaps, and reviewer guidance. Noisy feedback or
|
|
202
|
+
missing-signal feedback lowers the confidence reason instead of hiding it.
|
|
203
|
+
- `projscan prove --changed` validates the current working tree against a saved
|
|
204
|
+
contract and emits a Proof Receipt for PRs, agents, and CI. Its changed-file
|
|
205
|
+
classes separate allowed production edits, expected tests, documentation,
|
|
206
|
+
generated proof artifacts, config/security drift, forbidden touches, and
|
|
207
|
+
unexpected production changes before giving a copyable reviewer decision.
|
|
208
|
+
- `projscan prove --record-command "<command>" --exit-code <code>` appends a
|
|
209
|
+
local Proof Ledger row with command, duration, changed-file fingerprint,
|
|
210
|
+
redacted output summary, and optional log path. `prove --changed` replays
|
|
211
|
+
those rows and reports passed, missing, failed, partial, or stale proof.
|
|
212
|
+
- Saved Mission Control bundles append Proof Ledger rows while `mission.sh`
|
|
213
|
+
runs the existing proof queue. The script still writes proof logs and status
|
|
214
|
+
JSONL for humans.
|
|
215
|
+
- `projscan evidence-pack --pr-comment` includes the latest Proof Receipt
|
|
216
|
+
summary when a contract and ledger are available, so PR comments show proof
|
|
217
|
+
status, reviewer decision, scope, stale proof, failed proof, and the replay
|
|
218
|
+
command.
|
|
219
|
+
- MCP now includes `projscan_prove`, bringing the MCP surface to 48 tools.
|
|
220
|
+
|
|
221
|
+
## 4.12.1 Notes
|
|
222
|
+
|
|
223
|
+
4.12.1 is the simulator precision patch for the Proof Cards V2 release:
|
|
224
|
+
|
|
225
|
+
- `projscan simulate --plan` no longer treats one-letter filenames such as
|
|
226
|
+
`s.ts` as matches for broad plan text.
|
|
227
|
+
- Simulator term-overlap evidence now filters generated agent/cache paths and
|
|
228
|
+
weak planning terms, so logs or proof artifacts do not become likely files
|
|
229
|
+
when the plan names no concrete repo target.
|
|
230
|
+
|
|
176
231
|
## 4.12.0 Notes
|
|
177
232
|
|
|
178
233
|
4.12.0 is the Proof Cards V2 daily trust loop release:
|
|
@@ -245,6 +300,8 @@ npx -y projscan mcp --watch
|
|
|
245
300
|
| What should I fix first? | `projscan bug-hunt --format json` |
|
|
246
301
|
| What is risky and worth fixing this week? | `projscan assess --goal "make this repo safer to ship this week"` |
|
|
247
302
|
| Is this refactor worth doing? | `projscan simulate --plan "split bugHunt.ts into ranking, evidence, and output modules"` |
|
|
303
|
+
| Is my agent allowed to make this change? | `projscan prove --intent "is my agent allowed to change billing retry logic?"` |
|
|
304
|
+
| Did the change stay inside scope? | `projscan prove --changed --contract .projscan/proof-contract.json --format markdown` |
|
|
248
305
|
| Which files have high risk and low coverage? | `projscan coverage --format json` |
|
|
249
306
|
| What should my agent do next? | `projscan workplan --format json` |
|
|
250
307
|
| Which proof belongs in this PR? | `projscan evidence-pack --pr-comment` |
|
|
@@ -259,6 +316,7 @@ npx -y projscan mcp --watch
|
|
|
259
316
|
| `projscan preflight` | proceed, caution, or block gate for edit, commit, or merge |
|
|
260
317
|
| `projscan assess` | proof-first assessment with Proof Cards, risk delta, and fix-first guidance |
|
|
261
318
|
| `projscan simulate` | risk delta simulator for a proposed change plan before editing |
|
|
319
|
+
| `projscan prove` | executable Proof Contracts and reviewer-ready Proof Receipts |
|
|
262
320
|
| `projscan evidence-pack` | PR-ready proof with risks, owners, and next commands |
|
|
263
321
|
| `projscan bug-hunt` | ranked fix queue from health, hotspots, session, and preflight evidence |
|
|
264
322
|
| `projscan workplan` | ordered agent tasks with proof and handoff text |
|
|
@@ -448,7 +506,7 @@ Supply-chain scanners may flag package strings or APIs used by `git`, `npm audit
|
|
|
448
506
|
|
|
449
507
|
## Install Notes
|
|
450
508
|
|
|
451
|
-
`projscan@4.
|
|
509
|
+
`projscan@4.13.0` has seven direct runtime dependencies:
|
|
452
510
|
|
|
453
511
|
- `@babel/parser`
|
|
454
512
|
- `@babel/types`
|
|
@@ -458,7 +516,7 @@ Supply-chain scanners may flag package strings or APIs used by `git`, `npm audit
|
|
|
458
516
|
- `ora`
|
|
459
517
|
- `web-tree-sitter`
|
|
460
518
|
|
|
461
|
-
If npm prints `allow-scripts` warnings during a global install, check which package names it lists. projscan core does not need `node-gyp` grammar builds at runtime in 4.
|
|
519
|
+
If npm prints `allow-scripts` warnings during a global install, check which package names it lists. projscan core does not need `node-gyp` grammar builds at runtime in 4.13.0. Open an issue with the warning text if npm reports install scripts from `projscan@latest`, or run `projscan feedback intake --text "<warning text>" --format json` to turn it into a focused setup-trust task.
|
|
462
520
|
|
|
463
521
|
The grammar packages are build-time sources, not global-install dependencies. Published grammar assets include `tree-sitter-python.wasm` and `tree-sitter-c_sharp.wasm`.
|
|
464
522
|
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { assertFormatSupported, getRootPath, maybeCompactBanner, program, setupLogLevel, } from '../_shared.js';
|
|
3
|
+
import { computeProve } from '../../core/prove.js';
|
|
4
|
+
export function registerProve() {
|
|
5
|
+
program
|
|
6
|
+
.command('prove')
|
|
7
|
+
.description('Create or validate an executable Proof Contract for a change')
|
|
8
|
+
.option('--intent <text>', 'plain-language change intent to constrain before editing')
|
|
9
|
+
.option('--changed', 'validate the current working tree against a Proof Contract')
|
|
10
|
+
.option('--contract <path>', 'Proof Contract JSON path for --changed')
|
|
11
|
+
.option('--save-contract <path>', 'write the generated Proof Contract JSON in --intent mode')
|
|
12
|
+
.option('--max-files <count>', 'maximum likely touched files to include', parsePositiveInt)
|
|
13
|
+
.option('--feedback <path>', 'local projscan feedback artifact to apply as trust memory')
|
|
14
|
+
.option('--base-ref <ref>', 'base ref for changed-file detection')
|
|
15
|
+
.option('--record-command <command>', 'record a proof command outcome without executing it')
|
|
16
|
+
.option('--exit-code <code>', 'exit code for --record-command', parseExitCode)
|
|
17
|
+
.option('--duration-ms <ms>', 'duration in milliseconds for --record-command', parseDurationMs)
|
|
18
|
+
.option('--summary <text>', 'safe proof output summary for --record-command')
|
|
19
|
+
.option('--log <path>', 'redacted proof log path for --record-command')
|
|
20
|
+
.option('--ledger <path>', 'proof ledger JSONL path')
|
|
21
|
+
.action(async (cmdOpts) => {
|
|
22
|
+
setupLogLevel();
|
|
23
|
+
maybeCompactBanner();
|
|
24
|
+
const format = assertFormatSupported('prove');
|
|
25
|
+
try {
|
|
26
|
+
const selectedModes = [cmdOpts.intent, cmdOpts.changed, cmdOpts.recordCommand].filter(Boolean);
|
|
27
|
+
if (selectedModes.length > 1) {
|
|
28
|
+
throw new Error('prove accepts either --intent or --changed or --record-command');
|
|
29
|
+
}
|
|
30
|
+
if (selectedModes.length === 0) {
|
|
31
|
+
throw new Error('prove requires --intent "<change>", --changed, or --record-command');
|
|
32
|
+
}
|
|
33
|
+
const report = await computeProve(getRootPath(), {
|
|
34
|
+
intent: cmdOpts.intent,
|
|
35
|
+
changed: Boolean(cmdOpts.changed),
|
|
36
|
+
contractPath: cmdOpts.contract,
|
|
37
|
+
saveContractPath: cmdOpts.saveContract,
|
|
38
|
+
maxFiles: cmdOpts.maxFiles,
|
|
39
|
+
feedbackPath: cmdOpts.feedback,
|
|
40
|
+
baseRef: cmdOpts.baseRef,
|
|
41
|
+
ledgerPath: cmdOpts.ledger,
|
|
42
|
+
recordCommand: cmdOpts.recordCommand,
|
|
43
|
+
exitCode: cmdOpts.exitCode,
|
|
44
|
+
durationMs: cmdOpts.durationMs,
|
|
45
|
+
summary: cmdOpts.summary,
|
|
46
|
+
logPath: cmdOpts.log,
|
|
47
|
+
});
|
|
48
|
+
if (format === 'json') {
|
|
49
|
+
console.log(JSON.stringify(report, null, 2));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (format === 'markdown') {
|
|
53
|
+
console.log(renderProveMarkdown(report));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
printProveConsole(report);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function printProveConsole(report) {
|
|
65
|
+
const color = report.verdict === 'blocked'
|
|
66
|
+
? chalk.red
|
|
67
|
+
: report.verdict === 'needs-review'
|
|
68
|
+
? chalk.yellow
|
|
69
|
+
: chalk.green;
|
|
70
|
+
console.log(color(`Projscan Prove: ${report.verdict}`));
|
|
71
|
+
console.log(report.summary);
|
|
72
|
+
console.log('');
|
|
73
|
+
if (report.contract && report.mode === 'intent') {
|
|
74
|
+
printContractConsole(report.contract);
|
|
75
|
+
}
|
|
76
|
+
if (report.ledgerRecord) {
|
|
77
|
+
console.log(chalk.bold('Recorded Proof'));
|
|
78
|
+
console.log(`- ${report.ledgerRecord.status}: ${report.ledgerRecord.command}`);
|
|
79
|
+
console.log(`- ${report.ledgerRecord.changedFiles.length} changed file(s) fingerprinted`);
|
|
80
|
+
}
|
|
81
|
+
if (report.receipt) {
|
|
82
|
+
printReceiptConsole(report.receipt);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function printContractConsole(contract) {
|
|
86
|
+
console.log(chalk.bold('Allowed Files'));
|
|
87
|
+
printList(contract.allowedFiles, 'No concrete allowed files inferred');
|
|
88
|
+
console.log('');
|
|
89
|
+
console.log(chalk.bold('Forbidden Files'));
|
|
90
|
+
printList(contract.forbiddenFiles.slice(0, 8), 'No forbidden files inferred');
|
|
91
|
+
console.log('');
|
|
92
|
+
console.log(chalk.bold('Proof Commands'));
|
|
93
|
+
printList(contract.proofCommands.slice(0, 8), 'No proof commands inferred');
|
|
94
|
+
}
|
|
95
|
+
function printReceiptConsole(receipt) {
|
|
96
|
+
console.log(chalk.bold('Scope Decision'));
|
|
97
|
+
console.log(`- ${receipt.scope.status}`);
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log(chalk.bold('Changed Files'));
|
|
100
|
+
printList(receipt.scope.changedFiles, 'No changed files detected');
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log(chalk.bold('Allowed production'));
|
|
103
|
+
printList(receipt.scope.allowedProduction, 'No allowed production files touched');
|
|
104
|
+
console.log('');
|
|
105
|
+
console.log(chalk.bold('Expected tests'));
|
|
106
|
+
printList(receipt.scope.expectedTests, 'No expected tests touched');
|
|
107
|
+
if (receipt.scope.forbiddenTouched.length > 0) {
|
|
108
|
+
console.log('');
|
|
109
|
+
console.log(chalk.bold('Forbidden Touched'));
|
|
110
|
+
printList(receipt.scope.forbiddenTouched, 'No forbidden files touched');
|
|
111
|
+
}
|
|
112
|
+
console.log('');
|
|
113
|
+
console.log(chalk.bold('Proof Commands'));
|
|
114
|
+
printList(receipt.proofStatus.commandsRequired.slice(0, 8), 'No proof commands required');
|
|
115
|
+
console.log('');
|
|
116
|
+
console.log(chalk.bold('Proof Replay'));
|
|
117
|
+
console.log(`- status: ${receipt.proofStatus.status}`);
|
|
118
|
+
console.log(`- reviewer decision: ${receipt.reviewerDecision}`);
|
|
119
|
+
}
|
|
120
|
+
export function renderProveMarkdown(report) {
|
|
121
|
+
return report.receipt ? renderReceiptMarkdown(report, report.receipt) : renderContractMarkdown(report);
|
|
122
|
+
}
|
|
123
|
+
function renderContractMarkdown(report) {
|
|
124
|
+
const contract = report.contract;
|
|
125
|
+
const lines = ['# Projscan Proof Contract', ''];
|
|
126
|
+
lines.push(`- **Verdict:** ${report.verdict}`);
|
|
127
|
+
lines.push(`- **Summary:** ${report.summary}`);
|
|
128
|
+
if (!contract)
|
|
129
|
+
return lines.join('\n');
|
|
130
|
+
lines.push(`- **Intent:** ${contract.intent}`);
|
|
131
|
+
lines.push(`- **Confidence:** ${contract.confidence}`);
|
|
132
|
+
lines.push(`- **Evidence strength:** ${contract.evidenceStrength.level} (${contract.evidenceStrength.score})`);
|
|
133
|
+
lines.push('');
|
|
134
|
+
lines.push('## Allowed Files');
|
|
135
|
+
pushList(lines, contract.allowedFiles, 'No concrete allowed files inferred.');
|
|
136
|
+
lines.push('');
|
|
137
|
+
lines.push('## Forbidden Files');
|
|
138
|
+
pushList(lines, contract.forbiddenFiles, 'No forbidden files inferred.');
|
|
139
|
+
lines.push('');
|
|
140
|
+
lines.push('## Risky Contracts');
|
|
141
|
+
pushList(lines, contract.riskyContracts, 'No public contract inferred.');
|
|
142
|
+
lines.push('');
|
|
143
|
+
lines.push('## Likely Tests');
|
|
144
|
+
pushList(lines, contract.likelyTests, 'Add or identify a regression test first.');
|
|
145
|
+
lines.push('');
|
|
146
|
+
lines.push('## Proof Commands');
|
|
147
|
+
pushCodeList(lines, contract.proofCommands);
|
|
148
|
+
lines.push('');
|
|
149
|
+
lines.push('## Reviewer Guidance');
|
|
150
|
+
lines.push(contract.reviewerGuidance);
|
|
151
|
+
return lines.join('\n');
|
|
152
|
+
}
|
|
153
|
+
function renderReceiptMarkdown(report, receipt) {
|
|
154
|
+
const lines = ['# Projscan Proof Receipt', ''];
|
|
155
|
+
lines.push(`- **Verdict:** ${report.verdict}`);
|
|
156
|
+
lines.push(`- **Summary:** ${receipt.summary}`);
|
|
157
|
+
lines.push(`- **Commit readiness:** ${receipt.commitReadiness}`);
|
|
158
|
+
lines.push(`- **Scope:** ${receipt.scope.status}`);
|
|
159
|
+
lines.push(`- **Proof status:** ${receipt.proofStatus.status}`);
|
|
160
|
+
lines.push(`- **Reviewer decision:** ${receipt.reviewerDecision}`);
|
|
161
|
+
lines.push('');
|
|
162
|
+
lines.push('## Scope Decision');
|
|
163
|
+
lines.push(`- **Status:** ${receipt.scope.status}`);
|
|
164
|
+
lines.push(`- **Allowed production:** ${receipt.scope.allowedProduction.length}`);
|
|
165
|
+
lines.push(`- **Expected tests:** ${receipt.scope.expectedTests.length}`);
|
|
166
|
+
lines.push(`- **Unexpected production:** ${receipt.scope.unexpectedProduction.length}`);
|
|
167
|
+
lines.push(`- **Forbidden touched:** ${receipt.scope.forbiddenTouched.length}`);
|
|
168
|
+
lines.push('');
|
|
169
|
+
lines.push('## Changed File Classes');
|
|
170
|
+
lines.push('');
|
|
171
|
+
lines.push('### Allowed production');
|
|
172
|
+
pushList(lines, receipt.scope.allowedProduction, 'No allowed production files touched.');
|
|
173
|
+
lines.push('');
|
|
174
|
+
lines.push('### Expected tests');
|
|
175
|
+
pushList(lines, receipt.scope.expectedTests, 'No expected tests touched.');
|
|
176
|
+
lines.push('');
|
|
177
|
+
lines.push('### Unexpected production');
|
|
178
|
+
pushList(lines, receipt.scope.unexpectedProduction, 'No unexpected production files touched.');
|
|
179
|
+
lines.push('');
|
|
180
|
+
lines.push('### Config and security');
|
|
181
|
+
pushList(lines, unique([...receipt.scope.configTouched, ...receipt.scope.securitySensitiveTouched]), 'No config or security-sensitive files touched.');
|
|
182
|
+
lines.push('');
|
|
183
|
+
lines.push('### Documentation and generated artifacts');
|
|
184
|
+
pushList(lines, unique([...receipt.scope.documentationTouched, ...receipt.scope.generatedTouched]), 'No documentation or generated artifacts touched.');
|
|
185
|
+
lines.push('');
|
|
186
|
+
lines.push('## Changed Files');
|
|
187
|
+
pushList(lines, receipt.scope.changedFiles, 'No changed files detected.');
|
|
188
|
+
lines.push('');
|
|
189
|
+
lines.push('## Forbidden Touched');
|
|
190
|
+
pushList(lines, receipt.scope.forbiddenTouched, 'No forbidden files touched.');
|
|
191
|
+
lines.push('');
|
|
192
|
+
lines.push('## Outside Allowed Scope');
|
|
193
|
+
pushList(lines, receipt.scope.outsideAllowed, 'No changed files outside allowed scope.');
|
|
194
|
+
lines.push('');
|
|
195
|
+
lines.push('## Proof Commands');
|
|
196
|
+
pushCodeList(lines, receipt.proofStatus.commandsRequired);
|
|
197
|
+
lines.push('');
|
|
198
|
+
lines.push('## Proof Replay');
|
|
199
|
+
lines.push(`- **Proof status:** ${receipt.proofStatus.status}`);
|
|
200
|
+
lines.push(`- **Reviewer decision:** ${receipt.reviewerDecision}`);
|
|
201
|
+
lines.push(`- **Risk delta:** ${receipt.riskDeltaDirection} (${receipt.riskDelta.delta})`);
|
|
202
|
+
lines.push(`- **Commands required:** ${receipt.proofStatus.commandsRequired.length}`);
|
|
203
|
+
lines.push(`- **Commands recorded:** ${receipt.proofStatus.commandsRun.length}`);
|
|
204
|
+
lines.push('');
|
|
205
|
+
lines.push('### Command Evidence');
|
|
206
|
+
pushCommandEvidence(lines, receipt.proofStatus.commandEvidence);
|
|
207
|
+
lines.push('');
|
|
208
|
+
lines.push('### Missing Commands');
|
|
209
|
+
pushCodeList(lines, receipt.proofStatus.missingCommands);
|
|
210
|
+
lines.push('');
|
|
211
|
+
lines.push('### Failed Commands');
|
|
212
|
+
pushCodeList(lines, receipt.proofStatus.failedCommands);
|
|
213
|
+
lines.push('');
|
|
214
|
+
lines.push('### Stale Commands');
|
|
215
|
+
pushCodeList(lines, receipt.proofStatus.staleCommands);
|
|
216
|
+
lines.push('');
|
|
217
|
+
lines.push('## Evidence Gaps');
|
|
218
|
+
pushList(lines, receipt.evidenceGaps, 'No evidence gaps reported.');
|
|
219
|
+
lines.push('');
|
|
220
|
+
lines.push('## Reviewer Guidance');
|
|
221
|
+
lines.push(receipt.reviewerGuidance);
|
|
222
|
+
lines.push('');
|
|
223
|
+
lines.push('## Reviewer Checklist');
|
|
224
|
+
lines.push('- [ ] Confirm unexpected production/config/security files are intentional or removed.');
|
|
225
|
+
lines.push('- [ ] Confirm expected tests or a documented regression-test gap cover the change.');
|
|
226
|
+
lines.push('- [ ] Run every required proof command before approval.');
|
|
227
|
+
lines.push('- [ ] Confirm new risks and evidence gaps are acceptable for this commit.');
|
|
228
|
+
lines.push('');
|
|
229
|
+
lines.push('## Copyable Decision');
|
|
230
|
+
lines.push(`projscan prove: ${receipt.commitReadiness} (${receipt.scope.status}); proof ${receipt.proofStatus.status}; reviewer decision ${receipt.reviewerDecision}.`);
|
|
231
|
+
return lines.join('\n');
|
|
232
|
+
}
|
|
233
|
+
function printList(values, empty) {
|
|
234
|
+
if (values.length === 0) {
|
|
235
|
+
console.log(`- ${empty}`);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
for (const value of values)
|
|
239
|
+
console.log(`- ${value}`);
|
|
240
|
+
}
|
|
241
|
+
function pushList(lines, values, empty) {
|
|
242
|
+
if (values.length === 0) {
|
|
243
|
+
lines.push(`- ${empty}`);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
for (const value of values)
|
|
247
|
+
lines.push(`- ${value}`);
|
|
248
|
+
}
|
|
249
|
+
function pushCodeList(lines, values) {
|
|
250
|
+
if (values.length === 0) {
|
|
251
|
+
lines.push('- No proof commands required.');
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
for (const value of values)
|
|
255
|
+
lines.push(`- \`${value}\``);
|
|
256
|
+
}
|
|
257
|
+
function pushCommandEvidence(lines, values) {
|
|
258
|
+
if (values.length === 0) {
|
|
259
|
+
lines.push('- No proof command evidence recorded.');
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
for (const value of values)
|
|
263
|
+
lines.push(formatCommandEvidence(value));
|
|
264
|
+
}
|
|
265
|
+
function formatCommandEvidence(value) {
|
|
266
|
+
const state = value.fresh ? 'fresh' : value.staleReason ? 'stale' : value.status;
|
|
267
|
+
const exit = typeof value.exitCode === 'number' ? ` exit ${value.exitCode}` : ' no exit code';
|
|
268
|
+
const duration = typeof value.durationMs === 'number' ? `, ${value.durationMs}ms` : '';
|
|
269
|
+
const log = value.logPath ? `, log ${value.logPath}` : '';
|
|
270
|
+
const summary = value.outputSummary ? ` - ${value.outputSummary}` : '';
|
|
271
|
+
const stale = value.staleReason ? ` (${value.staleReason})` : '';
|
|
272
|
+
return `- **${value.status} ${state}:** \`${value.command}\` (${exit}${duration}${log})${stale}${summary}`;
|
|
273
|
+
}
|
|
274
|
+
function unique(values) {
|
|
275
|
+
return [...new Set(values)];
|
|
276
|
+
}
|
|
277
|
+
function parsePositiveInt(value) {
|
|
278
|
+
const parsed = Number.parseInt(value, 10);
|
|
279
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
280
|
+
throw new Error('value must be a positive integer');
|
|
281
|
+
}
|
|
282
|
+
return parsed;
|
|
283
|
+
}
|
|
284
|
+
function parseExitCode(value) {
|
|
285
|
+
const parsed = Number(value);
|
|
286
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
287
|
+
throw new Error('exit code must be a non-negative integer');
|
|
288
|
+
}
|
|
289
|
+
return parsed;
|
|
290
|
+
}
|
|
291
|
+
function parseDurationMs(value) {
|
|
292
|
+
const parsed = Number(value);
|
|
293
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
294
|
+
throw new Error('duration-ms must be a non-negative number');
|
|
295
|
+
}
|
|
296
|
+
return parsed;
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=prove.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prove.js","sourceRoot":"","sources":["../../../src/cli/commands/prove.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EACL,qBAAqB,EACrB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,UAAU,aAAa;IAC3B,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,8DAA8D,CAAC;SAC3E,MAAM,CAAC,iBAAiB,EAAE,0DAA0D,CAAC;SACrF,MAAM,CAAC,WAAW,EAAE,4DAA4D,CAAC;SACjF,MAAM,CAAC,mBAAmB,EAAE,wCAAwC,CAAC;SACrE,MAAM,CAAC,wBAAwB,EAAE,0DAA0D,CAAC;SAC5F,MAAM,CAAC,qBAAqB,EAAE,yCAAyC,EAAE,gBAAgB,CAAC;SAC1F,MAAM,CAAC,mBAAmB,EAAE,2DAA2D,CAAC;SACxF,MAAM,CAAC,kBAAkB,EAAE,qCAAqC,CAAC;SACjE,MAAM,CAAC,4BAA4B,EAAE,qDAAqD,CAAC;SAC3F,MAAM,CAAC,oBAAoB,EAAE,gCAAgC,EAAE,aAAa,CAAC;SAC7E,MAAM,CAAC,oBAAoB,EAAE,+CAA+C,EAAE,eAAe,CAAC;SAC9F,MAAM,CAAC,kBAAkB,EAAE,gDAAgD,CAAC;SAC5E,MAAM,CAAC,cAAc,EAAE,8CAA8C,CAAC;SACtE,MAAM,CAAC,iBAAiB,EAAE,yBAAyB,CAAC;SACpD,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,aAAa,EAAE,CAAC;QAChB,kBAAkB,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;QAE9C,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC/F,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;YACpF,CAAC;YACD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;YACxF,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,WAAW,EAAE,EAAE;gBAC/C,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;gBACjC,YAAY,EAAE,OAAO,CAAC,QAAQ;gBAC9B,gBAAgB,EAAE,OAAO,CAAC,YAAY;gBACtC,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,YAAY,EAAE,OAAO,CAAC,QAAQ;gBAC9B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,UAAU,EAAE,OAAO,CAAC,MAAM;gBAC1B,aAAa,EAAE,OAAO,CAAC,aAAa;gBACpC,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,OAAO,EAAE,OAAO,CAAC,GAAG;aACrB,CAAC,CAAC;YAEH,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC7C,OAAO;YACT,CAAC;YACD,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC;gBACzC,OAAO;YACT,CAAC;YACD,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAmB;IAC5C,MAAM,KAAK,GACT,MAAM,CAAC,OAAO,KAAK,SAAS;QAC1B,CAAC,CAAC,KAAK,CAAC,GAAG;QACX,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,cAAc;YACjC,CAAC,CAAC,KAAK,CAAC,MAAM;YACd,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,mBAAmB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAChD,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,YAAY,CAAC,MAAM,KAAK,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/E,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,MAAM,gCAAgC,CAAC,CAAC;IAC5F,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,QAAuB;IACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;IACzC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,oCAAoC,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC3C,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,6BAA6B,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC1C,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAqB;IAChD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;IACzC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,2BAA2B,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAC9C,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,qCAAqC,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC1C,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,2BAA2B,CAAC,CAAC;IACpE,IAAI,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAC7C,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,4BAA4B,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC1C,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,aAAa,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,wBAAwB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;AACzG,CAAC;AAED,SAAS,sBAAsB,CAAC,MAAmB;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,MAAM,KAAK,GAAa,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;IAC1D,KAAK,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,KAAK,CAAC,IAAI,CAAC,iBAAiB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,qBAAqB,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,4BAA4B,QAAQ,CAAC,gBAAgB,CAAC,KAAK,KAAK,QAAQ,CAAC,gBAAgB,CAAC,KAAK,GAAG,CAAC,CAAC;IAC/G,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,YAAY,EAAE,qCAAqC,CAAC,CAAC;IAC9E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,EAAE,8BAA8B,CAAC,CAAC;IACzE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,EAAE,8BAA8B,CAAC,CAAC;IACzE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,EAAE,0CAA0C,CAAC,CAAC;IAClF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAChC,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;IAC5C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACtC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,qBAAqB,CAAC,MAAmB,EAAE,OAAqB;IACvE,MAAM,KAAK,GAAa,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC;IACzD,KAAK,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,kBAAkB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAChD,KAAK,CAAC,IAAI,CAAC,2BAA2B,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACjE,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACnD,KAAK,CAAC,IAAI,CAAC,uBAAuB,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,4BAA4B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACnE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAChC,KAAK,CAAC,IAAI,CAAC,iBAAiB,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACpD,KAAK,CAAC,IAAI,CAAC,6BAA6B,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC;IAClF,KAAK,CAAC,IAAI,CAAC,yBAAyB,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1E,KAAK,CAAC,IAAI,CAAC,gCAAgC,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,MAAM,EAAE,CAAC,CAAC;IACxF,KAAK,CAAC,IAAI,CAAC,4BAA4B,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC;IAChF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACtC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,sCAAsC,CAAC,CAAC;IACzF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,4BAA4B,CAAC,CAAC;IAC3E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,yCAAyC,CAAC,CAAC;IAC/F,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACtC,QAAQ,CACN,KAAK,EACL,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,EACnF,gDAAgD,CACjD,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IACxD,QAAQ,CACN,KAAK,EACL,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,EAClF,kDAAkD,CACnD,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,4BAA4B,CAAC,CAAC;IAC1E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,6BAA6B,CAAC,CAAC;IAC/E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,yCAAyC,CAAC,CAAC;IACzF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAChC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAC1D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC9B,KAAK,CAAC,IAAI,CAAC,uBAAuB,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,4BAA4B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACnE,KAAK,CAAC,IAAI,CAAC,qBAAqB,OAAO,CAAC,kBAAkB,KAAK,OAAO,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC;IAC3F,KAAK,CAAC,IAAI,CAAC,4BAA4B,OAAO,CAAC,WAAW,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC;IACtF,KAAK,CAAC,IAAI,CAAC,4BAA4B,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IACjF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnC,mBAAmB,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IACzD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAClC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IACxD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACjC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,EAAE,4BAA4B,CAAC,CAAC;IACpE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACrC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,CAAC,uFAAuF,CAAC,CAAC;IACpG,KAAK,CAAC,IAAI,CAAC,oFAAoF,CAAC,CAAC;IACjG,KAAK,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;IACtE,KAAK,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;IACxF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnC,KAAK,CAAC,IAAI,CACR,mBAAmB,OAAO,CAAC,eAAe,KAAK,OAAO,CAAC,KAAK,CAAC,MAAM,YAAY,OAAO,CAAC,WAAW,CAAC,MAAM,uBAAuB,OAAO,CAAC,gBAAgB,GAAG,CAC5J,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,SAAS,CAAC,MAAgB,EAAE,KAAa;IAChD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;QAC1B,OAAO;IACT,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAe,EAAE,MAAgB,EAAE,KAAa;IAChE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;QACzB,OAAO;IACT,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,YAAY,CAAC,KAAe,EAAE,MAAgB;IACrD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAe,EAAE,MAAsD;IAClG,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QACpD,OAAO;IACT,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,qBAAqB,CAAC,KAA6D;IAC1F,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IACjF,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;IAC9F,MAAM,QAAQ,GAAG,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACvF,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,MAAM,OAAO,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,OAAO,OAAO,KAAK,CAAC,MAAM,IAAI,KAAK,SAAS,KAAK,CAAC,OAAO,OAAO,IAAI,GAAG,QAAQ,GAAG,GAAG,IAAI,KAAK,GAAG,OAAO,EAAE,CAAC;AAC7G,CAAC;AAED,SAAS,MAAM,CAAI,MAAW;IAC5B,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -115,13 +115,16 @@ function missionUnsafeCommandBlock() {
|
|
|
115
115
|
function missionProofLogSetup(report) {
|
|
116
116
|
return [
|
|
117
117
|
'MISSION_DIR=$(CDPATH= cd "$(dirname "$0")" && pwd)',
|
|
118
|
+
'PROJSCAN_ROOT=$(git -C "$MISSION_DIR" rev-parse --show-toplevel 2>/dev/null || pwd)',
|
|
118
119
|
'PROOF_LOG_DIR="${MISSION_DIR}/proof-logs"',
|
|
119
120
|
'PROOF_STATUS_FILE="${PROOF_LOG_DIR}/status.jsonl"',
|
|
120
121
|
'PROOF_REPORT_FILE="${PROOF_LOG_DIR}/run-report.md"',
|
|
121
122
|
'PROOF_SUMMARY_FILE="${PROOF_LOG_DIR}/summary.json"',
|
|
123
|
+
'PROOF_LEDGER_FILE="${PROJSCAN_ROOT}/.projscan/proof-ledger.jsonl"',
|
|
122
124
|
'mkdir -p "$PROOF_LOG_DIR"',
|
|
123
125
|
': > "$PROOF_STATUS_FILE"',
|
|
124
126
|
': > "$PROOF_REPORT_FILE"',
|
|
127
|
+
...scriptAppendProofLedgerFunction(),
|
|
125
128
|
...scriptInitRunReport(report),
|
|
126
129
|
scriptWriteSummaryJson('running'),
|
|
127
130
|
scriptPrintExpanded('Proof logs: ${PROOF_LOG_DIR}'),
|
|
@@ -523,6 +526,7 @@ function scriptCommandBlock(label, command, logTarget) {
|
|
|
523
526
|
'status=$?',
|
|
524
527
|
'set -e',
|
|
525
528
|
scriptAppendStatusJsonl(logTarget.id, label, logTarget.logName, command),
|
|
529
|
+
scriptAppendProofLedgerJsonl(logTarget.id, label, logTarget.logName, command),
|
|
526
530
|
scriptAppendReportRow(logTarget.id, label, logTarget.logName),
|
|
527
531
|
'if [ "$status" -ne 0 ]; then',
|
|
528
532
|
` ${scriptPrintError(`Command failed. See proof-logs/${logTarget.logName}.`)}`,
|
|
@@ -549,6 +553,40 @@ function scriptAppendStatusJsonl(id, label, logName, command) {
|
|
|
549
553
|
}).replace(/}$/, ',"exitCode":');
|
|
550
554
|
return `printf '%s%s%s\\n' ${shellQuote(prefix)} "$status" '}' >> "$PROOF_STATUS_FILE"`;
|
|
551
555
|
}
|
|
556
|
+
function scriptAppendProofLedgerFunction() {
|
|
557
|
+
return [
|
|
558
|
+
'append_proof_ledger_row() {',
|
|
559
|
+
' mkdir -p "$(dirname "$PROOF_LEDGER_FILE")" 2>/dev/null || true',
|
|
560
|
+
' node - "$PROJSCAN_ROOT" "$MISSION_DIR" "$1" "$2" "$3" "$4" "$5" <<\'NODE\' >> "$PROOF_LEDGER_FILE" 2>/dev/null || true',
|
|
561
|
+
'const crypto = require("node:crypto");',
|
|
562
|
+
'const path = require("node:path");',
|
|
563
|
+
'const { execFileSync } = require("node:child_process");',
|
|
564
|
+
'const [root, missionDir, id, label, logName, command, exitCodeRaw] = process.argv.slice(2);',
|
|
565
|
+
'function normalize(value) { return String(value || "").split(path.sep).join("/").replace(/^\\.\\//, ""); }',
|
|
566
|
+
'function changedFiles() {',
|
|
567
|
+
' try {',
|
|
568
|
+
' const output = execFileSync("git", ["-C", root, "status", "--porcelain", "--untracked-files=all"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });',
|
|
569
|
+
' return [...new Set(output.split("\\n").map((line) => line.slice(3).trim()).filter(Boolean).map((file) => file.includes(" -> ") ? file.split(" -> ").pop() : file).map(normalize).filter((file) => !file.startsWith(".projscan/")))].sort();',
|
|
570
|
+
' } catch {',
|
|
571
|
+
' return [];',
|
|
572
|
+
' }',
|
|
573
|
+
'}',
|
|
574
|
+
'const files = changedFiles();',
|
|
575
|
+
'const fingerprint = crypto.createHash("sha256").update(files.join("\\n")).digest("hex");',
|
|
576
|
+
'const completedAt = new Date().toISOString();',
|
|
577
|
+
'const exitCode = Number.parseInt(exitCodeRaw, 10);',
|
|
578
|
+
'const logPath = normalize(path.relative(root, path.join(missionDir, "proof-logs", logName)));',
|
|
579
|
+
'const digest = crypto.createHash("sha256").update(`${command}\\n${completedAt}\\n${exitCode}`).digest("hex").slice(0, 12);',
|
|
580
|
+
'const record = { schemaVersion: 1, id: `proof-ledger-${digest}`, command, normalizedCommand: command.trim().replace(/\\s+/g, " "), cwd: normalize(path.relative(root, missionDir) || "."), exitCode, status: exitCode === 0 ? "passed" : "failed", startedAt: completedAt, completedAt, durationMs: 0, changedFileFingerprint: fingerprint, changedFiles: files, outputSummary: `Mission proof ${label} exited ${exitCode}.`, source: "mission", logPath };',
|
|
581
|
+
'process.stdout.write(`${JSON.stringify(record)}\\n`);',
|
|
582
|
+
'NODE',
|
|
583
|
+
'}',
|
|
584
|
+
'',
|
|
585
|
+
];
|
|
586
|
+
}
|
|
587
|
+
function scriptAppendProofLedgerJsonl(id, label, logName, command) {
|
|
588
|
+
return `append_proof_ledger_row ${shellQuote(id)} ${shellQuote(label)} ${shellQuote(logName)} ${shellQuote(command)} "$status"`;
|
|
589
|
+
}
|
|
552
590
|
function scriptInitRunReport(report) {
|
|
553
591
|
const mission = report.missionControl;
|
|
554
592
|
return [
|