@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.
Files changed (57) hide show
  1. package/README.md +2 -1
  2. package/THIRD-PARTY-NOTICES.md +1 -24
  3. package/{r2000-acme-ident.ts → anno-acme-ident.ts} +13 -13
  4. package/anno-cli.ts +1465 -0
  5. package/{r2000-confidence.ts → anno-confidence.ts} +22 -22
  6. package/anno-coverage.ts +2465 -0
  7. package/{r2000-d64.ts → anno-d64.ts} +5 -5
  8. package/anno-derive.ts +590 -0
  9. package/anno-details.ts +169 -0
  10. package/anno-enum-gen.ts +533 -0
  11. package/anno-export-asm.ts +1310 -0
  12. package/anno-index.ts +150 -0
  13. package/{r2000-memmap-render.ts → anno-memmap-render.ts} +236 -95
  14. package/{r2000-regbits-gen.ts → anno-regbits-gen.ts} +20 -15
  15. package/{r2000-regbits.json → anno-regbits.json} +2 -2
  16. package/anno-register.ts +240 -0
  17. package/anno-store.ts +3486 -0
  18. package/anno-symbols.ts +266 -0
  19. package/anno-tools.ts +2111 -0
  20. package/anno-types.ts +1636 -0
  21. package/block-class.ts +201 -0
  22. package/build.ts +1 -1
  23. package/capability-registry.ts +3 -1
  24. package/disasm-decoder.ts +14 -14
  25. package/disasm-opcodes.ts +4 -4
  26. package/disasm-renderer.ts +2 -2
  27. package/hostpath.ts +1 -1
  28. package/install-resources.ts +1 -1
  29. package/package.json +23 -17
  30. package/prg-image.ts +119 -0
  31. package/repo-root.ts +20 -5
  32. package/resources/broker-launch.mjs +8 -4
  33. package/resources/vice-launcher.sh +3 -3
  34. package/stock-address.ts +5 -5
  35. package/stock-cia.ts +2 -2
  36. package/stock-condition.ts +7 -7
  37. package/stock-connect.ts +1 -1
  38. package/stock-dispatch.ts +35 -5
  39. package/stock-execution.ts +5 -3
  40. package/stock-input.ts +9 -9
  41. package/stock-machine.ts +17 -6
  42. package/stock-protocol.ts +16 -11
  43. package/stock-registers.ts +54 -29
  44. package/stock-sprites.ts +3 -3
  45. package/stock-symbols.ts +9 -9
  46. package/stock-timing.ts +1 -1
  47. package/stock-vicii.ts +1 -1
  48. package/version.ts +1 -1
  49. package/vice-proxy.ts +68 -46
  50. package/r2000-cli.ts +0 -1103
  51. package/r2000-enum-gen.ts +0 -574
  52. package/r2000-launch.ts +0 -357
  53. package/r2000-mcp-client.ts +0 -596
  54. package/r2000-project.ts +0 -190
  55. package/r2000-symbols.ts +0 -388
  56. package/r2000-tools.ts +0 -914
  57. 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
- }