@henols/vice-mcp 0.2.1 → 0.2.2
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 +2 -1
- package/THIRD-PARTY-NOTICES.md +1 -24
- package/{r2000-acme-ident.ts → anno-acme-ident.ts} +13 -13
- package/anno-cli.ts +1465 -0
- package/{r2000-confidence.ts → anno-confidence.ts} +22 -22
- package/anno-coverage.ts +2465 -0
- package/{r2000-d64.ts → anno-d64.ts} +5 -5
- package/anno-derive.ts +590 -0
- package/anno-details.ts +169 -0
- package/anno-enum-gen.ts +533 -0
- package/anno-export-asm.ts +1310 -0
- package/anno-index.ts +150 -0
- package/{r2000-memmap-render.ts → anno-memmap-render.ts} +236 -95
- package/{r2000-regbits-gen.ts → anno-regbits-gen.ts} +20 -15
- package/{r2000-regbits.json → anno-regbits.json} +2 -2
- package/anno-register.ts +240 -0
- package/anno-store.ts +3486 -0
- package/anno-symbols.ts +266 -0
- package/anno-tools.ts +2111 -0
- package/anno-types.ts +1636 -0
- package/block-class.ts +201 -0
- package/build.ts +1 -1
- package/capability-registry.ts +3 -1
- package/disasm-decoder.ts +14 -14
- package/disasm-opcodes.ts +4 -4
- package/disasm-renderer.ts +2 -2
- package/hostpath.ts +1 -1
- package/install-resources.ts +1 -1
- package/package.json +23 -17
- package/prg-image.ts +119 -0
- package/repo-root.ts +20 -5
- package/resources/broker-launch.mjs +8 -4
- package/resources/vice-launcher.sh +3 -3
- package/stock-address.ts +5 -5
- package/stock-cia.ts +2 -2
- package/stock-condition.ts +7 -7
- package/stock-connect.ts +1 -1
- package/stock-dispatch.ts +35 -5
- package/stock-execution.ts +5 -3
- package/stock-input.ts +9 -9
- package/stock-machine.ts +17 -6
- package/stock-protocol.ts +16 -11
- package/stock-registers.ts +54 -29
- package/stock-sprites.ts +3 -3
- package/stock-symbols.ts +9 -9
- package/stock-timing.ts +1 -1
- package/stock-vicii.ts +1 -1
- package/version.ts +1 -1
- package/vice-proxy.ts +68 -46
- package/r2000-cli.ts +0 -1103
- package/r2000-enum-gen.ts +0 -574
- package/r2000-launch.ts +0 -357
- package/r2000-mcp-client.ts +0 -596
- package/r2000-project.ts +0 -190
- package/r2000-symbols.ts +0 -388
- package/r2000-tools.ts +0 -914
- package/r2000-verify.ts +0 -184
package/r2000-verify.ts
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// r2000-verify.ts -- the ONE place that interprets regenerator2000's
|
|
3
|
-
// `--verify` output.
|
|
4
|
-
//
|
|
5
|
-
// WHY PARSING IS REQUIRED AT ALL (D-10, the concrete incident): with ACME
|
|
6
|
-
// absent from PATH and ca65 present, a real `regenerator2000 0.9.20 --verify`
|
|
7
|
-
// run on this host printed
|
|
8
|
-
//
|
|
9
|
-
// ✗ ACME — ACME not found in PATH (skipped)
|
|
10
|
-
// ✓ All roundtrip verifications passed.
|
|
11
|
-
// EXIT=0
|
|
12
|
-
//
|
|
13
|
-
// -- exit 0, and a summary line that reads as a full pass, while the one
|
|
14
|
-
// assembler this project actually cares about (`!cpu 6510`, ACME 0.97) never
|
|
15
|
-
// ran at all. Trusting the exit code here would let ACME be silently
|
|
16
|
-
// skipped and still report success. This is the WHAT-NOT-TO-DO for any
|
|
17
|
-
// future edit to this file: never derive `ok` from `status`, ever, no
|
|
18
|
-
// matter how tempting a bare zero-exit-status check looks. The verdict this
|
|
19
|
-
// module produces comes ONLY from parsing the per-assembler result lines
|
|
20
|
-
// and reading ACME's own line -- never from the process exit code, and
|
|
21
|
-
// never from the aggregate "All roundtrip verifications passed." summary
|
|
22
|
-
// line, which is itself the thing that lied in the transcript above.
|
|
23
|
-
//
|
|
24
|
-
// Both captured transcripts (the honest pass and this exact false-pass trap)
|
|
25
|
-
// are pinned verbatim as fixtures in r2000-verify.test.ts, so a future
|
|
26
|
-
// "simplification" back to an exit-code check fails a unit test immediately.
|
|
27
|
-
//
|
|
28
|
-
// WR-04 (10-REVIEW.md, fixed in plan 11-01): the verdict must also never
|
|
29
|
-
// trust just the FIRST ACME result line. `acmeVerdict()` used to select
|
|
30
|
-
// ACME's line with a bare array .find() over the first matching entry, so
|
|
31
|
-
// a transcript containing both a
|
|
32
|
-
// passing and a failing ACME line (a shape --verify has never printed as of
|
|
33
|
-
// 0.9.20, but one this defensive parser is explicitly meant to survive)
|
|
34
|
-
// reported `ok: true` from the first (passing) line while discarding the
|
|
35
|
-
// later failure -- exactly the "misleading success" this module exists to
|
|
36
|
-
// refuse. The fix requires UNANIMITY: every parsed ACME line must be `ok`,
|
|
37
|
-
// the first non-ok line (if any) drives the verdict, and if more than one
|
|
38
|
-
// ACME line is present after passing that check, the module refuses to
|
|
39
|
-
// guess which one is authoritative rather than picking one arbitrarily.
|
|
40
|
-
// Both the mixed-transcript case and the too-many-ACME-lines case are pinned
|
|
41
|
-
// verbatim as fixtures in r2000-verify.test.ts.
|
|
42
|
-
//
|
|
43
|
-
// Import nothing from `hostpath.ts`/`containerpath.ts` -- plan 10-01's
|
|
44
|
-
// absence assertion in `hostpath-consumers.test.ts` already names this file.
|
|
45
|
-
|
|
46
|
-
import { buildVerifyArgs, runR2000 } from "./r2000-launch.ts";
|
|
47
|
-
|
|
48
|
-
/** The three possible outcomes for a single per-assembler `--verify` result
|
|
49
|
-
* line. `"skipped"` and `"ok"` are DIFFERENT outcomes and must never be
|
|
50
|
-
* conflated -- a skipped assembler did not run, so it proves nothing, while
|
|
51
|
-
* an `ok` assembler was actually invoked and its output byte-diffed. */
|
|
52
|
-
export type AssemblerOutcome = "ok" | "skipped" | "failed";
|
|
53
|
-
|
|
54
|
-
export interface VerifyLine {
|
|
55
|
-
assembler: string;
|
|
56
|
-
outcome: AssemblerOutcome;
|
|
57
|
-
detail: string;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Matches exactly a per-assembler result line, e.g.:
|
|
61
|
-
// ✓ ACME — byte-identical (44 bytes)
|
|
62
|
-
// ✗ 64tass — 64tass not found in PATH (skipped)
|
|
63
|
-
// Tolerates an em-dash (U+2014), en-dash (U+2013) or plain hyphen as the
|
|
64
|
-
// separator, since only the ACME verdict is load-bearing here and the exact
|
|
65
|
-
// glyph regenerator2000 prints is an upstream formatting detail, not
|
|
66
|
-
// something this parser should be brittle against. Deliberately does NOT
|
|
67
|
-
// match the aggregate "✓ All roundtrip verifications passed." summary line
|
|
68
|
-
// (no separator token present there) or the "EXIT=N" line some transcripts
|
|
69
|
-
// carry -- both are excluded from the returned array by construction, not
|
|
70
|
-
// by a special-cased skip: they simply never match this shape.
|
|
71
|
-
const VERIFY_LINE_PATTERN = /^[✓✗]\s+(.+?)\s+[—–-]\s+(.+)$/;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Parses `regenerator2000 --verify`'s stdout into one `VerifyLine` per
|
|
75
|
-
* per-assembler result line. The aggregate `✓ All roundtrip verifications
|
|
76
|
-
* passed.` line is a summary, not an assembler line -- it never matches
|
|
77
|
-
* `VERIFY_LINE_PATTERN` (no `—`/`-` separator), so it is excluded from the
|
|
78
|
-
* result by construction rather than filtered out after the fact.
|
|
79
|
-
*/
|
|
80
|
-
export function parseVerifyOutput(stdout: string): VerifyLine[] {
|
|
81
|
-
const lines: VerifyLine[] = [];
|
|
82
|
-
for (const rawLine of stdout.split(/\r?\n/)) {
|
|
83
|
-
const trimmed = rawLine.trim();
|
|
84
|
-
if (!trimmed) continue;
|
|
85
|
-
const match = trimmed.match(VERIFY_LINE_PATTERN);
|
|
86
|
-
if (!match) continue;
|
|
87
|
-
const [, assemblerRaw, detailRaw] = match;
|
|
88
|
-
const assembler = assemblerRaw!.trim();
|
|
89
|
-
const detail = detailRaw!.trim();
|
|
90
|
-
// A "(skipped)" suffix always means skipped, regardless of the leading
|
|
91
|
-
// glyph. Anything else takes its outcome from the leading glyph: a
|
|
92
|
-
// leading ✓ is "ok", any other non-skipped result line is "failed" --
|
|
93
|
-
// this project has never observed a real ACME/ca65 failure transcript,
|
|
94
|
-
// but a future one must not silently parse as "ok".
|
|
95
|
-
const outcome: AssemblerOutcome = /\(skipped\)\s*$/i.test(detail)
|
|
96
|
-
? "skipped"
|
|
97
|
-
: trimmed.startsWith("✓")
|
|
98
|
-
? "ok"
|
|
99
|
-
: "failed";
|
|
100
|
-
lines.push({ assembler, outcome, detail });
|
|
101
|
-
}
|
|
102
|
-
return lines;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Derives the ACME-specific verdict from a parsed line set. `ok` only when
|
|
107
|
-
* at least one ACME line exists, EVERY parsed ACME line has outcome `"ok"`
|
|
108
|
-
* (unanimity -- WR-04), AND exactly one ACME line is present. A missing
|
|
109
|
-
* ACME line, any ACME line with outcome `"skipped"` or `"failed"`, and more
|
|
110
|
-
* than one `"ok"` ACME line each return `ok: false` with a distinct,
|
|
111
|
-
* quotable reason -- never conflate "skipped" with "passed", never let a
|
|
112
|
-
* passing line hide a later failing one, and never fall back to the summary
|
|
113
|
-
* line (which this module never even parses as a VerifyLine, see
|
|
114
|
-
* `parseVerifyOutput`).
|
|
115
|
-
*/
|
|
116
|
-
export function acmeVerdict(lines: VerifyLine[]): { ok: boolean; reason: string } {
|
|
117
|
-
const acmeLines = lines.filter((l) => l.assembler.toLowerCase() === "acme");
|
|
118
|
-
|
|
119
|
-
if (acmeLines.length === 0) {
|
|
120
|
-
return {
|
|
121
|
-
ok: false,
|
|
122
|
-
reason:
|
|
123
|
-
"no ACME line found in --verify output -- ACME was never invoked at all, which is a failure, " +
|
|
124
|
-
"not an absence of evidence",
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// First non-ok line wins -- so a passing ACME line earlier in the
|
|
129
|
-
// transcript can never hide a failing one later in it (WR-04).
|
|
130
|
-
const bad = acmeLines.find((l) => l.outcome !== "ok");
|
|
131
|
-
|
|
132
|
-
if (bad?.outcome === "skipped") {
|
|
133
|
-
return {
|
|
134
|
-
ok: false,
|
|
135
|
-
reason:
|
|
136
|
-
`ACME was skipped, not run -- "${bad.detail}". A skipped ACME is a failure, never a pass ` +
|
|
137
|
-
`(D-10): --verify can print "✓ All roundtrip verifications passed." and exit 0 even when ` +
|
|
138
|
-
`ACME never ran at all -- exactly the false pass observed live on this host with ACME absent ` +
|
|
139
|
-
`and ca65 present.`,
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (bad?.outcome === "failed") {
|
|
144
|
-
return { ok: false, reason: `ACME reported a failure: "${bad.detail}"` };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Every ACME line is ok at this point. Still refuse to guess which one is
|
|
148
|
-
// authoritative if more than one was printed (WR-04) -- unanimous is not
|
|
149
|
-
// the same as unambiguous.
|
|
150
|
-
if (acmeLines.length > 1) {
|
|
151
|
-
return {
|
|
152
|
-
ok: false,
|
|
153
|
-
reason: `--verify printed ${acmeLines.length} ACME result lines -- refusing to guess which one is the verdict`,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return { ok: true, reason: `ACME reported: ${acmeLines[0]!.detail}` };
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export interface VerifyProjectResult {
|
|
161
|
-
ok: boolean;
|
|
162
|
-
reason: string;
|
|
163
|
-
lines: VerifyLine[];
|
|
164
|
-
status: number | null;
|
|
165
|
-
stdout: string;
|
|
166
|
-
stderr: string;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Runs `regenerator2000 --verify` against `projectPath` (via
|
|
171
|
-
* `buildVerifyArgs()`/`runR2000()`, so the `--vice` scan applies here too),
|
|
172
|
-
* parses stdout, and derives `ok` from `acmeVerdict()` -- deliberately NOT
|
|
173
|
-
* from `status`. Returns the raw status and streams so a caller can print
|
|
174
|
-
* them for diagnostics, but no code path in this function ever lets a zero
|
|
175
|
-
* exit status alone make `ok` true. A warning on stderr is never treated as
|
|
176
|
-
* a failure -- only the parsed ACME result line decides the verdict.
|
|
177
|
-
*/
|
|
178
|
-
export function verifyProject(projectPath: string): VerifyProjectResult {
|
|
179
|
-
const argv = buildVerifyArgs({ projectPath });
|
|
180
|
-
const { status, stdout, stderr } = runR2000(argv);
|
|
181
|
-
const lines = parseVerifyOutput(stdout);
|
|
182
|
-
const verdict = acmeVerdict(lines);
|
|
183
|
-
return { ok: verdict.ok, reason: verdict.reason, lines, status, stdout, stderr };
|
|
184
|
-
}
|