c64bridge 0.7.4 → 0.8.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.
- package/.github/prompts/README.md +14 -4
- package/.github/prompts/assembly-routine-session.prompt.md +9 -9
- package/.github/prompts/basic-program-session.prompt.md +11 -9
- package/.github/prompts/drive-management-session.prompt.md +9 -9
- package/.github/prompts/hello-world-session.prompt.md +17 -0
- package/.github/prompts/petscii-art-session.prompt.md +9 -9
- package/.github/prompts/play-classic-game.prompt.md +9 -9
- package/.github/prompts/pr-converge.prompt.md +13 -0
- package/.github/prompts/sid-music-session.prompt.md +9 -9
- package/AGENTS.md +59 -60
- package/README.md +550 -191
- package/data/assembly/assembly-spec.md +290 -1
- package/data/context/bootstrap.md +26 -2
- package/data/context/fast-paths.md +44 -0
- package/data/graphics/petscii-style-guide.md +6 -2
- package/data/graphics/sprite-charset-best-practices.md +5 -5
- package/dist/.tsbuildinfo +1 -1
- package/dist/c64Client.js +990 -26
- package/dist/config.js +5 -1
- package/dist/device.js +680 -57
- package/dist/diagnostics.js +371 -0
- package/dist/mcp/metadata.js +39 -0
- package/dist/mcp-server.js +170 -20
- package/dist/platform.js +10 -2
- package/dist/prompts/registry.js +166 -309
- package/dist/rag/init.js +37 -1
- package/dist/rag/knowledgeIndex.js +18 -6
- package/dist/rag/rateLimiter.js +2 -2
- package/dist/streamCapture.js +135 -0
- package/dist/tools/audio.js +3 -1
- package/dist/tools/debug.js +470 -0
- package/dist/tools/developer.js +10 -4
- package/dist/tools/graphics.js +183 -17
- package/dist/tools/machineControl.js +11 -5
- package/dist/tools/memory.js +19 -10
- package/dist/tools/meta/audio.js +240 -1
- package/dist/tools/meta/config.js +20 -28
- package/dist/tools/meta/configInventory.js +104 -0
- package/dist/tools/meta/diagnostics.js +45 -2
- package/dist/tools/meta/graphics.js +14 -6
- package/dist/tools/meta/index.js +1 -0
- package/dist/tools/meta/memory.js +20 -6
- package/dist/tools/meta/program.js +473 -0
- package/dist/tools/pollValidator.js +4 -2
- package/dist/tools/programRunners.js +8 -4
- package/dist/tools/registry/config.js +17 -0
- package/dist/tools/registry/disk.js +7 -0
- package/dist/tools/registry/drive.js +3 -0
- package/dist/tools/registry/graphics.js +111 -27
- package/dist/tools/registry/index.js +6 -0
- package/dist/tools/registry/memory.js +1 -0
- package/dist/tools/registry/platform.js +121 -0
- package/dist/tools/registry/program.js +26 -8
- package/dist/tools/registry/sound.js +96 -0
- package/dist/tools/registry/system.js +15 -2
- package/dist/tools/storage.js +1 -0
- package/dist/tools/streaming.js +1 -0
- package/dist/tools/types.js +38 -4
- package/dist/tools/vice.js +160 -0
- package/dist/vicBitmap.js +317 -0
- package/dist/vice/mockServer.js +439 -0
- package/dist/vice/process.js +310 -0
- package/dist/vice/readiness.js +18 -2
- package/dist/vice/viceClient.js +382 -22
- package/doc/developer.md +71 -25
- package/doc/img/backend-switch/hello-c64u.png +0 -0
- package/doc/img/backend-switch/hello-vice-and-c64u.png +0 -0
- package/doc/img/backend-switch/hello-vice.png +0 -0
- package/doc/img/backend-switch/metadata.json +50 -0
- package/doc/plans/vice-backend-switch/plan.md +486 -0
- package/doc/plans/vice-backend-switch-2/plan.md +48 -0
- package/doc/plans/vice-support/notes.md +1 -0
- package/doc/plans/vice-support/plan.md +5 -0
- package/doc/plans/vice-support/rollout.md +23 -17
- package/doc/reviews/vice-support-review.md +185 -0
- package/doc/troubleshooting-mcp.md +35 -6
- package/doc/vice/support-matrix.md +54 -0
- package/mcp/prompts.json +292 -0
- package/mcp/protocol-examples.json +46 -0
- package/mcp/resources.json +940 -0
- package/mcp/schemas/c64_config.schema.json +350 -0
- package/mcp/schemas/c64_debug.schema.json +380 -0
- package/mcp/schemas/c64_disk.schema.json +278 -0
- package/mcp/schemas/c64_drive.schema.json +120 -0
- package/mcp/schemas/c64_extract.schema.json +302 -0
- package/mcp/schemas/c64_graphics.schema.json +333 -0
- package/mcp/schemas/c64_memory.schema.json +155 -0
- package/mcp/schemas/c64_printer.schema.json +218 -0
- package/mcp/schemas/c64_program.schema.json +391 -0
- package/mcp/schemas/c64_rag.schema.json +67 -0
- package/mcp/schemas/c64_select_backend.schema.json +32 -0
- package/mcp/schemas/c64_sound.schema.json +644 -0
- package/mcp/schemas/c64_stream.schema.json +61 -0
- package/mcp/schemas/c64_system.schema.json +227 -0
- package/mcp/schemas/c64_vice.schema.json +63 -0
- package/mcp/server.json +15 -0
- package/mcp/tools.json +4517 -0
- package/mcp.json +90 -15
- package/package.json +11 -4
- package/scripts/capture-backend-switch-screenshots.mjs +276 -0
- package/scripts/generate-mcp-interface.ts +289 -0
- package/scripts/invoke-bun.mjs +67 -21
- package/scripts/mockC64Server.mjs +162 -6
- package/scripts/prepare-release.mjs +59 -2
- package/scripts/run-coverage.mjs +284 -0
- package/scripts/run-tests.mjs +95 -39
- package/scripts/run-tests.ts +378 -73
- package/scripts/update-readme.ts +147 -13
- package/server.json +94 -0
package/dist/tools/graphics.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
2
|
import { createPetsciiArt } from "../petsciiArt.js";
|
|
3
|
+
import { importImageAsVicBitmap } from "../vicBitmap.js";
|
|
3
4
|
import { defineToolModule, OPERATION_DISCRIMINATOR, } from "./types.js";
|
|
4
5
|
import { booleanSchema, numberSchema, objectSchema, optionalSchema, stringSchema, } from "./schema.js";
|
|
5
6
|
import { jsonResult, textResult } from "./responses.js";
|
|
@@ -49,6 +50,37 @@ function decodeSpriteString(value, path) {
|
|
|
49
50
|
throw new ToolValidationError("Unable to parse sprite hex string", { path, cause: error });
|
|
50
51
|
}
|
|
51
52
|
}
|
|
53
|
+
function parseAddressValue(value) {
|
|
54
|
+
const trimmed = value.trim();
|
|
55
|
+
if (!trimmed) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const normalised = trimmed.startsWith("$") ? `0x${trimmed.slice(1)}` : trimmed;
|
|
59
|
+
const parsed = Number(normalised);
|
|
60
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 0xFFFF) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return parsed;
|
|
64
|
+
}
|
|
65
|
+
const addressSchema = {
|
|
66
|
+
jsonSchema: {
|
|
67
|
+
description: "Absolute C64 memory address, provided as an integer or hex string such as $2000.",
|
|
68
|
+
type: ["integer", "string"],
|
|
69
|
+
},
|
|
70
|
+
parse(value, path) {
|
|
71
|
+
const resolvedPath = path ?? "$";
|
|
72
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 0xFFFF) {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
if (typeof value === "string") {
|
|
76
|
+
const parsed = parseAddressValue(value);
|
|
77
|
+
if (parsed !== null) {
|
|
78
|
+
return parsed;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
throw new ToolValidationError("Address must be an integer or hex string within $0000-$FFFF", { path: resolvedPath });
|
|
82
|
+
},
|
|
83
|
+
};
|
|
52
84
|
const spriteBytesSchema = {
|
|
53
85
|
jsonSchema: {
|
|
54
86
|
description: "63-byte sprite definition provided as base64/hex string or array of bytes.",
|
|
@@ -90,7 +122,7 @@ const spriteBytesSchema = {
|
|
|
90
122
|
},
|
|
91
123
|
};
|
|
92
124
|
const spriteArgsSchema = objectSchema({
|
|
93
|
-
description: "
|
|
125
|
+
description: "Display a single sprite by writing supplied sprite data into RAM and patching the relevant VIC-II registers.",
|
|
94
126
|
properties: {
|
|
95
127
|
sprite: spriteBytesSchema,
|
|
96
128
|
index: numberSchema({
|
|
@@ -221,7 +253,7 @@ const petsciiImageArgsSchema = objectSchema({
|
|
|
221
253
|
maximum: 15,
|
|
222
254
|
})),
|
|
223
255
|
dryRun: booleanSchema({
|
|
224
|
-
description: "When true, skip uploading the BASIC program to the C64.",
|
|
256
|
+
description: "When true, skip uploading the generated BASIC program to the C64.",
|
|
225
257
|
default: false,
|
|
226
258
|
}),
|
|
227
259
|
bitmap: optionalSchema(bitmapSchema),
|
|
@@ -251,6 +283,49 @@ const renderPetsciiScreenArgsSchema = objectSchema({
|
|
|
251
283
|
required: ["text"],
|
|
252
284
|
additionalProperties: false,
|
|
253
285
|
});
|
|
286
|
+
const vicBitmapModeSchema = {
|
|
287
|
+
jsonSchema: {
|
|
288
|
+
description: "Bitmap encoding mode to generate for the VIC-II display.",
|
|
289
|
+
type: "string",
|
|
290
|
+
enum: ["hires", "multicolor"],
|
|
291
|
+
},
|
|
292
|
+
parse(value, path) {
|
|
293
|
+
if (value === "hires" || value === "multicolor") {
|
|
294
|
+
return value;
|
|
295
|
+
}
|
|
296
|
+
throw new ToolValidationError("Bitmap format must be either hires or multicolor", { path: path ?? "$" });
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
const generateBitmapArgsSchema = objectSchema({
|
|
300
|
+
description: "Import an image file, convert it to a VIC-II bitmap, write it into RAM, and enable bitmap mode.",
|
|
301
|
+
properties: {
|
|
302
|
+
imagePath: stringSchema({
|
|
303
|
+
description: "Filesystem path of the source image (PNG, JPEG, BMP, GIF, TIFF, and other Jimp-supported formats).",
|
|
304
|
+
minLength: 1,
|
|
305
|
+
}),
|
|
306
|
+
format: vicBitmapModeSchema,
|
|
307
|
+
bitmapAddress: optionalSchema(addressSchema, 0x2000),
|
|
308
|
+
screenAddress: optionalSchema(addressSchema, 0x0400),
|
|
309
|
+
borderColor: optionalSchema(numberSchema({
|
|
310
|
+
description: "Border colour index (0-15).",
|
|
311
|
+
integer: true,
|
|
312
|
+
minimum: 0,
|
|
313
|
+
maximum: 15,
|
|
314
|
+
}), 0),
|
|
315
|
+
backgroundColor: optionalSchema(numberSchema({
|
|
316
|
+
description: "Background colour index (0-15). Used for multicolor mode and aspect-ratio padding.",
|
|
317
|
+
integer: true,
|
|
318
|
+
minimum: 0,
|
|
319
|
+
maximum: 15,
|
|
320
|
+
}), 0),
|
|
321
|
+
preserveAspect: booleanSchema({
|
|
322
|
+
description: "Preserve the source image aspect ratio and pad with the background colour.",
|
|
323
|
+
default: true,
|
|
324
|
+
}),
|
|
325
|
+
},
|
|
326
|
+
required: ["imagePath", "format"],
|
|
327
|
+
additionalProperties: false,
|
|
328
|
+
});
|
|
254
329
|
function stripOperationDiscriminator(value) {
|
|
255
330
|
const { [OPERATION_DISCRIMINATOR]: _ignored, ...rest } = value;
|
|
256
331
|
return rest;
|
|
@@ -258,7 +333,7 @@ function stripOperationDiscriminator(value) {
|
|
|
258
333
|
async function executeGenerateSprite(rawArgs, ctx) {
|
|
259
334
|
try {
|
|
260
335
|
const parsed = spriteArgsSchema.parse(rawArgs ?? {});
|
|
261
|
-
ctx.logger.info("
|
|
336
|
+
ctx.logger.info("Rendering sprite", {
|
|
262
337
|
index: parsed.index,
|
|
263
338
|
x: parsed.x,
|
|
264
339
|
y: parsed.y,
|
|
@@ -274,11 +349,11 @@ async function executeGenerateSprite(rawArgs, ctx) {
|
|
|
274
349
|
multicolour: parsed.multicolour,
|
|
275
350
|
});
|
|
276
351
|
if (!result.success) {
|
|
277
|
-
throw new ToolExecutionError("C64 firmware reported failure while
|
|
352
|
+
throw new ToolExecutionError("C64 firmware reported failure while rendering sprite", {
|
|
278
353
|
details: normaliseFailure(result.details),
|
|
279
354
|
});
|
|
280
355
|
}
|
|
281
|
-
return textResult("Sprite
|
|
356
|
+
return textResult("Sprite rendered successfully.", {
|
|
282
357
|
success: true,
|
|
283
358
|
index: parsed.index,
|
|
284
359
|
x: parsed.x,
|
|
@@ -293,7 +368,9 @@ async function executeGenerateSprite(rawArgs, ctx) {
|
|
|
293
368
|
if (error instanceof ToolError) {
|
|
294
369
|
return toolErrorResult(error);
|
|
295
370
|
}
|
|
296
|
-
return
|
|
371
|
+
return toolErrorResult(new ToolExecutionError("Unable to render sprite", {
|
|
372
|
+
details: normaliseFailure(error instanceof Error ? { message: error.message } : error),
|
|
373
|
+
}));
|
|
297
374
|
}
|
|
298
375
|
}
|
|
299
376
|
async function executeRenderPetscii(rawArgs, ctx) {
|
|
@@ -322,7 +399,75 @@ async function executeRenderPetscii(rawArgs, ctx) {
|
|
|
322
399
|
if (error instanceof ToolError) {
|
|
323
400
|
return toolErrorResult(error);
|
|
324
401
|
}
|
|
325
|
-
return
|
|
402
|
+
return toolErrorResult(new ToolExecutionError("Unable to render PETSCII screen", {
|
|
403
|
+
details: normaliseFailure(error instanceof Error ? { message: error.message } : error),
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
async function executeGenerateBitmap(rawArgs, ctx) {
|
|
408
|
+
try {
|
|
409
|
+
const parsed = generateBitmapArgsSchema.parse(rawArgs ?? {});
|
|
410
|
+
ctx.logger.info("Rendering bitmap", {
|
|
411
|
+
imagePath: parsed.imagePath,
|
|
412
|
+
format: parsed.format,
|
|
413
|
+
bitmapAddress: parsed.bitmapAddress,
|
|
414
|
+
screenAddress: parsed.screenAddress,
|
|
415
|
+
preserveAspect: parsed.preserveAspect,
|
|
416
|
+
});
|
|
417
|
+
const prepared = await importImageAsVicBitmap({
|
|
418
|
+
imagePath: parsed.imagePath,
|
|
419
|
+
mode: parsed.format,
|
|
420
|
+
preserveAspect: parsed.preserveAspect,
|
|
421
|
+
backgroundColor: parsed.backgroundColor,
|
|
422
|
+
borderColor: parsed.borderColor,
|
|
423
|
+
});
|
|
424
|
+
const result = await ctx.client.displayBitmap(prepared, {
|
|
425
|
+
bitmapAddress: parsed.bitmapAddress,
|
|
426
|
+
screenAddress: parsed.screenAddress,
|
|
427
|
+
});
|
|
428
|
+
if (!result.success) {
|
|
429
|
+
throw new ToolExecutionError("C64 firmware reported failure while displaying bitmap image", {
|
|
430
|
+
details: normaliseFailure(result.details),
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
const details = toRecord(result.details) ?? {};
|
|
434
|
+
const data = {
|
|
435
|
+
mode: prepared.mode,
|
|
436
|
+
imagePath: parsed.imagePath,
|
|
437
|
+
sourceWidth: prepared.sourceWidth,
|
|
438
|
+
sourceHeight: prepared.sourceHeight,
|
|
439
|
+
logicalWidth: prepared.logicalWidth,
|
|
440
|
+
logicalHeight: prepared.logicalHeight,
|
|
441
|
+
displayWidth: prepared.displayWidth,
|
|
442
|
+
displayHeight: prepared.displayHeight,
|
|
443
|
+
backgroundColor: prepared.backgroundColor,
|
|
444
|
+
borderColor: prepared.borderColor,
|
|
445
|
+
bitmapAddress: details.bitmapAddress ?? null,
|
|
446
|
+
screenAddress: details.screenAddress ?? null,
|
|
447
|
+
colorRamAddress: details.colorRamAddress ?? null,
|
|
448
|
+
bank: details.bank ?? null,
|
|
449
|
+
registers: details.registers ?? null,
|
|
450
|
+
bitmapBytes: prepared.bitmapData.length,
|
|
451
|
+
screenBytes: prepared.screenRam.length,
|
|
452
|
+
colorRamBytes: prepared.colorRam.length,
|
|
453
|
+
};
|
|
454
|
+
return jsonResult(data, {
|
|
455
|
+
success: true,
|
|
456
|
+
mode: prepared.mode,
|
|
457
|
+
bank: details.bank ?? null,
|
|
458
|
+
bitmapAddress: details.bitmapAddress ?? null,
|
|
459
|
+
screenAddress: details.screenAddress ?? null,
|
|
460
|
+
sourceWidth: prepared.sourceWidth,
|
|
461
|
+
sourceHeight: prepared.sourceHeight,
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
catch (error) {
|
|
465
|
+
if (error instanceof ToolError) {
|
|
466
|
+
return toolErrorResult(error);
|
|
467
|
+
}
|
|
468
|
+
return toolErrorResult(new ToolExecutionError("Unable to import or display bitmap image", {
|
|
469
|
+
details: normaliseFailure(error instanceof Error ? { message: error.message } : error),
|
|
470
|
+
}));
|
|
326
471
|
}
|
|
327
472
|
}
|
|
328
473
|
async function executeCreatePetscii(rawArgs, ctx) {
|
|
@@ -392,9 +537,10 @@ async function executeCreatePetscii(rawArgs, ctx) {
|
|
|
392
537
|
}
|
|
393
538
|
}
|
|
394
539
|
export const graphicsOperationHandlers = {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
540
|
+
render_petscii_art: async (args, ctx) => executeCreatePetscii(stripOperationDiscriminator(args), ctx),
|
|
541
|
+
render_bitmap: async (args, ctx) => executeGenerateBitmap(stripOperationDiscriminator(args), ctx),
|
|
542
|
+
render_petscii_text: async (args, ctx) => executeRenderPetscii(stripOperationDiscriminator(args), ctx),
|
|
543
|
+
render_sprite: async (args, ctx) => executeGenerateSprite(stripOperationDiscriminator(args), ctx),
|
|
398
544
|
};
|
|
399
545
|
export const graphicsModule = defineToolModule({
|
|
400
546
|
domain: "graphics",
|
|
@@ -412,9 +558,9 @@ export const graphicsModule = defineToolModule({
|
|
|
412
558
|
],
|
|
413
559
|
tools: [
|
|
414
560
|
{
|
|
415
|
-
name: "
|
|
416
|
-
description: "
|
|
417
|
-
summary: "
|
|
561
|
+
name: "render_sprite",
|
|
562
|
+
description: "Display supplied 63-byte sprite data at the requested position and colour by writing memory and patching VIC-II registers directly. See c64://specs/vic for registers.",
|
|
563
|
+
summary: "Writes sprite data into RAM, updates the sprite pointer table, and patches VIC-II registers to render a sprite preview.",
|
|
418
564
|
inputSchema: spriteArgsSchema.jsonSchema,
|
|
419
565
|
relatedResources: ["c64://specs/vic"],
|
|
420
566
|
relatedPrompts: ["graphics-demo", "assembly-program"],
|
|
@@ -431,13 +577,31 @@ export const graphicsModule = defineToolModule({
|
|
|
431
577
|
"Use when the user supplies sprite bytes or asks to preview graphics quickly; describe resulting coordinates and colours.",
|
|
432
578
|
"Remind the user that sprites live in banked memory so further tweaks may require write_memory calls.",
|
|
433
579
|
],
|
|
580
|
+
supportedPlatforms: ["c64u", "vice"],
|
|
434
581
|
async execute(args, ctx) {
|
|
435
582
|
return executeGenerateSprite(args, ctx);
|
|
436
583
|
},
|
|
437
584
|
},
|
|
438
585
|
{
|
|
439
|
-
name: "
|
|
440
|
-
description: "
|
|
586
|
+
name: "render_bitmap",
|
|
587
|
+
description: "Import an image file, convert it to a VIC-II bitmap, write it into RAM, and display it.",
|
|
588
|
+
summary: "Decodes a source image, quantizes it into C64 colours, writes bitmap/screen/color RAM, and displays it in hires or multicolor bitmap mode.",
|
|
589
|
+
inputSchema: generateBitmapArgsSchema.jsonSchema,
|
|
590
|
+
relatedResources: ["c64://specs/vic", "c64://context/bootstrap"],
|
|
591
|
+
relatedPrompts: ["graphics-demo"],
|
|
592
|
+
tags: ["bitmap", "vic", "image"],
|
|
593
|
+
workflowHints: [
|
|
594
|
+
"Use when the user wants to display an external image on screen rather than generate PETSCII art.",
|
|
595
|
+
"Call out the selected bitmap and screen RAM addresses so follow-up memory inspection or raster work stays grounded.",
|
|
596
|
+
],
|
|
597
|
+
supportedPlatforms: ["c64u", "vice"],
|
|
598
|
+
async execute(args, ctx) {
|
|
599
|
+
return executeGenerateBitmap(args, ctx);
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
name: "render_petscii_text",
|
|
604
|
+
description: "Display PETSCII text with optional border and background colours. See c64://specs/basic.",
|
|
441
605
|
summary: "Generates a BASIC program that clears the screen, sets colours, and prints text.",
|
|
442
606
|
inputSchema: renderPetsciiScreenArgsSchema.jsonSchema,
|
|
443
607
|
relatedResources: ["c64://specs/basic", "c64://context/bootstrap"],
|
|
@@ -455,13 +619,14 @@ export const graphicsModule = defineToolModule({
|
|
|
455
619
|
"Call after generating PETSCII text or when the user wants border/background colour changes applied.",
|
|
456
620
|
"Echo the colour indices and mention CLEAR + PRINT so the user knows what ran.",
|
|
457
621
|
],
|
|
622
|
+
supportedPlatforms: ["c64u", "vice"],
|
|
458
623
|
async execute(args, ctx) {
|
|
459
624
|
return executeRenderPetscii(args, ctx);
|
|
460
625
|
},
|
|
461
626
|
},
|
|
462
627
|
{
|
|
463
|
-
name: "
|
|
464
|
-
description: "Create PETSCII art from prompts or
|
|
628
|
+
name: "render_petscii_art",
|
|
629
|
+
description: "Create PETSCII art from prompts, text, or bitmap input, and optionally display it on the C64. Returns metadata including PETSCII codes and glyphs. See c64://specs/basic, c64://specs/vic, and c64://specs/charset.",
|
|
465
630
|
summary: "Synthesises PETSCII art, generates a BASIC program with preview metadata (petsciiCodes, glyphs, dimensions), and uploads it unless dry-run is requested.",
|
|
466
631
|
inputSchema: petsciiImageArgsSchema.jsonSchema,
|
|
467
632
|
relatedResources: ["c64://specs/basic", "c64://specs/vic", "c64://specs/charset"],
|
|
@@ -480,6 +645,7 @@ export const graphicsModule = defineToolModule({
|
|
|
480
645
|
"Response includes petsciiCodes array and glyphs for character-level inspection.",
|
|
481
646
|
"Provide follow-up suggestions like saving the PRG or capturing the screen after rendering.",
|
|
482
647
|
],
|
|
648
|
+
supportedPlatforms: ["c64u", "vice"],
|
|
483
649
|
async execute(args, ctx) {
|
|
484
650
|
return executeCreatePetscii(args, ctx);
|
|
485
651
|
},
|
|
@@ -26,7 +26,7 @@ function normaliseFailure(details) {
|
|
|
26
26
|
}
|
|
27
27
|
const resetArgsSchema = createNoArgsSchema("No arguments required to reset the C64.");
|
|
28
28
|
const rebootArgsSchema = createNoArgsSchema("No arguments required to reboot the C64 firmware.");
|
|
29
|
-
const pauseArgsSchema = createNoArgsSchema("No arguments required to pause the machine
|
|
29
|
+
const pauseArgsSchema = createNoArgsSchema("No arguments required to pause the machine.");
|
|
30
30
|
const resumeArgsSchema = createNoArgsSchema("No arguments required to resume the machine after a pause.");
|
|
31
31
|
const poweroffArgsSchema = createNoArgsSchema("No arguments required to power off the machine.");
|
|
32
32
|
const menuButtonArgsSchema = createNoArgsSchema("No arguments required to toggle the Ultimate menu button.");
|
|
@@ -54,6 +54,7 @@ export const machineControlModule = defineToolModule({
|
|
|
54
54
|
workflowHints: [
|
|
55
55
|
"Use when the user wants a quick restart without losing power; mention that memory contents may persist.",
|
|
56
56
|
],
|
|
57
|
+
supportedPlatforms: ["c64u", "vice"],
|
|
57
58
|
async execute(args, ctx) {
|
|
58
59
|
try {
|
|
59
60
|
resetArgsSchema.parse(args ?? {});
|
|
@@ -91,6 +92,7 @@ export const machineControlModule = defineToolModule({
|
|
|
91
92
|
workflowHints: [
|
|
92
93
|
"Choose reboot when configuration changed or hardware is stuck; warn that it will interrupt any running program.",
|
|
93
94
|
],
|
|
95
|
+
supportedPlatforms: ["c64u", "vice"],
|
|
94
96
|
async execute(args, ctx) {
|
|
95
97
|
try {
|
|
96
98
|
rebootArgsSchema.parse(args ?? {});
|
|
@@ -117,8 +119,8 @@ export const machineControlModule = defineToolModule({
|
|
|
117
119
|
},
|
|
118
120
|
{
|
|
119
121
|
name: "pause",
|
|
120
|
-
description: "Pause the machine
|
|
121
|
-
summary: "Suspends CPU execution until resumed.",
|
|
122
|
+
description: "Pause the machine on Ultimate hardware. See memory safety checklist in c64://context/bootstrap.",
|
|
123
|
+
summary: "Suspends CPU execution on Ultimate hardware until resumed.",
|
|
122
124
|
inputSchema: pauseArgsSchema.jsonSchema,
|
|
123
125
|
tags: ["pause"],
|
|
124
126
|
prerequisites: [],
|
|
@@ -128,6 +130,7 @@ export const machineControlModule = defineToolModule({
|
|
|
128
130
|
workflowHints: [
|
|
129
131
|
"Pause when the user needs a stable memory snapshot; remind them to resume to continue execution.",
|
|
130
132
|
],
|
|
133
|
+
supportedPlatforms: ["c64u"],
|
|
131
134
|
async execute(args, ctx) {
|
|
132
135
|
try {
|
|
133
136
|
pauseArgsSchema.parse(args ?? {});
|
|
@@ -154,8 +157,8 @@ export const machineControlModule = defineToolModule({
|
|
|
154
157
|
},
|
|
155
158
|
{
|
|
156
159
|
name: "resume",
|
|
157
|
-
description: "Resume the machine after
|
|
158
|
-
summary: "Releases the
|
|
160
|
+
description: "Resume the machine after an Ultimate hardware pause.",
|
|
161
|
+
summary: "Releases the Ultimate hardware pause so the CPU can continue.",
|
|
159
162
|
inputSchema: resumeArgsSchema.jsonSchema,
|
|
160
163
|
tags: ["resume"],
|
|
161
164
|
prerequisites: ["pause"],
|
|
@@ -165,6 +168,7 @@ export const machineControlModule = defineToolModule({
|
|
|
165
168
|
workflowHints: [
|
|
166
169
|
"Call after a pause or diagnostic halt and confirm the machine is running again.",
|
|
167
170
|
],
|
|
171
|
+
supportedPlatforms: ["c64u"],
|
|
168
172
|
async execute(args, ctx) {
|
|
169
173
|
try {
|
|
170
174
|
resumeArgsSchema.parse(args ?? {});
|
|
@@ -202,6 +206,7 @@ export const machineControlModule = defineToolModule({
|
|
|
202
206
|
workflowHints: [
|
|
203
207
|
"Use when the user explicitly requests power off; remind them to power on manually or via drive controls afterwards.",
|
|
204
208
|
],
|
|
209
|
+
supportedPlatforms: ["c64u", "vice"],
|
|
205
210
|
async execute(args, ctx) {
|
|
206
211
|
try {
|
|
207
212
|
poweroffArgsSchema.parse(args ?? {});
|
|
@@ -239,6 +244,7 @@ export const machineControlModule = defineToolModule({
|
|
|
239
244
|
workflowHints: [
|
|
240
245
|
"Use when the user needs to open or close the Ultimate menu; suggest following up with drive operations if relevant.",
|
|
241
246
|
],
|
|
247
|
+
supportedPlatforms: ["c64u"],
|
|
242
248
|
async execute(args, ctx) {
|
|
243
249
|
try {
|
|
244
250
|
menuButtonArgsSchema.parse(args ?? {});
|
package/dist/tools/memory.js
CHANGED
|
@@ -75,6 +75,10 @@ function resolveAddressLabel(details, fallback) {
|
|
|
75
75
|
function resolveLength(details) {
|
|
76
76
|
return typeof details.length === "number" ? details.length : undefined;
|
|
77
77
|
}
|
|
78
|
+
function supportsMachinePause(ctx) {
|
|
79
|
+
const platformId = ctx.platform?.id;
|
|
80
|
+
return platformId !== "vice";
|
|
81
|
+
}
|
|
78
82
|
const readScreenArgsSchema = objectSchema({
|
|
79
83
|
description: "No arguments are required for reading the current screen contents.",
|
|
80
84
|
properties: {},
|
|
@@ -111,7 +115,7 @@ const writeMemoryArgsSchema = objectSchema({
|
|
|
111
115
|
pattern: /^[\s_0-9A-Fa-f$]+$/,
|
|
112
116
|
}),
|
|
113
117
|
verify: booleanSchema({
|
|
114
|
-
description: "When true,
|
|
118
|
+
description: "When true, verify the write by reading before and after the change; Ultimate hardware also pauses during verification.",
|
|
115
119
|
default: false,
|
|
116
120
|
}),
|
|
117
121
|
expected: optionalSchema(stringSchema({
|
|
@@ -208,15 +212,18 @@ async function executeWriteMemory(rawArgs, ctx) {
|
|
|
208
212
|
details: detailRecord,
|
|
209
213
|
});
|
|
210
214
|
}
|
|
215
|
+
const canPause = supportsMachinePause(ctx);
|
|
211
216
|
let paused = false;
|
|
212
217
|
try {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
+
if (canPause) {
|
|
219
|
+
const pauseResult = await ctx.client.pause();
|
|
220
|
+
if (!pauseResult.success) {
|
|
221
|
+
throw new ToolExecutionError("C64 firmware reported failure while pausing", {
|
|
222
|
+
details: normaliseFailure(pauseResult.details),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
paused = true;
|
|
218
226
|
}
|
|
219
|
-
paused = true;
|
|
220
227
|
const expectedBytes = expectedInfo?.bytes ?? new Uint8Array();
|
|
221
228
|
const maskBytes = maskInfo?.bytes;
|
|
222
229
|
const readLength = Math.max(1, Math.max(writeInfo.bytes.length, expectedBytes.length));
|
|
@@ -306,6 +313,7 @@ async function executeWriteMemory(rawArgs, ctx) {
|
|
|
306
313
|
details: detailRecord,
|
|
307
314
|
verified: true,
|
|
308
315
|
verification: verificationMetadata,
|
|
316
|
+
paused,
|
|
309
317
|
});
|
|
310
318
|
}
|
|
311
319
|
finally {
|
|
@@ -344,6 +352,7 @@ export const memoryOperationHandlers = {
|
|
|
344
352
|
export const memoryModule = defineToolModule({
|
|
345
353
|
domain: "memory",
|
|
346
354
|
summary: "Screen, main memory, and low-level inspection utilities.",
|
|
355
|
+
supportedPlatforms: ["c64u", "vice"],
|
|
347
356
|
resources: [
|
|
348
357
|
"c64://context/bootstrap",
|
|
349
358
|
"c64://specs/basic",
|
|
@@ -387,7 +396,7 @@ export const memoryModule = defineToolModule({
|
|
|
387
396
|
relatedResources: ["c64://context/bootstrap", "c64://specs/assembly", "c64://docs/index"],
|
|
388
397
|
relatedPrompts: ["memory-debug", "assembly-program"],
|
|
389
398
|
tags: ["memory", "hex"],
|
|
390
|
-
prerequisites: [
|
|
399
|
+
prerequisites: [],
|
|
391
400
|
examples: [
|
|
392
401
|
{
|
|
393
402
|
name: "Read screen memory",
|
|
@@ -406,12 +415,12 @@ export const memoryModule = defineToolModule({
|
|
|
406
415
|
{
|
|
407
416
|
name: "write",
|
|
408
417
|
description: "Write a hexadecimal byte sequence into main memory at the specified address. See c64://context/bootstrap for safety rules.",
|
|
409
|
-
summary: "Resolves symbols, validates hex data, and writes bytes to RAM
|
|
418
|
+
summary: "Resolves symbols, validates hex data, and writes bytes to RAM.",
|
|
410
419
|
inputSchema: writeMemoryArgsSchema.jsonSchema,
|
|
411
420
|
relatedResources: ["c64://context/bootstrap", "c64://specs/assembly", "c64://docs/index"],
|
|
412
421
|
relatedPrompts: ["memory-debug", "assembly-program"],
|
|
413
422
|
tags: ["memory", "hex", "write"],
|
|
414
|
-
prerequisites: ["
|
|
423
|
+
prerequisites: ["read"],
|
|
415
424
|
examples: [
|
|
416
425
|
{
|
|
417
426
|
name: "Write to screen",
|