@henols/c64-re-tools 1.0.0 → 2.0.0-rc.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 (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +190 -37
  3. package/distribution/package.ts +36 -0
  4. package/distribution/plugin.ts +120 -0
  5. package/package.json +34 -40
  6. package/skills/c64-assembler/SKILL.md +73 -0
  7. package/skills/c64-assembler/scripts/assemble.ts +103 -0
  8. package/skills/c64-basic/SKILL.md +67 -0
  9. package/skills/c64-basic/scripts/basic.ts +46 -0
  10. package/skills/c64-disk/SKILL.md +79 -0
  11. package/skills/c64-disk/scripts/disk.ts +65 -0
  12. package/skills/c64-emulator/SKILL.md +124 -0
  13. package/skills/c64-knowledge/SKILL.md +102 -0
  14. package/skills/c64-knowledge/scripts/knowledge.ts +257 -0
  15. package/skills/c64-memory-map/SKILL.md +76 -0
  16. package/skills/c64-memory-map/scripts/memmap.ts +81 -0
  17. package/skills/c64-memory-map/scripts/platform.ts +424 -0
  18. package/skills/c64-provenance/SKILL.md +76 -0
  19. package/skills/c64-provenance/scripts/compare.ts +92 -0
  20. package/skills/c64-provenance/scripts/provenance.ts +83 -0
  21. package/skills/c64-reverse-engineering/SKILL.md +90 -0
  22. package/skills/c64-static-analysis/SKILL.md +96 -0
  23. package/skills/c64-static-analysis/scripts/analyze.ts +175 -0
  24. package/skills/c64-static-analysis/scripts/findings.ts +73 -0
  25. package/skills/c64-testing/SKILL.md +79 -0
  26. package/skills/c64-testing/references/scenario-format.md +76 -0
  27. package/skills/c64-testing/scripts/checklist.ts +51 -0
  28. package/skills/c64-testing/scripts/scenario.ts +473 -0
  29. package/skills/c64-testing/scripts/test.ts +55 -0
  30. package/skills/c64-unpacker/SKILL.md +82 -0
  31. package/skills/c64-unpacker/scripts/evidence.ts +135 -0
  32. package/skills/c64-unpacker/scripts/unpack.ts +216 -0
  33. package/src/c64.ts +281 -0
  34. package/src/cli/ap-sdk.ts +44 -0
  35. package/src/cli/cleanup.ts +194 -0
  36. package/src/cli/main.ts +122 -0
  37. package/src/cli/status.ts +34 -0
  38. package/src/host/main.ts +121 -0
  39. package/src/host/server.ts +409 -0
  40. package/src/host/tools/c1541.ts +255 -0
  41. package/src/host/tools/index.ts +31 -0
  42. package/src/host/tools/petcat.ts +70 -0
  43. package/src/host/tools/status.ts +30 -0
  44. package/src/host/tools/version.ts +41 -0
  45. package/src/host/vice/adapter.ts +761 -0
  46. package/src/host/vice/binary-monitor.ts +389 -0
  47. package/src/host/vice/chips.ts +108 -0
  48. package/src/host/vice/connect.ts +34 -0
  49. package/src/host/vice/process.ts +402 -0
  50. package/src/host/vice/screen.ts +183 -0
  51. package/src/host/vice/session.ts +1316 -0
  52. package/src/host/vice/text-monitor.ts +223 -0
  53. package/src/host-client/connect.ts +241 -0
  54. package/src/host-client/tools.ts +89 -0
  55. package/src/host-client/transfer.ts +100 -0
  56. package/src/host-client/vice-session.ts +254 -0
  57. package/src/knowledge/database.ts +132 -0
  58. package/src/knowledge/history.ts +128 -0
  59. package/src/knowledge/import.ts +344 -0
  60. package/src/knowledge/read.ts +191 -0
  61. package/src/knowledge/schema.ts +140 -0
  62. package/src/knowledge/write.ts +348 -0
  63. package/src/mcp/main.ts +109 -0
  64. package/src/mcp/server.ts +307 -0
  65. package/src/mcp/tools/debug.ts +237 -0
  66. package/src/mcp/tools/execution.ts +116 -0
  67. package/src/mcp/tools/input.ts +69 -0
  68. package/src/mcp/tools/machine.ts +97 -0
  69. package/src/mcp/tools/media.ts +106 -0
  70. package/src/mcp/tools/memory.ts +203 -0
  71. package/src/mcp/tools/video.ts +260 -0
  72. package/src/native/acme.ts +116 -0
  73. package/src/native/discover.ts +141 -0
  74. package/src/native/dxa.ts +166 -0
  75. package/src/native/ghidra/analyze.ts +86 -0
  76. package/src/native/ghidra/index.ts +157 -0
  77. package/src/native/ghidra/language/c64rt_6510.cspec +34 -0
  78. package/src/native/ghidra/language/c64rt_6510.ldefs +15 -0
  79. package/src/native/ghidra/language/c64rt_6510.pspec +15 -0
  80. package/src/native/ghidra/language/c64rt_6510.slaspec +596 -0
  81. package/src/native/ghidra/scripts/C64Export.java +242 -0
  82. package/src/native/ghidra/scripts/C64Prepare.java +60 -0
  83. package/src/native/local.ts +34 -0
  84. package/src/native/processes.ts +350 -0
  85. package/src/native/run.ts +172 -0
  86. package/src/native/staging.ts +83 -0
  87. package/src/native/status.ts +101 -0
  88. package/src/native/types.ts +228 -0
  89. package/src/native/watchdog.ts +78 -0
  90. package/src/project.ts +39 -0
  91. package/src/protocol/framing.ts +132 -0
  92. package/src/protocol/messages.ts +252 -0
  93. package/src/protocol/tools.ts +247 -0
  94. package/src/protocol/vice.ts +1235 -0
  95. package/src/script.ts +59 -0
  96. package/src/time.ts +15 -0
  97. package/src/trace.ts +162 -0
  98. package/THIRD-PARTY-NOTICES.md +0 -26
  99. package/bin/cli.mjs +0 -283
  100. package/skills/acme-build/SKILL.md +0 -260
  101. package/skills/acme-build/scripts/acme.mjs +0 -341
  102. package/skills/acme-build/template.a +0 -53
  103. package/skills/c64-disk-access/SKILL.md +0 -159
  104. package/skills/c64-disk-access/scripts/c1541.mjs +0 -569
  105. package/skills/c64-memory-mapping/SKILL.md +0 -631
  106. package/skills/c64-memory-mapping/memmap.json +0 -8800
  107. package/skills/c64-memory-mapping/scripts/driver.mjs +0 -553
  108. package/skills/c64-petcat/SKILL.md +0 -87
  109. package/skills/c64-petcat/scripts/petcat.mjs +0 -221
  110. package/skills/c64-program-recon/SKILL.md +0 -706
  111. package/skills/c64-program-recon/references/control-flow.md +0 -180
  112. package/skills/c64-program-recon/references/graphics.md +0 -79
  113. package/skills/c64-program-recon/references/observation-hazards.md +0 -143
  114. package/skills/c64-program-recon/references/reconstruction.md +0 -133
  115. package/skills/c64-program-recon/references/sound-and-input.md +0 -74
  116. package/skills/c64-program-recon/references/tool-selection.md +0 -78
  117. package/skills/c64-program-recon/scripts/derive.mjs +0 -364
  118. package/skills/c64-program-recon/scripts/packer-finding.mjs +0 -709
  119. package/skills/c64-program-recon/templates/memory-map.template.md +0 -101
  120. package/skills/c64-provenance-diff/SKILL.md +0 -292
  121. package/skills/c64-provenance-diff/scripts/diff-images.mjs +0 -984
  122. package/skills/c64-provenance-diff/scripts/recovery-schema.mjs +0 -395
  123. package/skills/c64-ram-capture/RELEASES.json.example +0 -17
  124. package/skills/c64-ram-capture/SKILL.md +0 -474
  125. package/skills/c64-ram-capture/scripts/compare-cross-binary.mjs +0 -525
  126. package/skills/c64-ram-capture/scripts/compare.mjs +0 -258
  127. package/skills/c64-ram-capture/scripts/derive-transients.mjs +0 -575
  128. package/skills/c64-ram-capture/scripts/dump-artifacts.mjs +0 -317
  129. package/skills/c64-ram-capture/scripts/mcp-module.mjs +0 -174
  130. package/skills/c64-ram-capture/scripts/project-paths.mjs +0 -81
  131. package/skills/c64-ram-capture/scripts/releases.mjs +0 -109
  132. package/skills/c64-ram-capture/scripts/vsf-slice.mjs +0 -147
  133. package/skills/c64-ram-capture/scripts/watch-loads.mjs +0 -581
  134. package/skills/c64-ram-capture/templates/capture-record.template.md +0 -99
  135. package/skills/c64-ram-capture/transients/README.md +0 -137
  136. package/skills/routine-queue-walker/SKILL.md +0 -394
  137. package/skills/routine-queue-walker/scripts/completeness-report.mjs +0 -465
  138. package/skills/vice-wedge-triage/SKILL.md +0 -269
@@ -1,258 +0,0 @@
1
- #!/usr/bin/env node
2
- // Compare 65536-byte C64 RAM captures and classify every difference.
3
- //
4
- // Pure logic. This module reads files the agent already captured and does
5
- // arithmetic over them. It contacts nothing: the mcp__plugin_c64-re-tools_vice__* tools are the
6
- // only route to the emulator (.claude/CLAUDE.md § Emulator Access), and
7
- // nothing here opens a connection, reads broker state, or shells out.
8
- //
9
- // The classification rules are the ones c64-ram-capture/SKILL.md states, and
10
- // they live here so they are applied identically every time instead of being
11
- // re-derived by hand per session:
12
- //
13
- // volatile $0000-$0001, $0100-$01FF, $0200-$03FF, $D000-$DFFF -- counted,
14
- // reported, excluded from the verdict
15
- // drift exactly one bit differs -- listed as a candidate, does not fail
16
- // divergence two or more bits differ -- listed, and fails the comparison
17
- //
18
- // $D000-$DFFF is this module's one departure from what SKILL.md said when it was
19
- // written: that range is I/O, not RAM, so it can never be stable. See the VOLATILE
20
- // table below for the evidence (observed 2026-08-04).
21
-
22
- import { readFileSync } from "node:fs";
23
- import { createHash } from "node:crypto";
24
- import { basename } from "node:path";
25
-
26
- const IMAGE_BYTES = 65536;
27
-
28
- // Volatile spans, inclusive. A difference inside these is expected on any two
29
- // captures of the same checkpoint and never fails a comparison.
30
- const VOLATILE = [
31
- [0x0000, 0x0001], // CPU port
32
- [0x0100, 0x01ff], // stack page
33
- [0x0200, 0x03ff], // KERNAL work area / BASIC input buffer
34
- // $D000-$DFFF is I/O, not RAM: the VIC's registers repeat every $40 across
35
- // $D000-$D3FF and the SID's across $D400-$D7FF, so reading this range samples
36
- // live hardware and two captures can never agree here. Added 2026-08-04 after
37
- // every divergence across all six committed gameentry pairings landed either
38
- // here ($D344, $D625, $D628) or in RAM under KERNAL ROM -- see
39
- // Observed 2026-08-04. Confidence HIGH: structural.
40
- [0xd000, 0xdfff],
41
- ];
42
-
43
- // Deliberately NOT volatile: $E000-$FFFF (RAM under KERNAL ROM when HIRAM=0).
44
- // $FAD8 and $FC51 do differ across captures, but only 2 addresses out of 8192 --
45
- // far too few for power-on garbage, and unexplained. Blanket-excluding 8 KB on
46
- // two data points would hide real divergence, so these still fail and the
47
- // capture record carries the explanation. Confidence MEDIUM, see the same entry.
48
-
49
- const isVolatile = (a) => VOLATILE.some(([lo, hi]) => a >= lo && a <= hi);
50
-
51
- const hex4 = (n) => "$" + n.toString(16).toUpperCase().padStart(4, "0");
52
- const hex2 = (n) => "$" + n.toString(16).toUpperCase().padStart(2, "0");
53
- const bin8 = (n) => "%" + n.toString(2).padStart(8, "0");
54
-
55
- const popcount = (n) => {
56
- let c = 0;
57
- while (n) {
58
- n &= n - 1;
59
- c++;
60
- }
61
- return c;
62
- };
63
-
64
- function loadImage(path) {
65
- const buf = readFileSync(path);
66
- if (buf.length !== IMAGE_BYTES) {
67
- throw new Error(
68
- `${path}: ${buf.length} bytes, expected ${IMAGE_BYTES} — not a full 64K image`,
69
- );
70
- }
71
- return buf;
72
- }
73
-
74
- const sha256 = (buf) => createHash("sha256").update(buf).digest("hex");
75
-
76
- /**
77
- * Classify every differing address between two images.
78
- * Returns { volatile[], drift[], divergence[], pass } — the three lists
79
- * SKILL.md requires, plus the verdict.
80
- */
81
- function compare(a, b) {
82
- const volatile_ = [];
83
- const drift = [];
84
- const divergence = [];
85
-
86
- for (let addr = 0; addr < IMAGE_BYTES; addr++) {
87
- const x = a[addr];
88
- const y = b[addr];
89
- if (x === y) continue;
90
-
91
- const bits = popcount(x ^ y);
92
- const rec = { addr, a: x, b: y, bits };
93
-
94
- // Volatile wins over bit-count: an address in a volatile span is excluded
95
- // from the verdict regardless of how many bits moved.
96
- if (isVolatile(addr)) volatile_.push(rec);
97
- else if (bits === 1) drift.push(rec);
98
- else divergence.push(rec);
99
- }
100
-
101
- return { volatile: volatile_, drift, divergence, pass: divergence.length === 0 };
102
- }
103
-
104
- const fmtRow = (r) =>
105
- ` ${hex4(r.addr)} ${hex2(r.a)} ${bin8(r.a)} -> ${hex2(r.b)} ${bin8(r.b)} ${r.bits} bit${r.bits === 1 ? "" : "s"}`;
106
-
107
- function printList(title, rows, limit) {
108
- console.log(`\n${title}: ${rows.length}`);
109
- if (!rows.length) return;
110
- // --limit 0 means unlimited, matching the usage text. Anything else caps.
111
- const shown = limit ? rows.slice(0, limit) : rows;
112
- for (const r of shown) console.log(fmtRow(r));
113
- if (shown.length < rows.length) {
114
- console.log(` … ${rows.length - shown.length} more (--limit 0 for all)`);
115
- }
116
- }
117
-
118
- function cmdCompare(argv) {
119
- const limit = limitFrom(argv);
120
- const paths = argv.filter((s) => !s.startsWith("--") && !/^\d+$/.test(s));
121
- if (paths.length !== 2) throw new Error("compare needs exactly two image paths");
122
-
123
- const [pa, pb] = paths;
124
- const a = loadImage(pa);
125
- const b = loadImage(pb);
126
-
127
- const ha = sha256(a);
128
- const hb = sha256(b);
129
-
130
- console.log(`A ${basename(pa)} sha256 ${ha}`);
131
- console.log(`B ${basename(pb)} sha256 ${hb}`);
132
-
133
- if (ha === hb) {
134
- console.log("\nIDENTICAL — the two images are byte-for-byte equal.");
135
- console.log("\nVERDICT: PASS");
136
- return 0;
137
- }
138
-
139
- const r = compare(a, b);
140
-
141
- printList("volatile (excluded from the verdict)", r.volatile, limit);
142
- printList("drift — exactly one bit, reported as candidates", r.drift, limit);
143
- printList("DIVERGENCE — two or more bits, fails the comparison", r.divergence, limit);
144
-
145
- const total = r.volatile.length + r.drift.length + r.divergence.length;
146
- console.log(`\ntotal differing addresses: ${total} of ${IMAGE_BYTES}`);
147
- console.log(`\nVERDICT: ${r.pass ? "PASS" : "FAIL"}`);
148
- if (r.pass && r.drift.length) {
149
- console.log("Drift candidates present — pass, but record them with the capture.");
150
- }
151
- return r.pass ? 0 : 1;
152
- }
153
-
154
- /**
155
- * Drift floor across N captures of the same checkpoint: every address that
156
- * differed in ANY pairing. Reported as a floor, never as a complete set —
157
- * more captures can only widen it.
158
- */
159
- function cmdFloor(argv) {
160
- const limit = limitFrom(argv);
161
- const paths = argv.filter((s) => !s.startsWith("--") && !/^\d+$/.test(s));
162
- if (paths.length < 2) throw new Error("floor needs at least two image paths");
163
-
164
- const imgs = paths.map((p) => ({ path: p, buf: loadImage(p) }));
165
- for (const i of imgs) console.log(`${basename(i.path)} sha256 ${sha256(i.buf)}`);
166
-
167
- const floor = new Map(); // addr -> Set of distinct values seen
168
- let worstPair = null;
169
-
170
- for (let i = 0; i < imgs.length; i++) {
171
- for (let j = i + 1; j < imgs.length; j++) {
172
- const r = compare(imgs[i].buf, imgs[j].buf);
173
- for (const rec of [...r.volatile, ...r.drift, ...r.divergence]) {
174
- if (!floor.has(rec.addr)) floor.set(rec.addr, new Set());
175
- floor.get(rec.addr).add(rec.a);
176
- floor.get(rec.addr).add(rec.b);
177
- }
178
- const label = `${basename(imgs[i].path)} vs ${basename(imgs[j].path)}`;
179
- console.log(
180
- `\n${label}: ${r.volatile.length} volatile, ${r.drift.length} drift, ${r.divergence.length} divergence -> ${r.pass ? "PASS" : "FAIL"}`,
181
- );
182
- if (!r.pass && (!worstPair || r.divergence.length > worstPair.n)) {
183
- worstPair = { label, n: r.divergence.length };
184
- }
185
- }
186
- }
187
-
188
- const addrs = [...floor.keys()].sort((x, y) => x - y);
189
- const vol = addrs.filter(isVolatile).length;
190
-
191
- console.log(`\nDRIFT FLOOR: ${addrs.length} addresses (${vol} inside volatile spans)`);
192
- const shown = limit === 0 ? addrs : addrs.slice(0, limit || 40);
193
- for (const a of shown) {
194
- const vals = [...floor.get(a)].sort((p, q) => p - q).map(hex2).join(" / ");
195
- console.log(` ${hex4(a)}${isVolatile(a) ? " [volatile]" : " "} ${vals}`);
196
- }
197
- if (shown.length < addrs.length) {
198
- console.log(` … ${addrs.length - shown.length} more (--limit 0 for all)`);
199
- }
200
-
201
- console.log(
202
- "\nThis is a FLOOR, not a complete set — more captures of the same checkpoint can only widen it.",
203
- );
204
- if (worstPair) {
205
- const n = worstPair.n;
206
- console.log(`Worst pairing: ${worstPair.label} (${n} divergence${n === 1 ? "" : "s"}).`);
207
- }
208
- return 0;
209
- }
210
-
211
- /** SHA-256 and size of each image, for recording alongside a capture. */
212
- function cmdDigest(argv) {
213
- const paths = argv.filter((s) => !s.startsWith("--"));
214
- if (!paths.length) throw new Error("digest needs at least one image path");
215
- for (const p of paths) {
216
- const buf = readFileSync(p);
217
- const ok = buf.length === IMAGE_BYTES;
218
- console.log(
219
- `${sha256(buf)} ${buf.length} bytes${ok ? "" : " *** NOT 65536 — not a full image ***"} ${basename(p)}`,
220
- );
221
- }
222
- return 0;
223
- }
224
-
225
- function limitFrom(argv) {
226
- const i = argv.indexOf("--limit");
227
- if (i < 0) return undefined;
228
- const n = Number(argv[i + 1]);
229
- if (!Number.isInteger(n) || n < 0) throw new Error("--limit needs a non-negative integer");
230
- return n;
231
- }
232
-
233
- const commands = { compare: cmdCompare, floor: cmdFloor, digest: cmdDigest };
234
-
235
- const [cmd, ...rest] = process.argv.slice(2);
236
- if (!cmd || !commands[cmd]) {
237
- console.error(`usage: node compare.mjs <command>
238
-
239
- compare <a.bin> <b.bin> [--limit N] classify every difference, print a verdict
240
- floor <a.bin> <b.bin> [...] [--limit N] drift floor across N captures of one checkpoint
241
- digest <image.bin>... sha256 + size, for the capture record
242
-
243
- Volatile (counted, excluded from the verdict): $0000-$0001, $0100-$01FF, $0200-$03FF, $D000-$DFFF.
244
- $D000-$DFFF is I/O, not RAM — reading it samples live hardware, so it can never be stable.
245
- One differing bit is drift and passes; two or more is divergence and fails.
246
- --limit 0 prints every row. Exit status is 1 on a FAIL verdict.
247
-
248
- Images come from the capture procedure in this skill's SKILL.md, via mcp__plugin_c64-re-tools_vice__*.
249
- This script contacts nothing.`);
250
- process.exit(cmd ? 1 : 0);
251
- }
252
-
253
- try {
254
- process.exit(commands[cmd](rest));
255
- } catch (e) {
256
- console.error(`error: ${e.message}`);
257
- process.exit(1);
258
- }