@henols/c64-re-tools 1.1.0 → 2.0.0-rc.11
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/LICENSE +21 -0
- package/README.md +154 -37
- package/distribution/package.ts +21 -0
- package/distribution/plugin.ts +122 -0
- package/package.json +34 -40
- package/skills/c64-assembler/SKILL.md +76 -0
- package/skills/c64-assembler/scripts/assemble.ts +110 -0
- package/skills/c64-assembler/scripts/compare.ts +84 -0
- package/skills/c64-basic/SKILL.md +66 -0
- package/skills/c64-basic/scripts/basic.ts +46 -0
- package/skills/c64-disk/SKILL.md +93 -0
- package/skills/c64-disk/scripts/containers.ts +124 -0
- package/skills/c64-disk/scripts/disk.ts +120 -0
- package/skills/c64-emulator/SKILL.md +134 -0
- package/skills/c64-knowledge/SKILL.md +192 -0
- package/skills/c64-knowledge/scripts/knowledge.ts +613 -0
- package/skills/c64-memory-map/SKILL.md +79 -0
- package/skills/c64-memory-map/scripts/memmap.ts +92 -0
- package/skills/c64-provenance/SKILL.md +110 -0
- package/skills/c64-provenance/scripts/compare.ts +152 -0
- package/skills/c64-provenance/scripts/provenance.ts +334 -0
- package/skills/c64-provenance/scripts/runtime.ts +191 -0
- package/skills/c64-provenance/scripts/separate.ts +140 -0
- package/skills/c64-reverse-engineering/SKILL.md +144 -0
- package/skills/c64-source/SKILL.md +133 -0
- package/skills/c64-source/scripts/generate.ts +503 -0
- package/skills/c64-source/scripts/loader.ts +589 -0
- package/skills/c64-source/scripts/opcodes.ts +61 -0
- package/skills/c64-source/scripts/source.ts +673 -0
- package/skills/c64-static-analysis/SKILL.md +120 -0
- package/skills/c64-static-analysis/scripts/analyze.ts +293 -0
- package/skills/c64-static-analysis/scripts/coverage.ts +78 -0
- package/skills/c64-static-analysis/scripts/findings.ts +75 -0
- package/skills/c64-static-analysis/scripts/idioms.ts +149 -0
- package/skills/c64-static-analysis/scripts/instructions.ts +105 -0
- package/skills/c64-static-analysis/scripts/pointers.ts +108 -0
- package/skills/c64-testing/SKILL.md +103 -0
- package/skills/c64-testing/references/scenario-format.md +116 -0
- package/skills/c64-testing/scripts/checklist.ts +51 -0
- package/skills/c64-testing/scripts/run.ts +189 -0
- package/skills/c64-testing/scripts/scenario.ts +493 -0
- package/skills/c64-testing/scripts/test.ts +65 -0
- package/skills/c64-unpacker/SKILL.md +135 -0
- package/skills/c64-unpacker/scripts/evidence.ts +207 -0
- package/skills/c64-unpacker/scripts/loads.ts +209 -0
- package/skills/c64-unpacker/scripts/machine.ts +80 -0
- package/skills/c64-unpacker/scripts/stages.ts +130 -0
- package/skills/c64-unpacker/scripts/unpack.ts +683 -0
- package/src/c64.ts +411 -0
- package/src/cli/ap-sdk.ts +44 -0
- package/src/cli/cleanup.ts +194 -0
- package/src/cli/main.ts +125 -0
- package/src/cli/status.ts +61 -0
- package/src/host/main.ts +134 -0
- package/src/host/server.ts +392 -0
- package/src/host/tools/c1541.ts +284 -0
- package/src/host/tools/index.ts +35 -0
- package/src/host/tools/petcat.ts +77 -0
- package/src/host/tools/status.ts +47 -0
- package/src/host/tools/version.ts +41 -0
- package/src/host/vice/adapter.ts +804 -0
- package/src/host/vice/binary-monitor.ts +389 -0
- package/src/host/vice/chips.ts +118 -0
- package/src/host/vice/connect.ts +34 -0
- package/src/host/vice/process.ts +413 -0
- package/src/host/vice/screen.ts +184 -0
- package/src/host/vice/session.ts +1426 -0
- package/src/host/vice/text-monitor.ts +223 -0
- package/src/host-client/autostart.ts +55 -0
- package/src/host-client/connect.ts +241 -0
- package/src/host-client/coverage.ts +63 -0
- package/src/host-client/image.ts +63 -0
- package/src/host-client/steps.ts +170 -0
- package/src/host-client/tools.ts +89 -0
- package/src/host-client/transfer.ts +126 -0
- package/src/host-client/vice-session.ts +316 -0
- package/src/knowledge/database.ts +132 -0
- package/src/knowledge/expression.ts +209 -0
- package/src/knowledge/history.ts +169 -0
- package/src/knowledge/import.ts +392 -0
- package/src/knowledge/read.ts +392 -0
- package/src/knowledge/schema.ts +250 -0
- package/src/knowledge/write.ts +837 -0
- package/src/mcp/main.ts +134 -0
- package/src/mcp/output.ts +32 -0
- package/src/mcp/server.ts +316 -0
- package/src/mcp/tools/debug.ts +327 -0
- package/src/mcp/tools/execution.ts +117 -0
- package/src/mcp/tools/input.ts +72 -0
- package/src/mcp/tools/machine.ts +100 -0
- package/src/mcp/tools/media.ts +129 -0
- package/src/mcp/tools/memory.ts +250 -0
- package/src/mcp/tools/video.ts +271 -0
- package/src/native/acme.ts +116 -0
- package/src/native/discover.ts +179 -0
- package/src/native/dxa.ts +166 -0
- package/src/native/ghidra/analyze.ts +86 -0
- package/src/native/ghidra/index.ts +173 -0
- package/src/native/ghidra/language/c64rt_6510.cspec +34 -0
- package/src/native/ghidra/language/c64rt_6510.ldefs +15 -0
- package/src/native/ghidra/language/c64rt_6510.pspec +15 -0
- package/src/native/ghidra/language/c64rt_6510.slaspec +596 -0
- package/src/native/ghidra/scripts/C64Export.java +274 -0
- package/src/native/ghidra/scripts/C64Prepare.java +60 -0
- package/src/native/local.ts +34 -0
- package/src/native/processes.ts +350 -0
- package/src/native/run.ts +172 -0
- package/src/native/staging.ts +83 -0
- package/src/native/status.ts +113 -0
- package/src/native/types.ts +257 -0
- package/src/native/watchdog.ts +78 -0
- package/src/package.ts +21 -0
- package/src/platform.ts +441 -0
- package/src/project.ts +39 -0
- package/src/protocol/framing.ts +132 -0
- package/src/protocol/messages.ts +259 -0
- package/src/protocol/tools.ts +266 -0
- package/src/protocol/vice.ts +1348 -0
- package/src/script.ts +60 -0
- package/src/time.ts +15 -0
- package/src/trace.ts +194 -0
- package/THIRD-PARTY-NOTICES.md +0 -26
- package/bin/cli.mjs +0 -283
- package/skills/acme-build/SKILL.md +0 -260
- package/skills/acme-build/scripts/acme.mjs +0 -341
- package/skills/acme-build/template.a +0 -53
- package/skills/c64-disk-access/SKILL.md +0 -159
- package/skills/c64-disk-access/scripts/c1541.mjs +0 -569
- package/skills/c64-memory-mapping/SKILL.md +0 -631
- package/skills/c64-memory-mapping/memmap.json +0 -8800
- package/skills/c64-memory-mapping/scripts/driver.mjs +0 -553
- package/skills/c64-petcat/SKILL.md +0 -87
- package/skills/c64-petcat/scripts/petcat.mjs +0 -221
- package/skills/c64-program-recon/SKILL.md +0 -706
- package/skills/c64-program-recon/references/control-flow.md +0 -180
- package/skills/c64-program-recon/references/graphics.md +0 -79
- package/skills/c64-program-recon/references/observation-hazards.md +0 -143
- package/skills/c64-program-recon/references/reconstruction.md +0 -133
- package/skills/c64-program-recon/references/sound-and-input.md +0 -74
- package/skills/c64-program-recon/references/tool-selection.md +0 -78
- package/skills/c64-program-recon/scripts/derive.mjs +0 -364
- package/skills/c64-program-recon/scripts/packer-finding.mjs +0 -709
- package/skills/c64-program-recon/templates/memory-map.template.md +0 -101
- package/skills/c64-provenance-diff/SKILL.md +0 -292
- package/skills/c64-provenance-diff/scripts/diff-images.mjs +0 -984
- package/skills/c64-provenance-diff/scripts/recovery-schema.mjs +0 -395
- package/skills/c64-ram-capture/RELEASES.json.example +0 -17
- package/skills/c64-ram-capture/SKILL.md +0 -474
- package/skills/c64-ram-capture/scripts/compare-cross-binary.mjs +0 -525
- package/skills/c64-ram-capture/scripts/compare.mjs +0 -258
- package/skills/c64-ram-capture/scripts/derive-transients.mjs +0 -575
- package/skills/c64-ram-capture/scripts/dump-artifacts.mjs +0 -317
- package/skills/c64-ram-capture/scripts/mcp-module.mjs +0 -174
- package/skills/c64-ram-capture/scripts/project-paths.mjs +0 -81
- package/skills/c64-ram-capture/scripts/releases.mjs +0 -109
- package/skills/c64-ram-capture/scripts/vsf-slice.mjs +0 -147
- package/skills/c64-ram-capture/scripts/watch-loads.mjs +0 -581
- package/skills/c64-ram-capture/templates/capture-record.template.md +0 -99
- package/skills/c64-ram-capture/transients/README.md +0 -137
- package/skills/routine-queue-walker/SKILL.md +0 -394
- package/skills/routine-queue-walker/scripts/completeness-report.mjs +0 -465
- package/skills/vice-wedge-triage/SKILL.md +0 -269
package/src/cli/main.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
// The human CLI: installs the skills and the VICE MCP
|
|
3
|
+
// declaration into agent harnesses through AP SDK, and reports status. It is
|
|
4
|
+
// thin: AP SDK does the harness-specific work.
|
|
5
|
+
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { parseArgs } from "node:util";
|
|
9
|
+
|
|
10
|
+
import { PACKAGE } from "../package.ts";
|
|
11
|
+
import { localToolContext } from "../native/local.ts";
|
|
12
|
+
import { localToolStatus } from "../native/status.ts";
|
|
13
|
+
import { WireFailure } from "../protocol/messages.ts";
|
|
14
|
+
import { startTrace } from "../trace.ts";
|
|
15
|
+
import { runApSdk } from "./ap-sdk.ts";
|
|
16
|
+
import { installedItems, parseTargets, tidyAfterUninstall, undoWindsurfProjectMcp, windsurfBefore, withoutWindsurfMcp, type Scope } from "./cleanup.ts";
|
|
17
|
+
import { hostStatusLines, toolLines } from "./status.ts";
|
|
18
|
+
|
|
19
|
+
const HELP = `c64-re-tools: Commodore 64 reverse engineering and development
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
c64-re-tools install [--target <harnesses>] [--global] install the skills and the VICE MCP
|
|
23
|
+
c64-re-tools update [--target <harnesses>] [--global] install this version over an earlier one
|
|
24
|
+
c64-re-tools uninstall [--target <harnesses>] [--global] remove them
|
|
25
|
+
c64-re-tools status version, package, tools and the Host Runtime
|
|
26
|
+
c64-re-tools --help
|
|
27
|
+
|
|
28
|
+
Harnesses: claude, codex, pi, opencode, gemini, copilot, cursor, windsurf
|
|
29
|
+
(comma-separated; default: all). Without --global the files go into the
|
|
30
|
+
current project; with --global into your home directory.
|
|
31
|
+
|
|
32
|
+
Run it in the project: npx -y ${PACKAGE.name}@${PACKAGE.tag} install. The VICE
|
|
33
|
+
MCP declaration starts the latest c64-re-tools-mcp through npx. The Host
|
|
34
|
+
Runtime runs on the machine with VICE: start it there with
|
|
35
|
+
npx -y --package=${PACKAGE.name}@${PACKAGE.tag} c64-re-tools-host.
|
|
36
|
+
It runs VICE and the tools that come with it (c1541, petcat). The skill
|
|
37
|
+
scripts run ACME, DXA and Ghidra themselves, on the machine of the agent.`;
|
|
38
|
+
|
|
39
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
40
|
+
|
|
41
|
+
/** Runs the AP SDK CLI. Writes its error output to stderr and returns its exit status and its report. */
|
|
42
|
+
async function apSdk(command: "install" | "uninstall", flags: readonly string[]): Promise<{ code: number; output: string }> {
|
|
43
|
+
// The report is printed after the CLI's own tidying, so the colours stay when this is a terminal.
|
|
44
|
+
const run = await runApSdk(command, flags, localToolContext(), process.stdout.isTTY ? { env: { ...process.env, FORCE_COLOR: "1" } } : {});
|
|
45
|
+
process.stderr.write(run.stderr);
|
|
46
|
+
return { code: run.code, output: run.stdout };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function status(): Promise<number> {
|
|
50
|
+
console.log(`c64-re-tools ${PACKAGE.version}`);
|
|
51
|
+
console.log(`Package: ${join(here, "..", "..")}`);
|
|
52
|
+
console.log(`Node: ${process.version} (${process.execPath})`);
|
|
53
|
+
// The skill scripts run these tools here, on this machine.
|
|
54
|
+
const local = await localToolStatus(localToolContext());
|
|
55
|
+
for (const line of toolLines("Tools here:", local)) console.log(line);
|
|
56
|
+
const host = await hostStatusLines();
|
|
57
|
+
for (const line of host.lines) console.log(line);
|
|
58
|
+
// A script or a CI check can tell a ready setup from a broken one.
|
|
59
|
+
return host.ready && local.every((tool) => tool.runs) ? 0 : 1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function main(argv: string[]): Promise<number> {
|
|
63
|
+
startTrace("cli", { warn: (line) => console.error(line) });
|
|
64
|
+
const { values, positionals } = parseArgs({
|
|
65
|
+
args: argv,
|
|
66
|
+
strict: true,
|
|
67
|
+
allowPositionals: true,
|
|
68
|
+
options: { target: { type: "string", short: "t" }, global: { type: "boolean", short: "g" }, help: { type: "boolean", short: "h" } },
|
|
69
|
+
});
|
|
70
|
+
const [command, ...rest] = positionals;
|
|
71
|
+
if (values.help || command === undefined) {
|
|
72
|
+
console.log(HELP);
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
if (rest.length > 0) {
|
|
76
|
+
console.error(`Too many arguments.\n\n${HELP}`);
|
|
77
|
+
return 2;
|
|
78
|
+
}
|
|
79
|
+
const flags = [...(values.target === undefined ? [] : ["--target", values.target]), ...(values.global ? ["--global"] : [])];
|
|
80
|
+
const scope: Scope = values.global ? "global" : "project";
|
|
81
|
+
const targets = parseTargets(values.target);
|
|
82
|
+
switch (command) {
|
|
83
|
+
case "install":
|
|
84
|
+
case "update": {
|
|
85
|
+
const before = windsurfBefore();
|
|
86
|
+
const { code, output } = await apSdk("install", flags);
|
|
87
|
+
// A project install leaves the home directory as it was.
|
|
88
|
+
const note = scope === "project" && (targets === undefined || targets.includes("windsurf")) ? undoWindsurfProjectMcp(before) : undefined;
|
|
89
|
+
process.stdout.write(note === undefined ? output : withoutWindsurfMcp(output));
|
|
90
|
+
if (note !== undefined) console.log(` ${note}\n`);
|
|
91
|
+
return code;
|
|
92
|
+
}
|
|
93
|
+
case "uninstall": {
|
|
94
|
+
const items = installedItems(scope, targets);
|
|
95
|
+
const { code, output } = await apSdk("uninstall", flags);
|
|
96
|
+
process.stdout.write(output);
|
|
97
|
+
if (code === 0) tidyAfterUninstall(items, scope);
|
|
98
|
+
return code;
|
|
99
|
+
}
|
|
100
|
+
case "status":
|
|
101
|
+
if (flags.length > 0) {
|
|
102
|
+
console.error(`status takes no --target or --global.\n\n${HELP}`);
|
|
103
|
+
return 2;
|
|
104
|
+
}
|
|
105
|
+
return status();
|
|
106
|
+
default:
|
|
107
|
+
console.error(`Unknown command ${command}.\n\n${HELP}`);
|
|
108
|
+
return 2;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if ((error as NodeJS.ErrnoException).code?.startsWith("ERR_PARSE_ARGS")) {
|
|
116
|
+
console.error(`${(error as Error).message}\n\n${HELP}`);
|
|
117
|
+
process.exitCode = 2;
|
|
118
|
+
} else if (error instanceof WireFailure) {
|
|
119
|
+
// A refusal by name, for example AP SDK that did not finish in time.
|
|
120
|
+
console.error(error.message);
|
|
121
|
+
process.exitCode = 1;
|
|
122
|
+
} else {
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// The status report of the CLI: the tools on this machine and the Host
|
|
2
|
+
// Runtime with its tools.
|
|
3
|
+
|
|
4
|
+
import { hostTools, type ToolCallOptions } from "../host-client/tools.ts";
|
|
5
|
+
import { viceVersionOf } from "../native/discover.ts";
|
|
6
|
+
import { PACKAGE } from "../package.ts";
|
|
7
|
+
import { STOP_AND_ASK } from "../protocol/messages.ts";
|
|
8
|
+
import type { HostInfo, ToolStatus } from "../protocol/tools.ts";
|
|
9
|
+
|
|
10
|
+
/** One line per tool under `heading`: its version, or why it does not run; then each known flaw of it. */
|
|
11
|
+
export function toolLines(heading: string, tools: readonly ToolStatus[]): string[] {
|
|
12
|
+
return [
|
|
13
|
+
heading,
|
|
14
|
+
...tools.flatMap((tool) => [
|
|
15
|
+
tool.runs
|
|
16
|
+
? ` ${tool.name}: ${tool.version} (${tool.path})`
|
|
17
|
+
: tool.found
|
|
18
|
+
? ` ${tool.name}: found at ${tool.path} but it does not run. ${tool.problem}`
|
|
19
|
+
: ` ${tool.name}: missing. ${tool.problem}`,
|
|
20
|
+
...(tool.flaws ?? []).map((flaw) => ` Known flaw: ${flaw}`),
|
|
21
|
+
]),
|
|
22
|
+
];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Whether the Host Runtime answers, and the tools it has. VICE and its tools
|
|
27
|
+
* live on the host; it finds and runs each one. One request shows both that
|
|
28
|
+
* the host answers and what it has. `ready` is true when the host answers and
|
|
29
|
+
* every tool on it runs.
|
|
30
|
+
*/
|
|
31
|
+
export async function hostStatusLines(options: ToolCallOptions = {}): Promise<{ lines: string[]; ready: boolean }> {
|
|
32
|
+
let host: HostInfo;
|
|
33
|
+
let tools: ToolStatus[];
|
|
34
|
+
try {
|
|
35
|
+
({ host, tools } = await hostTools(options));
|
|
36
|
+
} catch (error) {
|
|
37
|
+
// status is read by a person: the instruction for an agent (D37) stays out.
|
|
38
|
+
return { lines: [`Host Runtime: not reachable. ${(error as Error).message.replace(` ${STOP_AND_ASK}`, "")}`], ready: false };
|
|
39
|
+
}
|
|
40
|
+
const mixed = mixedViceBuilds(tools);
|
|
41
|
+
return {
|
|
42
|
+
lines: [
|
|
43
|
+
`Host Runtime: reachable, c64-re-tools ${host.version} on ${host.platform} ${host.release} (${host.arch})`,
|
|
44
|
+
...(host.version === PACKAGE.version ? [] : [` Warning: the Host Runtime is c64-re-tools ${host.version} and this is ${PACKAGE.version}. Start the host again so that both are the same version.`]),
|
|
45
|
+
...toolLines("Tools on the host:", tools),
|
|
46
|
+
...(mixed === undefined ? [] : [` Warning: ${mixed}`]),
|
|
47
|
+
],
|
|
48
|
+
ready: tools.every((tool) => tool.runs),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** A warning when x64sc, c1541 and petcat that run come from different VICE versions or builds. */
|
|
53
|
+
export function mixedViceBuilds(tools: readonly ToolStatus[]): string | undefined {
|
|
54
|
+
const running = tools.filter((tool) => tool.runs && tool.version !== undefined);
|
|
55
|
+
const builds = running.map((tool) => {
|
|
56
|
+
const version = viceVersionOf(tool.version!);
|
|
57
|
+
return version === undefined ? tool.version! : `VICE ${version.major}.${version.minor}${version.revision === undefined ? "" : ` SVN r${version.revision}`}`;
|
|
58
|
+
});
|
|
59
|
+
if (new Set(builds).size <= 1) return undefined;
|
|
60
|
+
return `the VICE tools come from different VICE builds: ${running.map((tool) => `${tool.version} (${tool.path})`).join(", ")}. Put x64sc, c1541 and petcat of one VICE first on PATH, or set C64RT_VICE, C64RT_C1541 and C64RT_PETCAT.`;
|
|
61
|
+
}
|
package/src/host/main.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
|
|
5
|
+
import { DEFAULT_HOST_PORT } from "../protocol/messages.ts";
|
|
6
|
+
import { ProcessSupervisor } from "../native/processes.ts";
|
|
7
|
+
import { startTrace, trace } from "../trace.ts";
|
|
8
|
+
import { ListenError, parsePort, startHostServer, stopSignal } from "./server.ts";
|
|
9
|
+
import { viceFlaws, type ViceVersion } from "../native/discover.ts";
|
|
10
|
+
import { createToolDispatcher } from "./tools/index.ts";
|
|
11
|
+
import { checkViceStarts, findVice } from "./vice/process.ts";
|
|
12
|
+
import { viceSessionFactory } from "./vice/session.ts";
|
|
13
|
+
import { PACKAGE } from "../package.ts";
|
|
14
|
+
|
|
15
|
+
const HELP = `c64-re-tools-host
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
npx -y --package=${PACKAGE.name}@${PACKAGE.tag} c64-re-tools-host [--port <port>] [--log-console] [--log-dir <directory>]
|
|
19
|
+
c64-re-tools-host --help
|
|
20
|
+
|
|
21
|
+
Runs the c64-re-tools Host Runtime in the foreground. It first starts VICE
|
|
22
|
+
once (x64sc on PATH, or C64RT_VICE) and does not start if VICE cannot run.
|
|
23
|
+
It listens on port ${DEFAULT_HOST_PORT} on every address, so a dev container
|
|
24
|
+
reaches it as host.docker.internal. It starts one VICE emulator for each
|
|
25
|
+
connected c64-re-tools-mcp process, and runs the tools that come with VICE
|
|
26
|
+
(c1541, petcat) for skill scripts. Stop it with Ctrl+C; that stops every
|
|
27
|
+
emulator and tool it started.
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
--port <port> Listen on this port instead (0 picks a free port).
|
|
31
|
+
--log-console Also print each request with its result, and each run
|
|
32
|
+
of c1541 or petcat, to the console.
|
|
33
|
+
--log-dir <directory> Write the same events as JSON lines to a file in this
|
|
34
|
+
directory, with a copy of each VICE log.
|
|
35
|
+
--help Show this help.
|
|
36
|
+
|
|
37
|
+
The host always logs its start and stop, connections, failures, and each call
|
|
38
|
+
from a skill script (c1541, petcat) with its outcome. --log-console adds the
|
|
39
|
+
calls of the MCP server and the tool runs. C64RT_TRACE does not apply to the host.`;
|
|
40
|
+
|
|
41
|
+
function log(line: string): void {
|
|
42
|
+
process.stderr.write(`c64-re-tools-host: ${line}\n`);
|
|
43
|
+
trace().log(line);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function main(): Promise<number> {
|
|
47
|
+
let values: { help?: boolean; port?: string; "log-console"?: boolean; "log-dir"?: string };
|
|
48
|
+
try {
|
|
49
|
+
({ values } = parseArgs({
|
|
50
|
+
options: { help: { type: "boolean" }, port: { type: "string" }, "log-console": { type: "boolean" }, "log-dir": { type: "string" } },
|
|
51
|
+
strict: true,
|
|
52
|
+
}));
|
|
53
|
+
} catch (error) {
|
|
54
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n\n${HELP}\n`);
|
|
55
|
+
return 2;
|
|
56
|
+
}
|
|
57
|
+
if (values.help) {
|
|
58
|
+
process.stdout.write(`${HELP}\n`);
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
const logDir = values["log-dir"];
|
|
62
|
+
if (logDir === "") {
|
|
63
|
+
process.stderr.write("--log-dir needs a directory.\n");
|
|
64
|
+
return 2;
|
|
65
|
+
}
|
|
66
|
+
startTrace("host", {
|
|
67
|
+
target: {
|
|
68
|
+
...(logDir === undefined ? {} : { dir: { path: logDir, given: `--log-dir ${logDir}` } }),
|
|
69
|
+
...(values["log-console"] ? { echo: (line: string) => process.stderr.write(`c64-re-tools-host: ${line}\n`) } : {}),
|
|
70
|
+
},
|
|
71
|
+
warn: log,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const port = values.port === undefined ? DEFAULT_HOST_PORT : parsePort(values.port);
|
|
75
|
+
if (port === undefined) {
|
|
76
|
+
process.stderr.write(`--port must be a number from 0 to 65535, written with digits only. You gave "${values.port}".\n`);
|
|
77
|
+
return 2;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Without an emulator the runtime is useless: refuse to start, by name and with the remedy.
|
|
81
|
+
try {
|
|
82
|
+
findVice(process.env);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
process.stderr.write(`${(error as Error).message}\n`);
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Every emulator and tool is started through this one supervisor; however
|
|
89
|
+
// this process ends, the exit guard takes their process groups down with it,
|
|
90
|
+
// and the watchdog does the same if this process is killed.
|
|
91
|
+
const supervisor = new ProcessSupervisor();
|
|
92
|
+
supervisor.startWatchdog("host");
|
|
93
|
+
|
|
94
|
+
// Finding x64sc is not enough: VICE without its ROM files exits at once.
|
|
95
|
+
let vice: ViceVersion;
|
|
96
|
+
try {
|
|
97
|
+
vice = await checkViceStarts({ supervisor });
|
|
98
|
+
} catch (error) {
|
|
99
|
+
process.stderr.write(`${(error as Error).message}\n`);
|
|
100
|
+
await supervisor.stopAll();
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
103
|
+
log(`VICE ${vice.major}.${vice.minor}${vice.revision === undefined ? "" : ` r${vice.revision}`} starts`);
|
|
104
|
+
const flaws = viceFlaws(vice);
|
|
105
|
+
// A known VICE flaw is named, not worked around (D56).
|
|
106
|
+
for (const flaw of flaws) log(`Known VICE flaw: ${flaw}`);
|
|
107
|
+
|
|
108
|
+
let server;
|
|
109
|
+
try {
|
|
110
|
+
server = await startHostServer({
|
|
111
|
+
host: "0.0.0.0",
|
|
112
|
+
port,
|
|
113
|
+
log,
|
|
114
|
+
createViceSession: viceSessionFactory({ supervisor, log, flaws }),
|
|
115
|
+
tools: createToolDispatcher({ supervisor, log, vice }),
|
|
116
|
+
});
|
|
117
|
+
} catch (error) {
|
|
118
|
+
if (error instanceof ListenError && error.code === "EADDRINUSE") {
|
|
119
|
+
process.stderr.write(`Port ${error.port} on ${error.address} is in use. Is another c64-re-tools-host running?\n`);
|
|
120
|
+
return 1;
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
const address = `${server.host}:${server.port}`;
|
|
125
|
+
process.stdout.write(`c64-re-tools-host listening on ${address}\n`);
|
|
126
|
+
trace().event("host.listening", { addresses: [address] });
|
|
127
|
+
|
|
128
|
+
trace().event("host.stop", { signal: await stopSignal(log) });
|
|
129
|
+
await server.close();
|
|
130
|
+
await supervisor.stopAll();
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
process.exitCode = await main();
|