c64bridge 0.8.1 → 0.9.1

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 (92) hide show
  1. package/.github/prompts/steer.prompt.md +55 -0
  2. package/AGENTS.md +9 -7
  3. package/README.md +192 -154
  4. package/data/embeddings_asm.json +1 -1
  5. package/data/embeddings_basic.json +1 -1
  6. package/data/embeddings_hardware.json +1 -1
  7. package/data/embeddings_mixed.json +1 -1
  8. package/data/embeddings_other.json +1 -1
  9. package/data/graphics/petscii-style-guide.md +4 -4
  10. package/data/graphics/sprite-charset-best-practices.md +9 -9
  11. package/data/vice/vice-binary-monitor-spec.md +938 -0
  12. package/dist/.tsbuildinfo +1 -1
  13. package/dist/c64Client.js +76 -2
  14. package/dist/device.js +129 -13
  15. package/dist/mcp-server.js +1 -1
  16. package/dist/prompts/registry.js +27 -25
  17. package/dist/rag/indexer.js +18 -8
  18. package/dist/rag/knowledgeIndex.js +112 -79
  19. package/dist/rag/resourceUris.js +93 -0
  20. package/dist/sidwaveCompiler.js +1 -1
  21. package/dist/{assemblyConverter.js → tools/assember.js} +10 -1
  22. package/dist/tools/audio.js +11 -11
  23. package/dist/{basicConverter.js → tools/basicTokenizer.js} +1 -1
  24. package/dist/tools/debug.js +159 -6
  25. package/dist/tools/developer.js +13 -13
  26. package/dist/tools/disassembler.js +478 -0
  27. package/dist/tools/graphics.js +10 -10
  28. package/dist/tools/input.js +338 -0
  29. package/dist/tools/machineControl.js +5 -5
  30. package/dist/tools/memory.js +336 -12
  31. package/dist/tools/meta/index.js +1 -1
  32. package/dist/tools/printer.js +11 -12
  33. package/dist/tools/programRunners.js +61 -22
  34. package/dist/tools/rag.js +9 -9
  35. package/dist/tools/registry/batch.js +167 -0
  36. package/dist/tools/registry/config.js +1 -1
  37. package/dist/tools/registry/disk.js +1 -1
  38. package/dist/tools/registry/drive.js +1 -1
  39. package/dist/tools/registry/extract.js +1 -1
  40. package/dist/tools/registry/graphics.js +102 -2
  41. package/dist/tools/registry/index.js +4 -0
  42. package/dist/tools/registry/input.js +2 -0
  43. package/dist/tools/registry/memory.js +62 -2
  44. package/dist/tools/registry/platform.js +1 -1
  45. package/dist/tools/registry/printer.js +1 -1
  46. package/dist/tools/registry/program.js +1 -1
  47. package/dist/tools/registry/rag.js +1 -1
  48. package/dist/tools/registry/sound.js +1 -1
  49. package/dist/tools/registry/stream.js +1 -1
  50. package/dist/tools/registry/system.js +1 -1
  51. package/dist/tools/schema.js +4 -5
  52. package/dist/tools/storage.js +15 -15
  53. package/dist/tools/streaming.js +3 -3
  54. package/dist/tools/symbolRegistry.js +49 -0
  55. package/dist/tools/types.js +56 -4
  56. package/dist/tools/vice.js +2 -5
  57. package/dist/vice/process.js +120 -2
  58. package/dist/vice/readiness.js +35 -0
  59. package/dist/vice/smokeOptions.js +44 -0
  60. package/dist/vice/viceClient.js +5 -1
  61. package/dist/viceRunner.js +2 -0
  62. package/doc/plans/prompts/README.md +7 -7
  63. package/mcp/prompts.json +42 -59
  64. package/mcp/protocol-examples.json +2 -2
  65. package/mcp/resources.json +179 -166
  66. package/mcp/schemas/c64_batch.schema.json +53 -0
  67. package/mcp/schemas/c64_config.schema.json +525 -283
  68. package/mcp/schemas/c64_debug.schema.json +763 -304
  69. package/mcp/schemas/c64_disk.schema.json +499 -243
  70. package/mcp/schemas/c64_drive.schema.json +165 -90
  71. package/mcp/schemas/c64_extract.schema.json +533 -274
  72. package/mcp/schemas/c64_graphics.schema.json +607 -295
  73. package/mcp/schemas/c64_input.schema.json +136 -0
  74. package/mcp/schemas/c64_memory.schema.json +637 -128
  75. package/mcp/schemas/c64_printer.schema.json +393 -196
  76. package/mcp/schemas/c64_program.schema.json +699 -340
  77. package/mcp/schemas/c64_rag.schema.json +100 -54
  78. package/mcp/schemas/c64_select_backend.schema.json +49 -23
  79. package/mcp/schemas/c64_sound.schema.json +1092 -577
  80. package/mcp/schemas/c64_stream.schema.json +89 -47
  81. package/mcp/schemas/c64_system.schema.json +351 -185
  82. package/mcp/schemas/c64_vice.schema.json +85 -47
  83. package/mcp/server.json +1 -1
  84. package/mcp/tools.json +7299 -3346
  85. package/mcp.json +3 -3
  86. package/package.json +17 -14
  87. package/scripts/fetch-external-sources.mjs +1 -2
  88. package/scripts/run-coverage.mjs +33 -1
  89. package/scripts/run-tests.mjs +2 -2
  90. package/scripts/run-tests.ts +275 -52
  91. package/scripts/update-readme.ts +132 -3
  92. package/server.json +2 -2
