@henols/vice-mcp 0.2.1 → 0.2.3
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 +4 -3
- package/THIRD-PARTY-NOTICES.md +423 -25
- package/{r2000-acme-ident.ts → anno-acme-ident.ts} +13 -13
- package/anno-bank.ts +171 -0
- package/anno-cli.ts +3040 -0
- package/{r2000-confidence.ts → anno-confidence.ts} +22 -22
- package/anno-coverage.ts +2465 -0
- package/anno-derive.ts +590 -0
- package/anno-details.ts +169 -0
- package/anno-enum-gen.ts +919 -0
- package/anno-export-asm.ts +2396 -0
- package/anno-graphics.ts +338 -0
- package/anno-hazard-report.ts +1367 -0
- package/anno-import.ts +495 -0
- package/anno-index.ts +150 -0
- package/anno-join.ts +480 -0
- package/{r2000-memmap-render.ts → anno-memmap-render.ts} +236 -95
- package/anno-provenance-ledger.ts +472 -0
- package/{r2000-regbits-gen.ts → anno-regbits-gen.ts} +20 -15
- package/{r2000-regbits.json → anno-regbits.json} +2 -2
- package/anno-register.ts +399 -0
- package/anno-store-export.ts +661 -0
- package/anno-store.ts +4002 -0
- package/anno-symbols.ts +266 -0
- package/anno-tools.ts +3264 -0
- package/anno-types.ts +1909 -0
- package/backend-detect.mts +124 -312
- package/block-class.ts +201 -0
- package/build.ts +4 -2
- package/capture-predicate.ts +597 -0
- package/channel-lock.ts +349 -0
- package/disasm-decoder.ts +14 -14
- package/disasm-opcodes.ts +4 -4
- package/disasm-renderer.ts +2 -2
- package/evid-ingest.ts +217 -0
- package/evid-reconcile.ts +316 -0
- package/host-tool-client.ts +430 -0
- package/hostpath.ts +1 -1
- package/incident-record.ts +23 -12
- package/install-resources.ts +30 -14
- package/memmap-lookup.ts +285 -0
- package/package.json +48 -23
- package/prg-image.ts +118 -0
- package/repo-root.ts +107 -8
- package/resources/backend-detect.mjs +98 -236
- package/resources/broker-control.mjs +189 -16
- package/resources/broker-epoch.mjs +1 -1
- package/resources/broker-kill.mjs +8 -2
- package/resources/broker-launch.mjs +373 -214
- package/resources/broker-state.mjs +64 -18
- package/resources/container-guard.mjs +1 -1
- package/resources/ghidra-project.mjs +790 -0
- package/resources/host-tool.mjs +2561 -0
- package/resources/vice-broker.mjs +330 -184
- package/resources/vice-launcher.sh +130 -12
- package/stock-address.ts +6 -6
- package/stock-cia.ts +2 -2
- package/stock-condition.ts +8 -8
- package/stock-connect.ts +10 -6
- package/stock-derived.ts +29 -37
- package/stock-diagnose.ts +200 -36
- package/stock-dispatch.ts +200 -68
- package/stock-execution.ts +5 -3
- package/stock-handler.ts +1 -1
- package/stock-input.ts +9 -9
- package/stock-machine.ts +17 -6
- package/stock-paths.ts +18 -14
- package/stock-petscii.ts +1 -1
- package/stock-protocol.ts +17 -12
- package/stock-recycle.ts +83 -2
- package/stock-registers.ts +54 -29
- package/stock-reproducible-run.ts +811 -0
- package/stock-run-until.ts +100 -1
- package/stock-sprites.ts +3 -3
- package/stock-symbols.ts +13 -13
- package/stock-timing.ts +2 -2
- package/stock-vicii.ts +1 -1
- package/stop-oracle.ts +167 -0
- package/text-capability-probe.ts +660 -0
- package/text-connect.ts +157 -0
- package/text-protocol.ts +810 -0
- package/text-tools.ts +778 -0
- package/textmon-backtrace.ts +385 -0
- package/textmon-cpuhistory.ts +335 -0
- package/textmon-memmap.ts +494 -0
- package/textmon-profile.ts +458 -0
- package/textmon-registers.ts +748 -0
- package/tools-manifest.stock.json +864 -3
- package/version.ts +1 -1
- package/vice-broker-client.ts +189 -42
- package/vice-errors.ts +268 -0
- package/vice-proxy.ts +392 -2175
- package/vsf-slice.ts +640 -0
- package/capability-registry.ts +0 -388
- package/r2000-cli.ts +0 -1103
- package/r2000-d64.ts +0 -310
- 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/refresh-manifest.ts +0 -124
- package/tools-manifest.json +0 -1223
- package/vice-probe.ts +0 -278
- package/vice-sync.ts +0 -336
- package/vice.ts +0 -772
package/block-class.ts
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// block-class.ts
|
|
3
|
+
//
|
|
4
|
+
// The ONE place that translates an annotation store's own block-type
|
|
5
|
+
// vocabulary into a neutral block class. Nothing else in this tree may
|
|
6
|
+
// compare a store block-type string, and nothing else may read a store block
|
|
7
|
+
// listing on the census's behalf (SEAM-03).
|
|
8
|
+
//
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// WHY THIS FILE EXISTS
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// `anno-coverage.ts` is the coverage instrument: it implements two Validated
|
|
13
|
+
// requirements and measures how much of a binary has actually been reverse-
|
|
14
|
+
// engineered. Its census is a pure function of the raw bytes and the seed set
|
|
15
|
+
// the caller supplies -- deliberately, because deriving completeness from the
|
|
16
|
+
// store's own block table measures the annotator's bookkeeping rather than
|
|
17
|
+
// the annotation.
|
|
18
|
+
//
|
|
19
|
+
// Yet the census's ONLY tie to the external analyser this project rents its
|
|
20
|
+
// annotation store from was four inline comparisons against that analyser's
|
|
21
|
+
// Rust `Display` strings, spread across three code regions and reached from
|
|
22
|
+
// two lookup call sites. Four string literals were the entire reason a
|
|
23
|
+
// 2,292-line instrument looked like glue around somebody else's data model.
|
|
24
|
+
// Any prefix-driven deletion of the rented substrate would have taken the
|
|
25
|
+
// instrument with it.
|
|
26
|
+
//
|
|
27
|
+
// So the tie lives here, in one small module, behind one named function. A
|
|
28
|
+
// later phase swaps THIS module -- the store's vocabulary changes, the census
|
|
29
|
+
// does not. That is the whole point: the boundary is the module, never an
|
|
30
|
+
// argument threaded through the census.
|
|
31
|
+
//
|
|
32
|
+
// The neutral classes are LOWERCASE. That lowercase-ness was once claimed as
|
|
33
|
+
// a protection in its own right -- the argument being that a capitalised
|
|
34
|
+
// store spelling could not accidentally agree with it, so a comparison site
|
|
35
|
+
// left behind somewhere else would get a different answer and move a measured
|
|
36
|
+
// number, loudly. THAT PREMISE IS NOW FALSE, and the loss is recorded here
|
|
37
|
+
// rather than left to be rediscovered: this project's own
|
|
38
|
+
// store's vocabulary is LOWERCASE, and two of its twelve members -- the code
|
|
39
|
+
// spelling and the undefined spelling -- are string-identical to their
|
|
40
|
+
// neutral classes. A left-behind raw comparison against the store's own
|
|
41
|
+
// spelling therefore CAN accidentally agree now, silently, which is exactly
|
|
42
|
+
// what the old rationale promised could not happen.
|
|
43
|
+
//
|
|
44
|
+
// Two guards replace it, and they are why the mapping below is still
|
|
45
|
+
// defended. Neither is a claim in a header:
|
|
46
|
+
//
|
|
47
|
+
// (a) the derived TOTAL cross-check in `block-class.test.ts`. It iterates
|
|
48
|
+
// the store's frozen twelve-member vocabulary from its single home and
|
|
49
|
+
// asserts the class this module returns for EVERY member, with its own
|
|
50
|
+
// non-vacuity assertions on the counts. It reddens the moment either
|
|
51
|
+
// side drifts; a spot check would not.
|
|
52
|
+
// (b) `anno-coverage.test.ts`'s zero-overlap substitutability proof. Its
|
|
53
|
+
// substituted vocabulary (`EXECUTABLE_EXTENT` and its two siblings)
|
|
54
|
+
// shares no string with EITHER accepted vocabulary, so a left-behind
|
|
55
|
+
// comparison site is still observable there -- which is why that
|
|
56
|
+
// vocabulary list is DERIVED from both, not hand-written at four
|
|
57
|
+
// entries.
|
|
58
|
+
//
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// WHAT NOT TO DO -- each of these is a specific, named trap
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// 1. NEVER accept the census, the raw program bytes, a decoder, or a
|
|
63
|
+
// confidence grade as an argument here. `anno-coverage.ts` records a
|
|
64
|
+
// BYTES-VERSUS-STORE independence axis: one side classifies an address
|
|
65
|
+
// using only the raw bytes and the census, the other using only the
|
|
66
|
+
// store's own documentation, and NEITHER SIDE READS THE OTHER'S INPUT.
|
|
67
|
+
// That axis is the reason its reproducibility figure means anything.
|
|
68
|
+
// One extra argument here collapses it -- and it collapses QUIETLY: the
|
|
69
|
+
// independence test would keep passing while the claim it protects
|
|
70
|
+
// became void. The signature below is two arguments and must stay two.
|
|
71
|
+
// 2. NEVER compare a store vocabulary string outside this module. A second
|
|
72
|
+
// comparison site is a second answer to "what class is this address",
|
|
73
|
+
// and the census must have exactly one.
|
|
74
|
+
// 3. NEVER hold module-level mutable state. The lookup is a pure function
|
|
75
|
+
// of its two arguments, so interleaved or repeated calls cannot observe
|
|
76
|
+
// each other. There is nothing to reset and nothing to synchronise.
|
|
77
|
+
// 4. NEVER import anything census-side, disassembler-side, transport-side
|
|
78
|
+
// or path-translation-side. This module's import list is EMPTY and a
|
|
79
|
+
// committed structural assertion in `block-class.test.ts` keeps it that
|
|
80
|
+
// way -- see trap 1 for why the emptiness is load-bearing rather than
|
|
81
|
+
// tidy.
|
|
82
|
+
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// The neutral vocabulary
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The three neutral block classes every consumer speaks. Lowercase tokens.
|
|
89
|
+
*
|
|
90
|
+
* These tokens were once ALSO offered as a guard in their own right, on the
|
|
91
|
+
* ground that no store spelling could collide with them. Two of the store's
|
|
92
|
+
* twelve members now do collide, so that reading is gone -- see this file's
|
|
93
|
+
* header for the loss and for the two derived cross-checks that defend the
|
|
94
|
+
* mapping instead.
|
|
95
|
+
*
|
|
96
|
+
* Three-valued and no finer. The consumers compare this against a
|
|
97
|
+
* classification derived from completely different inputs, so a richer
|
|
98
|
+
* vocabulary would manufacture disagreement out of vocabulary drift rather
|
|
99
|
+
* than measure anything.
|
|
100
|
+
*/
|
|
101
|
+
export type BlockClass = "code" | "data" | "undefined";
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* One entry of a store's block listing, exactly as the curated read tool
|
|
105
|
+
* returns it.
|
|
106
|
+
*
|
|
107
|
+
* `type` carries the STORE'S OWN vocabulary -- whatever spelling the
|
|
108
|
+
* annotation substrate happens to use for its block kinds. This module is
|
|
109
|
+
* the only place in the tree that interprets that field. A consumer that
|
|
110
|
+
* reads `.type` and compares it is re-opening the boundary this file exists
|
|
111
|
+
* to close.
|
|
112
|
+
*/
|
|
113
|
+
export interface BlockEntry {
|
|
114
|
+
start_address: number;
|
|
115
|
+
end_address: number;
|
|
116
|
+
/** The store's own block-kind spelling. Interpreted HERE and nowhere else. */
|
|
117
|
+
type: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The shape of a block classifier: given a store's block listing and an
|
|
122
|
+
* address, the neutral class covering that address, or `null` when no block
|
|
123
|
+
* covers it.
|
|
124
|
+
*
|
|
125
|
+
* Named as a type so a consumer can be handed a substitute implementation
|
|
126
|
+
* for a substitutability proof without that consumer ever naming a concrete
|
|
127
|
+
* store vocabulary.
|
|
128
|
+
*/
|
|
129
|
+
export type BlockClassifier = (blocks: readonly BlockEntry[], address: number) => BlockClass | null;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The one production classifier.
|
|
133
|
+
*
|
|
134
|
+
* A linear scan, first-match-wins, with both range ends INCLUSIVE. A
|
|
135
|
+
* `null`/`undefined` hole in the array is skipped rather than thrown on --
|
|
136
|
+
* the listing arrives from a project file this process did not author. That
|
|
137
|
+
* premise applies to `blocks` ITSELF as well, so a non-array argument returns
|
|
138
|
+
* `null` here rather than throwing a `TypeError` out of the `for ... of`
|
|
139
|
+
* (IN-04). Both production callers already pre-guard with
|
|
140
|
+
* `Array.isArray(blocks) ? blocks : []`, so nothing is reachable today; the
|
|
141
|
+
* point is that the defence now lives in the module that DOCUMENTS the
|
|
142
|
+
* premise, instead of only in callers outside it.
|
|
143
|
+
*
|
|
144
|
+
* The mapping is total by construction over BOTH ACCEPTED VOCABULARIES: a
|
|
145
|
+
* code spelling from either becomes `"code"`, an undefined spelling from
|
|
146
|
+
* either becomes `"undefined"`, and EVERY other spelling becomes `"data"` --
|
|
147
|
+
* whether it belongs to one of the two vocabularies or to neither. That
|
|
148
|
+
* fallthrough is not a simplification; it is exactly what the two comparisons
|
|
149
|
+
* this function replaced did when read together, and it is what keeps an
|
|
150
|
+
* unrecognised spelling -- including one from a producer this module has
|
|
151
|
+
* never heard of -- from silently reading as code.
|
|
152
|
+
*
|
|
153
|
+
* The two arms are two VOCABULARIES that happen to differ in case, never one
|
|
154
|
+
* vocabulary compared case-insensitively. A case-insensitive or
|
|
155
|
+
* whitespace-trimming comparison here would silently accept a third spelling
|
|
156
|
+
* nobody chose; `block-class.test.ts` pins that it does not.
|
|
157
|
+
*/
|
|
158
|
+
export const blockClassAt: BlockClassifier = (blocks, address) => {
|
|
159
|
+
if (!Array.isArray(blocks)) return null;
|
|
160
|
+
for (const block of blocks) {
|
|
161
|
+
if (!block) continue;
|
|
162
|
+
if (address >= block.start_address && address <= block.end_address) {
|
|
163
|
+
// TWO ACCEPTED VOCABULARIES, one arm each, in the same order so the
|
|
164
|
+
// pairing reads at a glance. Deliberately NOT folded into a
|
|
165
|
+
// case-insensitive test -- see this function's doc comment.
|
|
166
|
+
//
|
|
167
|
+
// This project's own annotation store, whose twelve block types are
|
|
168
|
+
// lowercase and live in one frozen home the test cross-checks against:
|
|
169
|
+
if (block.type === "code") return "code";
|
|
170
|
+
if (block.type === "undefined") return "undefined";
|
|
171
|
+
// TRANSITIONAL -- the capitalised vocabulary, whose PRODUCER (the
|
|
172
|
+
// external analyser this project used to rent an annotation store from,
|
|
173
|
+
// whose Rust `Display` emitted these spellings) IS GONE AS OF PHASE 29,
|
|
174
|
+
// 2026-08-29. The trigger the previous comment named has therefore
|
|
175
|
+
// already fired, and the arm still stands. That is a decision, recorded
|
|
176
|
+
// here rather than left to be rediscovered as an inert branch:
|
|
177
|
+
//
|
|
178
|
+
// WHY IT SURVIVES ITS OWN TRIGGER: every committed coverage fixture
|
|
179
|
+
// under `fixtures/coverage/**/store.json` is still SPELLED in this
|
|
180
|
+
// vocabulary ("Code", "Byte", "Undefined"). Deleting the two arms
|
|
181
|
+
// below today reclassifies every fixture block as `data` -- silently,
|
|
182
|
+
// because `data` is the total fallthrough and no error is raised
|
|
183
|
+
// anywhere. The fixtures are the census's own controls, so that would
|
|
184
|
+
// move the numbers the controls exist to pin.
|
|
185
|
+
//
|
|
186
|
+
// THE NEW REMOVAL TRIGGER is therefore the FIXTURES being re-spelled
|
|
187
|
+
// into the store's own lowercase vocabulary -- not the producer being
|
|
188
|
+
// deleted, which has happened. Re-spell the fixtures (and their
|
|
189
|
+
// generator) first, observe the census unchanged, then delete these
|
|
190
|
+
// two lines.
|
|
191
|
+
//
|
|
192
|
+
// FATE: carried as a Phase 32 guard-fate item ("every guard pinned to
|
|
193
|
+
// the deleted subject has a recorded fate"), so the ledger picks this
|
|
194
|
+
// arm up deliberately instead of finding it red or inert in CI.
|
|
195
|
+
if (block.type === "Code") return "code";
|
|
196
|
+
if (block.type === "Undefined") return "undefined";
|
|
197
|
+
return "data";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return null;
|
|
201
|
+
};
|
package/build.ts
CHANGED
|
@@ -48,6 +48,8 @@ export const HOST_BOUND_ARTIFACTS: string[] = [
|
|
|
48
48
|
"broker-epoch.mjs",
|
|
49
49
|
"broker-control.mjs",
|
|
50
50
|
"backend-detect.mjs",
|
|
51
|
+
"host-tool.mjs",
|
|
52
|
+
"ghidra-project.mjs",
|
|
51
53
|
];
|
|
52
54
|
|
|
53
55
|
/** The generated-file banner (01.6-RESEARCH.md §F), a function of the
|
|
@@ -61,7 +63,7 @@ export function GENERATED_BANNER(relSourcePath: string): string {
|
|
|
61
63
|
`// Compiled by \`tsc\` from ${relSourcePath}. Edit the TypeScript source and rebuild;\n` +
|
|
62
64
|
"// changes made directly to this file are silently overwritten by the next build, and are never\n" +
|
|
63
65
|
"// deployed to the host on their own -- install-resources.mjs copies THIS file's on-disk contents\n" +
|
|
64
|
-
"// verbatim to tools/, so an edit made only here reaches the host but is lost on the very next\n" +
|
|
66
|
+
"// verbatim to .c64-re-tools/bin/, so an edit made only here reaches the host but is lost on the very next\n" +
|
|
65
67
|
"// rebuild.\n"
|
|
66
68
|
);
|
|
67
69
|
}
|
|
@@ -138,7 +140,7 @@ export interface BuildOptions {
|
|
|
138
140
|
* `renameSync()` per artifact, and `rename(2)` fails `EXDEV` across mounts.
|
|
139
141
|
* That is why the original implementation staged at `dirname(outDirAbs)`.
|
|
140
142
|
* 2. **Outside any directory a test walks.** Staging at `dirname(outDirAbs)`
|
|
141
|
-
* put a transient `.build-tmp-*` inside
|
|
143
|
+
* put a transient `.build-tmp-*` inside `src/mcp/vice/`, and
|
|
142
144
|
* `vice-mcp-selector-docs.test.ts`'s `walkFiles()` recurses through every
|
|
143
145
|
* directory there except `node_modules` — so a concurrent walk descended
|
|
144
146
|
* into the staging dir and died `ENOENT` when the rename removed it. That
|