c64bridge 1.0.5 → 1.0.6

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 (46) hide show
  1. package/README.md +2 -2
  2. package/data/sound/sidwave.md +113 -36
  3. package/data/sound/sidwave.schema.json +138 -28
  4. package/dist/.tsbuildinfo +1 -1
  5. package/dist/c64Client.js +83 -93
  6. package/dist/config.js +21 -4
  7. package/dist/device.js +130 -24
  8. package/dist/diagnostics.js +10 -2
  9. package/dist/mcp-server.js +12 -4
  10. package/dist/sidwave.js +453 -61
  11. package/dist/sidwaveCompiler.js +1424 -269
  12. package/dist/tools/audio.js +70 -12
  13. package/dist/tools/developer.js +7 -7
  14. package/dist/tools/errors.js +7 -0
  15. package/dist/tools/graphics.js +4 -4
  16. package/dist/tools/input.js +8 -11
  17. package/dist/tools/machineControl.js +6 -6
  18. package/dist/tools/memory.js +6 -6
  19. package/dist/tools/meta/audio.js +8 -2
  20. package/dist/tools/meta/graphics.js +1 -1
  21. package/dist/tools/meta/memory.js +4 -4
  22. package/dist/tools/meta/program.js +12 -8
  23. package/dist/tools/printer.js +4 -4
  24. package/dist/tools/programRunners.js +8 -8
  25. package/dist/tools/registry/disk.js +7 -5
  26. package/dist/tools/storage.js +21 -17
  27. package/dist/tools/streaming.js +2 -2
  28. package/dist/tools/translation/assembler.js +44 -12
  29. package/dist/tools/translation/basicTokenizer.js +5 -1
  30. package/dist/tools/translation/opcodeInventory.js +1 -1
  31. package/dist/tools/vice.js +1 -1
  32. package/dist/vice/mockServer.js +92 -5
  33. package/dist/vice/readiness.js +4 -9
  34. package/dist/vice/viceClient.js +18 -0
  35. package/mcp/schemas/c64_disk.schema.json +2 -2
  36. package/mcp/schemas/c64_input.schema.json +3 -3
  37. package/mcp/schemas/c64_program.schema.json +2 -2
  38. package/mcp/schemas/c64_vice.schema.json +3 -3
  39. package/mcp/server.json +1 -1
  40. package/mcp/tools.json +14 -10
  41. package/mcp.json +1 -1
  42. package/package.json +1 -1
  43. package/scripts/mockC64Server.mjs +15 -1
  44. package/scripts/run-coverage.mjs +31 -1
  45. package/scripts/update-readme.ts +3 -2
  46. package/server.json +2 -2
@@ -178,7 +178,7 @@
178
178
  "required": [
179
179
  "op"
180
180
  ],
181
- "description": "Input operations: write_text, key, keyboard, joystick, release_all, state.\n\nOperations:\n- write_text: Send a text string to the keyboard buffer, with PETSCII token expansion. Required inputs: text. Optional inputs: delayMs.\n- key: Tap a single key or hold it for a duration. Required inputs: key. Optional inputs: durationMs, count.\n- joystick: Simulate joystick input. On C64U/U64 this uses machine:input; VICE uses Binary Monitor Joyport Set. Required inputs: port, controls, action. Optional inputs: durationMs.\n- keyboard: Send physical C64 keyboard matrix events through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: inputs, transition.\n- release_all: Release every key and joystick control injected through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: none.\n- state: Read the keys and joystick controls held through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: none.",
181
+ "description": "Input operations: write_text, key, keyboard, joystick, release_all, state.\n\nOperations:\n- write_text: Send a text string to the keyboard buffer, with PETSCII token expansion. Required inputs: text. Optional inputs: delayMs.\n- key: Tap a single key or hold it for a duration. Required inputs: key. Optional inputs: durationMs, count.\n- joystick: Simulate joystick input. On C64U/U64 this uses machine:input. On VICE it attaches VICE's I/O simulation joyport device while pressed; that device also pulls CIA lines 5-7 low, so port 1 produces phantom keys (e.g. SHIFT+C=) and port 2 reads $1E for up instead of $7E. Prefer port 2 on VICE and test bits 0-4. Required inputs: port, controls, action. Optional inputs: durationMs.\n- keyboard: Send physical C64 keyboard matrix events through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: inputs, transition.\n- release_all: Release every key and joystick control injected through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: none.\n- state: Read the keys and joystick controls held through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: none.",
182
182
  "additionalProperties": false,
