@henols/c64-re-tools 0.2.4 → 1.0.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/package.json +2 -2
- package/skills/acme-build/SKILL.md +22 -22
- package/skills/c64-disk-access/SKILL.md +49 -46
- package/skills/c64-memory-mapping/SKILL.md +71 -70
- package/skills/c64-petcat/SKILL.md +11 -11
- package/skills/c64-program-recon/SKILL.md +109 -105
- package/skills/c64-program-recon/references/control-flow.md +13 -13
- package/skills/c64-program-recon/references/graphics.md +6 -6
- package/skills/c64-program-recon/references/observation-hazards.md +7 -7
- package/skills/c64-program-recon/references/reconstruction.md +6 -6
- package/skills/c64-program-recon/references/sound-and-input.md +8 -8
- package/skills/c64-program-recon/references/tool-selection.md +11 -11
- package/skills/c64-program-recon/templates/memory-map.template.md +16 -12
- package/skills/c64-provenance-diff/SKILL.md +43 -43
- package/skills/c64-ram-capture/SKILL.md +96 -45
- package/skills/c64-ram-capture/scripts/compare-cross-binary.mjs +525 -0
- package/skills/c64-ram-capture/templates/capture-record.template.md +11 -11
- package/skills/c64-ram-capture/transients/README.md +11 -10
- package/skills/routine-queue-walker/SKILL.md +205 -176
- package/skills/vice-wedge-triage/SKILL.md +48 -48
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@henols/c64-re-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Installer that adds the C64 reverse-engineering skills and the VICE emulator MCP server (@henols/vice-mcp) to a project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"installer"
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@henols/vice-mcp": "0.
|
|
48
|
+
"@henols/vice-mcp": "1.0.0"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"sync-skills": "node scripts/sync-skills.mjs",
|
|
@@ -22,10 +22,10 @@ absent `run` verb is not an omission). It contacts nothing.
|
|
|
22
22
|
Options: `-o FILE` `--out-dir DIR` `-f FORMAT` `--setpc ADDR` `-DSYM=VAL`
|
|
23
23
|
`-I DIR` `--no-report` `--json`.
|
|
24
24
|
|
|
25
|
-
`-I DIR`
|
|
26
|
-
broker
|
|
27
|
-
go through — before it ever reaches the assembler.
|
|
28
|
-
`-I` directory
|
|
25
|
+
The seam resolves `-I DIR` **workspace-relative** to the project root the host
|
|
26
|
+
broker starts with — the same resolution `source`/`--out-dir` already
|
|
27
|
+
go through — before it ever reaches the assembler. The seam refuses an absolute
|
|
28
|
+
or escaping `-I` directory rather than passing it to ACME. This is a
|
|
29
29
|
documented contract change from earlier releases, when an absolute include
|
|
30
30
|
reached the assembler unchecked.
|
|
31
31
|
|
|
@@ -96,13 +96,13 @@ Inspect the result with `od`:
|
|
|
96
96
|
od -An -tx1 game.prg | head -2
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
The first two bytes are the little-endian load address (`01 08` = `$0801`)
|
|
99
|
+
The first two bytes are the little-endian load address (`01 08` = `$0801`). Code
|
|
100
100
|
follows.
|
|
101
101
|
|
|
102
102
|
## Writing source
|
|
103
103
|
|
|
104
|
-
Start from the scaffold — it carries a BASIC stub
|
|
105
|
-
so the entry point stays correct as the program grows:
|
|
104
|
+
Start from the scaffold — it carries a BASIC stub that computes its `SYS` target
|
|
105
|
+
rather than hard-coding it, so the entry point stays correct as the program grows:
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
108
|
node $A new game.asm
|
|
@@ -142,17 +142,17 @@ you also assemble by hand, so these stay recognised as mnemonics.
|
|
|
142
142
|
This skill does not disassemble. The route that does is `anno export-asm`, and
|
|
143
143
|
it lives in the `anno` CLI rather than here.
|
|
144
144
|
|
|
145
|
-
**Dated withdrawal 2026-08-29, dated return 2026-08-31 —
|
|
146
|
-
because the withdrawal
|
|
145
|
+
**Dated withdrawal 2026-08-29, dated return 2026-08-31 — this document keeps
|
|
146
|
+
both halves, because the withdrawal records why the route has its current shape.**
|
|
147
147
|
Whole-program static disassembly was WITHDRAWN on 2026-08-29 rather than left standing on an unverified reassembly claim: the removed route
|
|
148
148
|
settled correctness with a transcript parser, and the recorded false pass that
|
|
149
149
|
discipline exists against read `ACME not found in PATH (skipped)` / `All
|
|
150
150
|
roundtrip verifications passed.` / `EXIT=0` — exit zero, an aggregate line
|
|
151
151
|
reading as a full pass, and the one assembler this project cares about never
|
|
152
152
|
having run. On **2026-08-31 the route returned**, rebuilt over the annotation
|
|
153
|
-
store as `anno export-asm`. It is not a rename of
|
|
154
|
-
correctness
|
|
155
|
-
the bytes against the input** — never
|
|
153
|
+
store as `anno export-asm`. It is not a rename of the removed route: its
|
|
154
|
+
correctness comes from **assembling the output with a real ACME and diffing
|
|
155
|
+
the bytes against the input** — never from an exit code, and never from a string
|
|
156
156
|
match on the exporter's own output.
|
|
157
157
|
|
|
158
158
|
**The live invocation:**
|
|
@@ -162,14 +162,14 @@ npx -y @henols/vice-mcp anno export-asm game.prg --store game.annostore --out ga
|
|
|
162
162
|
node <plugin-root>/src/mcp/vice/vice-proxy.ts anno export-asm game.prg --store game.annostore
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
-
`<image>` and `--store` are **two separate arguments and neither
|
|
165
|
+
`<image>` and `--store` are **two separate arguments, and neither one derives from
|
|
166
166
|
the other** — the image supplies the bytes, the store supplies the names, ranges,
|
|
167
167
|
typed regions and comments, and naming one does not name the other. `--out` names
|
|
168
|
-
a **directory
|
|
168
|
+
a **directory**: the verb writes the whole export into it, defaulting to the image's
|
|
169
169
|
basename stem beside the **store**, not beside the image, because the export is a
|
|
170
170
|
generated view of the annotations. The directory holds a root file that sources
|
|
171
171
|
the rest, one file per annotation scope, and an `unscoped.a` for anything inside
|
|
172
|
-
no scope.
|
|
172
|
+
no scope. The verb refuses a non-empty destination rather than overwriting it, unless you
|
|
173
173
|
pass `--force`.
|
|
174
174
|
|
|
175
175
|
**The verb writes source text and runs no assembler.** Its own second output line
|
|
@@ -180,10 +180,10 @@ export-asm: this file has NOT been assembled -- this command writes source text
|
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
The real-ACME byte-diff oracle is **test-only** — it lives in
|
|
183
|
-
`src/mcp/vice/acme-verify.ts`,
|
|
184
|
-
in CI with `VICE_REQUIRE_ACME=1`), and
|
|
183
|
+
`src/mcp/vice/acme-verify.ts`, `acme-verify.test.ts` exercises it (hard-failed
|
|
184
|
+
in CI with `VICE_REQUIRE_ACME=1`), and it stays deliberately absent from the published
|
|
185
185
|
package, so nothing on the runtime path can reach it. A clean `export-asm` run is
|
|
186
|
-
therefore evidence that
|
|
186
|
+
therefore evidence that the verb wrote source and nothing more. It is not an
|
|
187
187
|
assembler verdict. If you need to know the emitted source reassembles, assemble
|
|
188
188
|
it yourself — that is what this skill's own build route is for.
|
|
189
189
|
|
|
@@ -191,7 +191,7 @@ it yourself — that is what this skill's own build route is for.
|
|
|
191
191
|
`anno_read_region` and `anno_disassemble` render an explicit inclusive range out
|
|
192
192
|
of the image on demand, capped at 4096 bytes per call and REFUSED by name above
|
|
193
193
|
the cap rather than truncated. `c64-program-recon` documents that route and this
|
|
194
|
-
history together
|
|
194
|
+
history together. It is not restated there.
|
|
195
195
|
|
|
196
196
|
## Setup
|
|
197
197
|
|
|
@@ -245,11 +245,11 @@ This one turns source into bytes. It does not restate what the others carry.
|
|
|
245
245
|
Record findings that make RE faster in your own project notes **at the moment you
|
|
246
246
|
find them**, graded with `Evidence:` and `Confidence:`. Promote a finding by
|
|
247
247
|
re-logging it with the new evidence, never by editing an old grade in place — the
|
|
248
|
-
grade is only worth anything if it says what
|
|
248
|
+
grade is only worth anything if it says what you actually knew when you wrote it.
|
|
249
249
|
|
|
250
250
|
## Troubleshooting
|
|
251
251
|
|
|
252
|
-
| Symptom |
|
|
252
|
+
| Symptom | Correct |
|
|
253
253
|
|---|---|
|
|
254
254
|
| `install the ACME cross assembler and put acme on PATH` | Install ACME. |
|
|
255
255
|
| `for <...> includes, set $ACME to …` | `export ACME=<dir holding cbm/c64/vic.a>`. |
|
|
@@ -257,4 +257,4 @@ grade is only worth anything if it says what was actually known when it was writ
|
|
|
257
257
|
| `Label name not in leftmost column` + `Syntax error` on a mnemonic | Add `!cpu 6510`. |
|
|
258
258
|
| `Output file already chosen` | Remove `!to` from the source and keep `-o`. |
|
|
259
259
|
| `Number does not fit in 8 bits` | Pass a value 0–255, or drop the `#` if you meant an address. |
|
|
260
|
-
| `This tool cannot read binary files. The file appears to be a binary .a file.` | The file is fine
|
|
260
|
+
| `This tool cannot read binary files. The file appears to be a binary .a file.` | The file is fine. ACME source is plain text. The agent's Read tool refuses the `.a` extension regardless of content. Edit needs a prior successful Read. Scaffold and write source as `.asm` instead — the driver accepts `.a`/`.asm`/`.s`, all three assemble byte-identically (verified both directions in this container, 2026-08-04). To read an existing `.a` file, use `sed -n '1,60p' file.a`. |
|
|
@@ -20,7 +20,7 @@ node $S audit --image path/to/image.d64 # find fabricated/co
|
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
The script wraps `c1541` and nothing else — **read-only**. `bam`/`dir`/`audit`
|
|
23
|
-
need only `--image
|
|
23
|
+
need only `--image`. `entry`/`chain`/`read` also need `--name`, a CBM
|
|
24
24
|
filename or glob pattern (never a path). No `-format`, `-write`, `-bwrite`
|
|
25
25
|
or `-delete` verb is reachable from here, deliberately: this skill only
|
|
26
26
|
ever reads a disk image, never mutates one.
|
|
@@ -30,11 +30,11 @@ Options: `--image PATH` `--name CBM-NAME` `--out-dir DIR` `--json`.
|
|
|
30
30
|
`--out-dir` defaults to the image's own directory, exactly like
|
|
31
31
|
`acme-build`'s own `--out-dir` default. Both `--image` and `--out-dir` are
|
|
32
32
|
resolved **workspace-relative** to the smallest ancestor directory
|
|
33
|
-
containing both, before the request
|
|
34
|
-
resolution `acme-build`'s `source`/`--out-dir` already go through.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
containing both, before the request reaches the seam. This is the same
|
|
34
|
+
resolution `acme-build`'s `source`/`--out-dir` already go through. The seam
|
|
35
|
+
passes `--name` straight through and never resolves it as a path. The seam
|
|
36
|
+
refuses a value beginning with `-` before it spawns any child process.
|
|
37
|
+
Otherwise `c1541`'s own CLI would read it as a flag.
|
|
38
38
|
|
|
39
39
|
## Directory listing
|
|
40
40
|
|
|
@@ -57,9 +57,9 @@ Prints the seam's response verbatim as one line of JSON:
|
|
|
57
57
|
node $S bam --image game.d64 --json
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
Same response shape as `dir
|
|
61
|
-
per-sector allocation row per track
|
|
62
|
-
an allocated sector
|
|
60
|
+
Same response shape as `dir`. `results[0].path` names a file carrying one
|
|
61
|
+
per-sector allocation row per track. Each row is a run of `*`/`.`
|
|
62
|
+
characters, `*` for an allocated sector.
|
|
63
63
|
|
|
64
64
|
## One directory entry's raw fields
|
|
65
65
|
|
|
@@ -68,10 +68,11 @@ node $S entry --image game.d64 --name FILENAME --json
|
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
`results[0].path` names a file carrying the entry's raw 32-byte directory
|
|
71
|
-
record (as a hex dump)
|
|
72
|
-
|
|
73
|
-
`firstSector` as numeric fields on the JSON response
|
|
74
|
-
the file itself is still the
|
|
71
|
+
record (as a hex dump). A `T/S: <t>/<s>, <n> blocks` summary line follows
|
|
72
|
+
the record. This script also parses that line back and adds
|
|
73
|
+
`firstTrack`/`firstSector` as numeric fields on the JSON response. These
|
|
74
|
+
fields exist purely to show the values — the file itself is still the
|
|
75
|
+
authoritative source.
|
|
75
76
|
|
|
76
77
|
## A named file's sector chain
|
|
77
78
|
|
|
@@ -81,7 +82,7 @@ node $S chain --image game.d64 --name FILENAME --json
|
|
|
81
82
|
|
|
82
83
|
`results[0].path` names a file listing every `(track,sector)` hop the file
|
|
83
84
|
occupies, in order. A single-sector file's chain shows one hop with no
|
|
84
|
-
second tuple on the arrow's right side
|
|
85
|
+
second tuple on the arrow's right side. A multi-sector file's chain repeats
|
|
85
86
|
the tuple at every hop.
|
|
86
87
|
|
|
87
88
|
## Extracting a named file's bytes
|
|
@@ -90,8 +91,8 @@ the tuple at every hop.
|
|
|
90
91
|
node $S read --image game.d64 --name FILENAME --out-dir /scratch --json
|
|
91
92
|
```
|
|
92
93
|
|
|
93
|
-
Writes the file's raw bytes
|
|
94
|
-
is NOT a captured-stdout listing — `c1541` writes the output file itself
|
|
94
|
+
Writes the file's raw bytes. Unlike the other four capabilities, this one
|
|
95
|
+
is NOT a captured-stdout listing — `c1541` writes the output file itself.
|
|
95
96
|
`results[0]` carries that file's `path`/`sha256`/`byteLength`.
|
|
96
97
|
|
|
97
98
|
## Auditing for fabricated or corrupted entries
|
|
@@ -100,56 +101,58 @@ is NOT a captured-stdout listing — `c1541` writes the output file itself).
|
|
|
100
101
|
node $S audit --image game.d64 --json
|
|
101
102
|
```
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
map),
|
|
105
|
-
|
|
104
|
+
The `audit` command composes `dir` (names and block counts) and `bam` (the
|
|
105
|
+
per-sector allocation map). For each name, it also makes one `entry` call
|
|
106
|
+
to get that file's own claimed first track/sector and its directory
|
|
107
|
+
sector's "next directory" pointer. Together these calls form a ported,
|
|
106
108
|
read-only detector — no `-format`/`-write`/mutating verb, and no seventh
|
|
107
|
-
`host_tool` id
|
|
109
|
+
`host_tool` id. This is three existing capabilities composed client-side.
|
|
108
110
|
|
|
109
|
-
|
|
110
|
-
bare boolean**, on any of:
|
|
111
|
+
The `audit` command flags a directory entry `suspicious`, with **named
|
|
112
|
+
reasons, never a bare boolean**, on any of:
|
|
111
113
|
|
|
112
|
-
1. its block count is `0
|
|
113
|
-
2. its first track/sector lies outside the image's own geometry
|
|
114
|
-
no such track, or no such sector on that track
|
|
115
|
-
3. its first **sector** — not merely its whole
|
|
116
|
-
|
|
114
|
+
1. its block count is `0`.
|
|
115
|
+
2. its first track/sector lies outside the image's own geometry. There is
|
|
116
|
+
no such track, or no such sector on that track.
|
|
117
|
+
3. the allocation map reports its first **sector** — not merely its whole
|
|
118
|
+
track — free, meaning the file cannot really start there. This is
|
|
117
119
|
sharper than checking only whether the whole track is free, because the
|
|
118
120
|
per-sector map is available.
|
|
119
121
|
|
|
120
|
-
A cyclic or self-referential
|
|
121
|
-
first track/sector
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
122
|
+
A directory chain is cyclic or self-referential when two entries claim the
|
|
123
|
+
same first track/sector. It is also cyclic or self-referential when a
|
|
124
|
+
"next directory" pointer refers back to a sector already seen, including
|
|
125
|
+
the directory's own starting sector. When this happens, the command stops
|
|
126
|
+
treating the repeat as new information. Instead of looping, it reports a
|
|
127
|
+
top-level `chain_error` naming the repeated pointer. Every remaining entry
|
|
128
|
+
is still audited afterward — a chain error on one entry never hides another
|
|
129
|
+
entry's own independent flag.
|
|
127
130
|
|
|
128
131
|
```json
|
|
129
132
|
{"entries":[{"name":"basicstub","blocks":1,"first_track":17,"first_sector":0,"suspicious":false,"suspicious_reasons":[]}],"chain_error":null}
|
|
130
133
|
```
|
|
131
134
|
|
|
132
135
|
**A flag is a signal to investigate, not a verdict.** A directory entry a
|
|
133
|
-
cracker fabricated for a file never actually written, a genuinely
|
|
134
|
-
image, and (rarely) an unusual-but-legitimate disk layout can
|
|
135
|
-
flag
|
|
136
|
-
interpretation to whoever is looking at the disk.
|
|
136
|
+
cracker fabricated for a file never actually written, a genuinely
|
|
137
|
+
corrupted image, and (rarely) an unusual-but-legitimate disk layout can
|
|
138
|
+
all produce a flag. This command reports what it finds, named, and leaves
|
|
139
|
+
the interpretation to whoever is looking at the disk.
|
|
137
140
|
|
|
138
141
|
## Failure shape
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
cannot service
|
|
142
|
-
non-zero exit code
|
|
143
|
-
result. `c1541` itself exits `0` even on a genuine failure (it
|
|
144
|
-
own `Error - ...` lines to stdout instead)
|
|
145
|
-
the exit code, is what decides success here.
|
|
143
|
+
The seam reports a nonexistent image, a nonexistent named entry, or any
|
|
144
|
+
other call `c1541` cannot service as `{"ok":false,"message":"..."}` with a
|
|
145
|
+
non-zero exit code. This is **never** a success envelope over an empty or
|
|
146
|
+
partial result. `c1541` itself exits `0` even on a genuine failure (it
|
|
147
|
+
prints its own `Error - ...` lines to stdout instead). The seam's own
|
|
148
|
+
classifier, not the exit code, is what decides success here.
|
|
146
149
|
|
|
147
150
|
## What this skill does NOT do
|
|
148
151
|
|
|
149
152
|
- **No mutating verb.** `-format`/`-write`/`-bwrite`/`-delete` are never
|
|
150
153
|
reachable from this script, on the wire, or anywhere in this skill's tree
|
|
151
|
-
— only the six read-only capabilities above
|
|
152
|
-
- **No direct binary spawn.** `c1541` runs host-side
|
|
154
|
+
— this skill exposes only the six read-only capabilities above.
|
|
155
|
+
- **No direct binary spawn.** `c1541` runs host-side. This script only ever
|
|
153
156
|
constructs a typed request and reads the produced files back off the
|
|
154
157
|
shared workspace tree — the host-tool execution seam is the only route.
|
|
155
158
|
- **No emulator dependency.** This skill names no VICE emulator tool at
|