c64-debug-mcp 1.0.0 → 1.0.2
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/dist/http.cjs +53 -11
- package/dist/http.js +53 -11
- package/dist/stdio.cjs +53 -11
- package/dist/stdio.js +53 -11
- package/package.json +1 -1
package/dist/http.cjs
CHANGED
|
@@ -1370,6 +1370,8 @@ var DEFAULT_INPUT_TAP_MS = 75;
|
|
|
1370
1370
|
var DEFAULT_KEYBOARD_REPEAT_MS = 100;
|
|
1371
1371
|
var VICE_PROCESS_LOG_PATH = import_node_path.default.join(import_node_os.default.tmpdir(), "c64-debug-mcp-x64sc.log");
|
|
1372
1372
|
var DISPLAY_CAPTURE_DIR = import_node_path.default.resolve(process.cwd(), ".vice-debug-mcp-artifacts");
|
|
1373
|
+
var CLEANUP_ENABLED = !/^(0|false|no|off)$/i.test(process.env.C64_CLEANUP_SCREENSHOTS ?? "");
|
|
1374
|
+
var CLEANUP_MAX_AGE_MINUTES = Number.parseInt(process.env.C64_CLEANUP_MAX_AGE_MINUTES ?? "20", 10);
|
|
1373
1375
|
var MIRROR_EMULATOR_LOGS_TO_STDERR = /^(1|true|yes|on)$/i.test(process.env.C64_DEBUG_CONSOLE_LOGS ?? "");
|
|
1374
1376
|
var EXECUTION_EVENT_WAIT_MS = 1e3;
|
|
1375
1377
|
var EXECUTION_SETTLE_DELAY_MS = 2e3;
|
|
@@ -1518,6 +1520,7 @@ var ViceSession = class {
|
|
|
1518
1520
|
#displayOperationLock = null;
|
|
1519
1521
|
constructor(portAllocator = new PortAllocator()) {
|
|
1520
1522
|
this.#portAllocator = portAllocator;
|
|
1523
|
+
void this.#cleanupOldScreenshots();
|
|
1521
1524
|
this.#client.on("response", (response) => {
|
|
1522
1525
|
this.#lastResponseAt = nowIso();
|
|
1523
1526
|
this.#writeProcessLogLine(`[monitor-response] type=${response.type} requestId=${response.requestId} errorCode=${response.errorCode}`);
|
|
@@ -1709,7 +1712,7 @@ var ViceSession = class {
|
|
|
1709
1712
|
};
|
|
1710
1713
|
}
|
|
1711
1714
|
async readMemory(start, end, bank = 0) {
|
|
1712
|
-
await this.#
|
|
1715
|
+
await this.#ensureReady();
|
|
1713
1716
|
this.#validateRange(start, end);
|
|
1714
1717
|
const response = await this.#client.readMemory(start, end, bank);
|
|
1715
1718
|
return {
|
|
@@ -3160,6 +3163,45 @@ var ViceSession = class {
|
|
|
3160
3163
|
}
|
|
3161
3164
|
this.#syncMonitorRuntimeState();
|
|
3162
3165
|
}
|
|
3166
|
+
async #cleanupOldScreenshots() {
|
|
3167
|
+
if (!CLEANUP_ENABLED) {
|
|
3168
|
+
return;
|
|
3169
|
+
}
|
|
3170
|
+
try {
|
|
3171
|
+
const maxAgeMinutes = Math.max(1, Math.min(525600, CLEANUP_MAX_AGE_MINUTES));
|
|
3172
|
+
const maxAgeMs = maxAgeMinutes * 60 * 1e3;
|
|
3173
|
+
const cutoffTime = Date.now() - maxAgeMs;
|
|
3174
|
+
this.#writeProcessLogLine(`[cleanup] scanning ${DISPLAY_CAPTURE_DIR} for screenshots older than ${maxAgeMinutes}m`);
|
|
3175
|
+
let entries;
|
|
3176
|
+
try {
|
|
3177
|
+
entries = await import_promises.default.readdir(DISPLAY_CAPTURE_DIR);
|
|
3178
|
+
} catch (error) {
|
|
3179
|
+
if (error.code === "ENOENT") {
|
|
3180
|
+
return;
|
|
3181
|
+
}
|
|
3182
|
+
throw error;
|
|
3183
|
+
}
|
|
3184
|
+
const pngFiles = entries.filter((name) => name.endsWith(".png") && name.startsWith("capture-"));
|
|
3185
|
+
let deletedCount = 0;
|
|
3186
|
+
let errorCount = 0;
|
|
3187
|
+
for (const filename of pngFiles) {
|
|
3188
|
+
try {
|
|
3189
|
+
const filePath = import_node_path.default.join(DISPLAY_CAPTURE_DIR, filename);
|
|
3190
|
+
const stats = await import_promises.default.stat(filePath);
|
|
3191
|
+
if (stats.mtime.getTime() < cutoffTime) {
|
|
3192
|
+
await import_promises.default.unlink(filePath);
|
|
3193
|
+
deletedCount++;
|
|
3194
|
+
}
|
|
3195
|
+
} catch (error) {
|
|
3196
|
+
errorCount++;
|
|
3197
|
+
this.#writeProcessLogLine(`[cleanup] failed to delete ${filename}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
this.#writeProcessLogLine(`[cleanup] completed: ${deletedCount} deleted, ${errorCount} errors, ${pngFiles.length - deletedCount - errorCount} retained`);
|
|
3201
|
+
} catch (error) {
|
|
3202
|
+
this.#writeProcessLogLine(`[cleanup] failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3163
3205
|
};
|
|
3164
3206
|
function splitCommandLine(input) {
|
|
3165
3207
|
const result = [];
|
|
@@ -3262,14 +3304,14 @@ var getMonitorStateTool = createViceTool({
|
|
|
3262
3304
|
});
|
|
3263
3305
|
var getSessionStateTool = createViceTool({
|
|
3264
3306
|
id: "get_session_state",
|
|
3265
|
-
description: "Returns
|
|
3307
|
+
description: "Returns emulator session state including transport/process status, auto-resume state, and the most recent hit checkpoint.",
|
|
3266
3308
|
inputSchema: noInputSchema,
|
|
3267
3309
|
dataSchema: sessionStateResultSchema,
|
|
3268
3310
|
execute: async () => c64Session.snapshot()
|
|
3269
3311
|
});
|
|
3270
3312
|
var getRegistersTool = createViceTool({
|
|
3271
3313
|
id: "get_registers",
|
|
3272
|
-
description:
|
|
3314
|
+
description: 'Returns the current C64 register snapshot. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3273
3315
|
inputSchema: noInputSchema,
|
|
3274
3316
|
dataSchema: import_zod4.z.object({
|
|
3275
3317
|
registers: c64RegisterValueSchema
|
|
@@ -3278,7 +3320,7 @@ var getRegistersTool = createViceTool({
|
|
|
3278
3320
|
});
|
|
3279
3321
|
var setRegistersTool = createViceTool({
|
|
3280
3322
|
id: "set_registers",
|
|
3281
|
-
description:
|
|
3323
|
+
description: 'Sets one or more C64 registers by field name. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3282
3324
|
inputSchema: import_zod4.z.object({
|
|
3283
3325
|
registers: c64PartialRegisterValueSchema
|
|
3284
3326
|
}),
|
|
@@ -3314,7 +3356,7 @@ var readMemoryTool = createViceTool({
|
|
|
3314
3356
|
});
|
|
3315
3357
|
var writeMemoryTool = createViceTool({
|
|
3316
3358
|
id: "memory_write",
|
|
3317
|
-
description:
|
|
3359
|
+
description: 'Writes raw byte values into the active C64 memory space. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3318
3360
|
inputSchema: import_zod4.z.object({
|
|
3319
3361
|
address: address16Schema.describe("Start address in the 16-bit C64 address space"),
|
|
3320
3362
|
data: byteArraySchema.min(1).describe("Raw bytes to write into memory")
|
|
@@ -3430,7 +3472,7 @@ var programLoadTool = createViceTool({
|
|
|
3430
3472
|
});
|
|
3431
3473
|
var captureDisplayTool = createViceTool({
|
|
3432
3474
|
id: "capture_display",
|
|
3433
|
-
description: "Captures the current screen to a PNG file and returns the saved image path.
|
|
3475
|
+
description: "Captures the current screen to a PNG file and returns the saved image path.",
|
|
3434
3476
|
inputSchema: import_zod4.z.object({
|
|
3435
3477
|
useVic: import_zod4.z.boolean().default(true).describe("Whether to capture the VIC-II display when supported")
|
|
3436
3478
|
}),
|
|
@@ -3439,21 +3481,21 @@ var captureDisplayTool = createViceTool({
|
|
|
3439
3481
|
});
|
|
3440
3482
|
var getDisplayStateTool = createViceTool({
|
|
3441
3483
|
id: "get_display_state",
|
|
3442
|
-
description: "Returns screen RAM, color RAM, the current graphics mode, screen memory addresses, and the current border and background colors.
|
|
3484
|
+
description: "Returns screen RAM, color RAM, the current graphics mode, screen memory addresses, and the current border and background colors.",
|
|
3443
3485
|
inputSchema: noInputSchema,
|
|
3444
3486
|
dataSchema: displayStateResultSchema,
|
|
3445
3487
|
execute: async () => await c64Session.getDisplayState()
|
|
3446
3488
|
});
|
|
3447
3489
|
var getDisplayTextTool = createViceTool({
|
|
3448
3490
|
id: "get_display_text",
|
|
3449
|
-
description: "Returns the current text screen as readable text when the C64 is in a text mode.
|
|
3491
|
+
description: "Returns the current text screen as readable text when the C64 is in a text mode.",
|
|
3450
3492
|
inputSchema: noInputSchema,
|
|
3451
3493
|
dataSchema: displayTextResultSchema,
|
|
3452
3494
|
execute: async () => await c64Session.getDisplayText()
|
|
3453
3495
|
});
|
|
3454
3496
|
var writeTextTool = createViceTool({
|
|
3455
3497
|
id: "write_text",
|
|
3456
|
-
description:
|
|
3498
|
+
description: 'Types text into the C64. Requires emulator to be running - call execute(action="resume") first if stopped. Supports escaped characters and PETSCII brace tokens like {RETURN}, {CLR}, {HOME}, {PI}, and color names. Limit 64 bytes per request.',
|
|
3457
3499
|
inputSchema: import_zod4.z.object({
|
|
3458
3500
|
text: import_zod4.z.string()
|
|
3459
3501
|
}),
|
|
@@ -3465,7 +3507,7 @@ var writeTextTool = createViceTool({
|
|
|
3465
3507
|
});
|
|
3466
3508
|
var keyboardInputTool = createViceTool({
|
|
3467
3509
|
id: "keyboard_input",
|
|
3468
|
-
description:
|
|
3510
|
+
description: 'Sends one to four keys or PETSCII tokens to the C64. Requires emulator to be running - call execute(action="resume") first if stopped. Use for key presses, releases, and taps.',
|
|
3469
3511
|
inputSchema: import_zod4.z.object({
|
|
3470
3512
|
action: inputActionSchema.describe("Use tap for a single key event or press/release for repeated buffered input"),
|
|
3471
3513
|
keys: import_zod4.z.array(import_zod4.z.string().min(1)).min(1).max(4).describe("One to four literal keys or PETSCII token names such as RETURN, CLR, HOME, PI, LEFT, RED, or F1"),
|
|
@@ -3476,7 +3518,7 @@ var keyboardInputTool = createViceTool({
|
|
|
3476
3518
|
});
|
|
3477
3519
|
var joystickInputTool = createViceTool({
|
|
3478
3520
|
id: "joystick_input",
|
|
3479
|
-
description:
|
|
3521
|
+
description: 'Sends joystick input to C64 joystick port 1 or 2. Requires emulator to be running - call execute(action="resume") first if stopped.',
|
|
3480
3522
|
inputSchema: import_zod4.z.object({
|
|
3481
3523
|
port: joystickPortSchema.describe("Joystick port number"),
|
|
3482
3524
|
action: inputActionSchema.describe("Joystick action to apply"),
|
package/dist/http.js
CHANGED
|
@@ -1347,6 +1347,8 @@ var DEFAULT_INPUT_TAP_MS = 75;
|
|
|
1347
1347
|
var DEFAULT_KEYBOARD_REPEAT_MS = 100;
|
|
1348
1348
|
var VICE_PROCESS_LOG_PATH = path.join(os.tmpdir(), "c64-debug-mcp-x64sc.log");
|
|
1349
1349
|
var DISPLAY_CAPTURE_DIR = path.resolve(process.cwd(), ".vice-debug-mcp-artifacts");
|
|
1350
|
+
var CLEANUP_ENABLED = !/^(0|false|no|off)$/i.test(process.env.C64_CLEANUP_SCREENSHOTS ?? "");
|
|
1351
|
+
var CLEANUP_MAX_AGE_MINUTES = Number.parseInt(process.env.C64_CLEANUP_MAX_AGE_MINUTES ?? "20", 10);
|
|
1350
1352
|
var MIRROR_EMULATOR_LOGS_TO_STDERR = /^(1|true|yes|on)$/i.test(process.env.C64_DEBUG_CONSOLE_LOGS ?? "");
|
|
1351
1353
|
var EXECUTION_EVENT_WAIT_MS = 1e3;
|
|
1352
1354
|
var EXECUTION_SETTLE_DELAY_MS = 2e3;
|
|
@@ -1495,6 +1497,7 @@ var ViceSession = class {
|
|
|
1495
1497
|
#displayOperationLock = null;
|
|
1496
1498
|
constructor(portAllocator = new PortAllocator()) {
|
|
1497
1499
|
this.#portAllocator = portAllocator;
|
|
1500
|
+
void this.#cleanupOldScreenshots();
|
|
1498
1501
|
this.#client.on("response", (response) => {
|
|
1499
1502
|
this.#lastResponseAt = nowIso();
|
|
1500
1503
|
this.#writeProcessLogLine(`[monitor-response] type=${response.type} requestId=${response.requestId} errorCode=${response.errorCode}`);
|
|
@@ -1686,7 +1689,7 @@ var ViceSession = class {
|
|
|
1686
1689
|
};
|
|
1687
1690
|
}
|
|
1688
1691
|
async readMemory(start, end, bank = 0) {
|
|
1689
|
-
await this.#
|
|
1692
|
+
await this.#ensureReady();
|
|
1690
1693
|
this.#validateRange(start, end);
|
|
1691
1694
|
const response = await this.#client.readMemory(start, end, bank);
|
|
1692
1695
|
return {
|
|
@@ -3137,6 +3140,45 @@ var ViceSession = class {
|
|
|
3137
3140
|
}
|
|
3138
3141
|
this.#syncMonitorRuntimeState();
|
|
3139
3142
|
}
|
|
3143
|
+
async #cleanupOldScreenshots() {
|
|
3144
|
+
if (!CLEANUP_ENABLED) {
|
|
3145
|
+
return;
|
|
3146
|
+
}
|
|
3147
|
+
try {
|
|
3148
|
+
const maxAgeMinutes = Math.max(1, Math.min(525600, CLEANUP_MAX_AGE_MINUTES));
|
|
3149
|
+
const maxAgeMs = maxAgeMinutes * 60 * 1e3;
|
|
3150
|
+
const cutoffTime = Date.now() - maxAgeMs;
|
|
3151
|
+
this.#writeProcessLogLine(`[cleanup] scanning ${DISPLAY_CAPTURE_DIR} for screenshots older than ${maxAgeMinutes}m`);
|
|
3152
|
+
let entries;
|
|
3153
|
+
try {
|
|
3154
|
+
entries = await fs.readdir(DISPLAY_CAPTURE_DIR);
|
|
3155
|
+
} catch (error) {
|
|
3156
|
+
if (error.code === "ENOENT") {
|
|
3157
|
+
return;
|
|
3158
|
+
}
|
|
3159
|
+
throw error;
|
|
3160
|
+
}
|
|
3161
|
+
const pngFiles = entries.filter((name) => name.endsWith(".png") && name.startsWith("capture-"));
|
|
3162
|
+
let deletedCount = 0;
|
|
3163
|
+
let errorCount = 0;
|
|
3164
|
+
for (const filename of pngFiles) {
|
|
3165
|
+
try {
|
|
3166
|
+
const filePath = path.join(DISPLAY_CAPTURE_DIR, filename);
|
|
3167
|
+
const stats = await fs.stat(filePath);
|
|
3168
|
+
if (stats.mtime.getTime() < cutoffTime) {
|
|
3169
|
+
await fs.unlink(filePath);
|
|
3170
|
+
deletedCount++;
|
|
3171
|
+
}
|
|
3172
|
+
} catch (error) {
|
|
3173
|
+
errorCount++;
|
|
3174
|
+
this.#writeProcessLogLine(`[cleanup] failed to delete ${filename}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
this.#writeProcessLogLine(`[cleanup] completed: ${deletedCount} deleted, ${errorCount} errors, ${pngFiles.length - deletedCount - errorCount} retained`);
|
|
3178
|
+
} catch (error) {
|
|
3179
|
+
this.#writeProcessLogLine(`[cleanup] failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3140
3182
|
};
|
|
3141
3183
|
function splitCommandLine(input) {
|
|
3142
3184
|
const result = [];
|
|
@@ -3239,14 +3281,14 @@ var getMonitorStateTool = createViceTool({
|
|
|
3239
3281
|
});
|
|
3240
3282
|
var getSessionStateTool = createViceTool({
|
|
3241
3283
|
id: "get_session_state",
|
|
3242
|
-
description: "Returns
|
|
3284
|
+
description: "Returns emulator session state including transport/process status, auto-resume state, and the most recent hit checkpoint.",
|
|
3243
3285
|
inputSchema: noInputSchema,
|
|
3244
3286
|
dataSchema: sessionStateResultSchema,
|
|
3245
3287
|
execute: async () => c64Session.snapshot()
|
|
3246
3288
|
});
|
|
3247
3289
|
var getRegistersTool = createViceTool({
|
|
3248
3290
|
id: "get_registers",
|
|
3249
|
-
description:
|
|
3291
|
+
description: 'Returns the current C64 register snapshot. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3250
3292
|
inputSchema: noInputSchema,
|
|
3251
3293
|
dataSchema: z3.object({
|
|
3252
3294
|
registers: c64RegisterValueSchema
|
|
@@ -3255,7 +3297,7 @@ var getRegistersTool = createViceTool({
|
|
|
3255
3297
|
});
|
|
3256
3298
|
var setRegistersTool = createViceTool({
|
|
3257
3299
|
id: "set_registers",
|
|
3258
|
-
description:
|
|
3300
|
+
description: 'Sets one or more C64 registers by field name. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3259
3301
|
inputSchema: z3.object({
|
|
3260
3302
|
registers: c64PartialRegisterValueSchema
|
|
3261
3303
|
}),
|
|
@@ -3291,7 +3333,7 @@ var readMemoryTool = createViceTool({
|
|
|
3291
3333
|
});
|
|
3292
3334
|
var writeMemoryTool = createViceTool({
|
|
3293
3335
|
id: "memory_write",
|
|
3294
|
-
description:
|
|
3336
|
+
description: 'Writes raw byte values into the active C64 memory space. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3295
3337
|
inputSchema: z3.object({
|
|
3296
3338
|
address: address16Schema.describe("Start address in the 16-bit C64 address space"),
|
|
3297
3339
|
data: byteArraySchema.min(1).describe("Raw bytes to write into memory")
|
|
@@ -3407,7 +3449,7 @@ var programLoadTool = createViceTool({
|
|
|
3407
3449
|
});
|
|
3408
3450
|
var captureDisplayTool = createViceTool({
|
|
3409
3451
|
id: "capture_display",
|
|
3410
|
-
description: "Captures the current screen to a PNG file and returns the saved image path.
|
|
3452
|
+
description: "Captures the current screen to a PNG file and returns the saved image path.",
|
|
3411
3453
|
inputSchema: z3.object({
|
|
3412
3454
|
useVic: z3.boolean().default(true).describe("Whether to capture the VIC-II display when supported")
|
|
3413
3455
|
}),
|
|
@@ -3416,21 +3458,21 @@ var captureDisplayTool = createViceTool({
|
|
|
3416
3458
|
});
|
|
3417
3459
|
var getDisplayStateTool = createViceTool({
|
|
3418
3460
|
id: "get_display_state",
|
|
3419
|
-
description: "Returns screen RAM, color RAM, the current graphics mode, screen memory addresses, and the current border and background colors.
|
|
3461
|
+
description: "Returns screen RAM, color RAM, the current graphics mode, screen memory addresses, and the current border and background colors.",
|
|
3420
3462
|
inputSchema: noInputSchema,
|
|
3421
3463
|
dataSchema: displayStateResultSchema,
|
|
3422
3464
|
execute: async () => await c64Session.getDisplayState()
|
|
3423
3465
|
});
|
|
3424
3466
|
var getDisplayTextTool = createViceTool({
|
|
3425
3467
|
id: "get_display_text",
|
|
3426
|
-
description: "Returns the current text screen as readable text when the C64 is in a text mode.
|
|
3468
|
+
description: "Returns the current text screen as readable text when the C64 is in a text mode.",
|
|
3427
3469
|
inputSchema: noInputSchema,
|
|
3428
3470
|
dataSchema: displayTextResultSchema,
|
|
3429
3471
|
execute: async () => await c64Session.getDisplayText()
|
|
3430
3472
|
});
|
|
3431
3473
|
var writeTextTool = createViceTool({
|
|
3432
3474
|
id: "write_text",
|
|
3433
|
-
description:
|
|
3475
|
+
description: 'Types text into the C64. Requires emulator to be running - call execute(action="resume") first if stopped. Supports escaped characters and PETSCII brace tokens like {RETURN}, {CLR}, {HOME}, {PI}, and color names. Limit 64 bytes per request.',
|
|
3434
3476
|
inputSchema: z3.object({
|
|
3435
3477
|
text: z3.string()
|
|
3436
3478
|
}),
|
|
@@ -3442,7 +3484,7 @@ var writeTextTool = createViceTool({
|
|
|
3442
3484
|
});
|
|
3443
3485
|
var keyboardInputTool = createViceTool({
|
|
3444
3486
|
id: "keyboard_input",
|
|
3445
|
-
description:
|
|
3487
|
+
description: 'Sends one to four keys or PETSCII tokens to the C64. Requires emulator to be running - call execute(action="resume") first if stopped. Use for key presses, releases, and taps.',
|
|
3446
3488
|
inputSchema: z3.object({
|
|
3447
3489
|
action: inputActionSchema.describe("Use tap for a single key event or press/release for repeated buffered input"),
|
|
3448
3490
|
keys: z3.array(z3.string().min(1)).min(1).max(4).describe("One to four literal keys or PETSCII token names such as RETURN, CLR, HOME, PI, LEFT, RED, or F1"),
|
|
@@ -3453,7 +3495,7 @@ var keyboardInputTool = createViceTool({
|
|
|
3453
3495
|
});
|
|
3454
3496
|
var joystickInputTool = createViceTool({
|
|
3455
3497
|
id: "joystick_input",
|
|
3456
|
-
description:
|
|
3498
|
+
description: 'Sends joystick input to C64 joystick port 1 or 2. Requires emulator to be running - call execute(action="resume") first if stopped.',
|
|
3457
3499
|
inputSchema: z3.object({
|
|
3458
3500
|
port: joystickPortSchema.describe("Joystick port number"),
|
|
3459
3501
|
action: inputActionSchema.describe("Joystick action to apply"),
|
package/dist/stdio.cjs
CHANGED
|
@@ -1367,6 +1367,8 @@ var DEFAULT_INPUT_TAP_MS = 75;
|
|
|
1367
1367
|
var DEFAULT_KEYBOARD_REPEAT_MS = 100;
|
|
1368
1368
|
var VICE_PROCESS_LOG_PATH = import_node_path.default.join(import_node_os.default.tmpdir(), "c64-debug-mcp-x64sc.log");
|
|
1369
1369
|
var DISPLAY_CAPTURE_DIR = import_node_path.default.resolve(process.cwd(), ".vice-debug-mcp-artifacts");
|
|
1370
|
+
var CLEANUP_ENABLED = !/^(0|false|no|off)$/i.test(process.env.C64_CLEANUP_SCREENSHOTS ?? "");
|
|
1371
|
+
var CLEANUP_MAX_AGE_MINUTES = Number.parseInt(process.env.C64_CLEANUP_MAX_AGE_MINUTES ?? "20", 10);
|
|
1370
1372
|
var MIRROR_EMULATOR_LOGS_TO_STDERR = /^(1|true|yes|on)$/i.test(process.env.C64_DEBUG_CONSOLE_LOGS ?? "");
|
|
1371
1373
|
var EXECUTION_EVENT_WAIT_MS = 1e3;
|
|
1372
1374
|
var EXECUTION_SETTLE_DELAY_MS = 2e3;
|
|
@@ -1515,6 +1517,7 @@ var ViceSession = class {
|
|
|
1515
1517
|
#displayOperationLock = null;
|
|
1516
1518
|
constructor(portAllocator = new PortAllocator()) {
|
|
1517
1519
|
this.#portAllocator = portAllocator;
|
|
1520
|
+
void this.#cleanupOldScreenshots();
|
|
1518
1521
|
this.#client.on("response", (response) => {
|
|
1519
1522
|
this.#lastResponseAt = nowIso();
|
|
1520
1523
|
this.#writeProcessLogLine(`[monitor-response] type=${response.type} requestId=${response.requestId} errorCode=${response.errorCode}`);
|
|
@@ -1706,7 +1709,7 @@ var ViceSession = class {
|
|
|
1706
1709
|
};
|
|
1707
1710
|
}
|
|
1708
1711
|
async readMemory(start, end, bank = 0) {
|
|
1709
|
-
await this.#
|
|
1712
|
+
await this.#ensureReady();
|
|
1710
1713
|
this.#validateRange(start, end);
|
|
1711
1714
|
const response = await this.#client.readMemory(start, end, bank);
|
|
1712
1715
|
return {
|
|
@@ -3157,6 +3160,45 @@ var ViceSession = class {
|
|
|
3157
3160
|
}
|
|
3158
3161
|
this.#syncMonitorRuntimeState();
|
|
3159
3162
|
}
|
|
3163
|
+
async #cleanupOldScreenshots() {
|
|
3164
|
+
if (!CLEANUP_ENABLED) {
|
|
3165
|
+
return;
|
|
3166
|
+
}
|
|
3167
|
+
try {
|
|
3168
|
+
const maxAgeMinutes = Math.max(1, Math.min(525600, CLEANUP_MAX_AGE_MINUTES));
|
|
3169
|
+
const maxAgeMs = maxAgeMinutes * 60 * 1e3;
|
|
3170
|
+
const cutoffTime = Date.now() - maxAgeMs;
|
|
3171
|
+
this.#writeProcessLogLine(`[cleanup] scanning ${DISPLAY_CAPTURE_DIR} for screenshots older than ${maxAgeMinutes}m`);
|
|
3172
|
+
let entries;
|
|
3173
|
+
try {
|
|
3174
|
+
entries = await import_promises.default.readdir(DISPLAY_CAPTURE_DIR);
|
|
3175
|
+
} catch (error) {
|
|
3176
|
+
if (error.code === "ENOENT") {
|
|
3177
|
+
return;
|
|
3178
|
+
}
|
|
3179
|
+
throw error;
|
|
3180
|
+
}
|
|
3181
|
+
const pngFiles = entries.filter((name) => name.endsWith(".png") && name.startsWith("capture-"));
|
|
3182
|
+
let deletedCount = 0;
|
|
3183
|
+
let errorCount = 0;
|
|
3184
|
+
for (const filename of pngFiles) {
|
|
3185
|
+
try {
|
|
3186
|
+
const filePath = import_node_path.default.join(DISPLAY_CAPTURE_DIR, filename);
|
|
3187
|
+
const stats = await import_promises.default.stat(filePath);
|
|
3188
|
+
if (stats.mtime.getTime() < cutoffTime) {
|
|
3189
|
+
await import_promises.default.unlink(filePath);
|
|
3190
|
+
deletedCount++;
|
|
3191
|
+
}
|
|
3192
|
+
} catch (error) {
|
|
3193
|
+
errorCount++;
|
|
3194
|
+
this.#writeProcessLogLine(`[cleanup] failed to delete ${filename}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
this.#writeProcessLogLine(`[cleanup] completed: ${deletedCount} deleted, ${errorCount} errors, ${pngFiles.length - deletedCount - errorCount} retained`);
|
|
3198
|
+
} catch (error) {
|
|
3199
|
+
this.#writeProcessLogLine(`[cleanup] failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3160
3202
|
};
|
|
3161
3203
|
function splitCommandLine(input) {
|
|
3162
3204
|
const result = [];
|
|
@@ -3259,14 +3301,14 @@ var getMonitorStateTool = createViceTool({
|
|
|
3259
3301
|
});
|
|
3260
3302
|
var getSessionStateTool = createViceTool({
|
|
3261
3303
|
id: "get_session_state",
|
|
3262
|
-
description: "Returns
|
|
3304
|
+
description: "Returns emulator session state including transport/process status, auto-resume state, and the most recent hit checkpoint.",
|
|
3263
3305
|
inputSchema: noInputSchema,
|
|
3264
3306
|
dataSchema: sessionStateResultSchema,
|
|
3265
3307
|
execute: async () => c64Session.snapshot()
|
|
3266
3308
|
});
|
|
3267
3309
|
var getRegistersTool = createViceTool({
|
|
3268
3310
|
id: "get_registers",
|
|
3269
|
-
description:
|
|
3311
|
+
description: 'Returns the current C64 register snapshot. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3270
3312
|
inputSchema: noInputSchema,
|
|
3271
3313
|
dataSchema: import_zod4.z.object({
|
|
3272
3314
|
registers: c64RegisterValueSchema
|
|
@@ -3275,7 +3317,7 @@ var getRegistersTool = createViceTool({
|
|
|
3275
3317
|
});
|
|
3276
3318
|
var setRegistersTool = createViceTool({
|
|
3277
3319
|
id: "set_registers",
|
|
3278
|
-
description:
|
|
3320
|
+
description: 'Sets one or more C64 registers by field name. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3279
3321
|
inputSchema: import_zod4.z.object({
|
|
3280
3322
|
registers: c64PartialRegisterValueSchema
|
|
3281
3323
|
}),
|
|
@@ -3311,7 +3353,7 @@ var readMemoryTool = createViceTool({
|
|
|
3311
3353
|
});
|
|
3312
3354
|
var writeMemoryTool = createViceTool({
|
|
3313
3355
|
id: "memory_write",
|
|
3314
|
-
description:
|
|
3356
|
+
description: 'Writes raw byte values into the active C64 memory space. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3315
3357
|
inputSchema: import_zod4.z.object({
|
|
3316
3358
|
address: address16Schema.describe("Start address in the 16-bit C64 address space"),
|
|
3317
3359
|
data: byteArraySchema.min(1).describe("Raw bytes to write into memory")
|
|
@@ -3427,7 +3469,7 @@ var programLoadTool = createViceTool({
|
|
|
3427
3469
|
});
|
|
3428
3470
|
var captureDisplayTool = createViceTool({
|
|
3429
3471
|
id: "capture_display",
|
|
3430
|
-
description: "Captures the current screen to a PNG file and returns the saved image path.
|
|
3472
|
+
description: "Captures the current screen to a PNG file and returns the saved image path.",
|
|
3431
3473
|
inputSchema: import_zod4.z.object({
|
|
3432
3474
|
useVic: import_zod4.z.boolean().default(true).describe("Whether to capture the VIC-II display when supported")
|
|
3433
3475
|
}),
|
|
@@ -3436,21 +3478,21 @@ var captureDisplayTool = createViceTool({
|
|
|
3436
3478
|
});
|
|
3437
3479
|
var getDisplayStateTool = createViceTool({
|
|
3438
3480
|
id: "get_display_state",
|
|
3439
|
-
description: "Returns screen RAM, color RAM, the current graphics mode, screen memory addresses, and the current border and background colors.
|
|
3481
|
+
description: "Returns screen RAM, color RAM, the current graphics mode, screen memory addresses, and the current border and background colors.",
|
|
3440
3482
|
inputSchema: noInputSchema,
|
|
3441
3483
|
dataSchema: displayStateResultSchema,
|
|
3442
3484
|
execute: async () => await c64Session.getDisplayState()
|
|
3443
3485
|
});
|
|
3444
3486
|
var getDisplayTextTool = createViceTool({
|
|
3445
3487
|
id: "get_display_text",
|
|
3446
|
-
description: "Returns the current text screen as readable text when the C64 is in a text mode.
|
|
3488
|
+
description: "Returns the current text screen as readable text when the C64 is in a text mode.",
|
|
3447
3489
|
inputSchema: noInputSchema,
|
|
3448
3490
|
dataSchema: displayTextResultSchema,
|
|
3449
3491
|
execute: async () => await c64Session.getDisplayText()
|
|
3450
3492
|
});
|
|
3451
3493
|
var writeTextTool = createViceTool({
|
|
3452
3494
|
id: "write_text",
|
|
3453
|
-
description:
|
|
3495
|
+
description: 'Types text into the C64. Requires emulator to be running - call execute(action="resume") first if stopped. Supports escaped characters and PETSCII brace tokens like {RETURN}, {CLR}, {HOME}, {PI}, and color names. Limit 64 bytes per request.',
|
|
3454
3496
|
inputSchema: import_zod4.z.object({
|
|
3455
3497
|
text: import_zod4.z.string()
|
|
3456
3498
|
}),
|
|
@@ -3462,7 +3504,7 @@ var writeTextTool = createViceTool({
|
|
|
3462
3504
|
});
|
|
3463
3505
|
var keyboardInputTool = createViceTool({
|
|
3464
3506
|
id: "keyboard_input",
|
|
3465
|
-
description:
|
|
3507
|
+
description: 'Sends one to four keys or PETSCII tokens to the C64. Requires emulator to be running - call execute(action="resume") first if stopped. Use for key presses, releases, and taps.',
|
|
3466
3508
|
inputSchema: import_zod4.z.object({
|
|
3467
3509
|
action: inputActionSchema.describe("Use tap for a single key event or press/release for repeated buffered input"),
|
|
3468
3510
|
keys: import_zod4.z.array(import_zod4.z.string().min(1)).min(1).max(4).describe("One to four literal keys or PETSCII token names such as RETURN, CLR, HOME, PI, LEFT, RED, or F1"),
|
|
@@ -3473,7 +3515,7 @@ var keyboardInputTool = createViceTool({
|
|
|
3473
3515
|
});
|
|
3474
3516
|
var joystickInputTool = createViceTool({
|
|
3475
3517
|
id: "joystick_input",
|
|
3476
|
-
description:
|
|
3518
|
+
description: 'Sends joystick input to C64 joystick port 1 or 2. Requires emulator to be running - call execute(action="resume") first if stopped.',
|
|
3477
3519
|
inputSchema: import_zod4.z.object({
|
|
3478
3520
|
port: joystickPortSchema.describe("Joystick port number"),
|
|
3479
3521
|
action: inputActionSchema.describe("Joystick action to apply"),
|
package/dist/stdio.js
CHANGED
|
@@ -1344,6 +1344,8 @@ var DEFAULT_INPUT_TAP_MS = 75;
|
|
|
1344
1344
|
var DEFAULT_KEYBOARD_REPEAT_MS = 100;
|
|
1345
1345
|
var VICE_PROCESS_LOG_PATH = path.join(os.tmpdir(), "c64-debug-mcp-x64sc.log");
|
|
1346
1346
|
var DISPLAY_CAPTURE_DIR = path.resolve(process.cwd(), ".vice-debug-mcp-artifacts");
|
|
1347
|
+
var CLEANUP_ENABLED = !/^(0|false|no|off)$/i.test(process.env.C64_CLEANUP_SCREENSHOTS ?? "");
|
|
1348
|
+
var CLEANUP_MAX_AGE_MINUTES = Number.parseInt(process.env.C64_CLEANUP_MAX_AGE_MINUTES ?? "20", 10);
|
|
1347
1349
|
var MIRROR_EMULATOR_LOGS_TO_STDERR = /^(1|true|yes|on)$/i.test(process.env.C64_DEBUG_CONSOLE_LOGS ?? "");
|
|
1348
1350
|
var EXECUTION_EVENT_WAIT_MS = 1e3;
|
|
1349
1351
|
var EXECUTION_SETTLE_DELAY_MS = 2e3;
|
|
@@ -1492,6 +1494,7 @@ var ViceSession = class {
|
|
|
1492
1494
|
#displayOperationLock = null;
|
|
1493
1495
|
constructor(portAllocator = new PortAllocator()) {
|
|
1494
1496
|
this.#portAllocator = portAllocator;
|
|
1497
|
+
void this.#cleanupOldScreenshots();
|
|
1495
1498
|
this.#client.on("response", (response) => {
|
|
1496
1499
|
this.#lastResponseAt = nowIso();
|
|
1497
1500
|
this.#writeProcessLogLine(`[monitor-response] type=${response.type} requestId=${response.requestId} errorCode=${response.errorCode}`);
|
|
@@ -1683,7 +1686,7 @@ var ViceSession = class {
|
|
|
1683
1686
|
};
|
|
1684
1687
|
}
|
|
1685
1688
|
async readMemory(start, end, bank = 0) {
|
|
1686
|
-
await this.#
|
|
1689
|
+
await this.#ensureReady();
|
|
1687
1690
|
this.#validateRange(start, end);
|
|
1688
1691
|
const response = await this.#client.readMemory(start, end, bank);
|
|
1689
1692
|
return {
|
|
@@ -3134,6 +3137,45 @@ var ViceSession = class {
|
|
|
3134
3137
|
}
|
|
3135
3138
|
this.#syncMonitorRuntimeState();
|
|
3136
3139
|
}
|
|
3140
|
+
async #cleanupOldScreenshots() {
|
|
3141
|
+
if (!CLEANUP_ENABLED) {
|
|
3142
|
+
return;
|
|
3143
|
+
}
|
|
3144
|
+
try {
|
|
3145
|
+
const maxAgeMinutes = Math.max(1, Math.min(525600, CLEANUP_MAX_AGE_MINUTES));
|
|
3146
|
+
const maxAgeMs = maxAgeMinutes * 60 * 1e3;
|
|
3147
|
+
const cutoffTime = Date.now() - maxAgeMs;
|
|
3148
|
+
this.#writeProcessLogLine(`[cleanup] scanning ${DISPLAY_CAPTURE_DIR} for screenshots older than ${maxAgeMinutes}m`);
|
|
3149
|
+
let entries;
|
|
3150
|
+
try {
|
|
3151
|
+
entries = await fs.readdir(DISPLAY_CAPTURE_DIR);
|
|
3152
|
+
} catch (error) {
|
|
3153
|
+
if (error.code === "ENOENT") {
|
|
3154
|
+
return;
|
|
3155
|
+
}
|
|
3156
|
+
throw error;
|
|
3157
|
+
}
|
|
3158
|
+
const pngFiles = entries.filter((name) => name.endsWith(".png") && name.startsWith("capture-"));
|
|
3159
|
+
let deletedCount = 0;
|
|
3160
|
+
let errorCount = 0;
|
|
3161
|
+
for (const filename of pngFiles) {
|
|
3162
|
+
try {
|
|
3163
|
+
const filePath = path.join(DISPLAY_CAPTURE_DIR, filename);
|
|
3164
|
+
const stats = await fs.stat(filePath);
|
|
3165
|
+
if (stats.mtime.getTime() < cutoffTime) {
|
|
3166
|
+
await fs.unlink(filePath);
|
|
3167
|
+
deletedCount++;
|
|
3168
|
+
}
|
|
3169
|
+
} catch (error) {
|
|
3170
|
+
errorCount++;
|
|
3171
|
+
this.#writeProcessLogLine(`[cleanup] failed to delete ${filename}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
this.#writeProcessLogLine(`[cleanup] completed: ${deletedCount} deleted, ${errorCount} errors, ${pngFiles.length - deletedCount - errorCount} retained`);
|
|
3175
|
+
} catch (error) {
|
|
3176
|
+
this.#writeProcessLogLine(`[cleanup] failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3137
3179
|
};
|
|
3138
3180
|
function splitCommandLine(input) {
|
|
3139
3181
|
const result = [];
|
|
@@ -3236,14 +3278,14 @@ var getMonitorStateTool = createViceTool({
|
|
|
3236
3278
|
});
|
|
3237
3279
|
var getSessionStateTool = createViceTool({
|
|
3238
3280
|
id: "get_session_state",
|
|
3239
|
-
description: "Returns
|
|
3281
|
+
description: "Returns emulator session state including transport/process status, auto-resume state, and the most recent hit checkpoint.",
|
|
3240
3282
|
inputSchema: noInputSchema,
|
|
3241
3283
|
dataSchema: sessionStateResultSchema,
|
|
3242
3284
|
execute: async () => c64Session.snapshot()
|
|
3243
3285
|
});
|
|
3244
3286
|
var getRegistersTool = createViceTool({
|
|
3245
3287
|
id: "get_registers",
|
|
3246
|
-
description:
|
|
3288
|
+
description: 'Returns the current C64 register snapshot. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3247
3289
|
inputSchema: noInputSchema,
|
|
3248
3290
|
dataSchema: z3.object({
|
|
3249
3291
|
registers: c64RegisterValueSchema
|
|
@@ -3252,7 +3294,7 @@ var getRegistersTool = createViceTool({
|
|
|
3252
3294
|
});
|
|
3253
3295
|
var setRegistersTool = createViceTool({
|
|
3254
3296
|
id: "set_registers",
|
|
3255
|
-
description:
|
|
3297
|
+
description: 'Sets one or more C64 registers by field name. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3256
3298
|
inputSchema: z3.object({
|
|
3257
3299
|
registers: c64PartialRegisterValueSchema
|
|
3258
3300
|
}),
|
|
@@ -3288,7 +3330,7 @@ var readMemoryTool = createViceTool({
|
|
|
3288
3330
|
});
|
|
3289
3331
|
var writeMemoryTool = createViceTool({
|
|
3290
3332
|
id: "memory_write",
|
|
3291
|
-
description:
|
|
3333
|
+
description: 'Writes raw byte values into the active C64 memory space. Requires emulator to be stopped - call execute(action="pause") first if running.',
|
|
3292
3334
|
inputSchema: z3.object({
|
|
3293
3335
|
address: address16Schema.describe("Start address in the 16-bit C64 address space"),
|
|
3294
3336
|
data: byteArraySchema.min(1).describe("Raw bytes to write into memory")
|
|
@@ -3404,7 +3446,7 @@ var programLoadTool = createViceTool({
|
|
|
3404
3446
|
});
|
|
3405
3447
|
var captureDisplayTool = createViceTool({
|
|
3406
3448
|
id: "capture_display",
|
|
3407
|
-
description: "Captures the current screen to a PNG file and returns the saved image path.
|
|
3449
|
+
description: "Captures the current screen to a PNG file and returns the saved image path.",
|
|
3408
3450
|
inputSchema: z3.object({
|
|
3409
3451
|
useVic: z3.boolean().default(true).describe("Whether to capture the VIC-II display when supported")
|
|
3410
3452
|
}),
|
|
@@ -3413,21 +3455,21 @@ var captureDisplayTool = createViceTool({
|
|
|
3413
3455
|
});
|
|
3414
3456
|
var getDisplayStateTool = createViceTool({
|
|
3415
3457
|
id: "get_display_state",
|
|
3416
|
-
description: "Returns screen RAM, color RAM, the current graphics mode, screen memory addresses, and the current border and background colors.
|
|
3458
|
+
description: "Returns screen RAM, color RAM, the current graphics mode, screen memory addresses, and the current border and background colors.",
|
|
3417
3459
|
inputSchema: noInputSchema,
|
|
3418
3460
|
dataSchema: displayStateResultSchema,
|
|
3419
3461
|
execute: async () => await c64Session.getDisplayState()
|
|
3420
3462
|
});
|
|
3421
3463
|
var getDisplayTextTool = createViceTool({
|
|
3422
3464
|
id: "get_display_text",
|
|
3423
|
-
description: "Returns the current text screen as readable text when the C64 is in a text mode.
|
|
3465
|
+
description: "Returns the current text screen as readable text when the C64 is in a text mode.",
|
|
3424
3466
|
inputSchema: noInputSchema,
|
|
3425
3467
|
dataSchema: displayTextResultSchema,
|
|
3426
3468
|
execute: async () => await c64Session.getDisplayText()
|
|
3427
3469
|
});
|
|
3428
3470
|
var writeTextTool = createViceTool({
|
|
3429
3471
|
id: "write_text",
|
|
3430
|
-
description:
|
|
3472
|
+
description: 'Types text into the C64. Requires emulator to be running - call execute(action="resume") first if stopped. Supports escaped characters and PETSCII brace tokens like {RETURN}, {CLR}, {HOME}, {PI}, and color names. Limit 64 bytes per request.',
|
|
3431
3473
|
inputSchema: z3.object({
|
|
3432
3474
|
text: z3.string()
|
|
3433
3475
|
}),
|
|
@@ -3439,7 +3481,7 @@ var writeTextTool = createViceTool({
|
|
|
3439
3481
|
});
|
|
3440
3482
|
var keyboardInputTool = createViceTool({
|
|
3441
3483
|
id: "keyboard_input",
|
|
3442
|
-
description:
|
|
3484
|
+
description: 'Sends one to four keys or PETSCII tokens to the C64. Requires emulator to be running - call execute(action="resume") first if stopped. Use for key presses, releases, and taps.',
|
|
3443
3485
|
inputSchema: z3.object({
|
|
3444
3486
|
action: inputActionSchema.describe("Use tap for a single key event or press/release for repeated buffered input"),
|
|
3445
3487
|
keys: z3.array(z3.string().min(1)).min(1).max(4).describe("One to four literal keys or PETSCII token names such as RETURN, CLR, HOME, PI, LEFT, RED, or F1"),
|
|
@@ -3450,7 +3492,7 @@ var keyboardInputTool = createViceTool({
|
|
|
3450
3492
|
});
|
|
3451
3493
|
var joystickInputTool = createViceTool({
|
|
3452
3494
|
id: "joystick_input",
|
|
3453
|
-
description:
|
|
3495
|
+
description: 'Sends joystick input to C64 joystick port 1 or 2. Requires emulator to be running - call execute(action="resume") first if stopped.',
|
|
3454
3496
|
inputSchema: z3.object({
|
|
3455
3497
|
port: joystickPortSchema.describe("Joystick port number"),
|
|
3456
3498
|
action: inputActionSchema.describe("Joystick action to apply"),
|