@henols/vice-mcp 1.0.0 → 1.1.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/THIRD-PARTY-NOTICES.md +6 -4
- package/anno-cli.ts +1 -1
- package/anno-store.ts +1 -1
- package/backend-detect.mts +143 -19
- package/build.ts +42 -1
- package/evid-ingest.ts +7 -3
- package/host-tool-client.ts +7 -3
- package/package.json +3 -1
- package/prerequisites.json +416 -0
- package/prg-image.ts +1 -1
- package/repo-root.ts +19 -8
- package/resources/backend-detect.mjs +90 -18
- package/resources/broker-launch.mjs +11 -2
- package/resources/ghidra-project.mjs +2 -2
- package/resources/host-tool.mjs +306 -82
- package/resources/prerequisites.json +416 -0
- package/resources/tool-location.mjs +750 -0
- package/resources/vice-broker.mjs +85 -12
- package/stock-checkpoints.ts +2 -2
- package/stock-connect.ts +12 -10
- package/stock-execution.ts +4 -2
- package/stock-memory-search.ts +3 -2
- package/stock-protocol.ts +60 -28
- package/stock-registers.ts +3 -1
- package/text-protocol.ts +6 -3
- package/textmon-profile.ts +8 -3
- package/version.ts +34 -246
- package/vice-proxy.ts +23 -23
package/THIRD-PARTY-NOTICES.md
CHANGED
|
@@ -501,9 +501,11 @@ appears in `src/mcp/vice/package.json`'s `files[]`, `dependencies`, or
|
|
|
501
501
|
VICE is GPL-2 and this repository is MIT. **No opcode fact, protocol
|
|
502
502
|
constant, or line of code in this repository is sourced from VICE's own
|
|
503
503
|
source tree.** The stock backend is built against the binary-monitor
|
|
504
|
-
**protocol**
|
|
505
|
-
|
|
506
|
-
|
|
504
|
+
**protocol** this project independently reverse-engineered and specified as
|
|
505
|
+
its own normative wire format -- the 11-byte request header, 12-byte
|
|
506
|
+
response header, and confirmed command/response/error code set -- derived
|
|
507
|
+
from independent probing against a running VICE binary, never from reading
|
|
508
|
+
VICE's own C source.
|
|
507
509
|
|
|
508
510
|
## Explicitly NOT a source: `fluffy-6502`
|
|
509
511
|
|
|
@@ -530,5 +532,5 @@ have been.
|
|
|
530
532
|
No new runtime dependency was added by the disassembler (`disasm-opcodes.ts`,
|
|
531
533
|
`disasm-decoder.ts`, `disasm-renderer.ts`, `stock-disassemble.ts` import only
|
|
532
534
|
this package's own sibling modules and Node built-ins). This is a checkable
|
|
533
|
-
claim, not a prose one:
|
|
535
|
+
claim, not a prose one: the packed
|
|
534
536
|
tarball's runtime `dependencies` are exactly these two, by key set and count.
|
package/anno-cli.ts
CHANGED
|
@@ -131,7 +131,7 @@ import { renderMemoryMap, checkRenderedMemoryMap } from "./anno-memmap-render.ts
|
|
|
131
131
|
// one. `acme-verify.ts` -- the module that DOES spawn ACME -- is deliberately
|
|
132
132
|
// NOT imported here and must never be: it is test-only (it is absent from
|
|
133
133
|
// `package.json`'s `files[]` on purpose), so a shipped module importing it
|
|
134
|
-
// would drag it into the published closure
|
|
134
|
+
// would drag it into the published closure.
|
|
135
135
|
import { exportAsmTree } from "./anno-export-asm.ts";
|
|
136
136
|
import type { ExportAsmTreeResult } from "./anno-export-asm.ts";
|
|
137
137
|
// The coverage instrument. It declares its own input shapes
|
package/anno-store.ts
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
// THIS MODULE MUST BE LISTED IN `package.json`'s `files[]`, and the reason is
|
|
51
51
|
// NOT the reachability reason `prg-image.ts:30-36` gives for itself. This
|
|
52
52
|
// module is not yet reachable from the published entry point's import closure,
|
|
53
|
-
// and
|
|
53
|
+
// and only one direction was ever asserted mechanically -- every
|
|
54
54
|
// REACHABLE module must be listed -- never the converse. The real reason to
|
|
55
55
|
// list it: the shipped-module assertion scans `shippedTsModules()`, which is derived
|
|
56
56
|
// from `files[]`, so an unlisted module makes that assertion VACUOUS. It would
|
package/backend-detect.mts
CHANGED
|
@@ -41,6 +41,30 @@
|
|
|
41
41
|
// is the exact failure class the 2026-08-01 triple-launch outage came
|
|
42
42
|
// from (D-03/T-02-25) -- unchanged reasoning from before this plan, only
|
|
43
43
|
// the mechanism inside resolvedBackend() changed.
|
|
44
|
+
//
|
|
45
|
+
// Phase 60 (LOC-01/LOC-02, PD-01/PD-02/PD-03): resolvedBackend() gains a real
|
|
46
|
+
// VALUE dependency on the tool-location seam (tool-location.mts) for the
|
|
47
|
+
// emulator binary's own resolution -- when neither `viceBin` nor
|
|
48
|
+
// `resolveBinPath` is injected, resolution goes through the seam's
|
|
49
|
+
// `resolveTool("x64sc", ...)` instead of this file's own ordering, so a
|
|
50
|
+
// `.c64-re-tools/tools.json` entry for `x64sc` now changes what this broker
|
|
51
|
+
// actually spawns. `defaultResolveBinPath()` collapses into a thin wrapper
|
|
52
|
+
// over the seam's own exported `resolveOnPath()` -- the first of Phase 59
|
|
53
|
+
// D-02's three independent `$PATH`-walk copies to collapse.
|
|
54
|
+
//
|
|
55
|
+
// This file ships two ways (see the cache-section comment below): unbuilt,
|
|
56
|
+
// imported directly by container-side .ts (vice-proxy.ts's own `import *
|
|
57
|
+
// as backendDetect from "./backend-detect.mts"`), and compiled into
|
|
58
|
+
// resources/ for the host (vice-broker.mts's own `./backend-detect.mjs`
|
|
59
|
+
// value import). A STATIC `import ... from "./tool-location.mjs"` would
|
|
60
|
+
// resolve in only the SECOND form -- that file exists as a real sibling
|
|
61
|
+
// only once both are compiled into resources/, never beside the unbuilt
|
|
62
|
+
// source. Loading it instead through node:module's `createRequire()`
|
|
63
|
+
// (`toolLocationSeam()` below) defers resolution to the call site rather
|
|
64
|
+
// than parse time, so trying the compiled sibling first and falling back to
|
|
65
|
+
// the unbuilt source sibling keeps this ONE seam call working in both
|
|
66
|
+
// shipped forms -- one implementation, no #ifdef-style split, and every
|
|
67
|
+
// existing unbuilt importer of this file needs no change at all.
|
|
44
68
|
import {
|
|
45
69
|
existsSync,
|
|
46
70
|
readFileSync,
|
|
@@ -50,7 +74,17 @@ import {
|
|
|
50
74
|
mkdirSync,
|
|
51
75
|
statSync,
|
|
52
76
|
} from "node:fs";
|
|
53
|
-
import {
|
|
77
|
+
import { dirname, join } from "node:path";
|
|
78
|
+
import { fileURLToPath } from "node:url";
|
|
79
|
+
import { createRequire } from "node:module";
|
|
80
|
+
import type { ResolveToolDeps, resolveTool, resolveOnPath } from "./tool-location.mjs";
|
|
81
|
+
|
|
82
|
+
/** `typeof` the seam's own exported functions -- imported as VALUES above
|
|
83
|
+
* (under `import type`, so still fully erased at runtime; see this file's
|
|
84
|
+
* own header for why the REAL call goes through `toolLocationSeam()`
|
|
85
|
+
* instead) purely so their call signatures can be named as types here. */
|
|
86
|
+
type ResolveToolFn = typeof resolveTool;
|
|
87
|
+
type ResolveOnPathFn = typeof resolveOnPath;
|
|
54
88
|
|
|
55
89
|
/** The one shape this tree ever launches or speaks to. FORKRM-01 narrowed
|
|
56
90
|
* this from a two-member union ("fork" | "stock") to this single literal --
|
|
@@ -201,18 +235,48 @@ export interface BinaryIdentity {
|
|
|
201
235
|
sizeBytes: number;
|
|
202
236
|
}
|
|
203
237
|
|
|
238
|
+
/** This module's own directory. Computed once, purely to seed
|
|
239
|
+
* `toolLocationSeam()`'s two-candidate join below -- mirrors
|
|
240
|
+
* `tool-location.mts`'s own `HERE` constant and its `readDeclaration()`
|
|
241
|
+
* "beside `here`, take the first that exists" idiom exactly. */
|
|
242
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
243
|
+
|
|
244
|
+
/** The tool-location seam's runtime shape, as this file actually calls it --
|
|
245
|
+
* an interface, not a value import, because the interface itself is
|
|
246
|
+
* satisfied by `import type` (erased entirely, resolved for TYPES only via
|
|
247
|
+
* tsc's own NodeNext ".mjs" -> ".mts" mapping) while the REAL call happens
|
|
248
|
+
* through `toolLocationSeam()` below. */
|
|
249
|
+
interface ToolLocationSeam {
|
|
250
|
+
resolveTool: ResolveToolFn;
|
|
251
|
+
resolveOnPath: ResolveOnPathFn;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Loads the tool-location seam through `node:module`'s `createRequire()`
|
|
255
|
+
* rather than a static ESM import -- see this file's own header for why a
|
|
256
|
+
* static specifier cannot work in both of this file's two shipped forms.
|
|
257
|
+
* `require()` resolves at THIS call site, not at parse time, so trying the
|
|
258
|
+
* compiled resources/ sibling first and falling back to the unbuilt source
|
|
259
|
+
* sibling (the exact two-candidate order `tool-location.mts`'s own
|
|
260
|
+
* `readDeclaration()` already uses for `prerequisites.json`) lets the SAME
|
|
261
|
+
* source file resolve correctly whichever way this file itself was loaded.
|
|
262
|
+
* Never memoised here -- `resolvedBackend()`'s own `memoisedResult` already
|
|
263
|
+
* ensures this runs at most once in the one production path that reaches
|
|
264
|
+
* it, and a test process that resets that memo between scenarios must be
|
|
265
|
+
* free to call this again, cheaply, rather than replay a stale answer. */
|
|
266
|
+
function toolLocationSeam(): ToolLocationSeam {
|
|
267
|
+
const req = createRequire(import.meta.url);
|
|
268
|
+
const specifier = existsSync(join(HERE, "tool-location.mjs")) ? "./tool-location.mjs" : "./tool-location.mts";
|
|
269
|
+
return req(specifier) as ToolLocationSeam;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Reduced (Phase 60) to a thin wrapper over the seam's own exported
|
|
273
|
+
* `resolveOnPath()` -- the first of Phase 59 D-02's three independent
|
|
274
|
+
* `$PATH`-walk copies to collapse. Kept as a named function (rather than
|
|
275
|
+
* inlined at its one call site) only because `ResolvedBackendDeps.resolveBinPath`
|
|
276
|
+
* needs a real default to fall back to when a caller supplies `viceBin` but
|
|
277
|
+
* not this override (PD-02). */
|
|
204
278
|
function defaultResolveBinPath(bin: string, env: NodeJS.ProcessEnv): string | null {
|
|
205
|
-
|
|
206
|
-
const abs = resolvePath(bin);
|
|
207
|
-
return existsSync(abs) ? abs : null;
|
|
208
|
-
}
|
|
209
|
-
const pathEnv = env.PATH ?? "";
|
|
210
|
-
for (const dir of pathEnv.split(":")) {
|
|
211
|
-
if (!dir) continue;
|
|
212
|
-
const candidate = join(dir, bin);
|
|
213
|
-
if (existsSync(candidate)) return candidate;
|
|
214
|
-
}
|
|
215
|
-
return null;
|
|
279
|
+
return toolLocationSeam().resolveOnPath(bin, env).path;
|
|
216
280
|
}
|
|
217
281
|
|
|
218
282
|
function defaultStat(resolvedPath: string): BinaryIdentity | null {
|
|
@@ -247,13 +311,27 @@ export interface ResolvedBackendResult {
|
|
|
247
311
|
* the two it has, instead of a reader having to guess from whether the string
|
|
248
312
|
* happens to contain a slash. */
|
|
249
313
|
binPathResolved: boolean;
|
|
314
|
+
/** Phase 60 gap closure (LOC-03, PD-13): the tool-location seam's own
|
|
315
|
+
* `ResolveToolResult.refusal` verbatim, carried through unchanged, when
|
|
316
|
+
* resolution went through the seam (the PD-01 branch below) AND the seam
|
|
317
|
+
* refused. `null` in every other case -- including the PD-02
|
|
318
|
+
* injected-override branch, which never calls the seam at all and so has
|
|
319
|
+
* no refusal to carry. This is what lets `vice-broker.mts` write a
|
|
320
|
+
* readable startup line naming which environment-variable override was
|
|
321
|
+
* refused and why, without itself reading any of the four declared
|
|
322
|
+
* variable names. */
|
|
323
|
+
locationRefusal: string | null;
|
|
250
324
|
}
|
|
251
325
|
|
|
252
326
|
export interface ResolvedBackendDeps {
|
|
253
327
|
env?: NodeJS.ProcessEnv;
|
|
254
|
-
/**
|
|
255
|
-
*
|
|
256
|
-
*
|
|
328
|
+
/** An explicit override that BYPASSES the seam entirely (PD-02) --
|
|
329
|
+
* defaults to the literal "x64sc" when omitted but `resolveBinPath` below
|
|
330
|
+
* IS supplied. This no longer "defaults to VICE_BIN or x64sc": when BOTH
|
|
331
|
+
* this field and `resolveBinPath` are omitted, resolution goes through the
|
|
332
|
+
* tool-location seam instead (PD-01) and this field plays no part in it.
|
|
333
|
+
* Every existing caller that injects this field keeps its exact prior
|
|
334
|
+
* behaviour, byte-for-byte. */
|
|
257
335
|
viceBin?: string;
|
|
258
336
|
/** See this module's own header comment on the cache section above --
|
|
259
337
|
* NEVER defaulted here. Omitted entirely disables the on-disk cache
|
|
@@ -262,6 +340,21 @@ export interface ResolvedBackendDeps {
|
|
|
262
340
|
resolveBinPath?: (bin: string, env: NodeJS.ProcessEnv) => string | null;
|
|
263
341
|
stat?: (resolvedPath: string) => BinaryIdentity | null;
|
|
264
342
|
now?: () => number;
|
|
343
|
+
/** The directory holding `.c64-re-tools/tools.json` -- passed straight
|
|
344
|
+
* into the seam's `resolveTool()` call when neither `viceBin` nor
|
|
345
|
+
* `resolveBinPath` above is supplied (PD-01). Derived from `supervisorDir`
|
|
346
|
+
* (PD-03) when omitted and a `supervisorDir` IS given -- vice-broker.mts's
|
|
347
|
+
* own `args.stateDir` IS `.c64-re-tools/supervisor` under this broker's
|
|
348
|
+
* repo root, so that derivation is exact, not a guess -- otherwise
|
|
349
|
+
* `process.cwd()`. */
|
|
350
|
+
toolsDir?: string;
|
|
351
|
+
/** The project root a relative `tools.json` value resolves against --
|
|
352
|
+
* same PD-03 derivation rule as `toolsDir` above. */
|
|
353
|
+
projectRoot?: string;
|
|
354
|
+
/** Test-only override for the seam call itself -- defaults to
|
|
355
|
+
* `toolLocationSeam()`'s own lazily-loaded `resolveTool`. Follows the same
|
|
356
|
+
* injection convention as `resolveBinPath`/`stat`/`now` above. */
|
|
357
|
+
locate?: ResolveToolFn;
|
|
265
358
|
}
|
|
266
359
|
|
|
267
360
|
// Memoised answer -- a long-running process (the real broker) resolves once
|
|
@@ -309,12 +402,43 @@ export function resolvedBackend(deps: ResolvedBackendDeps = {}): ResolvedBackend
|
|
|
309
402
|
if (memoisedResult !== null) return memoisedResult;
|
|
310
403
|
|
|
311
404
|
const env = deps.env ?? process.env;
|
|
312
|
-
const viceBin = deps.viceBin ?? env.VICE_BIN ?? "x64sc";
|
|
313
|
-
const resolveBinPath = deps.resolveBinPath ?? defaultResolveBinPath;
|
|
314
405
|
const stat = deps.stat ?? defaultStat;
|
|
315
406
|
const now = deps.now ?? ((): number => Date.now());
|
|
316
407
|
|
|
317
|
-
|
|
408
|
+
let viceBin: string;
|
|
409
|
+
let resolvedPath: string | null;
|
|
410
|
+
// Phase 60 gap closure (LOC-03, PD-13): non-null only in the PD-01 branch
|
|
411
|
+
// below, and only when the seam itself refused. Carried verbatim onto the
|
|
412
|
+
// returned result's own `locationRefusal` field (see that field's own doc
|
|
413
|
+
// comment for why); this module reads no environment variable to compose
|
|
414
|
+
// it, and reads none to name it here either.
|
|
415
|
+
let locationRefusal: string | null = null;
|
|
416
|
+
|
|
417
|
+
if (deps.viceBin !== undefined || deps.resolveBinPath !== undefined) {
|
|
418
|
+
// PD-02: an explicit override bypasses the seam entirely -- byte-for-byte
|
|
419
|
+
// the same behaviour every existing injected test case already exercises.
|
|
420
|
+
viceBin = deps.viceBin ?? "x64sc";
|
|
421
|
+
const resolveBinPath = deps.resolveBinPath ?? defaultResolveBinPath;
|
|
422
|
+
resolvedPath = resolveBinPath(viceBin, env);
|
|
423
|
+
} else {
|
|
424
|
+
// PD-01: resolvedBackend() gains the tools.json layer internally by
|
|
425
|
+
// calling the seam; it keeps no ordering of its own. The seam's WHOLE
|
|
426
|
+
// result is taken here (PD-13), not only its `path`: the display name
|
|
427
|
+
// handed to binPathFields() below falls back to the seam's own
|
|
428
|
+
// `envCandidate` -- the value the developer actually wrote -- when the
|
|
429
|
+
// seam reports one, and to the literal "x64sc" only when it does not
|
|
430
|
+
// (retiring the hardcoded display name IN-01 logged). `refusal` is
|
|
431
|
+
// carried onto `locationRefusal` above unchanged.
|
|
432
|
+
const projectRoot = deps.projectRoot ?? (deps.supervisorDir !== undefined ? dirname(dirname(deps.supervisorDir)) : process.cwd());
|
|
433
|
+
const toolsDir = deps.toolsDir ?? (deps.supervisorDir !== undefined ? dirname(deps.supervisorDir) : join(process.cwd(), ".c64-re-tools"));
|
|
434
|
+
const locate: ResolveToolFn = deps.locate ?? toolLocationSeam().resolveTool;
|
|
435
|
+
const locateDeps: ResolveToolDeps = { toolsDir, projectRoot, env };
|
|
436
|
+
const locateResult = locate("x64sc", locateDeps);
|
|
437
|
+
resolvedPath = locateResult.path;
|
|
438
|
+
viceBin = locateResult.envCandidate ?? "x64sc";
|
|
439
|
+
locationRefusal = locateResult.refusal;
|
|
440
|
+
}
|
|
441
|
+
|
|
318
442
|
const identity = resolvedPath ? stat(resolvedPath) : null;
|
|
319
443
|
const cacheEligible = resolvedPath !== null && identity !== null && typeof deps.supervisorDir === "string";
|
|
320
444
|
|
|
@@ -336,7 +460,7 @@ export function resolvedBackend(deps: ResolvedBackendDeps = {}): ResolvedBackend
|
|
|
336
460
|
}
|
|
337
461
|
}
|
|
338
462
|
|
|
339
|
-
const result: ResolvedBackendResult = { backend: "stock", ...binPathFields(resolvedPath, viceBin) };
|
|
463
|
+
const result: ResolvedBackendResult = { backend: "stock", ...binPathFields(resolvedPath, viceBin), locationRefusal };
|
|
340
464
|
memoisedResult = result;
|
|
341
465
|
return result;
|
|
342
466
|
}
|
package/build.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// under bare `node`, exactly like vice-broker.mts.
|
|
12
12
|
import { execFileSync } from "node:child_process";
|
|
13
13
|
import {
|
|
14
|
+
copyFileSync,
|
|
14
15
|
existsSync,
|
|
15
16
|
mkdirSync,
|
|
16
17
|
mkdtempSync,
|
|
@@ -50,8 +51,30 @@ export const HOST_BOUND_ARTIFACTS: string[] = [
|
|
|
50
51
|
"backend-detect.mjs",
|
|
51
52
|
"host-tool.mjs",
|
|
52
53
|
"ghidra-project.mjs",
|
|
54
|
+
"tool-location.mjs",
|
|
53
55
|
];
|
|
54
56
|
|
|
57
|
+
/** A plain data file that travels WITH the compiled artifacts above, never
|
|
58
|
+
* compiled by `tsc` and never asserted against `HOST_BOUND_ARTIFACTS`'s own
|
|
59
|
+
* emitted-file-set check (that check is `.mjs`-only, per
|
|
60
|
+
* `emittedMjsFilesUnder()` below). Found missing by Plan 60-05's own
|
|
61
|
+
* required full-suite baseline diff: `tool-location.mts`'s
|
|
62
|
+
* `readDeclaration()` locates `prerequisites.json` "beside `here`" or one
|
|
63
|
+
* directory up from wherever the compiled module actually runs. That
|
|
64
|
+
* candidate pair only ever resolved correctly while the compiled artifact
|
|
65
|
+
* ran IN PLACE inside `src/mcp/vice/resources/` (one directory up lands on
|
|
66
|
+
* `src/mcp/vice/prerequisites.json`) -- once `vice-broker.mts` started
|
|
67
|
+
* resolving `x64sc` through the seam at STARTUP (Plan 60-01), a real
|
|
68
|
+
* deployment into a consuming project's `.c64-re-tools/bin/` (where
|
|
69
|
+
* neither candidate exists) made the broker throw before it ever wrote
|
|
70
|
+
* `broker.json`. Copying it into `resources/` here, alongside every
|
|
71
|
+
* compiled artifact, makes `install-resources.ts`'s own generic recursive
|
|
72
|
+
* walk of `resources/` deploy it automatically -- no separate deploy-side
|
|
73
|
+
* code needed -- and gives `readDeclaration()`'s FIRST candidate ("beside
|
|
74
|
+
* `here`") a real file at every location the compiled module ever runs
|
|
75
|
+
* from, deployed or not. */
|
|
76
|
+
export const HOST_BOUND_DATA_FILES: string[] = ["prerequisites.json"];
|
|
77
|
+
|
|
55
78
|
/** The generated-file banner (01.6-RESEARCH.md §F), a function of the
|
|
56
79
|
* source's relative path. Prepended to every emitted file by build() below --
|
|
57
80
|
* this is the ONLY place that produces this text, so a sync test built
|
|
@@ -230,6 +253,24 @@ export function build({ outDir = "resources" }: BuildOptions = {}): void {
|
|
|
230
253
|
}
|
|
231
254
|
}
|
|
232
255
|
|
|
256
|
+
// HOST_BOUND_DATA_FILES: a plain copy, never compiled by tsc and never
|
|
257
|
+
// part of the emitted-file-set assertion above (that check is
|
|
258
|
+
// `.mjs`-only). Staged and renamed the SAME atomic way as every
|
|
259
|
+
// compiled artifact -- never exposed at an `outDir` path half-written --
|
|
260
|
+
// so it must be moved into place BEFORE the leftover check below, or its
|
|
261
|
+
// own staged copy would itself register as an unexplained leftover.
|
|
262
|
+
for (const rel of HOST_BOUND_DATA_FILES) {
|
|
263
|
+
const staged = join(stagingDir, rel);
|
|
264
|
+
copyFileSync(join(HERE, rel), staged);
|
|
265
|
+
const to = join(outDirAbs, rel);
|
|
266
|
+
try {
|
|
267
|
+
renameSync(staged, to);
|
|
268
|
+
} catch (e) {
|
|
269
|
+
const detail = (e as NodeJS.ErrnoException).code === "EXDEV" ? " (EXDEV: staging dir and outDir are on different filesystems -- outDir must be reachable via a same-filesystem sibling)" : "";
|
|
270
|
+
throw new Error(`build: failed to move staged data file into place: ${staged} -> ${to}${detail}`, { cause: e });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
233
274
|
// tsc emits exactly HOST_BOUND_ARTIFACTS today (verified). A leftover
|
|
234
275
|
// here means the compiler started emitting something this list does not
|
|
235
276
|
// describe -- fail loudly rather than silently drop a file that used to
|
|
@@ -263,7 +304,7 @@ if (process.argv[1] && resolvePath(process.argv[1]) === fileURLToPath(import.met
|
|
|
263
304
|
try {
|
|
264
305
|
build(opts);
|
|
265
306
|
const outDirAbs = resolveOutDirAbs(opts.outDir ?? "resources");
|
|
266
|
-
process.stderr.write(`build: wrote ${HOST_BOUND_ARTIFACTS.length} artifact(s) to ${outDirAbs}\n`);
|
|
307
|
+
process.stderr.write(`build: wrote ${HOST_BOUND_ARTIFACTS.length} artifact(s) and ${HOST_BOUND_DATA_FILES.length} data file(s) to ${outDirAbs}\n`);
|
|
267
308
|
} catch (e) {
|
|
268
309
|
process.stderr.write(`build: FAILED -- ${(e as Error).message}\n`);
|
|
269
310
|
process.exitCode = 1;
|
package/evid-ingest.ts
CHANGED
|
@@ -92,9 +92,13 @@ export interface IngestRunIdentity {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/** `runIdentityFrom()`'s answer: the bare `(imageSha256, argvDigest, seed)`
|
|
95
|
-
* triple the `no-change` run-identity decision selected
|
|
96
|
-
*
|
|
97
|
-
*
|
|
95
|
+
* triple the `no-change` run-identity decision selected -- measured by an
|
|
96
|
+
* A/B capture comparison that ran the identical anchor-counted AUTOSTART
|
|
97
|
+
* sequence with and without runtime evidence dialed over the text channel
|
|
98
|
+
* and found the two byte-for-byte equivalent at both tested anchor depths,
|
|
99
|
+
* so recording evidence does not perturb the capture and the run identity
|
|
100
|
+
* needs no extra discriminator -- no `runClass` discriminator field exists
|
|
101
|
+
* on this type. */
|
|
98
102
|
export interface RunIdentity {
|
|
99
103
|
readonly imageSha256: string;
|
|
100
104
|
readonly argvDigest: string;
|
package/host-tool-client.ts
CHANGED
|
@@ -40,9 +40,13 @@
|
|
|
40
40
|
// this new family off that five-member list entirely, by construction.
|
|
41
41
|
//
|
|
42
42
|
// Do not write the tokens `binPath`, `viceBin`, `VICE_BIN` or `x64sc`
|
|
43
|
-
// anywhere in this file -- it ships (package.json `files[]`)
|
|
44
|
-
// by
|
|
45
|
-
//
|
|
43
|
+
// anywhere in this file -- it ships (package.json `files[]`). This is kept
|
|
44
|
+
// deliberately, by CONVENTION, not by a mechanical guard: the test that once
|
|
45
|
+
// scanned for those four tokens (its own file) was deleted in commit
|
|
46
|
+
// `276c15c9` and is not revived here. What IS mechanically enforced, over
|
|
47
|
+
// the four tool-location environment-variable names this project reads, is
|
|
48
|
+
// the closed consumer set `tool-location-consumers.test.ts` (plan 60-05)
|
|
49
|
+
// asserts.
|
|
46
50
|
import { readFileSync } from "node:fs";
|
|
47
51
|
import { spawn } from "node:child_process";
|
|
48
52
|
import { connect } from "node:net";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@henols/vice-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "VICE emulator MCP server for C64 reverse-engineering: a stdio MCP server that proxies vice tools to a host VICE MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"anno-symbols.ts",
|
|
66
66
|
"anno-regbits-gen.ts",
|
|
67
67
|
"anno-regbits.json",
|
|
68
|
+
"prerequisites.json",
|
|
68
69
|
"anno-enum-gen.ts",
|
|
69
70
|
"anno-acme-ident.ts",
|
|
70
71
|
"anno-confidence.ts",
|
|
@@ -133,6 +134,7 @@
|
|
|
133
134
|
"test:manual": "node test-gate.mjs --manual",
|
|
134
135
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
135
136
|
"build": "node build.ts",
|
|
137
|
+
"generate:readme": "node prereq-readme-gen.ts --write",
|
|
136
138
|
"smoke": "node smoke.mjs"
|
|
137
139
|
},
|
|
138
140
|
"dependencies": {
|