183
183
  "x-c64bridge-operations": [
184
184
  {
@@ -274,7 +274,7 @@
274
274
  },
275
275
  {
276
276
  "op": "joystick",
277
- "description": "Simulate joystick input. On C64U/U64 this uses machine:input; VICE uses Binary Monitor Joyport Set.",
277
+ "description": "Simulate joystick input. On C64U/U64 this uses machine:input. On VICE it attaches VICE's I/O simulation joyport device while pressed; that device also pulls CIA lines 5-7 low, so port 1 produces phantom keys (e.g. SHIFT+C=) and port 2 reads $1E for up instead of $7E. Prefer port 2 on VICE and test bits 0-4.",
278
278
  "required": [
279
279
  "port",
280
280
  "controls",
@@ -285,7 +285,7 @@
285
285
  ],
286
286
  "inputSchema": {
287
287
  "type": "object",
288
- "description": "Simulate joystick input. On C64U/U64 this uses machine:input; VICE uses Binary Monitor Joyport Set.",
288
+ "description": "Simulate joystick input. On C64U/U64 this uses machine:input. On VICE it attaches VICE's I/O simulation joyport device while pressed; that device also pulls CIA lines 5-7 low, so port 1 produces phantom keys (e.g. SHIFT+C=) and port 2 reads $1E for up instead of $7E. Prefer port 2 on VICE and test bits 0-4.",
289
289
  "properties": {
290
290
  "op": {
291
291
  "const": "joystick"
@@ -60,7 +60,7 @@
60
60
  "properties": {
61
61
  "type": {
62
62
  "type": "string",
63
- "description": "Assertion type",
63
+ "description": "Assertion type; sid_silent needs the C64 Ultimate audio stream (c64u backend).",
64
64
  "enum": [
65
65
  "screen_contains",
66
66
  "memory_equals",
@@ -462,7 +462,7 @@
462
462
  "properties": {
463
463
  "type": {
464
464
  "type": "string",
465
- "description": "Assertion type",
465
+ "description": "Assertion type; sid_silent needs the C64 Ultimate audio stream (c64u backend).",
466
466
  "enum": [
467
467
  "screen_contains",
468
468
  "memory_equals",
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "name": {
13
13
  "type": "string",
14
- "description": "VICE resource name (example: SidEngine, C64Model).",
14
+ "description": "VICE resource name (example: SidEngine, SidModel).",
15
15
  "minLength": 1,
16
16
  "maxLength": 64,
17
17
  "pattern": "^[A-Z][A-Za-z0-9_.-]{0,63}$"
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "name": {
48
48
  "type": "string",
49
- "description": "VICE resource name (example: SidEngine, C64Model).",
49
+ "description": "VICE resource name (example: SidEngine, SidModel).",
50
50
  "minLength": 1,
51
51
  "maxLength": 64,
52
52
  "pattern": "^[A-Z][A-Za-z0-9_.-]{0,63}$"
@@ -76,7 +76,7 @@
76
76
  },
77
77
  "name": {
78
78
  "type": "string",
79
- "description": "VICE resource name (example: SidEngine, C64Model).",
79
+ "description": "VICE resource name (example: SidEngine, SidModel).",
80
80
  "minLength": 1,
81
81
  "maxLength": 64,
82
82
  "pattern": "^[A-Z][A-Za-z0-9_.-]{0,63}$"
package/mcp/server.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c64bridge",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Stdio-based Model Context Protocol (MCP) server that bridges Commodore 64 Ultimate hardware with AI agents.",
5
5
  "transports": [
6
6
  "stdio"
package/mcp/tools.json CHANGED
@@ -66,7 +66,7 @@
66
66
  "properties": {
67
67
  "type": {
68
68
  "type": "string",
69
- "description": "Assertion type",
69
+ "description": "Assertion type; sid_silent needs the C64 Ultimate audio stream (c64u backend).",
70
70
  "enum": [
71
71
  "screen_contains",
72
72
  "memory_equals",
@@ -468,7 +468,7 @@
468
468
  "properties": {
469
469
  "type": {
470
470
  "type": "string",
471
- "description": "Assertion type",
471
+ "description": "Assertion type; sid_silent needs the C64 Ultimate audio stream (c64u backend).",
472
472
  "enum": [
473
473
  "screen_contains",
474
474
  "memory_equals",
@@ -4483,7 +4483,7 @@
4483
4483
  "integer",
4484
4484
  "null"
4485
4485
  ],
4486
- "description": "Track count (D64 supports 35 or 40; DNP requires explicit tracks).",
4486
+ "description": "Track count (D64 supports 35 to 41; DNP requires explicit tracks).",
4487
4487
  "minimum": 1,
4488
4488
  "maximum": 255
4489
4489
  },
@@ -4785,7 +4785,7 @@
4785
4785
  "integer",
4786
4786
  "null"
4787
4787
  ],
4788
- "description": "Track count (D64 supports 35 or 40; DNP requires explicit tracks).",
4788
+ "description": "Track count (D64 supports 35 to 41; DNP requires explicit tracks).",
4789
4789
  "minimum": 1,
4790
4790
  "maximum": 255
4791
4791
  },
@@ -4949,6 +4949,10 @@
4949
4949
  "vice"
4950
4950
  ],
4951
4951
  "operationPlatforms": {
4952
+ "unmount": [
4953
+ "c64u",
4954
+ "u2"
4955
+ ],
4952
4956
  "file_info": [
4953
4957
  "c64u",
4954
4958
  "u2"
@@ -8075,7 +8079,7 @@
8075
8079
  },
8076
8080
  "name": {
8077
8081
  "type": "string",
8078
- "description": "VICE resource name (example: SidEngine, C64Model).",
8082
+ "description": "VICE resource name (example: SidEngine, SidModel).",
8079
8083
  "minLength": 1,
8080
8084
  "maxLength": 64,
8081
8085
  "pattern": "^[A-Z][A-Za-z0-9_.-]{0,63}$"
@@ -8110,7 +8114,7 @@
8110
8114
  },
8111
8115
  "name": {
8112
8116
  "type": "string",
8113
- "description": "VICE resource name (example: SidEngine, C64Model).",
8117
+ "description": "VICE resource name (example: SidEngine, SidModel).",
8114
8118
  "minLength": 1,
8115
8119
  "maxLength": 64,
8116
8120
  "pattern": "^[A-Z][A-Za-z0-9_.-]{0,63}$"
@@ -8140,7 +8144,7 @@
8140
8144
  },
8141
8145
  "name": {
8142
8146
  "type": "string",
8143
- "description": "VICE resource name (example: SidEngine, C64Model).",
8147
+ "description": "VICE resource name (example: SidEngine, SidModel).",
8144
8148
  "minLength": 1,
8145
8149
  "maxLength": 64,
8146
8150
  "pattern": "^[A-Z][A-Za-z0-9_.-]{0,63}$"
@@ -8392,7 +8396,7 @@
8392
8396
  "required": [
8393
8397
  "op"
8394
8398
  ],
8395
- "description": "Input operations: write_text, key, keyboard, joystick, release_all, state.\n\nOperations:\n- write_text: Send a text string to the keyboard buffer, with PETSCII token expansion. Required inputs: text. Optional inputs: delayMs.\n- key: Tap a single key or hold it for a duration. Required inputs: key. Optional inputs: durationMs, count.\n- joystick: Simulate joystick input. On C64U/U64 this uses machine:input; VICE uses Binary Monitor Joyport Set. Required inputs: port, controls, action. Optional inputs: durationMs.\n- keyboard: Send physical C64 keyboard matrix events through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: inputs, transition.\n- release_all: Release every key and joystick control injected through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: none.\n- state: Read the keys and joystick controls held through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: none.",
8399
+ "description": "Input operations: write_text, key, keyboard, joystick, release_all, state.\n\nOperations:\n- write_text: Send a text string to the keyboard buffer, with PETSCII token expansion. Required inputs: text. Optional inputs: delayMs.\n- key: Tap a single key or hold it for a duration. Required inputs: key. Optional inputs: durationMs, count.\n- joystick: Simulate joystick input. On C64U/U64 this uses machine:input. On VICE it attaches VICE's I/O simulation joyport device while pressed; that device also pulls CIA lines 5-7 low, so port 1 produces phantom keys (e.g. SHIFT+C=) and port 2 reads $1E for up instead of $7E. Prefer port 2 on VICE and test bits 0-4. Required inputs: port, controls, action. Optional inputs: durationMs.\n- keyboard: Send physical C64 keyboard matrix events through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: inputs, transition.\n- release_all: Release every key and joystick control injected through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: none.\n- state: Read the keys and joystick controls held through machine:input (a C64U firmware version that provides it, or U64 3.15+). Required inputs: none.",
8396
8400
  "additionalProperties": false,
8397
8401
  "x-c64bridge-operations": [
8398
8402
  {
@@ -8488,7 +8492,7 @@
8488
8492
  },
8489
8493
  {
8490
8494
  "op": "joystick",
8491
- "description": "Simulate joystick input. On C64U/U64 this uses machine:input; VICE uses Binary Monitor Joyport Set.",
8495
+ "description": "Simulate joystick input. On C64U/U64 this uses machine:input. On VICE it attaches VICE's I/O simulation joyport device while pressed; that device also pulls CIA lines 5-7 low, so port 1 produces phantom keys (e.g. SHIFT+C=) and port 2 reads $1E for up instead of $7E. Prefer port 2 on VICE and test bits 0-4.",
8492
8496
  "required": [
8493
8497
  "port",
8494
8498
  "controls",
@@ -8499,7 +8503,7 @@
8499
8503
  ],
8500
8504
  "inputSchema": {
8501
8505
  "type": "object",
8502
- "description": "Simulate joystick input. On C64U/U64 this uses machine:input; VICE uses Binary Monitor Joyport Set.",
8506
+ "description": "Simulate joystick input. On C64U/U64 this uses machine:input. On VICE it attaches VICE's I/O simulation joyport device while pressed; that device also pulls CIA lines 5-7 low, so port 1 produces phantom keys (e.g. SHIFT+C=) and port 2 reads $1E for up instead of $7E. Prefer port 2 on VICE and test bits 0-4.",
8503
8507
  "properties": {
8504
8508
  "op": {
8505
8509
  "const": "joystick"
package/mcp.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c64bridge",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Stdio-based Model Context Protocol (MCP) server that bridges Commodore 64 Ultimate hardware with AI agents.",
5
5
  "entry": "dist/index.js",
6
6
  "type": "stdio",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c64bridge",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "mcpName": "io.github.chrisgleissner/c64bridge",
5
5
  "description": "C64 Bridge MCP server for Commodore 64 Ultimate hardware and VICE emulator control",
6
6
  "repository": {
@@ -685,7 +685,21 @@ export async function startMockC64Server(options = {}) {
685
685
  const lengthValue = routeUrl.searchParams.get("length") ?? "256";
686
686
  const address = parseNumeric(addressValue);
687
687
  const length = Math.max(0, parseNumeric(lengthValue, 10));
688
- const bytes = readMemoryWithHeartbeat(state, address, length);
688
+ // Same checks as the firmware (route_machine.cc readmem).
689
+ if (length < 1 || length > 65536) {
690
+ sendJson(res, { errors: ["Invalid length"] }, 400);
691
+ return;
692
+ }
693
+ if (address + length > 65536) {
694
+ sendJson(res, { errors: ["Memory read exceeds location $FFFF"] }, 400);
695
+ return;
696
+ }
697
+ const bytes = Uint8Array.from(readMemoryWithHeartbeat(state, address, length));
698
+ // SID registers $D400-$D418 are write-only; the Ultimate 64 reads them as $00.
699
+ for (let i = 0; i < bytes.length; i += 1) {
700
+ const target = address + i;
701
+ if (target >= 0xd400 && target <= 0xd418) bytes[i] = 0;
702
+ }
689
703
 
690
704
  const accept = String(req.headers["accept"] || "");
691
705
  if (accept.includes("application/octet-stream")) {
@@ -98,7 +98,10 @@ export async function main() {
98
98
  legOutputs.push(legPath);
99
99
  }
100
100
 
101
- const finalReport = mergeReports(await Promise.all(legOutputs.map(readReport)));
101
+ const finalReport = await dropNonCodeLines(
102
+ mergeReports(await Promise.all(legOutputs.map(readReport))),
103
+ (relativePath) => fs.readFile(path.join(repoRoot, relativePath), "utf8"),
104
+ );
102
105
  const finalPath = path.join(coverageDir, "lcov.info");
103
106
  await fs.writeFile(finalPath, serializeReport(finalReport), "utf8");
104
107
 
@@ -265,6 +268,33 @@ function parseReport(text) {
265
268
  return report;
266
269
  }
267
270
 
271
+ /**
272
+ * Bun's LCOV output lists blank and comment-only lines inside executed
273
+ * functions as executable lines that were never hit. Drop them, using each
274
+ * file's source, so coverage counts only code.
275
+ */
276
+ export async function dropNonCodeLines(report, readSource) {
277
+ const result = new Map();
278
+ for (const [filePath, record] of report.entries()) {
279
+ let sourceLines;
280
+ try {
281
+ sourceLines = (await readSource(filePath)).split(/\r?\n/);
282
+ } catch {
283
+ result.set(filePath, record);
284
+ continue;
285
+ }
286
+ const lines = new Map();
287
+ for (const [lineNo, hits] of record.lines.entries()) {
288
+ const text = (sourceLines[lineNo - 1] ?? "").trim();
289
+ const isComment = text.startsWith("//") || text.startsWith("/*") || text.startsWith("*");
290
+ if (text === "" || isComment) continue;
291
+ lines.set(lineNo, hits);
292
+ }
293
+ result.set(filePath, { ...record, lines });
294
+ }
295
+ return result;
296
+ }
297
+
268
298
  function mergeReports(reports) {
269
299
  const merged = new Map();
270
300
  for (const report of reports) {
@@ -485,8 +485,9 @@ export async function updateReadme(): Promise<boolean> {
485
485
  const generatedDocs = `\n\n${buildDocumentation()}\n\n`;
486
486
  const generatedEnv = `\n\n${buildEnvironmentDocumentation()}\n\n`;
487
487
  const nextReadme = readme
488
- .replace(docsPattern, `${START_MARKER}${generatedDocs}${END_MARKER}`)
489
- .replace(envPattern, `${ENV_START_MARKER}${generatedEnv}${ENV_END_MARKER}`);
488
+ // Replacement functions, not strings: generated text such as "$1E" must not be read as "$1".
489
+ .replace(docsPattern, () => `${START_MARKER}${generatedDocs}${END_MARKER}`)
490
+ .replace(envPattern, () => `${ENV_START_MARKER}${generatedEnv}${ENV_END_MARKER}`);
490
491
 
491
492
  if (nextReadme === readme) {
492
493
  return false;
package/server.json CHANGED
@@ -8,12 +8,12 @@
8
8
  "source": "github"
9
9
  },
10
10
  "websiteUrl": "https://github.com/chrisgleissner/c64bridge",
11
- "version": "1.0.5",
11
+ "version": "1.0.6",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "npm",
15
15
  "identifier": "c64bridge",
16
- "version": "1.0.5",
16
+ "version": "1.0.6",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  },