@@ -3,10 +3,37 @@ import fs from "node:fs";
3
3
  import net from "node:net";
4
4
  import { createOutputTailCapture, getDiagnosticsSessionInfo, writeDiagnosticEvent } from "../diagnostics.js";
5
5
  const DEFAULT_DISPLAY = ":99";
6
+ function hasDisplayArtifacts(display) {
7
+ const match = /^:([0-9]+)$/.exec(display.trim());
8
+ if (!match) {
9
+ return false;
10
+ }
11
+ const displayNumber = match[1];
12
+ return fs.existsSync(`/tmp/.X11-unix/X${displayNumber}`) || fs.existsSync(`/tmp/.X${displayNumber}-lock`);
13
+ }
14
+ export function resolveXvfbDisplayForLaunch(display) {
15
+ const explicitDisplay = process.env.VICE_XVFB_DISPLAY?.trim();
16
+ if (explicitDisplay) {
17
+ return explicitDisplay;
18
+ }
19
+ if (display !== DEFAULT_DISPLAY || !hasDisplayArtifacts(display)) {
20
+ return display;
21
+ }
22
+ const baseDisplay = Number.parseInt(display.slice(1), 10);
23
+ for (let candidate = baseDisplay + 1; candidate < baseDisplay + 100; candidate += 1) {
24
+ const candidateDisplay = `:${candidate}`;
25
+ if (!hasDisplayArtifacts(candidateDisplay)) {
26
+ return candidateDisplay;
27
+ }
28
+ }
29
+ return display;
30
+ }
6
31
  export function delay(ms) {
7
32
  return new Promise((resolve) => setTimeout(resolve, ms));
8
33
  }
9
34
  function hasGraphicalSession() {
35
+ if (process.platform === "darwin" || process.platform === "win32")
36
+ return true;
10
37
  return configuredDisplay() !== undefined || configuredWaylandDisplay() !== undefined;
11
38
  }
12
39
  function configuredDisplay() {
@@ -64,6 +91,53 @@ export async function waitForPort(host, port, timeoutMs = 4000) {
64
91
  }
65
92
  throw new Error(`Timeout waiting for VICE monitor at ${host}:${port}`);
66
93
  }
