@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.
Files changed (162) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -37
  3. package/distribution/package.ts +21 -0
  4. package/distribution/plugin.ts +122 -0
  5. package/package.json +34 -40
  6. package/skills/c64-assembler/SKILL.md +76 -0
  7. package/skills/c64-assembler/scripts/assemble.ts +110 -0
  8. package/skills/c64-assembler/scripts/compare.ts +84 -0
  9. package/skills/c64-basic/SKILL.md +66 -0
  10. package/skills/c64-basic/scripts/basic.ts +46 -0
  11. package/skills/c64-disk/SKILL.md +93 -0
  12. package/skills/c64-disk/scripts/containers.ts +124 -0
  13. package/skills/c64-disk/scripts/disk.ts +120 -0
  14. package/skills/c64-emulator/SKILL.md +134 -0
  15. package/skills/c64-knowledge/SKILL.md +192 -0
  16. package/skills/c64-knowledge/scripts/knowledge.ts +613 -0
  17. package/skills/c64-memory-map/SKILL.md +79 -0
  18. package/skills/c64-memory-map/scripts/memmap.ts +92 -0
  19. package/skills/c64-provenance/SKILL.md +110 -0
  20. package/skills/c64-provenance/scripts/compare.ts +152 -0
  21. package/skills/c64-provenance/scripts/provenance.ts +334 -0
  22. package/skills/c64-provenance/scripts/runtime.ts +191 -0
  23. package/skills/c64-provenance/scripts/separate.ts +140 -0
  24. package/skills/c64-reverse-engineering/SKILL.md +144 -0
  25. package/skills/c64-source/SKILL.md +133 -0
  26. package/skills/c64-source/scripts/generate.ts +503 -0
  27. package/skills/c64-source/scripts/loader.ts +589 -0
  28. package/skills/c64-source/scripts/opcodes.ts +61 -0
  29. package/skills/c64-source/scripts/source.ts +673 -0
  30. package/skills/c64-static-analysis/SKILL.md +120 -0
  31. package/skills/c64-static-analysis/scripts/analyze.ts +293 -0
  32. package/skills/c64-static-analysis/scripts/coverage.ts +78 -0
  33. package/skills/c64-static-analysis/scripts/findings.ts +75 -0
  34. package/skills/c64-static-analysis/scripts/idioms.ts +149 -0
  35. package/skills/c64-static-analysis/scripts/instructions.ts +105 -0
  36. package/skills/c64-static-analysis/scripts/pointers.ts +108 -0
  37. package/skills/c64-testing/SKILL.md +103 -0
  38. package/skills/c64-testing/references/scenario-format.md +116 -0
  39. package/skills/c64-testing/scripts/checklist.ts +51 -0
  40. package/skills/c64-testing/scripts/run.ts +189 -0
  41. package/skills/c64-testing/scripts/scenario.ts +493 -0
  42. package/skills/c64-testing/scripts/test.ts +65 -0
  43. package/skills/c64-unpacker/SKILL.md +135 -0
  44. package/skills/c64-unpacker/scripts/evidence.ts +207 -0
  45. package/skills/c64-unpacker/scripts/loads.ts +209 -0
  46. package/skills/c64-unpacker/scripts/machine.ts +80 -0
  47. package/skills/c64-unpacker/scripts/stages.ts +130 -0
  48. package/skills/c64-unpacker/scripts/unpack.ts +683 -0
  49. package/src/c64.ts +411 -0
  50. package/src/cli/ap-sdk.ts +44 -0
  51. package/src/cli/cleanup.ts +194 -0
  52. package/src/cli/main.ts +125 -0
  53. package/src/cli/status.ts +61 -0
  54. package/src/host/main.ts +134 -0
  55. package/src/host/server.ts +392 -0
  56. package/src/host/tools/c1541.ts +284 -0
  57. package/src/host/tools/index.ts +35 -0
  58. package/src/host/tools/petcat.ts +77 -0
  59. package/src/host/tools/status.ts +47 -0
  60. package/src/host/tools/version.ts +41 -0
  61. package/src/host/vice/adapter.ts +804 -0
  62. package/src/host/vice/binary-monitor.ts +389 -0
  63. package/src/host/vice/chips.ts +118 -0
  64. package/src/host/vice/connect.ts +34 -0
  65. package/src/host/vice/process.ts +413 -0
  66. package/src/host/vice/screen.ts +184 -0
  67. package/src/host/vice/session.ts +1426 -0
  68. package/src/host/vice/text-monitor.ts +223 -0
  69. package/src/host-client/autostart.ts +55 -0
  70. package/src/host-client/connect.ts +241 -0
  71. package/src/host-client/coverage.ts +63 -0
  72. package/src/host-client/image.ts +63 -0
  73. package/src/host-client/steps.ts +170 -0
  74. package/src/host-client/tools.ts +89 -0
  75. package/src/host-client/transfer.ts +126 -0
  76. package/src/host-client/vice-session.ts +316 -0
  77. package/src/knowledge/database.ts +132 -0
  78. package/src/knowledge/expression.ts +209 -0
  79. package/src/knowledge/history.ts +169 -0
  80. package/src/knowledge/import.ts +392 -0
  81. package/src/knowledge/read.ts +392 -0
  82. package/src/knowledge/schema.ts +250 -0
  83. package/src/knowledge/write.ts +837 -0
  84. package/src/mcp/main.ts +134 -0
  85. package/src/mcp/output.ts +32 -0
  86. package/src/mcp/server.ts +316 -0
  87. package/src/mcp/tools/debug.ts +327 -0
  88. package/src/mcp/tools/execution.ts +117 -0
  89. package/src/mcp/tools/input.ts +72 -0
  90. package/src/mcp/tools/machine.ts +100 -0
  91. package/src/mcp/tools/media.ts +129 -0
  92. package/src/mcp/tools/memory.ts +250 -0
  93. package/src/mcp/tools/video.ts +271 -0
  94. package/src/native/acme.ts +116 -0
  95. package/src/native/discover.ts +179 -0
  96. package/src/native/dxa.ts +166 -0
  97. package/src/native/ghidra/analyze.ts +86 -0
  98. package/src/native/ghidra/index.ts +173 -0
  99. package/src/native/ghidra/language/c64rt_6510.cspec +34 -0
  100. package/src/native/ghidra/language/c64rt_6510.ldefs +15 -0
  101. package/src/native/ghidra/language/c64rt_6510.pspec +15 -0
  102. package/src/native/ghidra/language/c64rt_6510.slaspec +596 -0
  103. package/src/native/ghidra/scripts/C64Export.java +274 -0
  104. package/src/native/ghidra/scripts/C64Prepare.java +60 -0
  105. package/src/native/local.ts +34 -0
  106. package/src/native/processes.ts +350 -0
  107. package/src/native/run.ts +172 -0
  108. package/src/native/staging.ts +83 -0
  109. package/src/native/status.ts +113 -0
  110. package/src/native/types.ts +257 -0
  111. package/src/native/watchdog.ts +78 -0
  112. package/src/package.ts +21 -0
  113. package/src/platform.ts +441 -0
  114. package/src/project.ts +39 -0
  115. package/src/protocol/framing.ts +132 -0
  116. package/src/protocol/messages.ts +259 -0
  117. package/src/protocol/tools.ts +266 -0
  118. package/src/protocol/vice.ts +1348 -0
  119. package/src/script.ts +60 -0
  120. package/src/time.ts +15 -0
  121. package/src/trace.ts +194 -0
  122. package/THIRD-PARTY-NOTICES.md +0 -26
  123. package/bin/cli.mjs +0 -283
  124. package/skills/acme-build/SKILL.md +0 -260
  125. package/skills/acme-build/scripts/acme.mjs +0 -341
  126. package/skills/acme-build/template.a +0 -53
  127. package/skills/c64-disk-access/SKILL.md +0 -159
  128. package/skills/c64-disk-access/scripts/c1541.mjs +0 -569
  129. package/skills/c64-memory-mapping/SKILL.md +0 -631
  130. package/skills/c64-memory-mapping/memmap.json +0 -8800
  131. package/skills/c64-memory-mapping/scripts/driver.mjs +0 -553
  132. package/skills/c64-petcat/SKILL.md +0 -87
  133. package/skills/c64-petcat/scripts/petcat.mjs +0 -221
  134. package/skills/c64-program-recon/SKILL.md +0 -706
  135. package/skills/c64-program-recon/references/control-flow.md +0 -180
  136. package/skills/c64-program-recon/references/graphics.md +0 -79
  137. package/skills/c64-program-recon/references/observation-hazards.md +0 -143
  138. package/skills/c64-program-recon/references/reconstruction.md +0 -133
  139. package/skills/c64-program-recon/references/sound-and-input.md +0 -74
  140. package/skills/c64-program-recon/references/tool-selection.md +0 -78
  141. package/skills/c64-program-recon/scripts/derive.mjs +0 -364
  142. package/skills/c64-program-recon/scripts/packer-finding.mjs +0 -709
  143. package/skills/c64-program-recon/templates/memory-map.template.md +0 -101
  144. package/skills/c64-provenance-diff/SKILL.md +0 -292
  145. package/skills/c64-provenance-diff/scripts/diff-images.mjs +0 -984
  146. package/skills/c64-provenance-diff/scripts/recovery-schema.mjs +0 -395
  147. package/skills/c64-ram-capture/RELEASES.json.example +0 -17
  148. package/skills/c64-ram-capture/SKILL.md +0 -474
  149. package/skills/c64-ram-capture/scripts/compare-cross-binary.mjs +0 -525
  150. package/skills/c64-ram-capture/scripts/compare.mjs +0 -258
  151. package/skills/c64-ram-capture/scripts/derive-transients.mjs +0 -575
  152. package/skills/c64-ram-capture/scripts/dump-artifacts.mjs +0 -317
  153. package/skills/c64-ram-capture/scripts/mcp-module.mjs +0 -174
  154. package/skills/c64-ram-capture/scripts/project-paths.mjs +0 -81
  155. package/skills/c64-ram-capture/scripts/releases.mjs +0 -109
  156. package/skills/c64-ram-capture/scripts/vsf-slice.mjs +0 -147
  157. package/skills/c64-ram-capture/scripts/watch-loads.mjs +0 -581
  158. package/skills/c64-ram-capture/templates/capture-record.template.md +0 -99
  159. package/skills/c64-ram-capture/transients/README.md +0 -137
  160. package/skills/routine-queue-walker/SKILL.md +0 -394
  161. package/skills/routine-queue-walker/scripts/completeness-report.mjs +0 -465
  162. package/skills/vice-wedge-triage/SKILL.md +0 -269
@@ -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
+ }
@@ -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();