94
+ async function sendResumeMonitorCommand(host, port, timeoutMs = 1500) {
95
+ const deadline = Date.now() + timeoutMs;
96
+ let lastError;
97
+ while (Date.now() < deadline) {
98
+ try {
99
+ await new Promise((resolve, reject) => {
100
+ const socket = net.connect({ host, port });
101
+ const cleanup = () => {
102
+ socket.removeAllListeners();
103
+ socket.destroy();
104
+ };
105
+ const packet = Buffer.alloc(11);
106
+ packet[0] = 0x02;
107
+ packet[1] = 0x02;
108
+ packet.writeUInt32LE(0, 2);
109
+ packet.writeUInt32LE(1, 6);
110
+ packet[10] = 0xaa;
111
+ socket.setTimeout(500, () => {
112
+ cleanup();
113
+ reject(new Error(`Timed out sending VICE monitor resume command to ${host}:${port}`));
114
+ });
115
+ socket.once("error", (error) => {
116
+ cleanup();
117
+ reject(error);
118
+ });
119
+ socket.once("connect", () => {
120
+ socket.write(packet, (error) => {
121
+ cleanup();
122
+ if (error) {
123
+ reject(error);
124
+ return;
125
+ }
126
+ resolve();
127
+ });
128
+ });
129
+ });
130
+ return;
131
+ }
132
+ catch (error) {
133
+ lastError = error;
134
+ await delay(50);
135
+ }
136
+ }
137
+ throw lastError instanceof Error
138
+ ? lastError
139
+ : new Error(`Failed to resume VICE monitor at ${host}:${port}`);
140
+ }
67
141
  async function waitForXvfb(display, timeoutMs = 5000) {
68
142
  const match = /^:([0-9]+)/.exec(display.trim());
69
143
  if (!match) {
@@ -113,7 +187,19 @@ export async function terminateProcess(child, signal = "SIGTERM", timeoutMs = 10
113
187
  }
114
188
  export async function startViceProcess(options) {
115
189
  const debugEnabled = process.env.VICE_DEVICE_TEST_DEBUG === "1";
116
- const { useXvfb, display } = shouldUseXvfb(options.visible);
190
+ // When headless=true, skip Xvfb entirely and rely on VICE's own -headless flag (VICE 3.5+).
191
+ const useHeadless = options.headless === true || process.env.VICE_HEADLESS === "1";
192
+ let useXvfb;
193
+ let display;
194
+ if (useHeadless) {
195
+ useXvfb = false;
196
+ display = "";
197
+ }
198
+ else {
199
+ const probe = shouldUseXvfb(options.visible);
200
+ useXvfb = probe.useXvfb;
201
+ display = useXvfb ? resolveXvfbDisplayForLaunch(probe.display) : probe.display;
202
+ }
117
203
  const viceEnv = { ...process.env };
118
204
  let xvfb = null;
119
205
  const xvfbOutput = createOutputTailCapture("xvfb");
@@ -123,6 +209,7 @@ export async function startViceProcess(options) {
123
209
  directory: options.directory,
124
210
  display,
125
211
  extraArgs: options.extraArgs ?? [],
212
+ headless: useHeadless,
126
213
  host: options.host,
127
214
  port: options.port,
128
215
  useXvfb,
@@ -157,12 +244,14 @@ export async function startViceProcess(options) {
157
244
  });
158
245
  viceEnv.DISPLAY = display;
159
246
  await waitForXvfb(display);
247
+ await delay(300);
160
248
  }
161
249
  const args = [
162
250
  "-binarymonitor",
163
251
  "-binarymonitoraddress", `${options.host}:${options.port}`,
164
252
  "-sounddev", "dummy",
165
253
  "-config", "/dev/null",
254
+ ...(useHeadless ? ["-headless"] : []),
166
255
  ...(options.directory ? ["-directory", options.directory] : []),
167
256
  ...(options.extraArgs ?? []),
168
257
  ];
@@ -216,7 +305,8 @@ export async function startViceProcess(options) {
216
305
  child.once("exit", onExit);
217
306
  child.once("error", onError);
218
307
  waitForPort(options.host, options.port)
219
- .then(() => {
308
+ .then(async () => {
309
+ await sendResumeMonitorCommand(options.host, options.port);
220
310
  if (debugEnabled) {
221
311
  console.error("[vice-process] monitor port is ready", { host: options.host, port: options.port });
222
312
  }
@@ -293,15 +383,43 @@ export async function startViceProcess(options) {
293
383
  });
294
384
  return { host: options.host, port: options.port, process: child, stop };
295
385
  }
386
+ function isIgnorableSocketDirError(error) {
387
+ if (!error || typeof error !== "object" || !("code" in error)) {
388
+ return false;
389
+ }
390
+ const code = String(error.code ?? "");
391
+ return code === "EACCES" || code === "EPERM" || code === "EROFS" || code === "EEXIST";
392
+ }
296
393
  export function ensureXvfbSocketDir(debugEnabled) {
297
394
  const socketDir = "/tmp/.X11-unix";
298
395
  try {
299
396
  if (!fs.existsSync(socketDir)) {
300
397
  fs.mkdirSync(socketDir, { mode: 0o1777 });
301
398
  }
399
+ }
400
+ catch (error) {
401
+ if (isIgnorableSocketDirError(error)) {
402
+ if (debugEnabled) {
403
+ console.error("[vice-process] unable to create Xvfb socket dir; continuing", error);
404
+ }
405
+ return;
406
+ }
407
+ writeDiagnosticEvent("xvfb_socket_dir_failed", { socketDir, error });
408
+ if (debugEnabled) {
409
+ console.error("[vice-process] failed to prepare Xvfb socket dir", error);
410
+ }
411
+ return;
412
+ }
413
+ try {
302
414
  fs.chmodSync(socketDir, 0o1777);
303
415
  }
304
416
  catch (error) {
417
+ if (isIgnorableSocketDirError(error)) {
418
+ if (debugEnabled) {
419
+ console.error("[vice-process] unable to chmod Xvfb socket dir; continuing", error);
420
+ }
421
+ return;
422
+ }
305
423
  writeDiagnosticEvent("xvfb_socket_dir_failed", { socketDir, error });
306
424
  if (debugEnabled) {
307
425
  console.error("[vice-process] failed to prepare Xvfb socket dir", error);
@@ -30,6 +30,41 @@ export async function waitForScreenPattern(bm, pattern, timeoutMs, tickMs = 50,
30
30
  await exitMonitorIfNeeded(bm);
31
31
  return idx;
32
32
  }
33
+ export async function waitForStableScreenPattern(bm, pattern, timeoutMs, tickMs = 50, stableReads = 2, onRead, between) {
34
+ const requiredStableReads = Math.max(1, stableReads);
35
+ const start = nowNs();
36
+ let idx = -1;
37
+ let stableIdx = -1;
38
+ let consecutiveMatches = 0;
39
+ while (msSince(start) < timeoutMs) {
40
+ const t = nowNs();
41
+ const screen = await bm.memGet(0x0400, 0x0400 + 999);
42
+ onRead?.("bm_read_screen", t);
43
+ idx = screen.indexOf(pattern);
44
+ if (idx >= 0) {
45
+ if (idx === stableIdx) {
46
+ consecutiveMatches += 1;
47
+ }
48
+ else {
49
+ stableIdx = idx;
50
+ consecutiveMatches = 1;
51
+ }
52
+ if (consecutiveMatches >= requiredStableReads) {
53
+ break;
54
+ }
55
+ }
56
+ else {
57
+ stableIdx = -1;
58
+ consecutiveMatches = 0;
59
+ }
60
+ await exitMonitorIfNeeded(bm);
61
+ if (between)
62
+ await between();
63
+ await new Promise((r) => setTimeout(r, Math.max(1, tickMs)));
64
+ }
65
+ await exitMonitorIfNeeded(bm);
66
+ return consecutiveMatches >= requiredStableReads ? idx : -1;
67
+ }
33
68
  /** Wait until any non-blank (non-0x00/0x20) character appears on the text screen. */
34
69
  export async function waitForAnyScreenText(bm, timeoutMs, tickMs = 50, onRead, between) {
35
70
  const start = nowNs();
@@ -0,0 +1,44 @@
1
+ const TRUE_VALUES = new Set(["1", "true", "yes", "on"]);
2
+ const FALSE_VALUES = new Set(["0", "false", "no", "off"]);
3
+ function parseVicePort(value) {
4
+ const normalized = value?.trim();
5
+ if (!normalized) {
6
+ return { configuredPort: 6502, hasExplicitPort: false };
7
+ }
8
+ const parsed = Number(normalized);
9
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) {
10
+ return { configuredPort: 6502, hasExplicitPort: false };
11
+ }
12
+ return { configuredPort: parsed, hasExplicitPort: true };
13
+ }
14
+ export function parseEnvBoolean(value) {
15
+ const normalized = value?.trim().toLowerCase();
16
+ if (!normalized) {
17
+ return undefined;
18
+ }
19
+ if (TRUE_VALUES.has(normalized)) {
20
+ return true;
21
+ }
22
+ if (FALSE_VALUES.has(normalized)) {
23
+ return false;
24
+ }
25
+ return undefined;
26
+ }
27
+ export function resolveViceSmokeOptions(env = process.env, argv = process.argv.slice(2)) {
28
+ const visibleDemo = argv.includes("--visible-demo") || parseEnvBoolean(env.VICE_VISIBLE_DEMO) === true;
29
+ const useMock = String(env.VICE_TEST_TARGET ?? "").trim().toLowerCase() === "mock";
30
+ const { configuredPort, hasExplicitPort } = parseVicePort(env.VICE_PORT);
31
+ const visible = visibleDemo || parseEnvBoolean(env.VICE_VISIBLE) === true;
32
+ const keepOpen = visibleDemo || parseEnvBoolean(env.VICE_KEEP_OPEN) === true;
33
+ const warpSetting = parseEnvBoolean(env.VICE_WARP);
34
+ return {
35
+ useMock,
36
+ configuredPort,
37
+ hasExplicitPort,
38
+ visible,
39
+ keepOpen,
40
+ warp: useMock ? true : visibleDemo ? false : warpSetting ?? true,
41
+ display: env.DISPLAY || ":99",
42
+ visibleDemo,
43
+ };
44
+ }
@@ -9,6 +9,9 @@ export class ViceClient {
9
9
  this.pending = new Map();
10
10
  this.closing = false;
11
11
  }
12
+ setUnsolicitedHandler(handler) {
13
+ this.onUnsolicitedHandler = handler;
14
+ }
12
15
  async connect(port, host = "127.0.0.1") {
13
16
  this.socket = net.connect({ host, port });
14
17
  this.closing = false;
@@ -77,7 +80,8 @@ export class ViceClient {
77
80
  const err = frame[7];
78
81
  const reqId = frame.readUInt32LE(8);
79
82
  if (reqId === 0xffffffff) {
80
- continue; // unsolicited event
83
+ this.onUnsolicitedHandler?.(responseType, frame);
84
+ continue;
81
85
  }
82
86
  const pending = this.pending.get(reqId);
83
87
  if (!pending) {
@@ -65,6 +65,8 @@ function which(binary) {
65
65
  return null;
66
66
  }
67
67
  function shouldUseXvfb() {
68
+ if (process.platform === "darwin" || process.platform === "win32")
69
+ return false;
68
70
  if (process.env.FORCE_XVFB === "1")
69
71
  return true;
70
72
  const ciValue = (process.env.CI || "").toLowerCase();
@@ -27,13 +27,13 @@ suite can assert expectations in upcoming steps.
27
27
 
28
28
  | Family | Baseline Resources (URIs) | Rationale |
29
29
  | --- | --- | --- |
30
- | `basic-program` | `c64://specs/basic`, `c64://context/bootstrap`, `c64://docs/index` | Reinforce BASIC token rules, PETSCII gotchas, workflow expectations. |
31
- | `assembly-program` | `c64://specs/assembly`, `c64://context/bootstrap`, `c64://specs/vic`, `c64://specs/sid` | Provide opcode tables, IRQ setup, VIC/SID register references. |
32
- | `sid-music` | `c64://specs/sid`, `c64://specs/sidwave`, `c64://docs/sid/file-structure` | Supply register map, SIDWAVE format, SID file metadata. |
33
- | `graphics-demo` | `c64://specs/vic`, `c64://context/bootstrap` | Cover VIC mode bits, raster constraints, general workflow guidance. |
34
- | `printer-job` | `c64://specs/printer`, `c64://docs/printer/guide`, `c64://docs/printer/prompts` | Document PETSCII vs ESC/P workflows, sample templates, and safety checks. |
35
- | `memory-debug` | `c64://context/bootstrap`, `c64://specs/assembly`, `c64://docs/index` | Highlight addressing safeguards, workflow rules, and knowledge map summaries. |
36
- | `drive-manager` | `c64://context/bootstrap` | Ensure awareness of system-wide safety rules before altering drives. |
30
+ | `basic-program` | `c64://basic/spec`, `c64://guide/bootstrap`, `c64://guide/index` | Reinforce BASIC token rules, PETSCII gotchas, workflow expectations. |
31
+ | `assembly-program` | `c64://assembly/6510-spec`, `c64://guide/bootstrap`, `c64://graphics/vic/spec`, `c64://sound/sid/spec` | Provide opcode tables, IRQ setup, VIC/SID register references. |
32
+ | `sid-music` | `c64://sound/sid/spec`, `c64://sound/sidwave/spec`, `c64://sound/sid/file-format` | Supply register map, SIDWAVE format, SID file metadata. |
33
+ | `graphics-demo` | `c64://graphics/vic/spec`, `c64://guide/bootstrap` | Cover VIC mode bits, raster constraints, general workflow guidance. |
34
+ | `printer-job` | `c64://printer/spec`, `c64://printer/commodore/text`, `c64://printer/prompt-guide` | Document PETSCII vs ESC/P workflows, sample templates, and safety checks. |
35
+ | `memory-debug` | `c64://guide/bootstrap`, `c64://assembly/6510-spec`, `c64://guide/index` | Highlight addressing safeguards, workflow rules, and knowledge map summaries. |
36
+ | `drive-manager` | `c64://guide/bootstrap` | Ensure awareness of system-wide safety rules before altering drives. |
37
37
 
38
38
  Notes:
39
39
 
package/mcp/prompts.json CHANGED
@@ -6,9 +6,9 @@
6
6
  "description": "Route ultra-fast hello-world and smoke-test requests to the canonical greeting skill.",
7
7
  "_meta": {
8
8
  "requiredResources": [
9
- "c64://context/bootstrap",
10
- "c64://context/fast-paths",
11
- "c64://docs/index"
9
+ "c64://guide/bootstrap",
10
+ "c64://guide/fast-paths",
11
+ "c64://guide/index"
12
12
  ],
13
13
  "optionalResources": [],
14
14
  "tools": [
@@ -29,12 +29,12 @@
29
29
  "description": "Route bespoke Commodore BASIC v2 requests to the canonical BASIC skill.",
30
30
  "_meta": {
31
31
  "requiredResources": [
32
- "c64://specs/basic",
33
- "c64://context/bootstrap",
34
- "c64://docs/index"
32
+ "c64://basic/spec",
33
+ "c64://guide/bootstrap",
34
+ "c64://guide/index"
35
35
  ],
36
36
  "optionalResources": [
37
- "c64://context/fast-paths"
37
+ "c64://guide/fast-paths"
38
38
  ],
39
39
  "tools": [
40
40
  "c64_program",
@@ -53,9 +53,9 @@
53
53
  "description": "Route quick visible demo requests to the cross-platform demo skill.",
54
54
  "_meta": {
55
55
  "requiredResources": [
56
- "c64://context/bootstrap",
57
- "c64://context/fast-paths",
58
- "c64://docs/index"
56
+ "c64://guide/bootstrap",
57
+ "c64://guide/fast-paths",
58
+ "c64://guide/index"
59
59
  ],
60
60
  "optionalResources": [],
61
61
  "tools": [
@@ -75,12 +75,12 @@
75
75
  "description": "Route quick recognizable tune requests to the SID music skill.",
76
76
  "_meta": {
77
77
  "requiredResources": [
78
- "c64://specs/sid",
79
- "c64://specs/sidwave",
80
- "c64://context/fast-paths"
78
+ "c64://sound/sid/spec",
79
+ "c64://sound/sidwave/spec",
80
+ "c64://guide/fast-paths"
81
81
  ],
82
82
  "optionalResources": [
83
- "c64://docs/sid/best-practices"
83
+ "c64://sound/sid/best-practices"
84
84
  ],
85
85
  "tools": [
86
86
  "c64_sound"
@@ -100,24 +100,18 @@
100
100
  "arguments": [
101
101
  {
102
102
  "name": "hardware",
103
- "description": "Optional focus area for the routine (sid, vic, cia, or multi for combined work).",
104
- "options": [
105
- "sid",
106
- "vic",
107
- "cia",
108
- "multi"
109
- ]
103
+ "description": "Optional focus area for the routine (sid, vic, cia, or multi for combined work)."
110
104
  }
111
105
  ],
112
106
  "_meta": {
113
107
  "requiredResources": [
114
- "c64://specs/assembly",
115
- "c64://specs/vic",
116
- "c64://specs/sid",
117
- "c64://context/bootstrap"
108
+ "c64://assembly/6510-spec",
109
+ "c64://graphics/vic/spec",
110
+ "c64://sound/sid/spec",
111
+ "c64://guide/bootstrap"
118
112
  ],
119
113
  "optionalResources": [
120
- "c64://docs/sid/best-practices"
114
+ "c64://sound/sid/best-practices"
121
115
  ],
122
116
  "tools": [
123
117
  "c64_program",
@@ -143,13 +137,13 @@
143
137
  "description": "Route SID playback and composition work to the canonical SID skill.",
144
138
  "_meta": {
145
139
  "requiredResources": [
146
- "c64://specs/sid",
147
- "c64://specs/sidwave",
148
- "c64://docs/sid/file-structure",
149
- "c64://docs/sid/best-practices"
140
+ "c64://sound/sid/spec",
141
+ "c64://sound/sidwave/spec",
142
+ "c64://sound/sid/file-format",
143
+ "c64://sound/sid/best-practices"
150
144
  ],
151
145
  "optionalResources": [
152
- "c64://context/fast-paths"
146
+ "c64://guide/fast-paths"
153
147
  ],
154
148
  "tools": [
155
149
  "c64_sound"
@@ -168,24 +162,18 @@
168
162
  "arguments": [
169
163
  {
170
164
  "name": "mode",
171
- "description": "Target VIC-II technique (text, multicolour, bitmap, or sprite).",
172
- "options": [
173
- "text",
174
- "multicolour",
175
- "bitmap",
176
- "sprite"
177
- ]
165
+ "description": "Target VIC-II technique (text, multicolour, bitmap, or sprite)."
178
166
  }
179
167
  ],
180
168
  "_meta": {
181
169
  "requiredResources": [
182
- "c64://specs/vic",
183
- "c64://context/bootstrap"
170
+ "c64://graphics/vic/spec",
171
+ "c64://guide/bootstrap"
184
172
  ],
185
173
  "optionalResources": [
186
- "c64://specs/assembly",
187
- "c64://specs/charset",
188
- "c64://docs/petscii-style"
174
+ "c64://assembly/6510-spec",
175
+ "c64://graphics/character-set",
176
+ "c64://graphics/petscii/style-guide"
189
177
  ],
190
178
  "tools": [
191
179
  "c64_program",
@@ -213,24 +201,19 @@
213
201
  "arguments": [
214
202
  {
215
203
  "name": "printerType",
216
- "description": "Select Commodore (device 4) or Epson FX workflow helpers.",
217
- "options": [
218
- "commodore",
219
- "epson"
220
- ]
204
+ "description": "Select Commodore (device 4) or Epson FX workflow helpers."
221
205
  }
222
206
  ],
223
207
  "_meta": {
224
208
  "requiredResources": [
225
- "c64://specs/printer",
226
- "c64://docs/printer/guide",
227
- "c64://docs/printer/prompts"
209
+ "c64://printer/spec",
210
+ "c64://printer/prompt-guide"
228
211
  ],
229
212
  "optionalResources": [
230
- "c64://docs/printer/commodore-text",
231
- "c64://docs/printer/commodore-bitmap",
232
- "c64://docs/printer/epson-text",
233
- "c64://docs/printer/epson-bitmap"
213
+ "c64://printer/commodore/text",
214
+ "c64://printer/commodore/bitmap",
215
+ "c64://printer/epson/text",
216
+ "c64://printer/epson/bitmap"
234
217
  ],
235
218
  "tools": [
236
219
  "c64_printer"
@@ -252,9 +235,9 @@
252
235
  "description": "Route reversible memory inspection or patching work to the canonical memory skill.",
253
236
  "_meta": {
254
237
  "requiredResources": [
255
- "c64://context/bootstrap",
256
- "c64://specs/assembly",
257
- "c64://docs/index"
238
+ "c64://guide/bootstrap",
239
+ "c64://assembly/6510-spec",
240
+ "c64://guide/index"
258
241
  ],
259
242
  "optionalResources": [],
260
243
  "tools": [
@@ -274,7 +257,7 @@
274
257
  "description": "Route disk-image and drive-state requests to the canonical drive skill.",
275
258
  "_meta": {
276
259
  "requiredResources": [
277
- "c64://context/bootstrap"
260
+ "c64://guide/bootstrap"
278
261
  ],
279
262
  "optionalResources": [],
280
263
  "tools": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "protocolVersion": "2025-06-18",
2
+ "protocolVersion": "2025-11-25",
3
3
  "examples": {
4
4
  "initialize": {
5
5
  "description": "Client initialization request sent immediately after connecting to the stdio MCP server.",
@@ -8,7 +8,7 @@
8
8
  "id": 1,
9
9
  "method": "initialize",
10
10
  "params": {
11
- "protocolVersion": "2025-06-18",
11
+ "protocolVersion": "2025-11-25",
12
12
  "capabilities": {
13
13
  "resources": {},
14
14
  "tools": {},